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_Pixmap.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: Fl_Pixmap.cxx 8190 2011-01-05 10:21:45Z manolo $"
00003 //
00004 // Pixmap drawing code 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 
00037 // Draws X pixmap data, keeping it stashed in a server pixmap so it
00038 // redraws fast.
00039 
00040 // See fl_draw_pixmap.cxx for code used to get the actual data into pixmap.
00041 // Implemented without using the xpm library (which I can't use because
00042 // it interferes with the color cube used by fl_draw_image).
00043 
00044 #include <FL/Fl.H>
00045 #include <FL/fl_draw.H>
00046 #include <FL/x.H>
00047 #include <FL/Fl_Widget.H>
00048 #include <FL/Fl_Menu_Item.H>
00049 #include <FL/Fl_Pixmap.H>
00050 #include <FL/Fl_Printer.H>
00051 
00052 #include <stdio.h>
00053 #include "flstring.h"
00054 #include <ctype.h>
00055 
00056 #ifdef WIN32
00057 extern void fl_release_dc(HWND, HDC);      // located in Fl_win32.cxx
00058 #endif
00059 
00060 #ifdef __APPLE_QUARTZ__
00061 extern Fl_Offscreen fl_create_offscreen_with_alpha(int w, int h);
00062 #endif
00063 
00064 extern uchar **fl_mask_bitmap; // used by fl_draw_pixmap.cxx to store mask
00065 void fl_restore_clip(); // in fl_rect.cxx
00066 
00067 void Fl_Pixmap::measure() {
00068   int W, H;
00069 
00070   // ignore empty or bad pixmap data:
00071   if (w()<0 && data()) {
00072     fl_measure_pixmap(data(), W, H);
00073     w(W); h(H);
00074   }
00075 }
00076 
00077 void Fl_Pixmap::draw(int XP, int YP, int WP, int HP, int cx, int cy) {
00078   fl_graphics_driver->draw(this, XP, YP, WP, HP, cx, cy);
00079 }
00080 
00081 static int start(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int w, int h, int &cx, int &cy, 
00082                  int &X, int &Y, int &W, int &H)
00083 {
00084   // ignore empty or bad pixmap data:
00085   if (!pxm->data()) {
00086     return 2;
00087   }
00088   if (WP == -1) {
00089     WP = w;
00090     HP = h;
00091   }
00092   if (!w) {
00093     return 2;
00094   }
00095   // account for current clip region (faster on Irix):
00096   fl_clip_box(XP,YP,WP,HP,X,Y,W,H);
00097   cx += X-XP; cy += Y-YP;
00098   // clip the box down to the size of image, quit if empty:
00099   if (cx < 0) {W += cx; X -= cx; cx = 0;}
00100   if (cx+W > w) W = w-cx;
00101   if (W <= 0) return 1;
00102   if (cy < 0) {H += cy; Y -= cy; cy = 0;}
00103   if (cy+H > h) H = h-cy;
00104   if (H <= 0) return 1;
00105   return 0;
00106 }
00107 
00108 #ifdef __APPLE__
00109 void Fl_Quartz_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) {
00110   int X, Y, W, H;
00111   if (pxm->w() < 0) pxm->measure();
00112   int code = start(pxm, XP, YP, WP, HP, pxm->w(), pxm->h(), cx, cy, X, Y, W, H);
00113   if (code) {
00114     if (code == 2) pxm->draw_empty(XP, YP);
00115     return;
00116     }
00117   if (!pxm->id_) {
00118     pxm->id_ = fl_create_offscreen_with_alpha(pxm->w(), pxm->h());
00119     fl_begin_offscreen((Fl_Offscreen)pxm->id_);
00120     fl_draw_pixmap(pxm->data(), 0, 0, FL_GREEN);
00121     fl_end_offscreen();
00122     }
00123   fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)pxm->id_, cx, cy);
00124 }
00125 
00126 #elif defined(WIN32)
00127 void Fl_GDI_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) {
00128   int X, Y, W, H;
00129   if (pxm->w() < 0) pxm->measure();
00130   int code = start(pxm, XP, YP, WP, HP, pxm->w(), pxm->h(), cx, cy, X, Y, W, H);
00131   if (code) {
00132     if (code == 2) pxm->draw_empty(XP, YP);
00133     return;
00134   }
00135   if (!pxm->id_) {
00136     pxm->id_ = fl_create_offscreen(pxm->w(), pxm->h());
00137     fl_begin_offscreen((Fl_Offscreen)pxm->id_);
00138     uchar *bitmap = 0;
00139     fl_mask_bitmap = &bitmap;
00140     fl_draw_pixmap(pxm->data(), 0, 0, FL_BLACK);
00141     fl_mask_bitmap = 0;
00142     if (bitmap) {
00143       pxm->mask_ = fl_create_bitmask(pxm->w(), pxm->h(), bitmap);
00144       delete[] bitmap;
00145     }
00146     fl_end_offscreen();
00147   }
00148   if (fl_surface->class_name() == Fl_Printer::class_id) {
00149     typedef BOOL (WINAPI* fl_transp_func)  (HDC,int,int,int,int,HDC,int,int,int,int,UINT);
00150     static HMODULE hMod = NULL;
00151     static fl_transp_func fl_TransparentBlt = NULL;
00152     if (!hMod) {
00153       hMod = LoadLibrary("MSIMG32.DLL");
00154       if(hMod) fl_TransparentBlt = (fl_transp_func)GetProcAddress(hMod, "TransparentBlt");
00155     }
00156     if (fl_TransparentBlt) {
00157       Fl_Offscreen tmp_id = fl_create_offscreen(pxm->w(), pxm->h());
00158       fl_begin_offscreen(tmp_id);
00159       uchar *bitmap = 0;
00160       fl_mask_bitmap = &bitmap;
00161       // draw pixmap to offscreen
00162       fl_draw_pixmap(pxm->data(), 0, 0); 
00163       fl_end_offscreen();
00164       HDC new_gc = CreateCompatibleDC(fl_gc);
00165       int save = SaveDC(new_gc);
00166       SelectObject(new_gc, (void*)tmp_id);
00167       // print all of offscreen but its parts in background color
00168       extern UINT win_pixmap_bg_color; // computed by fl_draw_pixmap()
00169       fl_TransparentBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, pxm->w(), pxm->h(), win_pixmap_bg_color );
00170       RestoreDC(new_gc,save);
00171       DeleteDC(new_gc);
00172       fl_delete_offscreen(tmp_id);
00173     }
00174     else {
00175       fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)pxm->id_, cx, cy);
00176     }
00177   }
00178   else if (pxm->mask_) {
00179     HDC new_gc = CreateCompatibleDC(fl_gc);
00180     int save = SaveDC(new_gc);
00181     SelectObject(new_gc, (void*)pxm->mask_);
00182     BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCAND);
00183     SelectObject(new_gc, (void*)pxm->id_);
00184     BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCPAINT);
00185     RestoreDC(new_gc,save);
00186     DeleteDC(new_gc);
00187   } else {
00188     fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)pxm->id_, cx, cy);
00189   }
00190 }
00191 
00192 #else // Xlib
00193 void Fl_Xlib_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) {
00194   int X, Y, W, H;
00195   if (pxm->w() < 0) pxm->measure();
00196   int code = start(pxm, XP, YP, WP, HP, pxm->w(), pxm->h(), cx, cy, X, Y, W, H);
00197   if (code) {
00198     if (code == 2) pxm->draw_empty(XP, YP);
00199     return;
00200   }
00201   if (!pxm->id_) {
00202     pxm->id_ = fl_create_offscreen(pxm->w(), pxm->h());
00203     fl_begin_offscreen((Fl_Offscreen)pxm->id_);
00204     uchar *bitmap = 0;
00205     fl_mask_bitmap = &bitmap;
00206     fl_draw_pixmap(pxm->data(), 0, 0, FL_BLACK);
00207     fl_mask_bitmap = 0;
00208     if (bitmap) {
00209       pxm->mask_ = fl_create_bitmask(pxm->w(), pxm->h(), bitmap);
00210       delete[] bitmap;
00211     }
00212     fl_end_offscreen();
00213   }
00214   if (pxm->mask_) {
00215     // I can't figure out how to combine a mask with existing region,
00216     // so cut the image down to a clipped rectangle:
00217     int nx, ny; fl_clip_box(X,Y,W,H,nx,ny,W,H);
00218     cx += nx-X; X = nx;
00219     cy += ny-Y; Y = ny;
00220     // make X use the bitmap as a mask:
00221     XSetClipMask(fl_display, fl_gc, pxm->mask_);
00222     int ox = X-cx; if (ox < 0) ox += pxm->w();
00223     int oy = Y-cy; if (oy < 0) oy += pxm->h();
00224     XSetClipOrigin(fl_display, fl_gc, X-cx, Y-cy);
00225   }
00226   fl_copy_offscreen(X, Y, W, H, pxm->id_, cx, cy);
00227   if (pxm->mask_) {
00228     // put the old clip region back
00229     XSetClipOrigin(fl_display, fl_gc, 0, 0);
00230     fl_restore_clip();
00231   }
00232 }
00233 
00234 #endif
00235 
00240 Fl_Pixmap::~Fl_Pixmap() {
00241   uncache();
00242   delete_data();
00243 }
00244 
00245 void Fl_Pixmap::uncache() {
00246   if (id_) {
00247     fl_delete_offscreen((Fl_Offscreen)id_);
00248     id_ = 0;
00249   }
00250 
00251   if (mask_) {
00252     fl_delete_bitmask((Fl_Bitmask)mask_);
00253     mask_ = 0;
00254   }
00255 }
00256 
00257 void Fl_Pixmap::label(Fl_Widget* widget) {
00258   widget->image(this);
00259 }
00260 
00261 void Fl_Pixmap::label(Fl_Menu_Item* m) {
00262   Fl::set_labeltype(_FL_IMAGE_LABEL, labeltype, Fl_Image::measure);
00263   m->label(_FL_IMAGE_LABEL, (const char*)this);
00264 }
00265 
00266 void Fl_Pixmap::copy_data() {
00267   if (alloc_data) return;
00268 
00269   char          **new_data,     // New data array
00270                 **new_row;      // Current row in image
00271   int           i,              // Looping var
00272                 ncolors,        // Number of colors in image
00273                 chars_per_pixel,// Characters per color
00274                 chars_per_line; // Characters per line 
00275 
00276   // Figure out how many colors there are, and how big they are...
00277   sscanf(data()[0],"%*d%*d%d%d", &ncolors, &chars_per_pixel);
00278   chars_per_line = chars_per_pixel * w() + 1;
00279 
00280   // Allocate memory for the new array...
00281   if (ncolors < 0) new_data = new char *[h() + 2];
00282   else new_data = new char *[h() + ncolors + 1];
00283 
00284   new_data[0] = new char[strlen(data()[0]) + 1];
00285   strcpy(new_data[0], data()[0]);
00286 
00287   // Copy colors...
00288   if (ncolors < 0) {
00289     // Copy FLTK colormap values...
00290     ncolors = -ncolors;
00291     new_row = new_data + 1;
00292     *new_row = new char[ncolors * 4];
00293     memcpy(*new_row, data()[1], ncolors * 4);
00294     ncolors = 1;
00295     new_row ++;
00296   } else {
00297     // Copy standard XPM colormap values...
00298     for (i = 0, new_row = new_data + 1; i < ncolors; i ++, new_row ++) {
00299       *new_row = new char[strlen(data()[i + 1]) + 1];
00300       strcpy(*new_row, data()[i + 1]);
00301     }
00302   }
00303 
00304   // Copy image data...
00305   for (i = 0; i < h(); i ++, new_row ++) {
00306     *new_row = new char[chars_per_line];
00307     memcpy(*new_row, data()[i + ncolors + 1], chars_per_line);
00308   }
00309 
00310   // Update pointers...
00311   data((const char **)new_data, h() + ncolors + 1);
00312   alloc_data = 1;  
00313 }
00314 
00315 Fl_Image *Fl_Pixmap::copy(int W, int H) {
00316   Fl_Pixmap     *new_image;     // New pixmap
00317 
00318   // Optimize the simple copy where the width and height are the same...
00319   if (W == w() && H == h()) {
00320     // Make an exact copy of the image and return it...
00321     new_image = new Fl_Pixmap(data());
00322     new_image->copy_data();
00323     return new_image;
00324   }
00325   if (W <= 0 || H <= 0) return 0;
00326 
00327   // OK, need to resize the image data; allocate memory and 
00328   char          **new_data,     // New array for image data
00329                 **new_row,      // Pointer to row in image data
00330                 *new_ptr,       // Pointer into new array
00331                 new_info[255];  // New information line
00332   const char    *old_ptr;       // Pointer into old array
00333   int           i,              // Looping var
00334                 c,              // Channel number
00335                 sy,             // Source coordinate
00336                 dx, dy,         // Destination coordinates
00337                 xerr, yerr,     // X & Y errors
00338                 xmod, ymod,     // X & Y moduli
00339                 xstep, ystep;   // X & Y step increments
00340   int           ncolors,        // Number of colors in image
00341                 chars_per_pixel,// Characters per color
00342                 chars_per_line; // Characters per line 
00343 
00344   // Figure out how many colors there are, and how big they are...
00345   sscanf(data()[0],"%*d%*d%d%d", &ncolors, &chars_per_pixel);
00346   chars_per_line = chars_per_pixel * W + 1;
00347 
00348   sprintf(new_info, "%d %d %d %d", W, H, ncolors, chars_per_pixel);
00349 
00350   // Figure out Bresenheim step/modulus values...
00351   xmod   = w() % W;
00352   xstep  = (w() / W) * chars_per_pixel;
00353   ymod   = h() % H;
00354   ystep  = h() / H;
00355 
00356   // Allocate memory for the new array...
00357   if (ncolors < 0) new_data = new char *[H + 2];
00358   else new_data = new char *[H + ncolors + 1];
00359   new_data[0] = new char[strlen(new_info) + 1];
00360   strcpy(new_data[0], new_info);
00361 
00362   // Copy colors...
00363   if (ncolors < 0) {
00364     // Copy FLTK colormap values...
00365     ncolors = -ncolors;
00366     new_row = new_data + 1;
00367     *new_row = new char[ncolors * 4];
00368     memcpy(*new_row, data()[1], ncolors * 4);
00369     ncolors = 1;
00370     new_row ++;
00371   } else {
00372     // Copy standard XPM colormap values...
00373     for (i = 0, new_row = new_data + 1; i < ncolors; i ++, new_row ++) {
00374       *new_row = new char[strlen(data()[i + 1]) + 1];
00375       strcpy(*new_row, data()[i + 1]);
00376     }
00377   }
00378 
00379   // Scale the image using a nearest-neighbor algorithm...
00380   for (dy = H, sy = 0, yerr = H; dy > 0; dy --, new_row ++) {
00381     *new_row = new char[chars_per_line];
00382     new_ptr  = *new_row;
00383 
00384     for (dx = W, xerr = W, old_ptr = data()[sy + ncolors + 1];
00385          dx > 0;
00386          dx --) {
00387       for (c = 0; c < chars_per_pixel; c ++) *new_ptr++ = old_ptr[c];
00388 
00389       old_ptr += xstep;
00390       xerr    -= xmod;
00391 
00392       if (xerr <= 0) {
00393         xerr    += W;
00394         old_ptr += chars_per_pixel;
00395       }
00396     }
00397 
00398     *new_ptr = '\0';
00399     sy       += ystep;
00400     yerr     -= ymod;
00401     if (yerr <= 0) {
00402       yerr += H;
00403       sy ++;
00404     }
00405   }
00406 
00407   new_image = new Fl_Pixmap((char*const*)new_data);
00408   new_image->alloc_data = 1;
00409 
00410   return new_image;
00411 }
00412 
00413 void Fl_Pixmap::color_average(Fl_Color c, float i) {
00414   // Delete any existing pixmap/mask objects...
00415   uncache();
00416 
00417   // Allocate memory as needed...
00418   copy_data();
00419 
00420   // Get the color to blend with...
00421   uchar         r, g, b;
00422   unsigned      ia, ir, ig, ib;
00423 
00424   Fl::get_color(c, r, g, b);
00425   if (i < 0.0f) i = 0.0f;
00426   else if (i > 1.0f) i = 1.0f;
00427 
00428   ia = (unsigned)(256 * i);
00429   ir = r * (256 - ia);
00430   ig = g * (256 - ia);
00431   ib = b * (256 - ia);
00432 
00433   // Update the colormap to do the blend...
00434   char          line[255];      // New colormap line
00435   int           color,          // Looping var
00436                 ncolors,        // Number of colors in image
00437                 chars_per_pixel;// Characters per color
00438 
00439 
00440   sscanf(data()[0],"%*d%*d%d%d", &ncolors, &chars_per_pixel);
00441 
00442   if (ncolors < 0) {
00443     // Update FLTK colormap...
00444     ncolors = -ncolors;
00445     uchar *cmap = (uchar *)(data()[1]);
00446     for (color = 0; color < ncolors; color ++, cmap += 4) {
00447       cmap[1] = (ia * cmap[1] + ir) >> 8;
00448       cmap[2] = (ia * cmap[2] + ig) >> 8;
00449       cmap[3] = (ia * cmap[3] + ib) >> 8;
00450     }
00451   } else {
00452     // Update standard XPM colormap...
00453     for (color = 0; color < ncolors; color ++) {
00454       // look for "c word", or last word if none:
00455       const char *p = data()[color + 1] + chars_per_pixel + 1;
00456       const char *previous_word = p;
00457       for (;;) {
00458         while (*p && isspace(*p)) p++;
00459         char what = *p++;
00460         while (*p && !isspace(*p)) p++;
00461         while (*p && isspace(*p)) p++;
00462         if (!*p) {p = previous_word; break;}
00463         if (what == 'c') break;
00464         previous_word = p;
00465         while (*p && !isspace(*p)) p++;
00466       }
00467 
00468       if (fl_parse_color(p, r, g, b)) {
00469         r = (ia * r + ir) >> 8;
00470         g = (ia * g + ig) >> 8;
00471         b = (ia * b + ib) >> 8;
00472 
00473         if (chars_per_pixel > 1) sprintf(line, "%c%c c #%02X%02X%02X",
00474                                          data()[color + 1][0],
00475                                          data()[color + 1][1], r, g, b);
00476         else sprintf(line, "%c c #%02X%02X%02X", data()[color + 1][0], r, g, b);
00477 
00478         delete[] (char *)data()[color + 1];
00479         ((char **)data())[color + 1] = new char[strlen(line) + 1];
00480         strcpy((char *)data()[color + 1], line);
00481       }
00482     }
00483   }
00484 }
00485 
00486 void Fl_Pixmap::delete_data() {
00487   if (alloc_data) {
00488     for (int i = 0; i < count(); i ++) delete[] (char *)data()[i];
00489     delete[] (char **)data();
00490   }
00491 }
00492 
00493 void Fl_Pixmap::set_data(const char * const * p) {
00494   int   height,         // Number of lines in image
00495         ncolors;        // Number of colors in image
00496 
00497   if (p) {
00498     sscanf(p[0],"%*d%d%d", &height, &ncolors);
00499     if (ncolors < 0) data(p, height + 2);
00500     else data(p, height + ncolors + 1);
00501   }
00502 }
00503 
00504 
00505 void Fl_Pixmap::desaturate() {
00506   // Delete any existing pixmap/mask objects...
00507   uncache();
00508 
00509   // Allocate memory as needed...
00510   copy_data();
00511 
00512   // Update the colormap to grayscale...
00513   char          line[255];      // New colormap line
00514   int           i,              // Looping var
00515                 ncolors,        // Number of colors in image
00516                 chars_per_pixel;// Characters per color
00517   uchar         r, g, b;
00518 
00519   sscanf(data()[0],"%*d%*d%d%d", &ncolors, &chars_per_pixel);
00520 
00521   if (ncolors < 0) {
00522     // Update FLTK colormap...
00523     ncolors = -ncolors;
00524     uchar *cmap = (uchar *)(data()[1]);
00525     for (i = 0; i < ncolors; i ++, cmap += 4) {
00526       g = (uchar)((cmap[1] * 31 + cmap[2] * 61 + cmap[3] * 8) / 100);
00527       cmap[1] = cmap[2] = cmap[3] = g;
00528     }
00529   } else {
00530     // Update standard XPM colormap...
00531     for (i = 0; i < ncolors; i ++) {
00532       // look for "c word", or last word if none:
00533       const char *p = data()[i + 1] + chars_per_pixel + 1;
00534       const char *previous_word = p;
00535       for (;;) {
00536         while (*p && isspace(*p)) p++;
00537         char what = *p++;
00538         while (*p && !isspace(*p)) p++;
00539         while (*p && isspace(*p)) p++;
00540         if (!*p) {p = previous_word; break;}
00541         if (what == 'c') break;
00542         previous_word = p;
00543         while (*p && !isspace(*p)) p++;
00544       }
00545 
00546       if (fl_parse_color(p, r, g, b)) {
00547         g = (uchar)((r * 31 + g * 61 + b * 8) / 100);
00548 
00549         if (chars_per_pixel > 1) sprintf(line, "%c%c c #%02X%02X%02X", data()[i + 1][0],
00550                                          data()[i + 1][1], g, g, g);
00551         else sprintf(line, "%c c #%02X%02X%02X", data()[i + 1][0], g, g, g);
00552 
00553         delete[] (char *)data()[i + 1];
00554         ((char **)data())[i + 1] = new char[strlen(line) + 1];
00555         strcpy((char *)data()[i + 1], line);
00556       }
00557     }
00558   }
00559 }
00560 
00561 //
00562 // End of "$Id: Fl_Pixmap.cxx 8190 2011-01-05 10:21:45Z manolo $".
00563 //