themes: Workaround for bug where a background color of RGB 0,0,0 in Black color schem...
[ntk.git] / src / fl_draw_pixmap.cxx
blob68f7df6f1fd566c1a515b8cf1c8fad6b50a28233
1 //
2 // "$Id: fl_draw_pixmap.cxx 8362 2011-02-02 18:39:34Z 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 // 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!!!
38 #include <FL/Fl.H>
39 #include <FL/fl_draw.H>
40 #include <FL/x.H>
41 #include <stdio.h>
42 #include "flstring.h"
44 static int ncolors, chars_per_pixel;
46 /**
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);
59 /**
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;
67 return 1;
70 #ifdef U64
72 // The callback from fl_draw_image to get a row of data passes this:
73 struct pixmap_data {
74 int w, h;
75 const uchar*const* data;
76 union {
77 U64 colors[256];
78 U64* byte1[256];
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;
86 U64* q = (U64*)buf;
87 for (int X=w; X>0; X-=2, p += 2) {
88 if (X>1) {
89 # if WORDS_BIGENDIAN
90 *q++ = (d.colors[p[0]]<<32) | d.colors[p[1]];
91 # else
92 *q++ = (d.colors[p[1]]<<32) | d.colors[p[0]];
93 # endif
94 } else {
95 # if WORDS_BIGENDIAN
96 *q++ = d.colors[p[0]]<<32;
97 # else
98 *q++ = d.colors[p[0]];
99 # endif
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;
108 U64* q = (U64*)buf;
109 for (int X=w; X>0; X-=2) {
110 U64* colors = d.byte1[*p++];
111 int index = *p++;
112 if (X>1) {
113 U64* colors1 = d.byte1[*p++];
114 int index1 = *p++;
115 # if WORDS_BIGENDIAN
116 *q++ = (colors[index]<<32) | colors1[index1];
117 # else
118 *q++ = (colors1[index1]<<32) | colors[index];
119 # endif
120 } else {
121 # if WORDS_BIGENDIAN
122 *q++ = colors[index]<<32;
123 # else
124 *q++ = colors[index];
125 # endif
130 #else // U32
132 // The callback from fl_draw_image to get a row of data passes this:
133 struct pixmap_data {
134 int w, h;
135 const uchar*const* data;
136 union {
137 U32 colors[256];
138 U32* byte1[256];
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;
146 U32* q = (U32*)buf;
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;
154 U32* q = (U32*)buf;
155 for (int X=w; X--;) {
156 U32* colors = d.byte1[*p++];
157 *q++ = colors[*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);
178 #ifdef WIN32
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
188 int i;
189 r = 2; g = 3; b = 4;
190 while (1) {
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) {
195 free(used_colors);
196 win_pixmap_bg_color = RGB(r, g, b);
197 return;
199 if (r < 255) r++;
200 else {
201 r = 0;
202 if (g < 255) g++;
203 else {
204 g = 0;
205 b++;
210 #endif
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) {
217 pixmap_data d;
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
222 #ifdef WIN32
223 color_count = 0;
224 used_colors = (uchar *)malloc(abs(ncolors)*3*sizeof(uchar));
225 #endif
227 if (ncolors < 0) { // FLTK (non standard) compressed colormap
228 ncolors = -ncolors;
229 const uchar *p = *data++;
230 // if first color is ' ' it is transparent (put it later to make
231 // it not be transparent):
232 if (*p == ' ') {
233 uchar* c = (uchar*)&d.colors[(int)' '];
234 #ifdef U64
235 *(U64*)c = 0;
236 # if WORDS_BIGENDIAN
237 c += 4;
238 # endif
239 #endif
240 transparent_index = ' ';
241 Fl::get_color(bg, c[0], c[1], c[2]); c[3] = 0;
242 transparent_c = c;
243 p += 4;
244 ncolors--;
246 // read all the rest of the colors:
247 for (int i=0; i < ncolors; i++) {
248 uchar* c = (uchar*)&d.colors[*p++];
249 #ifdef U64
250 *(U64*)c = 0;
251 # if WORDS_BIGENDIAN
252 c += 4;
253 # endif
254 #endif
255 #ifdef WIN32
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);
259 color_count++;
260 #endif
261 *c++ = *p++;
262 *c++ = *p++;
263 *c++ = *p++;
264 #ifdef __APPLE_QUARTZ__
265 *c = 255;
266 #else
267 *c = 0;
268 #endif
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:
275 int ind = *p++;
276 uchar* c;
277 if (chars_per_pixel>1) {
278 #ifdef U64
279 U64* colors = d.byte1[ind];
280 if (!colors) colors = d.byte1[ind] = new U64[256];
281 #else
282 U32* colors = d.byte1[ind];
283 if (!colors) colors = d.byte1[ind] = new U32[256];
284 #endif
285 c = (uchar*)&colors[*p];
286 ind = (ind<<8)|*p++;
287 } else {
288 c = (uchar *)&d.colors[ind];
290 // look for "c word", or last word if none:
291 const uchar *previous_word = p;
292 for (;;) {
293 while (*p && isspace(*p)) p++;
294 uchar what = *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;
299 previous_word = p;
300 while (*p && !isspace(*p)) p++;
302 #ifdef U64
303 *(U64*)c = 0;
304 # if WORDS_BIGENDIAN
305 c += 4;
306 # endif
307 #endif
308 #ifdef __APPLE_QUARTZ__
309 c[3] = 255;
310 #endif
311 int parse = fl_parse_color((const char*)p, c[0], c[1], c[2]);
312 if (parse) {
313 #ifdef WIN32
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];
317 color_count++;
318 #endif
320 else {
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__
325 c[3] = 0;
326 #endif
327 transparent_index = ind;
328 transparent_c = c;
332 d.data = data;
333 #ifdef WIN32
334 if (transparent_c) {
335 make_unused_color(transparent_c[0], transparent_c[1], transparent_c[2]);
337 else {
338 uchar r, g, b;
339 make_unused_color(r, g, b);
341 #endif
343 #ifdef __APPLE_QUARTZ__
344 if (fl_graphics_driver->class_name() == Fl_Quartz_Graphics_Driver::class_id ) {
345 bool transparent = (transparent_index>=0);
346 transparent = true;
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++];
354 } else {
355 for (int X = 0; X < d.w; X++) {
356 U32* colors = (U32*)d.byte1[*p++];
357 *q++ = colors[*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);
371 Fl_X::q_end_image();
372 CGImageRelease(img);
373 delete[] array;
375 else {
376 #endif // __APPLE_QUARTZ__
378 // build the mask bitmap used by Fl_Pixmap:
379 if (fl_mask_bitmap && transparent_index >= 0) {
380 int W = (d.w+7)/8;
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) {
386 int dw = d.w;
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;
396 *bitmap++ = b;
398 } else {
399 uchar b = 0, bit = 1;
400 for (int X = 0; X < d.w; X++) {
401 int ind = *p++;
402 ind = (ind<<8) | (*p++);
403 if (ind != transparent_index) b |= bit;
405 if (bit < 128) bit <<= 1;
406 else {
407 *bitmap++ = b;
408 b = 0;
409 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__
421 #endif
423 if (chars_per_pixel > 1) for (int i = 0; i < 256; i++) delete[] d.byte1[i];
424 return 1;
428 // End of "$Id: fl_draw_pixmap.cxx 8362 2011-02-02 18:39:34Z manolo $".