1 //
2 // "$Id: image.cxx 4324 2005-05-09 21:47:22Z rokan $"
3 //
4 // Postscript image drawing implementation for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2010 by Bill Spitzak and others.
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // Library General Public License for more details.
17 //
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 // USA.
22 //
23 // Please report all bugs and problems on the following page:
24 //
25 //     http://www.fltk.org/str.php
26 //
27 
28 #ifndef FL_DOXYGEN
29 
30 #include <stdio.h>
31 #include <math.h>
32 #include <string.h>
33 
34 #include <FL/Fl_PostScript.H>
35 #include <FL/Fl.H>
36 #include <FL/Fl_Pixmap.H>
37 #include <FL/Fl_Bitmap.H>
38 
alpha_mask(const uchar * data,int w,int h,int D,int LD)39 int Fl_PostScript_Graphics_Driver::alpha_mask(const uchar * data, int w, int h, int D, int LD){
40 
41   mask = 0;
42   if ((D/2)*2 != D){ //no mask info
43     return 0;
44   }
45   int xx;
46   int i,j, k, l;
47   LD += w*D;
48   int V255=0;
49   int V0 =0;
50   int V_=0;
51   for (j=0;j<h;j++){
52     for (i=0;i<w;i++)
53       switch(data[j*LD+D*i+D-1]){
54         case 255: V255 = 1; break;
55         case 0: V0 = 1; break;
56         default: V_= 1;
57       }
58     if (V_) break;
59   };
60   if (!V_){
61     if (V0)
62       if (V255){// not true alpha, only masking
63         xx = (w+7)/8;
64         mask = new uchar[h * xx];
65         for (i=0;i<h * xx;i++) mask[i]=0;
66         for (j=0;j<h;j++)
67           for (i=0;i<w;i++)
68             if (data[j*LD+D*i+D-1])
69               mask[j*xx+i/8] |= 1 << (i % 8);
70         mx = w;
71         my = h; //mask imensions
72         return 0;
73       } else {
74         mask=0;
75         return 1; //everything masked
76       }
77     else
78       return 0;
79   }
80 
81 
82 
83   /////   Alpha dither, generating (4*w) * 4 mask area       /////
84   /////         with Floyd-Steinberg error diffusion         /////
85 
86   mask = new uchar[((w+1)/2) * h * 4];
87 
88   for (i = 0; i<((w+1)/2) * h * 4; i++) mask[i] = 0; //cleaning
89 
90 
91 
92   mx= w*4;
93   my=h*4; // mask dimensions
94 
95   xx = (w+1)/2;                //  mask line width in bytes
96 
97   short * errors1 = new short [w*4+2]; //  two rows of dither errors
98   short * errors2 = new short [w*4+2]; //  two rows of dither errors
99 
100   for (i=0; i<w*4+2; i++) errors2[i] = 0; // cleaning,after first swap will become current
101   for (i=0; i<w*4+2; i++) errors1[i] = 0; // cleaning,after first swap will become current
102 
103   short * current = errors1;
104   short * next = errors2;
105   short * swap;
106 
107   for (j=0; j<h; j++){
108     for (l=0; l<4; ){           // generating 4 rows of mask lines for 1 RGB line
109       int jj = j*4+l;
110 
111       /// mask row index
112       swap = next;
113       next = current;
114       current = swap;
115       *(next+1) = 0;          // must clean the first cell, next are overriden by *1
116       for (i=0; i<w; i++){
117         for (k=0; k<4; k++){   // generating 4 x-pixels for 1 RGB
118           short error, o1, o2, o3;
119           int ii = i*4+k;   // mask cell index
120           short val = data[j*LD+D*i+D-1] + current[1+ii];
121           if (val>127){
122             mask[jj*xx+ii/8]  |= 1 << (ii % 8); //set mask bit
123             error =  val-255;
124           }else
125             error = val;
126 
127           ////// error spreading /////
128           if (error >0){
129             next[ii] +=  o1 = (error * 3 + 8)/16;
130             current[ii+2] += o2 = (error * 7 + 8)/16;
131             next[ii+2] = o3 =(error + 8)/16;  // *1 - ok replacing (cleaning)
132           } else {
133             next[ii] += o1 = (error * 3 - 8)/16;
134             current[ii+2] += o2 = (error * 7 - 8)/16;
135             next[ii+2] = o3 = (error - 8)/16;
136           }
137           next[1+ii] += error - o1 - o2 - o3;
138         }
139       }
140       l++;
141 
142       ////// backward
143 
144       jj = j*4+l;
145       swap = next;
146       next = current;
147       current = swap;
148       *(next+1) = 0;          // must clean the first cell, next are overriden by *1
149 
150       for (i = w-1; i >= 0; i--){
151 
152         for (k=3; k>=0; k--){   // generating 4 x-pixels for 1 RGB
153           short error, o1, o2, o3;
154 
155           int ii = i*4+k;   // mask cell index
156           short val = data[j*LD+D*i+D-1] + current[1+ii];
157           if (val>127){
158 
159             mask[jj*xx+ii/8]  |= 1 << (ii % 8); //set mask bit
160             error =  val-255;
161           } else
162             error = val;
163 
164           ////// error spreading /////
165           if (error >0){
166             next[ii+2] +=  o1 = (error * 3 + 8)/16;
167             current[ii] += o2 = (error * 7 + 8)/16;
168             next[ii] = o3 =(error + 8)/16;  // *1 - ok replacing (cleaning)
169           } else {
170             next[ii+2] += o1 = (error * 3 - 8)/16;
171 
172             current[ii] += o2 = (error * 7 - 8)/16;
173             next[ii] = o3 = (error - 8)/16;
174           }
175           next[1+ii] += error - o1 - o2 - o3;
176         }
177       }
178       l++;
179     }
180   }
181   delete[] errors1;
182   delete[] errors2;
183   return 0;
184 }
185 
186 // bitwise inversion of all 4-bit quantities
187 static const unsigned char swapped[16] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15};
188 
189 // bitwise inversion of a byte
swap_byte(const uchar b)190 static inline uchar swap_byte(const uchar b) {
191   return (swapped[b & 0xF] << 4) | swapped[b >> 4];
192 }
193 
194 
195 extern uchar **fl_mask_bitmap;
196 
197 
draw_image(const uchar * data,int ix,int iy,int iw,int ih,int D,int LD)198 void Fl_PostScript_Graphics_Driver::draw_image(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD) {
199   double x = ix, y = iy, w = iw, h = ih;
200 
201   if (D<3){ //mono
202     draw_image_mono(data, ix, iy, iw, ih, D, LD);
203     return;
204   }
205 
206 
207   int i,j, k;
208 
209   fprintf(output,"save\n");
210 
211   const char * interpol;
212   if (lang_level_>1){
213     if (interpolate_)
214       interpol="true";
215     else
216       interpol="false";
217     if (mask && lang_level_>2)
218       fprintf(output, "%g %g %g %g %i %i %i %i %s CIM\n", x , y+h , w , -h , iw , ih, mx, my, interpol);
219     else
220       fprintf(output, "%g %g %g %g %i %i %s CII\n", x , y+h , w , -h , iw , ih, interpol);
221   } else
222     fprintf(output , "%g %g %g %g %i %i CI", x , y+h , w , -h , iw , ih);
223 
224 
225   if (!LD) LD = iw*D;
226   uchar *curmask=mask;
227 
228   for (j=0; j<ih;j++){
229     if (mask){
230 
231       for (k=0;k<my/ih;k++){
232         for (i=0; i<((mx+7)/8);i++){
233           if (!(i%80)) fprintf(output, "\n");
234           fprintf(output, "%.2x",swap_byte(*curmask));
235           curmask++;
236         }
237         fprintf(output,"\n");
238       }
239     }
240     const uchar *curdata=data+j*LD;
241     for (i=0 ; i<iw ; i++) {
242       uchar r = curdata[0];
243       uchar g =  curdata[1];
244       uchar b =  curdata[2];
245       if (lang_level_<3 && D>3) { //can do  mixing using bg_* colors)
246         unsigned int a2 = curdata[3]; //must be int
247         unsigned int a = 255-a2;
248         r = (a2 * r + bg_r * a)/255;
249         g = (a2 * g + bg_g * a)/255;
250         b = (a2 * b + bg_b * a)/255;
251       }
252       if (!(i%40)) fprintf(output, "\n");
253       fprintf(output, "%.2x%.2x%.2x", r, g, b);
254       curdata +=D;
255     }
256     fprintf(output,"\n");
257 
258   }
259 
260   fprintf(output," >\nrestore\n" );
261 
262 
263 }
264 
draw_image(Fl_Draw_Image_Cb call,void * data,int ix,int iy,int iw,int ih,int D)265 void Fl_PostScript_Graphics_Driver::draw_image(Fl_Draw_Image_Cb call, void *data, int ix, int iy, int iw, int ih, int D) {
266   double x = ix, y = iy, w = iw, h = ih;
267 
268   int level2_mask = 0;
269   fprintf(output,"save\n");
270   int i,j,k;
271   const char * interpol;
272   if (lang_level_ > 1) {
273     if (interpolate_) interpol="true";
274     else interpol="false";
275     if (mask && lang_level_ > 2) {
276       fprintf(output, "%g %g %g %g %i %i %i %i %s CIM\n", x , y+h , w , -h , iw , ih, mx, my, interpol);
277       }
278     else if (mask && lang_level_ == 2) {
279       level2_mask = 1; // use method for drawing masked color image with PostScript level 2
280       fprintf(output, " %g %g %g %g %d %d pixmap_plot\n", x, y, w, h, iw, ih);
281     }
282     else {
283       fprintf(output, "%g %g %g %g %i %i %s CII\n", x , y+h , w , -h , iw , ih, interpol);
284       }
285   } else {
286     fprintf(output , "%g %g %g %g %i %i CI", x , y+h , w , -h , iw , ih);
287     }
288 
289   int LD=iw*D;
290   uchar *rgbdata=new uchar[LD];
291   uchar *curmask=mask;
292 
293   if (level2_mask) {
294     for (j = ih - 1; j >= 0; j--) { // output full image data
295       call(data, 0, j, iw, rgbdata);
296       uchar *curdata = rgbdata;
297       for (i=0 ; i<iw ; i++) {
298 	if (!(i%20)) fputs("\n", output);
299 	fprintf(output, "%.2x%.2x%.2x", curdata[0], curdata[1], curdata[2]);
300 	curdata += D;
301 	}
302       fputs("\n", output);
303       }
304     fputs(">\n", output);
305     for (j = ih - 1; j >= 0; j--) { // output mask data
306       curmask = mask + j * (my/ih) * ((mx+7)/8);
307       for (k=0; k < my/ih; k++) {
308 	for (i=0; i < ((mx+7)/8); i++) {
309 	  if (!(i%40)) fputs("\n", output);
310 	  fprintf(output, "%.2x",swap_byte(*curmask));
311 	  curmask++;
312 	}
313 	fputs("\n", output);
314       }
315     }
316     fputs(">\n", output);
317   }
318   else {
319     for (j=0; j<ih;j++) {
320       if (mask && lang_level_ > 2) {  // InterleaveType 2 mask data
321 	for (k=0; k<my/ih;k++) { //for alpha pseudo-masking
322 	  for (i=0; i<((mx+7)/8);i++) {
323 	    if (!(i%40)) fputs("\n", output);
324 	    fprintf(output, "%.2x",swap_byte(*curmask));
325 	    curmask++;
326 	  }
327 	  fprintf(output,"\n");
328 	}
329       }
330       call(data,0,j,iw,rgbdata);
331       uchar *curdata=rgbdata;
332       for (i=0 ; i<iw ; i++) {
333 	uchar r = curdata[0];
334 	uchar g =  curdata[1];
335 	uchar b =  curdata[2];
336 
337 	if (!(i%40)) 	fputs("\n", output);
338 	fprintf(output, "%.2x%.2x%.2x", r, g, b);
339 
340 	curdata +=D;
341       }
342       fputs("\n", output);
343 
344     }
345     fputs(">\n", output);
346     }
347 
348   fprintf(output,"restore\n");
349   delete[] rgbdata;
350 }
351 
draw_image_mono(const uchar * data,int ix,int iy,int iw,int ih,int D,int LD)352 void Fl_PostScript_Graphics_Driver::draw_image_mono(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD) {
353   double x = ix, y = iy, w = iw, h = ih;
354 
355   fprintf(output,"save\n");
356 
357   int i,j, k;
358 
359   const char * interpol;
360   if (lang_level_>1){
361     if (interpolate_)
362       interpol="true";
363     else
364       interpol="false";
365     if (mask && lang_level_>2)
366       fprintf(output, "%g %g %g %g %i %i %i %i %s GIM\n", x , y+h , w , -h , iw , ih, mx, my, interpol);
367     else
368       fprintf(output, "%g %g %g %g %i %i %s GII\n", x , y+h , w , -h , iw , ih, interpol);
369   }else
370     fprintf(output , "%g %g %g %g %i %i GI", x , y+h , w , -h , iw , ih);
371 
372 
373   if (!LD) LD = iw*D;
374 
375 
376   int bg = (bg_r + bg_g + bg_b)/3;
377 
378   uchar *curmask=mask;
379   for (j=0; j<ih;j++){
380     if (mask){
381       for (k=0;k<my/ih;k++){
382         for (i=0; i<((mx+7)/8);i++){
383           if (!(i%80)) fprintf(output, "\n");
384           fprintf(output, "%.2x",swap_byte(*curmask));
385           curmask++;
386         }
387         fprintf(output,"\n");
388       }
389     }
390     const uchar *curdata=data+j*LD;
391     for (i=0 ; i<iw ; i++) {
392       if (!(i%80)) fprintf(output, "\n");
393       uchar r = curdata[0];
394       if (lang_level_<3 && D>1) { //can do  mixing
395 
396         unsigned int a2 = curdata[1]; //must be int
397         unsigned int a = 255-a2;
398         r = (a2 * r + bg * a)/255;
399       }
400       if (!(i%120)) fprintf(output, "\n");
401       fprintf(output, "%.2x", r);
402       curdata +=D;
403     }
404     fprintf(output,"\n");
405 
406   }
407 
408   fprintf(output," >\nrestore\n" );
409 
410 }
411 
412 
413 
draw_image_mono(Fl_Draw_Image_Cb call,void * data,int ix,int iy,int iw,int ih,int D)414 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) {
415   double x = ix, y = iy, w = iw, h = ih;
416 
417   fprintf(output,"save\n");
418   int i,j,k;
419   const char * interpol;
420   if (lang_level_>1){
421     if (interpolate_) interpol="true";
422     else interpol="false";
423     if (mask && lang_level_>2)
424       fprintf(output, "%g %g %g %g %i %i %i %i %s GIM\n", x , y+h , w , -h , iw , ih, mx, my, interpol);
425     else
426       fprintf(output, "%g %g %g %g %i %i %s GII\n", x , y+h , w , -h , iw , ih, interpol);
427   } else
428     fprintf(output , "%g %g %g %g %i %i GI", x , y+h , w , -h , iw , ih);
429 
430   int LD=iw*D;
431   uchar *rgbdata=new uchar[LD];
432   uchar *curmask=mask;
433   for (j=0; j<ih;j++){
434 
435     if (mask && lang_level_>2){  // InterleaveType 2 mask data
436       for (k=0; k<my/ih;k++){ //for alpha pseudo-masking
437         for (i=0; i<((mx+7)/8);i++){
438           if (!(i%40)) fprintf(output, "\n");
439           fprintf(output, "%.2x",swap_byte(*curmask));
440           curmask++;
441         }
442         fprintf(output,"\n");
443       }
444     }
445     call(data,0,j,iw,rgbdata);
446     uchar *curdata=rgbdata;
447     for (i=0 ; i<iw ; i++) {
448       uchar r = curdata[0];
449       if (!(i%120)) fprintf(output, "\n");
450       fprintf(output, "%.2x", r);
451       curdata +=D;
452     }
453     fprintf(output,"\n");
454   }
455   fprintf(output,">\n");
456   fprintf(output,"restore\n");
457   delete[] rgbdata;
458 }
459 
460 
461 ////////////////////////////// Image classes //////////////////////
462 
463 
draw(Fl_Pixmap * pxm,int XP,int YP,int WP,int HP,int cx,int cy)464 void Fl_PostScript_Graphics_Driver::draw(Fl_Pixmap * pxm,int XP, int YP, int WP, int HP, int cx, int cy){
465   const char * const * di =pxm->data();
466   int w,h;
467   if (!fl_measure_pixmap(di, w, h)) return;
468   mask=0;
469   fl_mask_bitmap=&mask;
470   mx = WP;
471   my = HP;
472   push_clip(XP, YP, WP, HP);
473   fl_draw_pixmap(di,XP -cx, YP -cy, FL_BLACK );
474   pop_clip();
475   delete[] mask;
476   mask=0;
477   fl_mask_bitmap=0;
478 }
479 
draw(Fl_RGB_Image * rgb,int XP,int YP,int WP,int HP,int cx,int cy)480 void Fl_PostScript_Graphics_Driver::draw(Fl_RGB_Image * rgb,int XP, int YP, int WP, int HP, int cx, int cy){
481   const uchar  * di = rgb->array;
482   int w = rgb->w();
483   int h = rgb->h();
484   mask=0;
485   if (lang_level_>2) //when not true, not making alphamask, mixing colors instead...
486   if (alpha_mask(di, w, h, rgb->d(),rgb->ld())) return; //everthing masked, no need for painting!
487   push_clip(XP, YP, WP, HP);
488   draw_image(di, XP + cx, YP + cy, w, h, rgb->d(), rgb->ld());
489   pop_clip();
490   delete[]mask;
491   mask=0;
492 }
493 
draw(Fl_Bitmap * bitmap,int XP,int YP,int WP,int HP,int cx,int cy)494 void Fl_PostScript_Graphics_Driver::draw(Fl_Bitmap * bitmap,int XP, int YP, int WP, int HP, int cx, int cy){
495   const uchar  * di = bitmap->array;
496   int w,h;
497   int LD=(bitmap->w()+7)/8;
498   int xx;
499 
500   if (WP> bitmap->w() - cx){// to assure that it does not go out of bounds;
501      w = bitmap->w() - cx;
502      xx = (bitmap->w()+7)/8 - cx/8; //length of mask in bytes
503   }else{
504     w =WP;
505     xx = (w+7)/8 - cx/8;
506   }
507   if ( HP > bitmap->h()-cy)
508     h = bitmap->h() - cy;
509   else
510     h = HP;
511 
512   di += cy*LD + cx/8;
513   int si = cx % 8; // small shift to be clipped, it is simpler than shifting whole mask
514 
515   int i,j;
516   push_clip(XP, YP, WP, HP);
517   fprintf(output , "%i %i %i %i %i %i MI", XP - si, YP + HP , WP , -HP , w , h);
518 
519   for (j=0; j<HP; j++){
520     for (i=0; i<xx; i++){
521       if (!(i%80)) fprintf(output, "\n"); // not have lines longer than 255 chars
522       fprintf(output, "%.2x", swap_byte(*di) );
523       di++;
524     }
525     fprintf(output,"\n");
526   }
527   fprintf(output,">\n");
528   pop_clip();
529 }
530 
531 #endif // FL_DOXYGEN
532 
533 //
534 // End of "$Id: image.cxx 4324 2005-05-09 21:47:22Z rokan $"
535 //
536 
537 
538 
539 
540 
541 
542 
543 
544 
545 
546 
547 
548 
549 
550 
551 
552 
553 
554