| // |
| // "$Id: image.cxx 4324 2005-05-09 21:47:22Z rokan $" |
| // |
| // Postscript image drawing implementation for the Fast Light Tool Kit (FLTK). |
| // |
| // Copyright 1998-2010 by Bill Spitzak and others. |
| // |
| // This library is free software; you can redistribute it and/or |
| // modify it under the terms of the GNU Library General Public |
| // License as published by the Free Software Foundation; either |
| // version 2 of the License, or (at your option) any later version. |
| // |
| // This library is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| // Library General Public License for more details. |
| // |
| // You should have received a copy of the GNU Library General Public |
| // License along with this library; if not, write to the Free Software |
| // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 |
| // USA. |
| // |
| // Please report all bugs and problems on the following page: |
| // |
| // http://www.fltk.org/str.php |
| // |
| |
| #ifndef FL_DOXYGEN |
| |
| #include <stdio.h> |
| #include <math.h> |
| #include <string.h> |
| |
| #include <FL/Fl_PostScript.H> |
| #include <FL/Fl.H> |
| #include <FL/Fl_Pixmap.H> |
| #include <FL/Fl_Bitmap.H> |
| |
| int Fl_PostScript_Graphics_Driver::alpha_mask(const uchar * data, int w, int h, int D, int LD){ |
| |
| mask = 0; |
| if ((D/2)*2 != D){ //no mask info |
| return 0; |
| } |
| int xx; |
| int i,j, k, l; |
| LD += w*D; |
| int V255=0; |
| int V0 =0; |
| int V_=0; |
| for (j=0;j<h;j++){ |
| for (i=0;i<w;i++) |
| switch(data[j*LD+D*i+D-1]){ |
| case 255: V255 = 1; break; |
| case 0: V0 = 1; break; |
| default: V_= 1; |
| } |
| if (V_) break; |
| }; |
| if (!V_){ |
| if (V0) |
| if (V255){// not true alpha, only masking |
| xx = (w+7)/8; |
| mask = new uchar[h * xx]; |
| for (i=0;i<h * xx;i++) mask[i]=0; |
| for (j=0;j<h;j++) |
| for (i=0;i<w;i++) |
| if (data[j*LD+D*i+D-1]) |
| mask[j*xx+i/8] |= 1 << (i % 8); |
| mx = w; |
| my = h; //mask imensions |
| return 0; |
| } else { |
| mask=0; |
| return 1; //everything masked |
| } |
| else |
| return 0; |
| } |
| |
| |
| |
| ///// Alpha dither, generating (4*w) * 4 mask area ///// |
| ///// with Floyd-Steinberg error diffusion ///// |
| |
| mask = new uchar[((w+1)/2) * h * 4]; |
| |
| for (i = 0; i<((w+1)/2) * h * 4; i++) mask[i] = 0; //cleaning |
| |
| |
| |
| mx= w*4; |
| my=h*4; // mask dimensions |
| |
| xx = (w+1)/2; // mask line width in bytes |
| |
| short * errors1 = new short [w*4+2]; // two rows of dither errors |
| short * errors2 = new short [w*4+2]; // two rows of dither errors |
| |
| for (i=0; i<w*4+2; i++) errors2[i] = 0; // cleaning,after first swap will become current |
| for (i=0; i<w*4+2; i++) errors1[i] = 0; // cleaning,after first swap will become current |
| |
| short * current = errors1; |
| short * next = errors2; |
| short * swap; |
| |
| for (j=0; j<h; j++){ |
| for (l=0; l<4; ){ // generating 4 rows of mask lines for 1 RGB line |
| int jj = j*4+l; |
| |
| /// mask row index |
| swap = next; |
| next = current; |
| current = swap; |
| *(next+1) = 0; // must clean the first cell, next are overriden by *1 |
| for (i=0; i<w; i++){ |
| for (k=0; k<4; k++){ // generating 4 x-pixels for 1 RGB |
| short error, o1, o2, o3; |
| int ii = i*4+k; // mask cell index |
| short val = data[j*LD+D*i+D-1] + current[1+ii]; |
| if (val>127){ |
| mask[jj*xx+ii/8] |= 1 << (ii % 8); //set mask bit |
| error = val-255; |
| }else |
| error = val; |
| |
| ////// error spreading ///// |
| if (error >0){ |
| next[ii] += o1 = (error * 3 + 8)/16; |
| current[ii+2] += o2 = (error * 7 + 8)/16; |
| next[ii+2] = o3 =(error + 8)/16; // *1 - ok replacing (cleaning) |
| } else { |
| next[ii] += o1 = (error * 3 - 8)/16; |
| current[ii+2] += o2 = (error * 7 - 8)/16; |
| next[ii+2] = o3 = (error - 8)/16; |
| } |
| next[1+ii] += error - o1 - o2 - o3; |
| } |
| } |
| l++; |
| |
| ////// backward |
| |
| jj = j*4+l; |
| swap = next; |
| next = current; |
| current = swap; |
| *(next+1) = 0; // must clean the first cell, next are overriden by *1 |
| |
| for (i = w-1; i >= 0; i--){ |
| |
| for (k=3; k>=0; k--){ // generating 4 x-pixels for 1 RGB |
| short error, o1, o2, o3; |
| |
| int ii = i*4+k; // mask cell index |
| short val = data[j*LD+D*i+D-1] + current[1+ii]; |
| if (val>127){ |
| |
| mask[jj*xx+ii/8] |= 1 << (ii % 8); //set mask bit |
| error = val-255; |
| } else |
| error = val; |
| |
| ////// error spreading ///// |
| if (error >0){ |
| next[ii+2] += o1 = (error * 3 + 8)/16; |
| current[ii] += o2 = (error * 7 + 8)/16; |
| next[ii] = o3 =(error + 8)/16; // *1 - ok replacing (cleaning) |
| } else { |
| next[ii+2] += o1 = (error * 3 - 8)/16; |
| |
| current[ii] += o2 = (error * 7 - 8)/16; |
| next[ii] = o3 = (error - 8)/16; |
| } |
| next[1+ii] += error - o1 - o2 - o3; |
| } |
| } |
| l++; |
| } |
| } |
| delete[] errors1; |
| delete[] errors2; |
| return 0; |
| } |
| |
| // bitwise inversion of all 4-bit quantities |
| static const unsigned char swapped[16] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15}; |
| |
| // bitwise inversion of a byte |
| static inline uchar swap_byte(const uchar b) { |
| return (swapped[b & 0xF] << 4) | swapped[b >> 4]; |
| } |
| |
| |
| extern uchar **fl_mask_bitmap; |
| |
| |
| void Fl_PostScript_Graphics_Driver::draw_image(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD) { |
| double x = ix, y = iy, w = iw, h = ih; |
| |
| if (D<3){ //mono |
| draw_image_mono(data, ix, iy, iw, ih, D, LD); |
| return; |
| } |
| |
| |
| int i,j, k; |
| |
| fprintf(output,"save\n"); |
| |
| const char * interpol; |
| if (lang_level_>1){ |
| if (interpolate_) |
| interpol="true"; |
| else |
| interpol="false"; |
| if (mask && lang_level_>2) |
| fprintf(output, "%g %g %g %g %i %i %i %i %s CIM\n", x , y+h , w , -h , iw , ih, mx, my, interpol); |
| else |
| fprintf(output, "%g %g %g %g %i %i %s CII\n", x , y+h , w , -h , iw , ih, interpol); |
| } else |
| fprintf(output , "%g %g %g %g %i %i CI", x , y+h , w , -h , iw , ih); |
| |
| |
| if (!LD) LD = iw*D; |
| uchar *curmask=mask; |
| |
| for (j=0; j<ih;j++){ |
| if (mask){ |
| |
| for (k=0;k<my/ih;k++){ |
| for (i=0; i<((mx+7)/8);i++){ |
| if (!(i%80)) fprintf(output, "\n"); |
| fprintf(output, "%.2x",swap_byte(*curmask)); |
| curmask++; |
| } |
| fprintf(output,"\n"); |
| } |
| } |
| const uchar *curdata=data+j*LD; |
| for (i=0 ; i<iw ; i++) { |
| uchar r = curdata[0]; |
| uchar g = curdata[1]; |
| uchar b = curdata[2]; |
| if (lang_level_<3 && D>3) { //can do mixing using bg_* colors) |
| unsigned int a2 = curdata[3]; //must be int |
| unsigned int a = 255-a2; |
| r = (a2 * r + bg_r * a)/255; |
| g = (a2 * g + bg_g * a)/255; |
| b = (a2 * b + bg_b * a)/255; |
| } |
| if (!(i%40)) fprintf(output, "\n"); |
| fprintf(output, "%.2x%.2x%.2x", r, g, b); |
| curdata +=D; |
| } |
| fprintf(output,"\n"); |
| |
| } |
| |
| fprintf(output," >\nrestore\n" ); |
| |
| |
| } |
| |
| void Fl_PostScript_Graphics_Driver::draw_image(Fl_Draw_Image_Cb call, void *data, int ix, int iy, int iw, int ih, int D) { |
| double x = ix, y = iy, w = iw, h = ih; |
| |
| int level2_mask = 0; |
| fprintf(output,"save\n"); |
| int i,j,k; |
| const char * interpol; |
| if (lang_level_ > 1) { |
| if (interpolate_) interpol="true"; |
| else interpol="false"; |
| if (mask && lang_level_ > 2) { |
| fprintf(output, "%g %g %g %g %i %i %i %i %s CIM\n", x , y+h , w , -h , iw , ih, mx, my, interpol); |
| } |
| else if (mask && lang_level_ == 2) { |
| level2_mask = 1; // use method for drawing masked color image with PostScript level 2 |
| fprintf(output, " %g %g %g %g %d %d pixmap_plot\n", x, y, w, h, iw, ih); |
| } |
| else { |
| fprintf(output, "%g %g %g %g %i %i %s CII\n", x , y+h , w , -h , iw , ih, interpol); |
| } |
| } else { |
| fprintf(output , "%g %g %g %g %i %i CI", x , y+h , w , -h , iw , ih); |
| } |
| |
| int LD=iw*D; |
| uchar *rgbdata=new uchar[LD]; |
| uchar *curmask=mask; |
| |
| if (level2_mask) { |
| for (j = ih - 1; j >= 0; j--) { // output full image data |
| call(data, 0, j, iw, rgbdata); |
| uchar *curdata = rgbdata; |
| for (i=0 ; i<iw ; i++) { |
| if (!(i%20)) fputs("\n", output); |
| fprintf(output, "%.2x%.2x%.2x", curdata[0], curdata[1], curdata[2]); |
| curdata += D; |
| } |
| fputs("\n", output); |
| } |
| fputs(">\n", output); |
| for (j = ih - 1; j >= 0; j--) { // output mask data |
| curmask = mask + j * (my/ih) * ((mx+7)/8); |
| for (k=0; k < my/ih; k++) { |
| for (i=0; i < ((mx+7)/8); i++) { |
| if (!(i%40)) fputs("\n", output); |
| fprintf(output, "%.2x",swap_byte(*curmask)); |
| curmask++; |
| } |
| fputs("\n", output); |
| } |
| } |
| fputs(">\n", output); |
| } |
| else { |
| for (j=0; j<ih;j++) { |
| if (mask && lang_level_ > 2) { // InterleaveType 2 mask data |
| for (k=0; k<my/ih;k++) { //for alpha pseudo-masking |
| for (i=0; i<((mx+7)/8);i++) { |
| if (!(i%40)) fputs("\n", output); |
| fprintf(output, "%.2x",swap_byte(*curmask)); |
| curmask++; |
| } |
| fprintf(output,"\n"); |
| } |
| } |
| call(data,0,j,iw,rgbdata); |
| uchar *curdata=rgbdata; |
| for (i=0 ; i<iw ; i++) { |
| uchar r = curdata[0]; |
| uchar g = curdata[1]; |
| uchar b = curdata[2]; |
| |
| if (!(i%40)) fputs("\n", output); |
| fprintf(output, "%.2x%.2x%.2x", r, g, b); |
| |
| curdata +=D; |
| } |
| fputs("\n", output); |
| |
| } |
| fputs(">\n", output); |
| } |
| |
| fprintf(output,"restore\n"); |
| delete[] rgbdata; |
| } |
| |
| void Fl_PostScript_Graphics_Driver::draw_image_mono(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD) { |
| double x = ix, y = iy, w = iw, h = ih; |
| |
| fprintf(output,"save\n"); |
| |
| int i,j, k; |
| |
| const char * interpol; |
| if (lang_level_>1){ |
| if (interpolate_) |
| interpol="true"; |
| else |
| interpol="false"; |
| if (mask && lang_level_>2) |
| fprintf(output, "%g %g %g %g %i %i %i %i %s GIM\n", x , y+h , w , -h , iw , ih, mx, my, interpol); |
| else |
| fprintf(output, "%g %g %g %g %i %i %s GII\n", x , y+h , w , -h , iw , ih, interpol); |
| }else |
| fprintf(output , "%g %g %g %g %i %i GI", x , y+h , w , -h , iw , ih); |
| |
| |
| if (!LD) LD = iw*D; |
| |
| |
| int bg = (bg_r + bg_g + bg_b)/3; |
| |
| uchar *curmask=mask; |
| for (j=0; j<ih;j++){ |
| if (mask){ |
| for (k=0;k<my/ih;k++){ |
| for (i=0; i<((mx+7)/8);i++){ |
| if (!(i%80)) fprintf(output, "\n"); |
| fprintf(output, "%.2x",swap_byte(*curmask)); |
| curmask++; |
| } |
| fprintf(output,"\n"); |
| } |
| } |
| const uchar *curdata=data+j*LD; |
| for (i=0 ; i<iw ; i++) { |
| if (!(i%80)) fprintf(output, "\n"); |
| uchar r = curdata[0]; |
| if (lang_level_<3 && D>1) { //can do mixing |
| |
| unsigned int a2 = curdata[1]; //must be int |
| unsigned int a = 255-a2; |
| r = (a2 * r + bg * a)/255; |
| } |
| if (!(i%120)) fprintf(output, "\n"); |
| fprintf(output, "%.2x", r); |
| curdata +=D; |
| } |
| fprintf(output,"\n"); |
| |
| } |
| |
| fprintf(output," >\nrestore\n" ); |
| |
| } |
| |
| |
| |
| void Fl_PostScript_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb call, void *data, int ix, int iy, int iw, int ih, int D) { |
| double x = ix, y = iy, w = iw, h = ih; |
| |
| fprintf(output,"save\n"); |
| int i,j,k; |
| const char * interpol; |
| if (lang_level_>1){ |
| if (interpolate_) interpol="true"; |
| else interpol="false"; |
| if (mask && lang_level_>2) |
| fprintf(output, "%g %g %g %g %i %i %i %i %s GIM\n", x , y+h , w , -h , iw , ih, mx, my, interpol); |
| else |
| fprintf(output, "%g %g %g %g %i %i %s GII\n", x , y+h , w , -h , iw , ih, interpol); |
| } else |
| fprintf(output , "%g %g %g %g %i %i GI", x , y+h , w , -h , iw , ih); |
| |
| int LD=iw*D; |
| uchar *rgbdata=new uchar[LD]; |
| uchar *curmask=mask; |
| for (j=0; j<ih;j++){ |
| |
| if (mask && lang_level_>2){ // InterleaveType 2 mask data |
| for (k=0; k<my/ih;k++){ //for alpha pseudo-masking |
| for (i=0; i<((mx+7)/8);i++){ |
| if (!(i%40)) fprintf(output, "\n"); |
| fprintf(output, "%.2x",swap_byte(*curmask)); |
| curmask++; |
| } |
| fprintf(output,"\n"); |
| } |
| } |
| call(data,0,j,iw,rgbdata); |
| uchar *curdata=rgbdata; |
| for (i=0 ; i<iw ; i++) { |
| uchar r = curdata[0]; |
| if (!(i%120)) fprintf(output, "\n"); |
| fprintf(output, "%.2x", r); |
| curdata +=D; |
| } |
| fprintf(output,"\n"); |
| } |
| fprintf(output,">\n"); |
| fprintf(output,"restore\n"); |
| delete[] rgbdata; |
| } |
| |
| |
| ////////////////////////////// Image classes ////////////////////// |
| |
| |
| void Fl_PostScript_Graphics_Driver::draw(Fl_Pixmap * pxm,int XP, int YP, int WP, int HP, int cx, int cy){ |
| const char * const * di =pxm->data(); |
| int w,h; |
| if (!fl_measure_pixmap(di, w, h)) return; |
| mask=0; |
| fl_mask_bitmap=&mask; |
| mx = WP; |
| my = HP; |
| push_clip(XP, YP, WP, HP); |
| fl_draw_pixmap(di,XP -cx, YP -cy, FL_BLACK ); |
| pop_clip(); |
| delete[] mask; |
| mask=0; |
| fl_mask_bitmap=0; |
| } |
| |
| void Fl_PostScript_Graphics_Driver::draw(Fl_RGB_Image * rgb,int XP, int YP, int WP, int HP, int cx, int cy){ |
| const uchar * di = rgb->array; |
| int w = rgb->w(); |
| int h = rgb->h(); |
| mask=0; |
| if (lang_level_>2) //when not true, not making alphamask, mixing colors instead... |
| if (alpha_mask(di, w, h, rgb->d(),rgb->ld())) return; //everthing masked, no need for painting! |
| push_clip(XP, YP, WP, HP); |
| draw_image(di, XP + cx, YP + cy, w, h, rgb->d(), rgb->ld()); |
| pop_clip(); |
| delete[]mask; |
| mask=0; |
| } |
| |
| void Fl_PostScript_Graphics_Driver::draw(Fl_Bitmap * bitmap,int XP, int YP, int WP, int HP, int cx, int cy){ |
| const uchar * di = bitmap->array; |
| int w,h; |
| int LD=(bitmap->w()+7)/8; |
| int xx; |
| |
| if (WP> bitmap->w() - cx){// to assure that it does not go out of bounds; |
| w = bitmap->w() - cx; |
| xx = (bitmap->w()+7)/8 - cx/8; //length of mask in bytes |
| }else{ |
| w =WP; |
| xx = (w+7)/8 - cx/8; |
| } |
| if ( HP > bitmap->h()-cy) |
| h = bitmap->h() - cy; |
| else |
| h = HP; |
| |
| di += cy*LD + cx/8; |
| int si = cx % 8; // small shift to be clipped, it is simpler than shifting whole mask |
| |
| int i,j; |
| push_clip(XP, YP, WP, HP); |
| fprintf(output , "%i %i %i %i %i %i MI", XP - si, YP + HP , WP , -HP , w , h); |
| |
| for (j=0; j<HP; j++){ |
| for (i=0; i<xx; i++){ |
| if (!(i%80)) fprintf(output, "\n"); // not have lines longer than 255 chars |
| fprintf(output, "%.2x", swap_byte(*di) ); |
| di++; |
| } |
| fprintf(output,"\n"); |
| } |
| fprintf(output,">\n"); |
| pop_clip(); |
| } |
| |
| #endif // FL_DOXYGEN |
| |
| // |
| // End of "$Id: image.cxx 4324 2005-05-09 21:47:22Z rokan $" |
| // |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |