themes: Workaround for bug where a background color of RGB 0,0,0 in Black color schem...
[ntk.git] / src / Fl_Pixmap.cxx
blob461d970e1634114bb80629d2c6a29acb8bcf3708
1 //
2 // "$Id: Fl_Pixmap.cxx 8360 2011-02-02 12:42:47Z manolo $"
3 //
4 // Pixmap drawing code 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.
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.
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.
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
28 /** \fn Fl_Pixmap::Fl_Pixmap(const char **data)
29 The constructors create a new pixmap from the specified XPM data.*/
31 /** \fn Fl_Pixmap::Fl_Pixmap(const unsigned char * const *data)
32 The constructors create a new pixmap from the specified XPM data.*/
34 /** \fn Fl_Pixmap::Fl_Pixmap(const unsigned char **data)
35 The constructors create a new pixmap from the specified XPM data.*/
37 // Draws X pixmap data, keeping it stashed in a server pixmap so it
38 // redraws fast.
40 // See fl_draw_pixmap.cxx for code used to get the actual data into pixmap.
41 // Implemented without using the xpm library (which I can't use because
42 // it interferes with the color cube used by fl_draw_image).
44 #include <FL/Fl.H>
45 #include <FL/fl_draw.H>
46 #include <FL/x.H>
47 #include <FL/Fl_Widget.H>
48 #include <FL/Fl_Menu_Item.H>
49 #include <FL/Fl_Pixmap.H>
50 #include <FL/Fl_Printer.H>
52 #include <stdio.h>
53 #include "flstring.h"
54 #include <ctype.h>
56 #ifdef WIN32
57 extern void fl_release_dc(HWND, HDC); // located in Fl_win32.cxx
58 #endif
60 #ifdef __APPLE_QUARTZ__
61 extern Fl_Offscreen fl_create_offscreen_with_alpha(int w, int h);
62 #endif
64 extern uchar **fl_mask_bitmap; // used by fl_draw_pixmap.cxx to store mask
65 void fl_restore_clip(); // in fl_rect.cxx
67 void Fl_Pixmap::measure() {
68 int W, H;
70 // ignore empty or bad pixmap data:
71 if (w()<0 && data()) {
72 fl_measure_pixmap(data(), W, H);
73 w(W); h(H);
77 void Fl_Pixmap::draw(int XP, int YP, int WP, int HP, int cx, int cy) {
78 fl_graphics_driver->draw(this, XP, YP, WP, HP, cx, cy);
81 static int start(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int w, int h, int &cx, int &cy,
82 int &X, int &Y, int &W, int &H)
84 // ignore empty or bad pixmap data:
85 if (!pxm->data()) {
86 return 2;
88 if (WP == -1) {
89 WP = w;
90 HP = h;
92 if (!w) {
93 return 2;
95 // account for current clip region (faster on Irix):
96 fl_clip_box(XP,YP,WP,HP,X,Y,W,H);
97 cx += X-XP; cy += Y-YP;
98 // clip the box down to the size of image, quit if empty:
99 if (cx < 0) {W += cx; X -= cx; cx = 0;}
100 if (cx+W > w) W = w-cx;
101 if (W <= 0) return 1;
102 if (cy < 0) {H += cy; Y -= cy; cy = 0;}
103 if (cy+H > h) H = h-cy;
104 if (H <= 0) return 1;
105 return 0;
108 #ifdef __APPLE__
109 void Fl_Quartz_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) {
110 int X, Y, W, H;
111 if (pxm->w() < 0) pxm->measure();
112 int code = start(pxm, XP, YP, WP, HP, pxm->w(), pxm->h(), cx, cy, X, Y, W, H);
113 if (code) {
114 if (code == 2) pxm->draw_empty(XP, YP);
115 return;
117 if (!pxm->id_) {
118 pxm->id_ = fl_create_offscreen_with_alpha(pxm->w(), pxm->h());
119 fl_begin_offscreen((Fl_Offscreen)pxm->id_);
120 fl_draw_pixmap(pxm->data(), 0, 0, FL_GREEN);
121 fl_end_offscreen();
123 fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)pxm->id_, cx, cy);
126 #elif defined(WIN32)
127 void Fl_GDI_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) {
128 int X, Y, W, H;
129 if (pxm->w() < 0) pxm->measure();
130 int code = start(pxm, XP, YP, WP, HP, pxm->w(), pxm->h(), cx, cy, X, Y, W, H);
131 if (code) {
132 if (code == 2) pxm->draw_empty(XP, YP);
133 return;
135 if (!pxm->id_) {
136 pxm->id_ = fl_create_offscreen(pxm->w(), pxm->h());
137 fl_begin_offscreen((Fl_Offscreen)pxm->id_);
138 uchar *bitmap = 0;
139 fl_mask_bitmap = &bitmap;
140 fl_draw_pixmap(pxm->data(), 0, 0, FL_BLACK);
141 fl_mask_bitmap = 0;
142 if (bitmap) {
143 pxm->mask_ = fl_create_bitmask(pxm->w(), pxm->h(), bitmap);
144 delete[] bitmap;
146 fl_end_offscreen();
148 if (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) {
149 typedef BOOL (WINAPI* fl_transp_func) (HDC,int,int,int,int,HDC,int,int,int,int,UINT);
150 static HMODULE hMod = NULL;
151 static fl_transp_func fl_TransparentBlt = NULL;
152 if (!hMod) {
153 hMod = LoadLibrary("MSIMG32.DLL");
154 if(hMod) fl_TransparentBlt = (fl_transp_func)GetProcAddress(hMod, "TransparentBlt");
156 if (fl_TransparentBlt) {
157 Fl_Offscreen tmp_id = fl_create_offscreen(pxm->w(), pxm->h());
158 fl_begin_offscreen(tmp_id);
159 uchar *bitmap = 0;
160 fl_mask_bitmap = &bitmap;
161 // draw pixmap to offscreen
162 fl_draw_pixmap(pxm->data(), 0, 0);
163 fl_end_offscreen();
164 HDC new_gc = CreateCompatibleDC(fl_gc);
165 int save = SaveDC(new_gc);
166 SelectObject(new_gc, (void*)tmp_id);
167 // print all of offscreen but its parts in background color
168 extern UINT win_pixmap_bg_color; // computed by fl_draw_pixmap()
169 fl_TransparentBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, pxm->w(), pxm->h(), win_pixmap_bg_color );
170 RestoreDC(new_gc,save);
171 DeleteDC(new_gc);
172 fl_delete_offscreen(tmp_id);
174 else {
175 fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)pxm->id_, cx, cy);
178 else if (pxm->mask_) {
179 HDC new_gc = CreateCompatibleDC(fl_gc);
180 int save = SaveDC(new_gc);
181 SelectObject(new_gc, (void*)pxm->mask_);
182 BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCAND);
183 SelectObject(new_gc, (void*)pxm->id_);
184 BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCPAINT);
185 RestoreDC(new_gc,save);
186 DeleteDC(new_gc);
187 } else {
188 fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)pxm->id_, cx, cy);
192 #else // Xlib
193 void Fl_Xlib_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) {
194 int X, Y, W, H;
195 if (pxm->w() < 0) pxm->measure();
196 int code = start(pxm, XP, YP, WP, HP, pxm->w(), pxm->h(), cx, cy, X, Y, W, H);
197 if (code) {
198 if (code == 2) pxm->draw_empty(XP, YP);
199 return;
201 if (!pxm->id_) {
202 pxm->id_ = fl_create_offscreen(pxm->w(), pxm->h());
203 fl_begin_offscreen((Fl_Offscreen)pxm->id_);
204 uchar *bitmap = 0;
205 fl_mask_bitmap = &bitmap;
206 fl_draw_pixmap(pxm->data(), 0, 0, FL_BLACK);
207 fl_mask_bitmap = 0;
208 if (bitmap) {
209 pxm->mask_ = fl_create_bitmask(pxm->w(), pxm->h(), bitmap);
210 delete[] bitmap;
212 fl_end_offscreen();
214 if (pxm->mask_) {
215 // I can't figure out how to combine a mask with existing region,
216 // so cut the image down to a clipped rectangle:
217 int nx, ny; fl_clip_box(X,Y,W,H,nx,ny,W,H);
218 cx += nx-X; X = nx;
219 cy += ny-Y; Y = ny;
220 // make X use the bitmap as a mask:
221 XSetClipMask(fl_display, fl_gc, pxm->mask_);
222 int ox = X-cx; if (ox < 0) ox += pxm->w();
223 int oy = Y-cy; if (oy < 0) oy += pxm->h();
224 XSetClipOrigin(fl_display, fl_gc, X-cx, Y-cy);
226 fl_copy_offscreen(X, Y, W, H, pxm->id_, cx, cy);
227 if (pxm->mask_) {
228 // put the old clip region back
229 XSetClipOrigin(fl_display, fl_gc, 0, 0);
230 fl_restore_clip();
234 #endif
237 The destructor free all memory and server resources that are used by
238 the pixmap.
240 Fl_Pixmap::~Fl_Pixmap() {
241 uncache();
242 delete_data();
245 void Fl_Pixmap::uncache() {
246 if (id_) {
247 fl_delete_offscreen((Fl_Offscreen)id_);
248 id_ = 0;
251 if (mask_) {
252 fl_delete_bitmask((Fl_Bitmask)mask_);
253 mask_ = 0;
257 void Fl_Pixmap::label(Fl_Widget* widget) {
258 widget->image(this);
261 void Fl_Pixmap::label(Fl_Menu_Item* m) {
262 Fl::set_labeltype(_FL_IMAGE_LABEL, labeltype, Fl_Image::measure);
263 m->label(_FL_IMAGE_LABEL, (const char*)this);
266 void Fl_Pixmap::copy_data() {
267 if (alloc_data) return;
269 char **new_data, // New data array
270 **new_row; // Current row in image
271 int i, // Looping var
272 ncolors, // Number of colors in image
273 chars_per_pixel,// Characters per color
274 chars_per_line; // Characters per line
276 // Figure out how many colors there are, and how big they are...
277 sscanf(data()[0],"%*d%*d%d%d", &ncolors, &chars_per_pixel);
278 chars_per_line = chars_per_pixel * w() + 1;
280 // Allocate memory for the new array...
281 if (ncolors < 0) new_data = new char *[h() + 2];
282 else new_data = new char *[h() + ncolors + 1];
284 new_data[0] = new char[strlen(data()[0]) + 1];
285 strcpy(new_data[0], data()[0]);
287 // Copy colors...
288 if (ncolors < 0) {
289 // Copy FLTK colormap values...
290 ncolors = -ncolors;
291 new_row = new_data + 1;
292 *new_row = new char[ncolors * 4];
293 memcpy(*new_row, data()[1], ncolors * 4);
294 ncolors = 1;
295 new_row ++;
296 } else {
297 // Copy standard XPM colormap values...
298 for (i = 0, new_row = new_data + 1; i < ncolors; i ++, new_row ++) {
299 *new_row = new char[strlen(data()[i + 1]) + 1];
300 strcpy(*new_row, data()[i + 1]);
304 // Copy image data...
305 for (i = 0; i < h(); i ++, new_row ++) {
306 *new_row = new char[chars_per_line];
307 memcpy(*new_row, data()[i + ncolors + 1], chars_per_line);
310 // Update pointers...
311 data((const char **)new_data, h() + ncolors + 1);
312 alloc_data = 1;
315 Fl_Image *Fl_Pixmap::copy(int W, int H) {
316 Fl_Pixmap *new_image; // New pixmap
318 // Optimize the simple copy where the width and height are the same...
319 if (W == w() && H == h()) {
320 // Make an exact copy of the image and return it...
321 new_image = new Fl_Pixmap(data());
322 new_image->copy_data();
323 return new_image;
325 if (W <= 0 || H <= 0) return 0;
327 // OK, need to resize the image data; allocate memory and
328 char **new_data, // New array for image data
329 **new_row, // Pointer to row in image data
330 *new_ptr, // Pointer into new array
331 new_info[255]; // New information line
332 const char *old_ptr; // Pointer into old array
333 int i, // Looping var
334 c, // Channel number
335 sy, // Source coordinate
336 dx, dy, // Destination coordinates
337 xerr, yerr, // X & Y errors
338 xmod, ymod, // X & Y moduli
339 xstep, ystep; // X & Y step increments
340 int ncolors, // Number of colors in image
341 chars_per_pixel,// Characters per color
342 chars_per_line; // Characters per line
344 // Figure out how many colors there are, and how big they are...
345 sscanf(data()[0],"%*d%*d%d%d", &ncolors, &chars_per_pixel);
346 chars_per_line = chars_per_pixel * W + 1;
348 sprintf(new_info, "%d %d %d %d", W, H, ncolors, chars_per_pixel);
350 // Figure out Bresenheim step/modulus values...
351 xmod = w() % W;
352 xstep = (w() / W) * chars_per_pixel;
353 ymod = h() % H;
354 ystep = h() / H;
356 // Allocate memory for the new array...
357 if (ncolors < 0) new_data = new char *[H + 2];
358 else new_data = new char *[H + ncolors + 1];
359 new_data[0] = new char[strlen(new_info) + 1];
360 strcpy(new_data[0], new_info);
362 // Copy colors...
363 if (ncolors < 0) {
364 // Copy FLTK colormap values...
365 ncolors = -ncolors;
366 new_row = new_data + 1;
367 *new_row = new char[ncolors * 4];
368 memcpy(*new_row, data()[1], ncolors * 4);
369 ncolors = 1;
370 new_row ++;
371 } else {
372 // Copy standard XPM colormap values...
373 for (i = 0, new_row = new_data + 1; i < ncolors; i ++, new_row ++) {
374 *new_row = new char[strlen(data()[i + 1]) + 1];
375 strcpy(*new_row, data()[i + 1]);
379 // Scale the image using a nearest-neighbor algorithm...
380 for (dy = H, sy = 0, yerr = H; dy > 0; dy --, new_row ++) {
381 *new_row = new char[chars_per_line];
382 new_ptr = *new_row;
384 for (dx = W, xerr = W, old_ptr = data()[sy + ncolors + 1];
385 dx > 0;
386 dx --) {
387 for (c = 0; c < chars_per_pixel; c ++) *new_ptr++ = old_ptr[c];
389 old_ptr += xstep;
390 xerr -= xmod;
392 if (xerr <= 0) {
393 xerr += W;
394 old_ptr += chars_per_pixel;
398 *new_ptr = '\0';
399 sy += ystep;
400 yerr -= ymod;
401 if (yerr <= 0) {
402 yerr += H;
403 sy ++;
407 new_image = new Fl_Pixmap((char*const*)new_data);
408 new_image->alloc_data = 1;
410 return new_image;
413 void Fl_Pixmap::color_average(Fl_Color c, float i) {
414 // Delete any existing pixmap/mask objects...
415 uncache();
417 // Allocate memory as needed...
418 copy_data();
420 // Get the color to blend with...
421 uchar r, g, b;
422 unsigned ia, ir, ig, ib;
424 Fl::get_color(c, r, g, b);
425 if (i < 0.0f) i = 0.0f;
426 else if (i > 1.0f) i = 1.0f;
428 ia = (unsigned)(256 * i);
429 ir = r * (256 - ia);
430 ig = g * (256 - ia);
431 ib = b * (256 - ia);
433 // Update the colormap to do the blend...
434 char line[255]; // New colormap line
435 int color, // Looping var
436 ncolors, // Number of colors in image
437 chars_per_pixel;// Characters per color
440 sscanf(data()[0],"%*d%*d%d%d", &ncolors, &chars_per_pixel);
442 if (ncolors < 0) {
443 // Update FLTK colormap...
444 ncolors = -ncolors;
445 uchar *cmap = (uchar *)(data()[1]);
446 for (color = 0; color < ncolors; color ++, cmap += 4) {
447 cmap[1] = (ia * cmap[1] + ir) >> 8;
448 cmap[2] = (ia * cmap[2] + ig) >> 8;
449 cmap[3] = (ia * cmap[3] + ib) >> 8;
451 } else {
452 // Update standard XPM colormap...
453 for (color = 0; color < ncolors; color ++) {
454 // look for "c word", or last word if none:
455 const char *p = data()[color + 1] + chars_per_pixel + 1;
456 const char *previous_word = p;
457 for (;;) {
458 while (*p && isspace(*p)) p++;
459 char what = *p++;
460 while (*p && !isspace(*p)) p++;
461 while (*p && isspace(*p)) p++;
462 if (!*p) {p = previous_word; break;}
463 if (what == 'c') break;
464 previous_word = p;
465 while (*p && !isspace(*p)) p++;
468 if (fl_parse_color(p, r, g, b)) {
469 r = (ia * r + ir) >> 8;
470 g = (ia * g + ig) >> 8;
471 b = (ia * b + ib) >> 8;
473 if (chars_per_pixel > 1) sprintf(line, "%c%c c #%02X%02X%02X",
474 data()[color + 1][0],
475 data()[color + 1][1], r, g, b);
476 else sprintf(line, "%c c #%02X%02X%02X", data()[color + 1][0], r, g, b);
478 delete[] (char *)data()[color + 1];
479 ((char **)data())[color + 1] = new char[strlen(line) + 1];
480 strcpy((char *)data()[color + 1], line);
486 void Fl_Pixmap::delete_data() {
487 if (alloc_data) {
488 for (int i = 0; i < count(); i ++) delete[] (char *)data()[i];
489 delete[] (char **)data();
493 void Fl_Pixmap::set_data(const char * const * p) {
494 int height, // Number of lines in image
495 ncolors; // Number of colors in image
497 if (p) {
498 sscanf(p[0],"%*d%d%d", &height, &ncolors);
499 if (ncolors < 0) data(p, height + 2);
500 else data(p, height + ncolors + 1);
505 void Fl_Pixmap::desaturate() {
506 // Delete any existing pixmap/mask objects...
507 uncache();
509 // Allocate memory as needed...
510 copy_data();
512 // Update the colormap to grayscale...
513 char line[255]; // New colormap line
514 int i, // Looping var
515 ncolors, // Number of colors in image
516 chars_per_pixel;// Characters per color
517 uchar r, g, b;
519 sscanf(data()[0],"%*d%*d%d%d", &ncolors, &chars_per_pixel);
521 if (ncolors < 0) {
522 // Update FLTK colormap...
523 ncolors = -ncolors;
524 uchar *cmap = (uchar *)(data()[1]);
525 for (i = 0; i < ncolors; i ++, cmap += 4) {
526 g = (uchar)((cmap[1] * 31 + cmap[2] * 61 + cmap[3] * 8) / 100);
527 cmap[1] = cmap[2] = cmap[3] = g;
529 } else {
530 // Update standard XPM colormap...
531 for (i = 0; i < ncolors; i ++) {
532 // look for "c word", or last word if none:
533 const char *p = data()[i + 1] + chars_per_pixel + 1;
534 const char *previous_word = p;
535 for (;;) {
536 while (*p && isspace(*p)) p++;
537 char what = *p++;
538 while (*p && !isspace(*p)) p++;
539 while (*p && isspace(*p)) p++;
540 if (!*p) {p = previous_word; break;}
541 if (what == 'c') break;
542 previous_word = p;
543 while (*p && !isspace(*p)) p++;
546 if (fl_parse_color(p, r, g, b)) {
547 g = (uchar)((r * 31 + g * 61 + b * 8) / 100);
549 if (chars_per_pixel > 1) sprintf(line, "%c%c c #%02X%02X%02X", data()[i + 1][0],
550 data()[i + 1][1], g, g, g);
551 else sprintf(line, "%c c #%02X%02X%02X", data()[i + 1][0], g, g, g);
553 delete[] (char *)data()[i + 1];
554 ((char **)data())[i + 1] = new char[strlen(line) + 1];
555 strcpy((char *)data()[i + 1], line);
562 // End of "$Id: Fl_Pixmap.cxx 8360 2011-02-02 12:42:47Z manolo $".