1 //
2 // "$Id: fl_draw_image.cxx 8731 2011-05-23 21:05:22Z AlbrechtS $"
3 //
4 // Image drawing routines 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 // I hope a simple and portable method of drawing color and monochrome
29 // images.  To keep this simple, only a single storage type is
30 // supported: 8 bit unsigned data, byte order RGB, and pixels are
31 // stored packed into rows with the origin at the top-left.  It is
32 // possible to alter the size of pixels with the "delta" argument, to
33 // add alpha or other information per pixel.  It is also possible to
34 // change the origin and direction of the image data by messing with
35 // the "delta" and "linedelta", making them negative, though this may
36 // defeat some of the shortcuts in translating the image for X.
37 
38 #ifdef WIN32
39 #  include "fl_draw_image_win32.cxx"
40 #elif defined(__APPLE__)
41 #  include "fl_draw_image_mac.cxx"
42 #else
43 
44 // A list of assumptions made about the X display:
45 
46 // bits_per_pixel must be one of 8, 16, 24, 32.
47 
48 // scanline_pad must be a power of 2 and greater or equal to 8.
49 
50 // PsuedoColor visuals must have 8 bits_per_pixel (although the depth
51 // may be less than 8).  This is the only limitation that affects any
52 // modern X displays, you can't use 12 or 16 bit colormaps.
53 
54 // The mask bits in TrueColor visuals for each color are
55 // contiguous and have at least one bit of each color.  This
56 // is not checked for.
57 
58 // For 24 and 32 bit visuals there must be at least 8 bits of each color.
59 
60 ////////////////////////////////////////////////////////////////
61 
62 #  include <FL/Fl.H>
63 #  include <FL/fl_draw.H>
64 #  include <FL/x.H>
65 #  include "Fl_XColor.H"
66 #  include "flstring.h"
67 
68 static XImage xi;	// template used to pass info to X
69 static int bytes_per_pixel;
70 static int scanline_add;
71 static int scanline_mask;
72 
73 static void (*converter)(const uchar *from, uchar *to, int w, int delta);
74 static void (*mono_converter)(const uchar *from, uchar *to, int w, int delta);
75 
76 static int dir;		// direction-alternator
77 static int ri,gi,bi;	// saved error-diffusion value
78 
79 #  if USE_COLORMAP
80 ////////////////////////////////////////////////////////////////
81 // 8-bit converter with error diffusion
82 
color8_converter(const uchar * from,uchar * to,int w,int delta)83 static void color8_converter(const uchar *from, uchar *to, int w, int delta) {
84   int r=ri, g=gi, b=bi;
85   int d, td;
86   if (dir) {
87     dir = 0;
88     from = from+(w-1)*delta;
89     to = to+(w-1);
90     d = -delta;
91     td = -1;
92   } else {
93     dir = 1;
94     d = delta;
95     td = 1;
96   }
97   for (; w--; from += d, to += td) {
98     r += from[0]; if (r < 0) r = 0; else if (r>255) r = 255;
99     g += from[1]; if (g < 0) g = 0; else if (g>255) g = 255;
100     b += from[2]; if (b < 0) b = 0; else if (b>255) b = 255;
101     Fl_Color i = fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256);
102     Fl_XColor& xmap = fl_xmap[0][i];
103     if (!xmap.mapped) {if (!fl_redmask) fl_xpixel(r,g,b); else fl_xpixel(i);}
104     r -= xmap.r;
105     g -= xmap.g;
106     b -= xmap.b;
107     *to = uchar(xmap.pixel);
108   }
109   ri = r; gi = g; bi = b;
110 }
111 
mono8_converter(const uchar * from,uchar * to,int w,int delta)112 static void mono8_converter(const uchar *from, uchar *to, int w, int delta) {
113   int r=ri, g=gi, b=bi;
114   int d, td;
115   if (dir) {
116     dir = 0;
117     from = from+(w-1)*delta;
118     to = to+(w-1);
119     d = -delta;
120     td = -1;
121   } else {
122     dir = 1;
123     d = delta;
124     td = 1;
125   }
126   for (; w--; from += d, to += td) {
127     r += from[0]; if (r < 0) r = 0; else if (r>255) r = 255;
128     g += from[0]; if (g < 0) g = 0; else if (g>255) g = 255;
129     b += from[0]; if (b < 0) b = 0; else if (b>255) b = 255;
130     Fl_Color i = fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256);
131     Fl_XColor& xmap = fl_xmap[0][i];
132     if (!xmap.mapped) {if (!fl_redmask) fl_xpixel(r,g,b); else fl_xpixel(i);}
133     r -= xmap.r;
134     g -= xmap.g;
135     b -= xmap.b;
136     *to = uchar(xmap.pixel);
137   }
138   ri = r; gi = g; bi = b;
139 }
140 
141 #  endif
142 
143 ////////////////////////////////////////////////////////////////
144 // 16 bit TrueColor converters with error diffusion
145 // Cray computers have no 16-bit type, so we use character pointers
146 // (which may be slow)
147 
148 #  ifdef U16
149 #    define OUTTYPE U16
150 #    define OUTSIZE 1
151 #    define OUTASSIGN(v) *t = v
152 #  else
153 #    define OUTTYPE uchar
154 #    define OUTSIZE 2
155 #    define OUTASSIGN(v) int tt=v; t[0] = uchar(tt>>8); t[1] = uchar(tt)
156 #  endif
157 
color16_converter(const uchar * from,uchar * to,int w,int delta)158 static void color16_converter(const uchar *from, uchar *to, int w, int delta) {
159   OUTTYPE *t = (OUTTYPE *)to;
160   int d, td;
161   if (dir) {
162     dir = 0;
163     from = from+(w-1)*delta;
164     t = t+(w-1)*OUTSIZE;
165     d = -delta;
166     td = -OUTSIZE;
167   } else {
168     dir = 1;
169     d = delta;
170     td = OUTSIZE;
171   }
172   int r=ri, g=gi, b=bi;
173   for (; w--; from += d, t += td) {
174     r = (r&~fl_redmask)  +from[0]; if (r>255) r = 255;
175     g = (g&~fl_greenmask)+from[1]; if (g>255) g = 255;
176     b = (b&~fl_bluemask) +from[2]; if (b>255) b = 255;
177     OUTASSIGN((
178       ((r&fl_redmask)<<fl_redshift)+
179       ((g&fl_greenmask)<<fl_greenshift)+
180       ((b&fl_bluemask)<<fl_blueshift)
181       ) >> fl_extrashift);
182   }
183   ri = r; gi = g; bi = b;
184 }
185 
mono16_converter(const uchar * from,uchar * to,int w,int delta)186 static void mono16_converter(const uchar *from,uchar *to,int w, int delta) {
187   OUTTYPE *t = (OUTTYPE *)to;
188   int d, td;
189   if (dir) {
190     dir = 0;
191     from = from+(w-1)*delta;
192     t = t+(w-1)*OUTSIZE;
193     d = -delta;
194     td = -OUTSIZE;
195   } else {
196     dir = 1;
197     d = delta;
198     td = OUTSIZE;
199   }
200   uchar mask = fl_redmask & fl_greenmask & fl_bluemask;
201   int r=ri;
202   for (; w--; from += d, t += td) {
203     r = (r&~mask) + *from; if (r > 255) r = 255;
204     uchar m = r&mask;
205     OUTASSIGN((
206       (m<<fl_redshift)+
207       (m<<fl_greenshift)+
208       (m<<fl_blueshift)
209       ) >> fl_extrashift);
210   }
211   ri = r;
212 }
213 
214 // special-case the 5r6g5b layout used by XFree86:
215 
c565_converter(const uchar * from,uchar * to,int w,int delta)216 static void c565_converter(const uchar *from, uchar *to, int w, int delta) {
217   OUTTYPE *t = (OUTTYPE *)to;
218   int d, td;
219   if (dir) {
220     dir = 0;
221     from = from+(w-1)*delta;
222     t = t+(w-1)*OUTSIZE;
223     d = -delta;
224     td = -OUTSIZE;
225   } else {
226     dir = 1;
227     d = delta;
228     td = OUTSIZE;
229   }
230   int r=ri, g=gi, b=bi;
231   for (; w--; from += d, t += td) {
232     r = (r&7)+from[0]; if (r>255) r = 255;
233     g = (g&3)+from[1]; if (g>255) g = 255;
234     b = (b&7)+from[2]; if (b>255) b = 255;
235     OUTASSIGN(((r&0xf8)<<8) + ((g&0xfc)<<3) + (b>>3));
236   }
237   ri = r; gi = g; bi = b;
238 }
239 
m565_converter(const uchar * from,uchar * to,int w,int delta)240 static void m565_converter(const uchar *from,uchar *to,int w, int delta) {
241   OUTTYPE *t = (OUTTYPE *)to;
242   int d, td;
243   if (dir) {
244     dir = 0;
245     from = from+(w-1)*delta;
246     t = t+(w-1)*OUTSIZE;
247     d = -delta;
248     td = -OUTSIZE;
249   } else {
250     dir = 1;
251     d = delta;
252     td = OUTSIZE;
253   }
254   int r=ri;
255   for (; w--; from += d, t += td) {
256     r = (r&7) + *from; if (r > 255) r = 255;
257     OUTASSIGN((r>>3) * 0x841);
258   }
259   ri = r;
260 }
261 
262 ////////////////////////////////////////////////////////////////
263 // 24bit TrueColor converters:
264 
rgb_converter(const uchar * from,uchar * to,int w,int delta)265 static void rgb_converter(const uchar *from, uchar *to, int w, int delta) {
266   int d = delta-3;
267   for (; w--; from += d) {
268     *to++ = *from++;
269     *to++ = *from++;
270     *to++ = *from++;
271   }
272 }
273 
bgr_converter(const uchar * from,uchar * to,int w,int delta)274 static void bgr_converter(const uchar *from, uchar *to, int w, int delta) {
275   for (; w--; from += delta) {
276     uchar r = from[0];
277     uchar g = from[1];
278     *to++ = from[2];
279     *to++ = g;
280     *to++ = r;
281   }
282 }
283 
rrr_converter(const uchar * from,uchar * to,int w,int delta)284 static void rrr_converter(const uchar *from, uchar *to, int w, int delta) {
285   for (; w--; from += delta) {
286     *to++ = *from;
287     *to++ = *from;
288     *to++ = *from;
289   }
290 }
291 
292 ////////////////////////////////////////////////////////////////
293 // 32bit TrueColor converters on a 32 or 64-bit machine:
294 
295 #    define STORETYPE U32
296 #    define INNARDS32(f) \
297   U32 *t = (U32*)to; for (; w--; from += delta) *t++ = f
298 
rgbx_converter(const uchar * from,uchar * to,int w,int delta)299 static void rgbx_converter(const uchar *from, uchar *to, int w, int delta) {
300   INNARDS32((unsigned(from[0])<<24)+(from[1]<<16)+(from[2]<<8));
301 }
302 
xbgr_converter(const uchar * from,uchar * to,int w,int delta)303 static void xbgr_converter(const uchar *from, uchar *to, int w, int delta) {
304   INNARDS32((from[0])+(from[1]<<8)+(from[2]<<16));
305 }
306 
xrgb_converter(const uchar * from,uchar * to,int w,int delta)307 static void xrgb_converter(const uchar *from, uchar *to, int w, int delta) {
308   INNARDS32((from[0]<<16)+(from[1]<<8)+(from[2]));
309 }
310 
bgrx_converter(const uchar * from,uchar * to,int w,int delta)311 static void bgrx_converter(const uchar *from, uchar *to, int w, int delta) {
312   INNARDS32((from[0]<<8)+(from[1]<<16)+(unsigned(from[2])<<24));
313 }
314 
rrrx_converter(const uchar * from,uchar * to,int w,int delta)315 static void rrrx_converter(const uchar *from, uchar *to, int w, int delta) {
316   INNARDS32(unsigned(*from) * 0x1010100U);
317 }
318 
xrrr_converter(const uchar * from,uchar * to,int w,int delta)319 static void xrrr_converter(const uchar *from, uchar *to, int w, int delta) {
320   INNARDS32(*from * 0x10101U);
321 }
322 
323 static void
color32_converter(const uchar * from,uchar * to,int w,int delta)324 color32_converter(const uchar *from, uchar *to, int w, int delta) {
325   INNARDS32(
326     (from[0]<<fl_redshift)+(from[1]<<fl_greenshift)+(from[2]<<fl_blueshift));
327 }
328 
329 static void
mono32_converter(const uchar * from,uchar * to,int w,int delta)330 mono32_converter(const uchar *from,uchar *to,int w, int delta) {
331   INNARDS32(
332     (*from << fl_redshift)+(*from << fl_greenshift)+(*from << fl_blueshift));
333 }
334 
335 ////////////////////////////////////////////////////////////////
336 
figure_out_visual()337 static void figure_out_visual() {
338 
339   fl_xpixel(FL_BLACK); // setup fl_redmask, etc, in fl_color.cxx
340   fl_xpixel(FL_WHITE); // also make sure white is allocated
341 
342   static XPixmapFormatValues *pfvlist;
343   static int FL_NUM_pfv;
344   if (!pfvlist) pfvlist = XListPixmapFormats(fl_display,&FL_NUM_pfv);
345   XPixmapFormatValues *pfv;
346   for (pfv = pfvlist; pfv < pfvlist+FL_NUM_pfv; pfv++)
347     if (pfv->depth == fl_visual->depth) break;
348   xi.format = ZPixmap;
349   xi.byte_order = ImageByteOrder(fl_display);
350 //i.bitmap_unit = 8;
351 //i.bitmap_bit_order = MSBFirst;
352 //i.bitmap_pad = 8;
353   xi.depth = fl_visual->depth;
354   xi.bits_per_pixel = pfv->bits_per_pixel;
355 
356   if (xi.bits_per_pixel & 7) bytes_per_pixel = 0; // produce fatal error
357   else bytes_per_pixel = xi.bits_per_pixel/8;
358 
359   unsigned int n = pfv->scanline_pad/8;
360   if (pfv->scanline_pad & 7 || (n&(n-1)))
361     Fl::fatal("Can't do scanline_pad of %d",pfv->scanline_pad);
362   if (n < sizeof(STORETYPE)) n = sizeof(STORETYPE);
363   scanline_add = n-1;
364   scanline_mask = -n;
365 
366 #  if USE_COLORMAP
367   if (bytes_per_pixel == 1) {
368     converter = color8_converter;
369     mono_converter = mono8_converter;
370     return;
371   }
372   if (!fl_visual->red_mask)
373     Fl::fatal("Can't do %d bits_per_pixel colormap",xi.bits_per_pixel);
374 #  endif
375 
376   // otherwise it is a TrueColor visual:
377 
378   int rs = fl_redshift;
379   int gs = fl_greenshift;
380   int bs = fl_blueshift;
381 
382   switch (bytes_per_pixel) {
383 
384   case 2:
385     // All 16-bit TrueColor visuals are supported on any machine with
386     // 24 or more bits per integer.
387 #  ifdef U16
388     xi.byte_order = WORDS_BIGENDIAN;
389 #  else
390     xi.byte_order = 1;
391 #  endif
392     if (rs == 11 && gs == 6 && bs == 0 && fl_extrashift == 3) {
393       converter = c565_converter;
394       mono_converter = m565_converter;
395     } else {
396       converter = color16_converter;
397       mono_converter = mono16_converter;
398     }
399     break;
400 
401   case 3:
402     if (xi.byte_order) {rs = 16-rs; gs = 16-gs; bs = 16-bs;}
403     if (rs == 0 && gs == 8 && bs == 16) {
404       converter = rgb_converter;
405       mono_converter = rrr_converter;
406     } else if (rs == 16 && gs == 8 && bs == 0) {
407       converter = bgr_converter;
408       mono_converter = rrr_converter;
409     } else {
410       Fl::fatal("Can't do arbitrary 24bit color");
411     }
412     break;
413 
414   case 4:
415     if ((xi.byte_order!=0) != WORDS_BIGENDIAN)
416       {rs = 24-rs; gs = 24-gs; bs = 24-bs;}
417     if (rs == 0 && gs == 8 && bs == 16) {
418       converter = xbgr_converter;
419       mono_converter = xrrr_converter;
420     } else if (rs == 24 && gs == 16 && bs == 8) {
421       converter = rgbx_converter;
422       mono_converter = rrrx_converter;
423     } else if (rs == 8 && gs == 16 && bs == 24) {
424       converter = bgrx_converter;
425       mono_converter = rrrx_converter;
426     } else if (rs == 16 && gs == 8 && bs == 0) {
427       converter = xrgb_converter;
428       mono_converter = xrrr_converter;
429     } else {
430       xi.byte_order = WORDS_BIGENDIAN;
431       converter = color32_converter;
432       mono_converter = mono32_converter;
433     }
434     break;
435 
436   default:
437     Fl::fatal("Can't do %d bits_per_pixel",xi.bits_per_pixel);
438   }
439 
440 }
441 
442 #  define MAXBUFFER 0x40000 // 256k
443 
innards(const uchar * buf,int X,int Y,int W,int H,int delta,int linedelta,int mono,Fl_Draw_Image_Cb cb,void * userdata)444 static void innards(const uchar *buf, int X, int Y, int W, int H,
445 		    int delta, int linedelta, int mono,
446 		    Fl_Draw_Image_Cb cb, void* userdata)
447 {
448   if (!linedelta) linedelta = W*delta;
449 
450   int dx, dy, w, h;
451   fl_clip_box(X,Y,W,H,dx,dy,w,h);
452   if (w<=0 || h<=0) return;
453   dx -= X;
454   dy -= Y;
455 
456   if (!bytes_per_pixel) figure_out_visual();
457   xi.width = w;
458   xi.height = h;
459 
460   void (*conv)(const uchar *from, uchar *to, int w, int delta) = converter;
461   if (mono) conv = mono_converter;
462 
463   // See if the data is already in the right format.  Unfortunately
464   // some 32-bit x servers (XFree86) care about the unknown 8 bits
465   // and they must be zero.  I can't confirm this for user-supplied
466   // data, so the 32-bit shortcut is disabled...
467   // This can set bytes_per_line negative if image is bottom-to-top
468   // I tested it on Linux, but it may fail on other Xlib implementations:
469   if (buf && (
470 #  if 0	// set this to 1 to allow 32-bit shortcut
471       delta == 4 &&
472 #    if WORDS_BIGENDIAN
473       conv == rgbx_converter
474 #    else
475       conv == xbgr_converter
476 #    endif
477       ||
478 #  endif
479       conv == rgb_converter && delta==3
480       ) && !(linedelta&scanline_add)) {
481     xi.data = (char *)(buf+delta*dx+linedelta*dy);
482     xi.bytes_per_line = linedelta;
483 
484   } else {
485     int linesize = ((w*bytes_per_pixel+scanline_add)&scanline_mask)/sizeof(STORETYPE);
486     int blocking = h;
487     static STORETYPE *buffer;	// our storage, always word aligned
488     static long buffer_size;
489     {int size = linesize*h;
490     if (size > MAXBUFFER) {
491       size = MAXBUFFER;
492       blocking = MAXBUFFER/linesize;
493     }
494     if (size > buffer_size) {
495       delete[] buffer;
496       buffer_size = size;
497       buffer = new STORETYPE[size];
498     }}
499     xi.data = (char *)buffer;
500     xi.bytes_per_line = linesize*sizeof(STORETYPE);
501     if (buf) {
502       buf += delta*dx+linedelta*dy;
503       for (int j=0; j<h; ) {
504 	STORETYPE *to = buffer;
505 	int k;
506 	for (k = 0; j<h && k<blocking; k++, j++) {
507 	  conv(buf, (uchar*)to, w, delta);
508 	  buf += linedelta;
509 	  to += linesize;
510 	}
511 	XPutImage(fl_display,fl_window,fl_gc, &xi, 0, 0, X+dx, Y+dy+j-k, w, k);
512       }
513     } else {
514       STORETYPE* linebuf = new STORETYPE[(W*delta+(sizeof(STORETYPE)-1))/sizeof(STORETYPE)];
515       for (int j=0; j<h; ) {
516 	STORETYPE *to = buffer;
517 	int k;
518 	for (k = 0; j<h && k<blocking; k++, j++) {
519 	  cb(userdata, dx, dy+j, w, (uchar*)linebuf);
520 	  conv((uchar*)linebuf, (uchar*)to, w, delta);
521 	  to += linesize;
522 	}
523 	XPutImage(fl_display,fl_window,fl_gc, &xi, 0, 0, X+dx, Y+dy+j-k, w, k);
524       }
525 
526       delete[] linebuf;
527     }
528   }
529 }
530 
draw_image(const uchar * buf,int x,int y,int w,int h,int d,int l)531 void Fl_Xlib_Graphics_Driver::draw_image(const uchar* buf, int x, int y, int w, int h, int d, int l){
532   innards(buf,x,y,w,h,d,l,(d<3&&d>-3),0,0);
533 }
draw_image(Fl_Draw_Image_Cb cb,void * data,int x,int y,int w,int h,int d)534 void Fl_Xlib_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data,
535 		   int x, int y, int w, int h,int d) {
536   innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data);
537 }
draw_image_mono(const uchar * buf,int x,int y,int w,int h,int d,int l)538 void Fl_Xlib_Graphics_Driver::draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){
539   innards(buf,x,y,w,h,d,l,1,0,0);
540 }
draw_image_mono(Fl_Draw_Image_Cb cb,void * data,int x,int y,int w,int h,int d)541 void Fl_Xlib_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb, void* data,
542 		   int x, int y, int w, int h,int d) {
543   innards(0,x,y,w,h,d,0,1,cb,data);
544 }
545 
fl_rectf(int x,int y,int w,int h,uchar r,uchar g,uchar b)546 void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) {
547   if (fl_visual->depth > 16) {
548     fl_color(r,g,b);
549     fl_rectf(x,y,w,h);
550   } else {
551     uchar c[3];
552     c[0] = r; c[1] = g; c[2] = b;
553     innards(c,x,y,w,h,0,0,0,0,0);
554   }
555 }
556 
557 #endif
558 
559 //
560 // End of "$Id: fl_draw_image.cxx 8731 2011-05-23 21:05:22Z AlbrechtS $".
561 //
562