Add ability to convert a Fl_Pixmap into a Fl_RGB_Image.

This is very convenient as a lot of other functions only accept
a Fl_RGB_Image. Adding this functionality also required a bit
of spring cleaning in the the drawing routines. STR #2659.


git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10192 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Pierre Ossman 2014-06-12 13:28:04 +00:00
parent 5e9624286a
commit ed7983f5b5
4 changed files with 109 additions and 247 deletions

View File

@ -26,6 +26,7 @@
#include <stdlib.h>
class Fl_Widget;
class Fl_Pixmap;
struct Fl_Menu_Item;
struct Fl_Label;
@ -203,6 +204,7 @@ public:
*/
Fl_RGB_Image(const uchar *bits, int W, int H, int D=3, int LD=0) :
Fl_Image(W,H,D), array(bits), alloc_array(0), id_(0), mask_(0) {data((const char **)&array, 1); ld(LD);}
Fl_RGB_Image(const Fl_Pixmap *pxm, Fl_Color bg=FL_GRAY);
virtual ~Fl_RGB_Image();
virtual Fl_Image *copy(int W, int H);
Fl_Image *copy() { return copy(w(), h()); }

View File

@ -165,7 +165,22 @@ Fl_Image::measure(const Fl_Label *lo, // I - Label
//
size_t Fl_RGB_Image::max_size_ = ~((size_t)0);
/** The destructor free all memory and server resources that are used by the image. */
int fl_convert_pixmap(const char*const* cdata, uchar* out, Fl_Color bg);
/** The constructor creates a new RGBA image from the specified Fl_Pixmap.
The RGBA image is built fully opaque except for the transparent area
of the pixmap that is assigned the \par bg color with full transparency */
Fl_RGB_Image::Fl_RGB_Image(const Fl_Pixmap *pxm, Fl_Color bg):
Fl_Image(pxm->w(), pxm->h(), 4), id_(0), mask_(0)
{
array = new uchar[w() * h() * d()];
alloc_array = 1;
fl_convert_pixmap(pxm->data(), (uchar*)array, bg);
data((const char **)&array, 1);
}
/** The destructor frees all memory and server resources that are used by the image. */
Fl_RGB_Image::~Fl_RGB_Image() {
uncache();
if (alloc_array) delete[] (uchar *)array;

View File

@ -64,99 +64,6 @@ int fl_measure_pixmap(const char * const *cdata, int &w, int &h) {
return 1;
}
#ifdef U64
// The callback from fl_draw_image to get a row of data passes this:
struct pixmap_data {
int w, h;
const uchar*const* data;
union {
U64 colors[256];
U64* byte1[256];
};
};
// callback for 1 byte per pixel:
static void cb1(void*v, int x, int y, int w, uchar* buf) {
pixmap_data& d = *(pixmap_data*)v;
const uchar* p = d.data[y]+x;
U64* q = (U64*)buf;
for (int X=w; X>0; X-=2, p += 2) {
if (X>1) {
# if WORDS_BIGENDIAN
*q++ = (d.colors[p[0]]<<32) | d.colors[p[1]];
# else
*q++ = (d.colors[p[1]]<<32) | d.colors[p[0]];
# endif
} else {
# if WORDS_BIGENDIAN
*q++ = d.colors[p[0]]<<32;
# else
*q++ = d.colors[p[0]];
# endif
}
}
}
// callback for 2 bytes per pixel:
static void cb2(void*v, int x, int y, int w, uchar* buf) {
pixmap_data& d = *(pixmap_data*)v;
const uchar* p = d.data[y]+2*x;
U64* q = (U64*)buf;
for (int X=w; X>0; X-=2) {
U64* colors = d.byte1[*p++];
int index = *p++;
if (X>1) {
U64* colors1 = d.byte1[*p++];
int index1 = *p++;
# if WORDS_BIGENDIAN
*q++ = (colors[index]<<32) | colors1[index1];
# else
*q++ = (colors1[index1]<<32) | colors[index];
# endif
} else {
# if WORDS_BIGENDIAN
*q++ = colors[index]<<32;
# else
*q++ = colors[index];
# endif
}
}
}
#else // U32
// The callback from fl_draw_image to get a row of data passes this:
struct pixmap_data {
int w, h;
const uchar*const* data;
union {
U32 colors[256];
U32* byte1[256];
};
};
// callback for 1 byte per pixel:
static void cb1(void*v, int x, int y, int w, uchar* buf) {
pixmap_data& d = *(pixmap_data*)v;
const uchar* p = d.data[y]+x;
U32* q = (U32*)buf;
for (int X=w; X--;) *q++ = d.colors[*p++];
}
// callback for 2 bytes per pixel:
static void cb2(void*v, int x, int y, int w, uchar* buf) {
pixmap_data& d = *(pixmap_data*)v;
const uchar* p = d.data[y]+2*x;
U32* q = (U32*)buf;
for (int X=w; X--;) {
U32* colors = d.byte1[*p++];
*q++ = colors[*p++];
}
}
#endif // U64 else U32
uchar **fl_mask_bitmap; // if non-zero, create bitmap and store pointer here
/**
@ -210,15 +117,19 @@ static void make_unused_color(uchar &r, uchar &g, uchar &b) {
}
#endif
/**
Draw XPM image data, with the top-left corner at the given position.
\see fl_draw_pixmap(char* const* data, int x, int y, Fl_Color bg)
*/
int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) {
pixmap_data d;
if (!fl_measure_pixmap(cdata, d.w, d.h)) return 0;
int fl_convert_pixmap(const char*const* cdata, uchar* out, Fl_Color bg) {
int w, h;
const uchar*const* data = (const uchar*const*)(cdata+1);
int transparent_index = -1;
if (!fl_measure_pixmap(cdata, w, h))
return 0;
if ((chars_per_pixel < 1) || (chars_per_pixel > 2))
return 0;
uchar colors[1<<(chars_per_pixel*8)][4];
#ifdef WIN32
uchar *transparent_c = (uchar *)0; // such that transparent_c[0,1,2] are the RGB of the transparent color
color_count = 0;
@ -231,13 +142,7 @@ int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) {
// if first color is ' ' it is transparent (put it later to make
// it not be transparent):
if (*p == ' ') {
uchar* c = (uchar*)&d.colors[(int)' '];
#ifdef U64
*(U64*)c = 0;
# if WORDS_BIGENDIAN
c += 4;
# endif
#endif
uchar* c = colors[(int)' '];
transparent_index = ' ';
Fl::get_color(bg, c[0], c[1], c[2]); c[3] = 0;
#ifdef WIN32
@ -248,13 +153,7 @@ int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) {
}
// read all the rest of the colors:
for (int i=0; i < ncolors; i++) {
uchar* c = (uchar*)&d.colors[*p++];
#ifdef U64
*(U64*)c = 0;
# if WORDS_BIGENDIAN
c += 4;
# endif
#endif
uchar* c = colors[*p++];
#ifdef WIN32
used_colors[color_count].r = *(p+0);
used_colors[color_count].g = *(p+1);
@ -264,32 +163,17 @@ int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) {
*c++ = *p++;
*c++ = *p++;
*c++ = *p++;
#ifdef __APPLE_QUARTZ__
*c = 255;
#else
*c = 0;
#endif
}
} else { // normal XPM colormap with names
if (chars_per_pixel>1) memset(d.byte1, 0, sizeof(d.byte1));
for (int i=0; i<ncolors; i++) {
const uchar *p = *data++;
// the first 1 or 2 characters are the color index:
int ind = *p++;
uchar* c;
if (chars_per_pixel>1) {
#ifdef U64
U64* colors = d.byte1[ind];
if (!colors) colors = d.byte1[ind] = new U64[256];
#else
U32* colors = d.byte1[ind];
if (!colors) colors = d.byte1[ind] = new U32[256];
#endif
c = (uchar*)&colors[*p];
if (chars_per_pixel>1)
ind = (ind<<8)|*p++;
} else {
c = (uchar *)&d.colors[ind];
}
c = colors[ind];
// look for "c word", or last word if none:
const uchar *previous_word = p;
for (;;) {
@ -302,16 +186,8 @@ int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) {
previous_word = p;
while (*p && !isspace(*p)) p++;
}
#ifdef U64
*(U64*)c = 0;
# if WORDS_BIGENDIAN
c += 4;
# endif
#endif
#ifdef __APPLE_QUARTZ__
c[3] = 255;
#endif
int parse = fl_parse_color((const char*)p, c[0], c[1], c[2]);
c[3] = 255;
if (parse) {
#ifdef WIN32
used_colors[color_count].r = c[0];
@ -323,9 +199,7 @@ int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) {
// assume "None" or "#transparent" for any errors
// "bg" should be transparent...
Fl::get_color(bg, c[0], c[1], c[2]);
#ifdef __APPLE_QUARTZ__
c[3] = 0;
#endif
transparent_index = ind;
#ifdef WIN32
transparent_c = c;
@ -333,7 +207,6 @@ int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) {
} // if parse
} // for ncolors
} // if ncolors
d.data = data;
#ifdef WIN32
if (transparent_c) {
make_unused_color(transparent_c[0], transparent_c[1], transparent_c[2]);
@ -342,78 +215,76 @@ int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) {
make_unused_color(r, g, b);
}
#endif
#ifdef __APPLE_QUARTZ__
if (Fl_Surface_Device::surface() == Fl_Display_Device::display_device()) {
U32 *array = new U32[d.w * d.h], *q = array;
for (int Y = 0; Y < d.h; Y++) {
U32 *q = (U32*)out;
for (int Y = 0; Y < h; Y++) {
const uchar* p = data[Y];
if (chars_per_pixel <= 1) {
for (int X = 0; X < d.w; X++) {
*q++ = d.colors[*p++];
}
for (int X = 0; X < w; X++)
memcpy(q++, colors[*p++], 4);
} else {
for (int X = 0; X < d.w; X++) {
U32* colors = (U32*)d.byte1[*p++];
*q++ = colors[*p++];
for (int X = 0; X < w; X++) {
int ind = (*p++)<<8;
ind |= *p++;
memcpy(q++, colors[ind], 4);
}
}
}
Fl_RGB_Image* rgb = new Fl_RGB_Image((uchar*)array, d.w, d.h, 4);
return 1;
}
/**
Draw XPM image data, with the top-left corner at the given position.
\see fl_draw_pixmap(char* const* data, int x, int y, Fl_Color bg)
*/
int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) {
int w, h;
if (!fl_measure_pixmap(cdata, w, h))
return 0;
uchar buffer[w*h*4];
if (!fl_convert_pixmap(cdata, buffer, bg))
return 0;
// FIXME: Hack until fl_draw_image() supports alpha properly
#ifdef __APPLE_QUARTZ__
if (Fl_Surface_Device::surface() == Fl_Display_Device::display_device()) {
Fl_RGB_Image* rgb = new Fl_RGB_Image(buffer, w, h, 4);
rgb->draw(x, y);
delete rgb;
delete[] array;
} else {
#endif // __APPLE_QUARTZ__
// build the mask bitmap used by Fl_Pixmap:
if (fl_mask_bitmap && transparent_index >= 0) {
int W = (d.w+7)/8;
uchar* bitmap = new uchar[W * d.h];
if (fl_mask_bitmap) {
int W = (w+7)/8;
uchar* bitmap = new uchar[W * h];
*fl_mask_bitmap = bitmap;
for (int Y = 0; Y < d.h; Y++) {
const uchar* p = data[Y];
if (chars_per_pixel <= 1) {
int dw = d.w;
for (int X = 0; X < W; X++) {
uchar b = (dw-->0 && *p++ != transparent_index);
if (dw-->0 && *p++ != transparent_index) b |= 2;
if (dw-->0 && *p++ != transparent_index) b |= 4;
if (dw-->0 && *p++ != transparent_index) b |= 8;
if (dw-->0 && *p++ != transparent_index) b |= 16;
if (dw-->0 && *p++ != transparent_index) b |= 32;
if (dw-->0 && *p++ != transparent_index) b |= 64;
if (dw-->0 && *p++ != transparent_index) b |= 128;
*bitmap++ = b;
}
} else {
uchar b = 0, bit = 1;
for (int X = 0; X < d.w; X++) {
int ind = *p++;
ind = (ind<<8) | (*p++);
if (ind != transparent_index) b |= bit;
if (bit < 128) {
const uchar *p = &buffer[3];
uchar b = 0;
for (int Y = 0; Y < h; Y++) {
b = 0;
for (int X = 0, bit = 1; X < w; X++, p += 4) {
if (*p > 127)
b |= bit;
bit <<= 1;
} else {
if (bit > 0x80 || X == w-1) {
*bitmap++ = b;
bit = 1;
b = 0;
bit = 1;
}
}
if (bit > 1) *bitmap++ = b;
} // if chars_per_pixel
} // for Y
}
fl_draw_image(chars_per_pixel==1 ? cb1 : cb2, &d, x, y, d.w, d.h, 4);
fl_draw_image(buffer, x, y, w, h, 4);
#ifdef __APPLE_QUARTZ__
}
#endif
if (chars_per_pixel > 1)
for (int i = 0; i < 256; i++)
delete[] d.byte1[i];
return 1;
}

View File

@ -185,72 +185,38 @@ static inline uchar swap_byte(const uchar b) {
extern uchar **fl_mask_bitmap;
struct callback_data {
const uchar *data;
int D, LD;
};
static void draw_image_cb(void *data, int x, int y, int w, uchar *buf) {
struct callback_data *cb_data;
const uchar *curdata;
cb_data = (struct callback_data*)data;
curdata = cb_data->data + x*cb_data->D + y*cb_data->LD;
memcpy(buf, curdata, w*cb_data->D);
}
void Fl_PostScript_Graphics_Driver::draw_image(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD) {
double x = ix, y = iy, w = iw, h = ih;
if (D<3){ //mono
draw_image_mono(data, ix, iy, iw, ih, D, LD);
return;
}
int i,j, k;
fprintf(output,"save\n");
const char * interpol;
if (lang_level_>1){
if (interpolate_)
interpol="true";
else
interpol="false";
if (mask && lang_level_>2)
fprintf(output, "%g %g %g %g %i %i %i %i %s CIM\n", x , y+h , w , -h , iw , ih, mx, my, interpol);
else
fprintf(output, "%g %g %g %g %i %i %s CII\n", x , y+h , w , -h , iw , ih, interpol);
} else
fprintf(output , "%g %g %g %g %i %i CI", x , y+h , w , -h , iw , ih);
struct callback_data cb_data;
if (!LD) LD = iw*D;
uchar *curmask=mask;
for (j=0; j<ih;j++){
if (mask){
for (k=0;k<my/ih;k++){
for (i=0; i<((mx+7)/8);i++){
if (!(i%80)) fprintf(output, "\n");
fprintf(output, "%.2x",swap_byte(*curmask));
curmask++;
}
fprintf(output,"\n");
}
}
const uchar *curdata=data+j*LD;
for (i=0 ; i<iw ; i++) {
uchar r = curdata[0];
uchar g = curdata[1];
uchar b = curdata[2];
if (lang_level_<3 && D>3) { //can do mixing using bg_* colors)
unsigned int a2 = curdata[3]; //must be int
unsigned int a = 255-a2;
r = (a2 * r + bg_r * a)/255;
g = (a2 * g + bg_g * a)/255;
b = (a2 * b + bg_b * a)/255;
}
if (!(i%40)) fprintf(output, "\n");
fprintf(output, "%.2x%.2x%.2x", r, g, b);
curdata +=D;
}
fprintf(output,"\n");
}
fprintf(output," >\nrestore\n" );
cb_data.data = data;
cb_data.D = D;
cb_data.LD = LD;
draw_image(draw_image_cb, &cb_data, ix, iy, iw, ih, D);
}
void Fl_PostScript_Graphics_Driver::draw_image(Fl_Draw_Image_Cb call, void *data, int ix, int iy, int iw, int ih, int D) {
@ -325,6 +291,14 @@ void Fl_PostScript_Graphics_Driver::draw_image(Fl_Draw_Image_Cb call, void *data
uchar g = curdata[1];
uchar b = curdata[2];
if (lang_level_<3 && D>3) { //can do mixing using bg_* colors)
unsigned int a2 = curdata[3]; //must be int
unsigned int a = 255-a2;
r = (a2 * r + bg_r * a)/255;
g = (a2 * g + bg_g * a)/255;
b = (a2 * b + bg_b * a)/255;
}
if (!(i%40)) fputs("\n", output);
fprintf(output, "%.2x%.2x%.2x", r, g, b);