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