2 // "$Id: fl_draw_pixmap.cxx 8362 2011-02-02 18:39:34Z 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 // Implemented without using the xpm library (which I can't use because
29 // it interferes with the color cube used by fl_draw_image).
30 // Current implementation is cheap and slow, and works best on a full-color
31 // display. Transparency is not handled, and colors are dithered to
32 // the color cube. Color index is achieved by adding the id
33 // characters together! Also mallocs a lot of temporary memory!
34 // Notice that there is no pixmap file interface. This is on purpose,
35 // as I want to discourage programs that require support files to work.
36 // All data needed by a program ui should be compiled in!!!
39 #include <FL/fl_draw.H>
44 static int ncolors
, chars_per_pixel
;
47 Get the dimensions of a pixmap.
48 An XPM image contains the dimensions in its data. This function
49 returns te width and height.
50 \param[in] data pointer to XPM image data.
51 \param[out] w,h width and height of image
52 \returns non-zero if the dimensions were parsed OK
53 \returns 0 if there were any problems
55 int fl_measure_pixmap(/*const*/ char* const* data
, int &w
, int &h
) {
56 return fl_measure_pixmap((const char*const*)data
,w
,h
);
60 Get the dimensions of a pixmap.
61 \see fl_measure_pixmap(char* const* data, int &w, int &h)
63 int fl_measure_pixmap(const char * const *cdata
, int &w
, int &h
) {
64 int i
= sscanf(cdata
[0],"%d%d%d%d",&w
,&h
,&ncolors
,&chars_per_pixel
);
65 if (i
<4 || w
<=0 || h
<=0 ||
66 (chars_per_pixel
!=1 && chars_per_pixel
!=2) ) return w
=0;
72 // The callback from fl_draw_image to get a row of data passes this:
75 const uchar
*const* data
;
82 // callback for 1 byte per pixel:
83 static void cb1(void*v
, int x
, int y
, int w
, uchar
* buf
) {
84 pixmap_data
& d
= *(pixmap_data
*)v
;
85 const uchar
* p
= d
.data
[y
]+x
;
87 for (int X
=w
; X
>0; X
-=2, p
+= 2) {
90 *q
++ = (d
.colors
[p
[0]]<<32) | d
.colors
[p
[1]];
92 *q
++ = (d
.colors
[p
[1]]<<32) | d
.colors
[p
[0]];
96 *q
++ = d
.colors
[p
[0]]<<32;
98 *q
++ = d
.colors
[p
[0]];
104 // callback for 2 bytes per pixel:
105 static void cb2(void*v
, int x
, int y
, int w
, uchar
* buf
) {
106 pixmap_data
& d
= *(pixmap_data
*)v
;
107 const uchar
* p
= d
.data
[y
]+2*x
;
109 for (int X
=w
; X
>0; X
-=2) {
110 U64
* colors
= d
.byte1
[*p
++];
113 U64
* colors1
= d
.byte1
[*p
++];
116 *q
++ = (colors
[index
]<<32) | colors1
[index1
];
118 *q
++ = (colors1
[index1
]<<32) | colors
[index
];
122 *q
++ = colors
[index
]<<32;
124 *q
++ = colors
[index
];
132 // The callback from fl_draw_image to get a row of data passes this:
135 const uchar
*const* data
;
142 // callback for 1 byte per pixel:
143 static void cb1(void*v
, int x
, int y
, int w
, uchar
* buf
) {
144 pixmap_data
& d
= *(pixmap_data
*)v
;
145 const uchar
* p
= d
.data
[y
]+x
;
147 for (int X
=w
; X
--;) *q
++ = d
.colors
[*p
++];
150 // callback for 2 bytes per pixel:
151 static void cb2(void*v
, int x
, int y
, int w
, uchar
* buf
) {
152 pixmap_data
& d
= *(pixmap_data
*)v
;
153 const uchar
* p
= d
.data
[y
]+2*x
;
155 for (int X
=w
; X
--;) {
156 U32
* colors
= d
.byte1
[*p
++];
161 #endif // U64 else U32
163 uchar
**fl_mask_bitmap
; // if non-zero, create bitmap and store pointer here
166 Draw XPM image data, with the top-left corner at the given position.
167 The image is dithered on 8-bit displays so you won't lose color
168 space for programs displaying both images and pixmaps.
169 \param[in] data pointer to XPM image data
170 \param[in] x,y position of top-left corner
171 \param[in] bg background color
172 \returns 0 if there was any error decoding the XPM data.
174 int fl_draw_pixmap(/*const*/ char* const* data
, int x
,int y
,Fl_Color bg
) {
175 return fl_draw_pixmap((const char*const*)data
,x
,y
,bg
);
179 // to compute an unused color to be used for the pixmap background
180 FL_EXPORT UINT win_pixmap_bg_color
; // the RGB() of the pixmap background color
181 static int color_count
; // # of non-transparent colors used in pixmap
182 static uchar
*used_colors
; // used_colors[3*i+j] j=0,1,2 are the RGB values of the ith used color
184 static void make_unused_color(uchar
&r
, uchar
&g
, uchar
&b
)
185 // makes an RGB triplet different from all the colors used in the pixmap
186 // and compute win_pixmap_bg_color from this triplet
191 for ( i
= 0; i
< color_count
; i
++) {
192 if(used_colors
[3*i
] == r
&& used_colors
[3*i
+1] == g
&& used_colors
[3*i
+2] == b
) break;
194 if (i
>= color_count
) {
196 win_pixmap_bg_color
= RGB(r
, g
, b
);
213 Draw XPM image data, with the top-left corner at the given position.
214 \see fl_draw_pixmap(char* const* data, int x, int y, Fl_Color bg)
216 int fl_draw_pixmap(const char*const* cdata
, int x
, int y
, Fl_Color bg
) {
218 if (!fl_measure_pixmap(cdata
, d
.w
, d
.h
)) return 0;
219 const uchar
*const* data
= (const uchar
*const*)(cdata
+1);
220 int transparent_index
= -1;
221 uchar
*transparent_c
= (uchar
*)0; // such that transparent_c[0,1,2] are the RGB of the transparent color
224 used_colors
= (uchar
*)malloc(abs(ncolors
)*3*sizeof(uchar
));
227 if (ncolors
< 0) { // FLTK (non standard) compressed colormap
229 const uchar
*p
= *data
++;
230 // if first color is ' ' it is transparent (put it later to make
231 // it not be transparent):
233 uchar
* c
= (uchar
*)&d
.colors
[(int)' '];
240 transparent_index
= ' ';
241 Fl::get_color(bg
, c
[0], c
[1], c
[2]); c
[3] = 0;
246 // read all the rest of the colors:
247 for (int i
=0; i
< ncolors
; i
++) {
248 uchar
* c
= (uchar
*)&d
.colors
[*p
++];
256 used_colors
[3*color_count
] = *p
;
257 used_colors
[3*color_count
+1] = *(p
+1);
258 used_colors
[3*color_count
+2] = *(p
+2);
264 #ifdef __APPLE_QUARTZ__
270 } else { // normal XPM colormap with names
271 if (chars_per_pixel
>1) memset(d
.byte1
, 0, sizeof(d
.byte1
));
272 for (int i
=0; i
<ncolors
; i
++) {
273 const uchar
*p
= *data
++;
274 // the first 1 or 2 characters are the color index:
277 if (chars_per_pixel
>1) {
279 U64
* colors
= d
.byte1
[ind
];
280 if (!colors
) colors
= d
.byte1
[ind
] = new U64
[256];
282 U32
* colors
= d
.byte1
[ind
];
283 if (!colors
) colors
= d
.byte1
[ind
] = new U32
[256];
285 c
= (uchar
*)&colors
[*p
];
288 c
= (uchar
*)&d
.colors
[ind
];
290 // look for "c word", or last word if none:
291 const uchar
*previous_word
= p
;
293 while (*p
&& isspace(*p
)) p
++;
295 while (*p
&& !isspace(*p
)) p
++;
296 while (*p
&& isspace(*p
)) p
++;
297 if (!*p
) {p
= previous_word
; break;}
298 if (what
== 'c') break;
300 while (*p
&& !isspace(*p
)) p
++;
308 #ifdef __APPLE_QUARTZ__
311 int parse
= fl_parse_color((const char*)p
, c
[0], c
[1], c
[2]);
314 used_colors
[3*color_count
] = c
[0];
315 used_colors
[3*color_count
+1] = c
[1];
316 used_colors
[3*color_count
+2] = c
[2];
321 // assume "None" or "#transparent" for any errors
322 // "bg" should be transparent...
323 Fl::get_color(bg
, c
[0], c
[1], c
[2]);
324 #ifdef __APPLE_QUARTZ__
327 transparent_index
= ind
;
335 make_unused_color(transparent_c
[0], transparent_c
[1], transparent_c
[2]);
339 make_unused_color(r
, g
, b
);
343 #ifdef __APPLE_QUARTZ__
344 if (fl_graphics_driver
->class_name() == Fl_Quartz_Graphics_Driver::class_id
) {
345 bool transparent
= (transparent_index
>=0);
347 U32
*array
= new U32
[d
.w
* d
.h
], *q
= array
;
348 for (int Y
= 0; Y
< d
.h
; Y
++) {
349 const uchar
* p
= data
[Y
];
350 if (chars_per_pixel
<= 1) {
351 for (int X
= 0; X
< d
.w
; X
++) {
352 *q
++ = d
.colors
[*p
++];
355 for (int X
= 0; X
< d
.w
; X
++) {
356 U32
* colors
= (U32
*)d
.byte1
[*p
++];
361 CGColorSpaceRef lut
= CGColorSpaceCreateDeviceRGB();
362 CGDataProviderRef src
= CGDataProviderCreateWithData( 0L, array
, d
.w
* d
.h
* 4, 0L);
363 CGImageRef img
= CGImageCreate(d
.w
, d
.h
, 8, 4*8, 4*d
.w
,
364 lut
, transparent
?kCGImageAlphaLast
:kCGImageAlphaNoneSkipLast
,
365 src
, 0L, false, kCGRenderingIntentDefault
);
366 CGColorSpaceRelease(lut
);
367 CGDataProviderRelease(src
);
368 CGRect rect
= { { x
, y
} , { d
.w
, d
.h
} };
369 Fl_X::q_begin_image(rect
, 0, 0, d
.w
, d
.h
);
370 CGContextDrawImage(fl_gc
, rect
, img
);
376 #endif // __APPLE_QUARTZ__
378 // build the mask bitmap used by Fl_Pixmap:
379 if (fl_mask_bitmap
&& transparent_index
>= 0) {
381 uchar
* bitmap
= new uchar
[W
* d
.h
];
382 *fl_mask_bitmap
= bitmap
;
383 for (int Y
= 0; Y
< d
.h
; Y
++) {
384 const uchar
* p
= data
[Y
];
385 if (chars_per_pixel
<= 1) {
387 for (int X
= 0; X
< W
; X
++) {
388 uchar b
= (dw
-->0 && *p
++ != transparent_index
);
389 if (dw
-->0 && *p
++ != transparent_index
) b
|= 2;
390 if (dw
-->0 && *p
++ != transparent_index
) b
|= 4;
391 if (dw
-->0 && *p
++ != transparent_index
) b
|= 8;
392 if (dw
-->0 && *p
++ != transparent_index
) b
|= 16;
393 if (dw
-->0 && *p
++ != transparent_index
) b
|= 32;
394 if (dw
-->0 && *p
++ != transparent_index
) b
|= 64;
395 if (dw
-->0 && *p
++ != transparent_index
) b
|= 128;
399 uchar b
= 0, bit
= 1;
400 for (int X
= 0; X
< d
.w
; X
++) {
402 ind
= (ind
<<8) | (*p
++);
403 if (ind
!= transparent_index
) b
|= bit
;
405 if (bit
< 128) bit
<<= 1;
413 if (bit
> 1) *bitmap
++ = b
;
418 fl_draw_image(chars_per_pixel
==1 ? cb1
: cb2
, &d
, x
, y
, d
.w
, d
.h
, 4);
419 #ifdef __APPLE_QUARTZ__
423 if (chars_per_pixel
> 1) for (int i
= 0; i
< 256; i
++) delete[] d
.byte1
[i
];
428 // End of "$Id: fl_draw_pixmap.cxx 8362 2011-02-02 18:39:34Z manolo $".