2 // "$Id: Fl_Pixmap.cxx 8360 2011-02-02 12:42:47Z manolo $"
4 // Pixmap drawing code for the Fast Light Tool Kit (FLTK).
6 // Copyright 1998-2010 by Bill Spitzak and others.
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
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
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).
45 #include <FL/fl_draw.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>
57 extern void fl_release_dc(HWND
, HDC
); // located in Fl_win32.cxx
60 #ifdef __APPLE_QUARTZ__
61 extern Fl_Offscreen
fl_create_offscreen_with_alpha(int w
, int h
);
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() {
70 // ignore empty or bad pixmap data:
71 if (w()<0 && data()) {
72 fl_measure_pixmap(data(), W
, 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:
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;
109 void Fl_Quartz_Graphics_Driver::draw(Fl_Pixmap
*pxm
, int XP
, int YP
, int WP
, int HP
, int cx
, int cy
) {
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
);
114 if (code
== 2) pxm
->draw_empty(XP
, YP
);
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
);
123 fl_copy_offscreen(X
, Y
, W
, H
, (Fl_Offscreen
)pxm
->id_
, cx
, cy
);
127 void Fl_GDI_Graphics_Driver::draw(Fl_Pixmap
*pxm
, int XP
, int YP
, int WP
, int HP
, int cx
, int cy
) {
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
);
132 if (code
== 2) pxm
->draw_empty(XP
, YP
);
136 pxm
->id_
= fl_create_offscreen(pxm
->w(), pxm
->h());
137 fl_begin_offscreen((Fl_Offscreen
)pxm
->id_
);
139 fl_mask_bitmap
= &bitmap
;
140 fl_draw_pixmap(pxm
->data(), 0, 0, FL_BLACK
);
143 pxm
->mask_
= fl_create_bitmask(pxm
->w(), pxm
->h(), bitmap
);
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
;
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
);
160 fl_mask_bitmap
= &bitmap
;
161 // draw pixmap to offscreen
162 fl_draw_pixmap(pxm
->data(), 0, 0);
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
);
172 fl_delete_offscreen(tmp_id
);
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
);
188 fl_copy_offscreen(X
, Y
, W
, H
, (Fl_Offscreen
)pxm
->id_
, cx
, cy
);
193 void Fl_Xlib_Graphics_Driver::draw(Fl_Pixmap
*pxm
, int XP
, int YP
, int WP
, int HP
, int cx
, int cy
) {
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
);
198 if (code
== 2) pxm
->draw_empty(XP
, YP
);
202 pxm
->id_
= fl_create_offscreen(pxm
->w(), pxm
->h());
203 fl_begin_offscreen((Fl_Offscreen
)pxm
->id_
);
205 fl_mask_bitmap
= &bitmap
;
206 fl_draw_pixmap(pxm
->data(), 0, 0, FL_BLACK
);
209 pxm
->mask_
= fl_create_bitmask(pxm
->w(), pxm
->h(), bitmap
);
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
);
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
);
228 // put the old clip region back
229 XSetClipOrigin(fl_display
, fl_gc
, 0, 0);
237 The destructor free all memory and server resources that are used by
240 Fl_Pixmap::~Fl_Pixmap() {
245 void Fl_Pixmap::uncache() {
247 fl_delete_offscreen((Fl_Offscreen
)id_
);
252 fl_delete_bitmask((Fl_Bitmask
)mask_
);
257 void Fl_Pixmap::label(Fl_Widget
* widget
) {
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]);
289 // Copy FLTK colormap values...
291 new_row
= new_data
+ 1;
292 *new_row
= new char[ncolors
* 4];
293 memcpy(*new_row
, data()[1], ncolors
* 4);
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);
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();
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
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...
352 xstep
= (w() / W
) * chars_per_pixel
;
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
);
364 // Copy FLTK colormap values...
366 new_row
= new_data
+ 1;
367 *new_row
= new char[ncolors
* 4];
368 memcpy(*new_row
, data()[1], ncolors
* 4);
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
];
384 for (dx
= W
, xerr
= W
, old_ptr
= data()[sy
+ ncolors
+ 1];
387 for (c
= 0; c
< chars_per_pixel
; c
++) *new_ptr
++ = old_ptr
[c
];
394 old_ptr
+= chars_per_pixel
;
407 new_image
= new Fl_Pixmap((char*const*)new_data
);
408 new_image
->alloc_data
= 1;
413 void Fl_Pixmap::color_average(Fl_Color c
, float i
) {
414 // Delete any existing pixmap/mask objects...
417 // Allocate memory as needed...
420 // Get the color to blend with...
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
);
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
);
443 // Update FLTK colormap...
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;
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
;
458 while (*p
&& isspace(*p
)) 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;
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() {
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
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...
509 // Allocate memory as needed...
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
519 sscanf(data()[0],"%*d%*d%d%d", &ncolors
, &chars_per_pixel
);
522 // Update FLTK colormap...
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
;
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
;
536 while (*p
&& isspace(*p
)) 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;
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 $".