fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

fl_draw_image.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: fl_draw_image.cxx 8128 2010-12-28 15:17:23Z manolo $"
00003 //
00004 // Image drawing routines for the Fast Light Tool Kit (FLTK).
00005 //
00006 // Copyright 1998-2010 by Bill Spitzak and others.
00007 //
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU Library General Public
00010 // License as published by the Free Software Foundation; either
00011 // version 2 of the License, or (at your option) any later version.
00012 //
00013 // This library is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 // Library General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU Library General Public
00019 // License along with this library; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00021 // USA.
00022 //
00023 // Please report all bugs and problems on the following page:
00024 //
00025 //     http://www.fltk.org/str.php
00026 //
00027 
00028 // I hope a simple and portable method of drawing color and monochrome
00029 // images.  To keep this simple, only a single storage type is
00030 // supported: 8 bit unsigned data, byte order RGB, and pixels are
00031 // stored packed into rows with the origin at the top-left.  It is
00032 // possible to alter the size of pixels with the "delta" argument, to
00033 // add alpha or other information per pixel.  It is also possible to
00034 // change the origin and direction of the image data by messing with
00035 // the "delta" and "linedelta", making them negative, though this may
00036 // defeat some of the shortcuts in translating the image for X.
00037 
00038 #ifdef WIN32
00039 #  include "fl_draw_image_win32.cxx"
00040 #elif defined(__APPLE__)
00041 #  include "fl_draw_image_mac.cxx"
00042 #else
00043 
00044 // A list of assumptions made about the X display:
00045 
00046 // bits_per_pixel must be one of 8, 16, 24, 32.
00047 
00048 // scanline_pad must be a power of 2 and greater or equal to 8.
00049 
00050 // PsuedoColor visuals must have 8 bits_per_pixel (although the depth
00051 // may be less than 8).  This is the only limitation that affects any
00052 // modern X displays, you can't use 12 or 16 bit colormaps.
00053 
00054 // The mask bits in TrueColor visuals for each color are
00055 // contiguous and have at least one bit of each color.  This
00056 // is not checked for.
00057 
00058 // For 24 and 32 bit visuals there must be at least 8 bits of each color.
00059 
00061 
00062 #  include <FL/Fl.H>
00063 #  include <FL/fl_draw.H>
00064 #  include <FL/x.H>
00065 #  include "Fl_XColor.H"
00066 #  include "flstring.h"
00067 
00068 static XImage xi;       // template used to pass info to X
00069 static int bytes_per_pixel;
00070 static int scanline_add;
00071 static int scanline_mask;
00072 
00073 static void (*converter)(const uchar *from, uchar *to, int w, int delta);
00074 static void (*mono_converter)(const uchar *from, uchar *to, int w, int delta);
00075 
00076 static int dir;         // direction-alternator
00077 static int ri,gi,bi;    // saved error-diffusion value
00078 
00079 #  if USE_COLORMAP
00080 
00081 // 8-bit converter with error diffusion
00082 
00083 static void color8_converter(const uchar *from, uchar *to, int w, int delta) {
00084   int r=ri, g=gi, b=bi;
00085   int d, td;
00086   if (dir) {
00087     dir = 0;
00088     from = from+(w-1)*delta;
00089     to = to+(w-1);
00090     d = -delta;
00091     td = -1;
00092   } else {
00093     dir = 1;
00094     d = delta;
00095     td = 1;
00096   }
00097   for (; w--; from += d, to += td) {
00098     r += from[0]; if (r < 0) r = 0; else if (r>255) r = 255;
00099     g += from[1]; if (g < 0) g = 0; else if (g>255) g = 255;
00100     b += from[2]; if (b < 0) b = 0; else if (b>255) b = 255;
00101     Fl_Color i = fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256);
00102     Fl_XColor& xmap = fl_xmap[0][i];
00103     if (!xmap.mapped) {if (!fl_redmask) fl_xpixel(r,g,b); else fl_xpixel(i);}
00104     r -= xmap.r;
00105     g -= xmap.g;
00106     b -= xmap.b;
00107     *to = uchar(xmap.pixel);
00108   }
00109   ri = r; gi = g; bi = b;
00110 }
00111 
00112 static void mono8_converter(const uchar *from, uchar *to, int w, int delta) {
00113   int r=ri, g=gi, b=bi;
00114   int d, td;
00115   if (dir) {
00116     dir = 0;
00117     from = from+(w-1)*delta;
00118     to = to+(w-1);
00119     d = -delta;
00120     td = -1;
00121   } else {
00122     dir = 1;
00123     d = delta;
00124     td = 1;
00125   }
00126   for (; w--; from += d, to += td) {
00127     r += from[0]; if (r < 0) r = 0; else if (r>255) r = 255;
00128     g += from[0]; if (g < 0) g = 0; else if (g>255) g = 255;
00129     b += from[0]; if (b < 0) b = 0; else if (b>255) b = 255;
00130     Fl_Color i = fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256);
00131     Fl_XColor& xmap = fl_xmap[0][i];
00132     if (!xmap.mapped) {if (!fl_redmask) fl_xpixel(r,g,b); else fl_xpixel(i);}
00133     r -= xmap.r;
00134     g -= xmap.g;
00135     b -= xmap.b;
00136     *to = uchar(xmap.pixel);
00137   }
00138   ri = r; gi = g; bi = b;
00139 }
00140 
00141 #  endif
00142 
00144 // 16 bit TrueColor converters with error diffusion
00145 // Cray computers have no 16-bit type, so we use character pointers
00146 // (which may be slow)
00147 
00148 #  ifdef U16
00149 #    define OUTTYPE U16
00150 #    define OUTSIZE 1
00151 #    define OUTASSIGN(v) *t = v
00152 #  else
00153 #    define OUTTYPE uchar
00154 #    define OUTSIZE 2
00155 #    define OUTASSIGN(v) int tt=v; t[0] = uchar(tt>>8); t[1] = uchar(tt)
00156 #  endif
00157 
00158 static void color16_converter(const uchar *from, uchar *to, int w, int delta) {
00159   OUTTYPE *t = (OUTTYPE *)to;
00160   int d, td;
00161   if (dir) {
00162     dir = 0;
00163     from = from+(w-1)*delta;
00164     t = t+(w-1)*OUTSIZE;
00165     d = -delta;
00166     td = -OUTSIZE;
00167   } else {
00168     dir = 1;
00169     d = delta;
00170     td = OUTSIZE;
00171   }
00172   int r=ri, g=gi, b=bi;
00173   for (; w--; from += d, t += td) {
00174     r = (r&~fl_redmask)  +from[0]; if (r>255) r = 255;
00175     g = (g&~fl_greenmask)+from[1]; if (g>255) g = 255;
00176     b = (b&~fl_bluemask) +from[2]; if (b>255) b = 255;
00177     OUTASSIGN((
00178       ((r&fl_redmask)<<fl_redshift)+
00179       ((g&fl_greenmask)<<fl_greenshift)+
00180       ((b&fl_bluemask)<<fl_blueshift)
00181       ) >> fl_extrashift);
00182   }
00183   ri = r; gi = g; bi = b;
00184 }
00185 
00186 static void mono16_converter(const uchar *from,uchar *to,int w, int delta) {
00187   OUTTYPE *t = (OUTTYPE *)to;
00188   int d, td;
00189   if (dir) {
00190     dir = 0;
00191     from = from+(w-1)*delta;
00192     t = t+(w-1)*OUTSIZE;
00193     d = -delta;
00194     td = -OUTSIZE;
00195   } else {
00196     dir = 1;
00197     d = delta;
00198     td = OUTSIZE;
00199   }
00200   uchar mask = fl_redmask & fl_greenmask & fl_bluemask;
00201   int r=ri;
00202   for (; w--; from += d, t += td) {
00203     r = (r&~mask) + *from; if (r > 255) r = 255;
00204     uchar m = r&mask;
00205     OUTASSIGN((
00206       (m<<fl_redshift)+
00207       (m<<fl_greenshift)+
00208       (m<<fl_blueshift)
00209       ) >> fl_extrashift);
00210   }
00211   ri = r;
00212 }
00213 
00214 // special-case the 5r6g5b layout used by XFree86:
00215 
00216 static void c565_converter(const uchar *from, uchar *to, int w, int delta) {
00217   OUTTYPE *t = (OUTTYPE *)to;
00218   int d, td;
00219   if (dir) {
00220     dir = 0;
00221     from = from+(w-1)*delta;
00222     t = t+(w-1)*OUTSIZE;
00223     d = -delta;
00224     td = -OUTSIZE;
00225   } else {
00226     dir = 1;
00227     d = delta;
00228     td = OUTSIZE;
00229   }
00230   int r=ri, g=gi, b=bi;
00231   for (; w--; from += d, t += td) {
00232     r = (r&7)+from[0]; if (r>255) r = 255;
00233     g = (g&3)+from[1]; if (g>255) g = 255;
00234     b = (b&7)+from[2]; if (b>255) b = 255;
00235     OUTASSIGN(((r&0xf8)<<8) + ((g&0xfc)<<3) + (b>>3));
00236   }
00237   ri = r; gi = g; bi = b;
00238 }
00239 
00240 static void m565_converter(const uchar *from,uchar *to,int w, int delta) {
00241   OUTTYPE *t = (OUTTYPE *)to;
00242   int d, td;
00243   if (dir) {
00244     dir = 0;
00245     from = from+(w-1)*delta;
00246     t = t+(w-1)*OUTSIZE;
00247     d = -delta;
00248     td = -OUTSIZE;
00249   } else {
00250     dir = 1;
00251     d = delta;
00252     td = OUTSIZE;
00253   }
00254   int r=ri;
00255   for (; w--; from += d, t += td) {
00256     r = (r&7) + *from; if (r > 255) r = 255;
00257     OUTASSIGN((r>>3) * 0x841);
00258   }
00259   ri = r;
00260 }
00261 
00263 // 24bit TrueColor converters:
00264 
00265 static void rgb_converter(const uchar *from, uchar *to, int w, int delta) {
00266   int d = delta-3;
00267   for (; w--; from += d) {
00268     *to++ = *from++;
00269     *to++ = *from++;
00270     *to++ = *from++;
00271   }
00272 }
00273 
00274 static void bgr_converter(const uchar *from, uchar *to, int w, int delta) {
00275   for (; w--; from += delta) {
00276     uchar r = from[0];
00277     uchar g = from[1];
00278     *to++ = from[2];
00279     *to++ = g;
00280     *to++ = r;
00281   }
00282 }
00283 
00284 static void rrr_converter(const uchar *from, uchar *to, int w, int delta) {
00285   for (; w--; from += delta) {
00286     *to++ = *from;
00287     *to++ = *from;
00288     *to++ = *from;
00289   }
00290 }
00291 
00293 // 32bit TrueColor converters on a 32 or 64-bit machine:
00294 
00295 #  ifdef U64
00296 #    define STORETYPE U64
00297 #    if WORDS_BIGENDIAN
00298 #      define INNARDS32(f) \
00299   U64 *t = (U64*)to; \
00300   int w1 = (w+1)/2; \
00301   for (; w1--; from += delta) {U64 i = f; from += delta; *t++ = (i<<32)|(f);}
00302 #    else
00303 #      define INNARDS32(f) \
00304   U64 *t = (U64*)to; \
00305   int w1 = (w+1)/2; \
00306   for (; w1--; from += delta) {U64 i=f; from+= delta; *t++ = ((U64)(f)<<32)|i;}
00307 #    endif
00308 #  else
00309 #    define STORETYPE U32
00310 #    define INNARDS32(f) \
00311   U32 *t = (U32*)to; for (; w--; from += delta) *t++ = f
00312 #  endif
00313 
00314 static void rgbx_converter(const uchar *from, uchar *to, int w, int delta) {
00315   INNARDS32((unsigned(from[0])<<24)+(from[1]<<16)+(from[2]<<8));
00316 }
00317 
00318 static void xbgr_converter(const uchar *from, uchar *to, int w, int delta) {
00319   INNARDS32((from[0])+(from[1]<<8)+(from[2]<<16));
00320 }
00321 
00322 static void xrgb_converter(const uchar *from, uchar *to, int w, int delta) {
00323   INNARDS32((from[0]<<16)+(from[1]<<8)+(from[2]));
00324 }
00325 
00326 static void bgrx_converter(const uchar *from, uchar *to, int w, int delta) {
00327   INNARDS32((from[0]<<8)+(from[1]<<16)+(unsigned(from[2])<<24));
00328 }
00329 
00330 static void rrrx_converter(const uchar *from, uchar *to, int w, int delta) {
00331   INNARDS32(unsigned(*from) * 0x1010100U);
00332 }
00333 
00334 static void xrrr_converter(const uchar *from, uchar *to, int w, int delta) {
00335   INNARDS32(*from * 0x10101U);
00336 }
00337 
00338 static void
00339 color32_converter(const uchar *from, uchar *to, int w, int delta) {
00340   INNARDS32(
00341     (from[0]<<fl_redshift)+(from[1]<<fl_greenshift)+(from[2]<<fl_blueshift));
00342 }
00343 
00344 static void
00345 mono32_converter(const uchar *from,uchar *to,int w, int delta) {
00346   INNARDS32(
00347     (*from << fl_redshift)+(*from << fl_greenshift)+(*from << fl_blueshift));
00348 }
00349 
00351 
00352 static void figure_out_visual() {
00353 
00354   fl_xpixel(FL_BLACK); // setup fl_redmask, etc, in fl_color.cxx
00355   fl_xpixel(FL_WHITE); // also make sure white is allocated
00356 
00357   static XPixmapFormatValues *pfvlist;
00358   static int FL_NUM_pfv;
00359   if (!pfvlist) pfvlist = XListPixmapFormats(fl_display,&FL_NUM_pfv);
00360   XPixmapFormatValues *pfv;
00361   for (pfv = pfvlist; pfv < pfvlist+FL_NUM_pfv; pfv++)
00362     if (pfv->depth == fl_visual->depth) break;
00363   xi.format = ZPixmap;
00364   xi.byte_order = ImageByteOrder(fl_display);
00365 //i.bitmap_unit = 8;
00366 //i.bitmap_bit_order = MSBFirst;
00367 //i.bitmap_pad = 8;
00368   xi.depth = fl_visual->depth;
00369   xi.bits_per_pixel = pfv->bits_per_pixel;
00370 
00371   if (xi.bits_per_pixel & 7) bytes_per_pixel = 0; // produce fatal error
00372   else bytes_per_pixel = xi.bits_per_pixel/8;
00373 
00374   unsigned int n = pfv->scanline_pad/8;
00375   if (pfv->scanline_pad & 7 || (n&(n-1)))
00376     Fl::fatal("Can't do scanline_pad of %d",pfv->scanline_pad);
00377   if (n < sizeof(STORETYPE)) n = sizeof(STORETYPE);
00378   scanline_add = n-1;
00379   scanline_mask = -n;
00380 
00381 #  if USE_COLORMAP
00382   if (bytes_per_pixel == 1) {
00383     converter = color8_converter;
00384     mono_converter = mono8_converter;
00385     return;
00386   }
00387   if (!fl_visual->red_mask)
00388     Fl::fatal("Can't do %d bits_per_pixel colormap",xi.bits_per_pixel);
00389 #  endif
00390 
00391   // otherwise it is a TrueColor visual:
00392 
00393   int rs = fl_redshift;
00394   int gs = fl_greenshift;
00395   int bs = fl_blueshift;
00396 
00397   switch (bytes_per_pixel) {
00398 
00399   case 2:
00400     // All 16-bit TrueColor visuals are supported on any machine with
00401     // 24 or more bits per integer.
00402 #  ifdef U16
00403     xi.byte_order = WORDS_BIGENDIAN;
00404 #  else
00405     xi.byte_order = 1;
00406 #  endif
00407     if (rs == 11 && gs == 6 && bs == 0 && fl_extrashift == 3) {
00408       converter = c565_converter;
00409       mono_converter = m565_converter;
00410     } else {
00411       converter = color16_converter;
00412       mono_converter = mono16_converter;
00413     }
00414     break;
00415 
00416   case 3:
00417     if (xi.byte_order) {rs = 16-rs; gs = 16-gs; bs = 16-bs;}
00418     if (rs == 0 && gs == 8 && bs == 16) {
00419       converter = rgb_converter;
00420       mono_converter = rrr_converter;
00421     } else if (rs == 16 && gs == 8 && bs == 0) {
00422       converter = bgr_converter;
00423       mono_converter = rrr_converter;
00424     } else {
00425       Fl::fatal("Can't do arbitrary 24bit color");
00426     }
00427     break;
00428 
00429   case 4:
00430     if ((xi.byte_order!=0) != WORDS_BIGENDIAN)
00431       {rs = 24-rs; gs = 24-gs; bs = 24-bs;}
00432     if (rs == 0 && gs == 8 && bs == 16) {
00433       converter = xbgr_converter;
00434       mono_converter = xrrr_converter;
00435     } else if (rs == 24 && gs == 16 && bs == 8) {
00436       converter = rgbx_converter;
00437       mono_converter = rrrx_converter;
00438     } else if (rs == 8 && gs == 16 && bs == 24) {
00439       converter = bgrx_converter;
00440       mono_converter = rrrx_converter;
00441     } else if (rs == 16 && gs == 8 && bs == 0) {
00442       converter = xrgb_converter;
00443       mono_converter = xrrr_converter;
00444     } else {
00445       xi.byte_order = WORDS_BIGENDIAN;
00446       converter = color32_converter;
00447       mono_converter = mono32_converter;
00448     }
00449     break;
00450 
00451   default:
00452     Fl::fatal("Can't do %d bits_per_pixel",xi.bits_per_pixel);
00453   }
00454 
00455 }
00456 
00457 #  define MAXBUFFER 0x40000 // 256k
00458 
00459 static void innards(const uchar *buf, int X, int Y, int W, int H,
00460                     int delta, int linedelta, int mono,
00461                     Fl_Draw_Image_Cb cb, void* userdata)
00462 {
00463   if (!linedelta) linedelta = W*delta;
00464 
00465   int dx, dy, w, h;
00466   fl_clip_box(X,Y,W,H,dx,dy,w,h);
00467   if (w<=0 || h<=0) return;
00468   dx -= X;
00469   dy -= Y;
00470 
00471   if (!bytes_per_pixel) figure_out_visual();
00472   xi.width = w;
00473   xi.height = h;
00474 
00475   void (*conv)(const uchar *from, uchar *to, int w, int delta) = converter;
00476   if (mono) conv = mono_converter;
00477 
00478   // See if the data is already in the right format.  Unfortunately
00479   // some 32-bit x servers (XFree86) care about the unknown 8 bits
00480   // and they must be zero.  I can't confirm this for user-supplied
00481   // data, so the 32-bit shortcut is disabled...
00482   // This can set bytes_per_line negative if image is bottom-to-top
00483   // I tested it on Linux, but it may fail on other Xlib implementations:
00484   if (buf && (
00485 #  if 0 // set this to 1 to allow 32-bit shortcut
00486       delta == 4 &&
00487 #    if WORDS_BIGENDIAN
00488       conv == rgbx_converter
00489 #    else
00490       conv == xbgr_converter
00491 #    endif
00492       ||
00493 #  endif
00494       conv == rgb_converter && delta==3
00495       ) && !(linedelta&scanline_add)) {
00496     xi.data = (char *)(buf+delta*dx+linedelta*dy);
00497     xi.bytes_per_line = linedelta;
00498 
00499   } else {
00500     int linesize = ((w*bytes_per_pixel+scanline_add)&scanline_mask)/sizeof(STORETYPE);
00501     int blocking = h;
00502     static STORETYPE *buffer;   // our storage, always word aligned
00503     static long buffer_size;
00504     {int size = linesize*h;
00505     if (size > MAXBUFFER) {
00506       size = MAXBUFFER;
00507       blocking = MAXBUFFER/linesize;
00508     }
00509     if (size > buffer_size) {
00510       delete[] buffer;
00511       buffer_size = size;
00512       buffer = new STORETYPE[size];
00513     }}
00514     xi.data = (char *)buffer;
00515     xi.bytes_per_line = linesize*sizeof(STORETYPE);
00516     if (buf) {
00517       buf += delta*dx+linedelta*dy;
00518       for (int j=0; j<h; ) {
00519         STORETYPE *to = buffer;
00520         int k;
00521         for (k = 0; j<h && k<blocking; k++, j++) {
00522           conv(buf, (uchar*)to, w, delta);
00523           buf += linedelta;
00524           to += linesize;
00525         }
00526         XPutImage(fl_display,fl_window,fl_gc, &xi, 0, 0, X+dx, Y+dy+j-k, w, k);
00527       }
00528     } else {
00529       STORETYPE* linebuf = new STORETYPE[(W*delta+(sizeof(STORETYPE)-1))/sizeof(STORETYPE)];
00530       for (int j=0; j<h; ) {
00531         STORETYPE *to = buffer;
00532         int k;
00533         for (k = 0; j<h && k<blocking; k++, j++) {
00534           cb(userdata, dx, dy+j, w, (uchar*)linebuf);
00535           conv((uchar*)linebuf, (uchar*)to, w, delta);
00536           to += linesize;
00537         }
00538         XPutImage(fl_display,fl_window,fl_gc, &xi, 0, 0, X+dx, Y+dy+j-k, w, k);
00539       }
00540 
00541       delete[] linebuf;
00542     }
00543   }
00544 }
00545 
00546 void Fl_Xlib_Graphics_Driver::draw_image(const uchar* buf, int x, int y, int w, int h, int d, int l){
00547   innards(buf,x,y,w,h,d,l,(d<3&&d>-3),0,0);
00548 }
00549 void Fl_Xlib_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data,
00550                    int x, int y, int w, int h,int d) {
00551   innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data);
00552 }
00553 void Fl_Xlib_Graphics_Driver::draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){
00554   innards(buf,x,y,w,h,d,l,1,0,0);
00555 }
00556 void Fl_Xlib_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb, void* data,
00557                    int x, int y, int w, int h,int d) {
00558   innards(0,x,y,w,h,d,0,1,cb,data);
00559 }
00560 
00561 void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) {
00562   if (fl_visual->depth > 16) {
00563     fl_color(r,g,b);
00564     fl_rectf(x,y,w,h);
00565   } else {
00566     uchar c[3];
00567     c[0] = r; c[1] = g; c[2] = b;
00568     innards(c,x,y,w,h,0,0,0,0,0);
00569   }
00570 }
00571 
00572 #endif
00573 
00574 //
00575 // End of "$Id: fl_draw_image.cxx 8128 2010-12-28 15:17:23Z manolo $".
00576 //