|
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) ![]() |
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 //