1
const char *rcsid_x11_png_c =
4
Crossfire client, a client program for the crossfire program.
6
Copyright (C) 2001 Mark Wedel & Crossfire Development Team
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 2 of the License, or
11
(at your option) any later version.
13
This program 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
16
GNU General Public License for more details.
18
You should have received a copy of the GNU General Public License
19
along with this program; if not, write to the Free Software
20
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
The author can be reached via e-mail to crossfire-devel@real-time.com
25
/* This is a light weight png -> xpixmap function. Most of the code is from
26
* the example png documentation.
27
* I wrote this because I could not find a simple function that did this -
28
* most all libraries out there tended to do a lot more than I needed for
29
* crossfire - in addition, imLib actually has bugs which prevents it from
30
* rendering some images properly.
32
* This function is far from complete, but does the job and removes the need
33
* for yet another library.
42
#include <X11/Xutil.h>
43
#include "client-types.h"
47
/* Defines for PNG return values */
48
/* These should be in a header file, but currently our calling functions
49
* routines just check for nonzero return status and don't really care
50
* why the load failed.
53
#define PNGX_OUTOFMEM 2
56
static unsigned char *data_cp;
57
static int data_len, data_start;
59
static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {
60
memcpy(data, data_cp + data_start, length);
65
uint8 *png_to_data(uint8 *data, int len, uint32 *width, uint32 *height)
68
static png_bytepp rows=NULL;
69
static int rows_byte=0;
73
int bit_depth, color_type, interlace_type, compression_type, y;
79
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
85
info_ptr = png_create_info_struct (png_ptr);
88
png_destroy_read_struct (&png_ptr, NULL, NULL);
91
if (setjmp (png_ptr->jmpbuf)) {
92
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
96
png_set_read_fn(png_ptr, NULL, user_read_data);
97
png_read_info (png_ptr, info_ptr);
99
/* Breaking these out instead of using png_get_IHDR fixes bug
100
* 1249877 - problems on 64 bit systems (amd64 at least)
102
*width = png_get_image_width(png_ptr, info_ptr);
103
*height = png_get_image_height(png_ptr, info_ptr);
104
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
105
color_type = png_get_color_type(png_ptr, info_ptr);
106
interlace_type = png_get_interlace_type(png_ptr, info_ptr);
107
compression_type = png_get_compression_type(png_ptr, info_ptr);
109
if (color_type == PNG_COLOR_TYPE_PALETTE &&
112
/* Convert indexed images to RGB */
113
png_set_expand (png_ptr);
115
} else if (color_type == PNG_COLOR_TYPE_GRAY &&
118
/* Convert grayscale to RGB */
119
png_set_expand (png_ptr);
121
} else if (png_get_valid (png_ptr,
122
info_ptr, PNG_INFO_tRNS)) {
124
/* If we have transparency header, convert it to alpha
126
png_set_expand(png_ptr);
128
} else if (bit_depth < 8) {
130
/* If we have < 8 scale it up to 8 */
131
png_set_expand(png_ptr);
134
/* Conceivably, png_set_packing() is a better idea;
135
* God only knows how libpng works
138
/* If we are 16-bit, convert to 8-bit */
139
if (bit_depth == 16) {
140
png_set_strip_16(png_ptr);
143
/* If gray scale, convert to RGB */
144
if (color_type == PNG_COLOR_TYPE_GRAY ||
145
color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
146
png_set_gray_to_rgb(png_ptr);
149
/* If interlaced, handle that */
150
if (interlace_type != PNG_INTERLACE_NONE) {
151
png_set_interlace_handling(png_ptr);
154
/* pad it to 4 bytes to make processing easier */
155
if (!(color_type & PNG_COLOR_MASK_ALPHA))
156
png_set_filler(png_ptr, 255, PNG_FILLER_AFTER);
158
/* Update the info the reflect our transformations */
159
png_read_update_info(png_ptr, info_ptr);
161
/* re-read due to transformations just made */
162
/* Breaking these out instead of using png_get_IHDR fixes bug
163
* 1249877 - problems on 64 bit systems (amd64 at least)
165
*width = png_get_image_width(png_ptr, info_ptr);
166
*height = png_get_image_height(png_ptr, info_ptr);
167
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
168
color_type = png_get_color_type(png_ptr, info_ptr);
169
interlace_type = png_get_interlace_type(png_ptr, info_ptr);
170
compression_type = png_get_compression_type(png_ptr, info_ptr);
172
pixels = (uint8*)malloc(*width * *height * 4);
175
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
176
fprintf(stderr,"Out of memory - exiting\n");
180
/* the png library needs the rows, but we will just return the raw data */
181
if (rows_byte == 0) {
182
rows =(png_bytepp) malloc(sizeof(char*) * *height);
184
} else if (*height > rows_byte) {
185
rows =(png_bytepp) realloc(rows, sizeof(char*) * *height);
189
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
193
for (y=0; y<*height; y++)
194
rows[y] = pixels + y * *width * 4;
196
png_read_image(png_ptr, rows);
197
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
203
/* rescale_png_image takes png data and scales it accordingly.
204
* This function is based on pnmscale, but has been modified to support alpha
205
* channel - instead of blending the alpha channel, it takes the most opaque
206
* value - blending it is not likely to give sane results IMO - for any image
207
* that has transparent information, if we blended the alpha, the result would
208
* be the edges of that region being partially transparent.
209
* This function has also been re-written to use more static data - in the
210
* case of the client, it will be called thousands of times, so it doesn't make
211
* sense to free the data and then re-allocate it.
213
* For pixels that are fully transparent, the end result after scaling is they
214
* will be tranparent black. This is a needed effect for blending to work properly.
216
* This function returns a new pointer to the scaled image data. This is
217
* malloc'd data, so should be freed at some point to prevent leaks.
218
* This function does not modify the data passed to it - the caller is responsible
219
* for freeing it if it is no longer needed.
221
* function arguments:
222
* data: PNG data - really, this is any 4 byte per pixel data, in RGBA format.
223
* *width, *height: The source width and height. These values are modified
224
* to contain the new image size.
225
* scale: percentage size that new image should be. 100 is a same size
226
* image - values larger than 100 will result in zoom, values less than
227
* 100 will result in a shrinkage.
230
/* RATIO is used to know what units scale is - in this case, a percentage, so
235
#define MAX_IMAGE_WIDTH 1024
236
#define MAX_IMAGE_HEIGHT 1024
239
uint8 *rescale_rgba_data(uint8 *data, int *width, int *height, int scale)
241
static int xrow[BPP * MAX_IMAGE_WIDTH], yrow[BPP*MAX_IMAGE_HEIGHT];
242
static uint8 *nrows[MAX_IMAGE_HEIGHT];
244
/* Figure out new height/width */
245
int new_width = *width * scale / RATIO, new_height = *height * scale / RATIO;
247
int sourcerow=0, ytoleft, ytofill, xtoleft, xtofill, dest_column=0, source_column=0, needcol,
253
if (*width > MAX_IMAGE_WIDTH || new_width > MAX_IMAGE_WIDTH
254
|| *height > MAX_IMAGE_HEIGHT || new_height > MAX_IMAGE_HEIGHT)
256
fprintf(stderr, "Image too big\n");
260
/* clear old values these may have */
261
memset(yrow, 0, sizeof(int) * *height * BPP);
263
ndata = (uint8*)malloc(new_width * new_height * BPP);
265
for (y=0; y<new_height; y++)
266
nrows[y] = (png_bytep) (ndata + y * new_width * BPP);
271
for (y=0,sourcerow=0; y < new_height; y++) {
272
memset(xrow, 0, sizeof(int) * *width * BPP);
273
while (ytoleft < ytofill) {
274
for (x=0; x< *width; ++x) {
275
/* Only want to copy the data if this is not a transperent pixel.
276
* If it is transparent, the color information is has is probably
277
* bogus, and blending that makes the results look worse.
279
if (data[(sourcerow * *width + x)*BPP+3] > 0 ) {
280
yrow[x*BPP] += ytoleft * data[(sourcerow * *width + x)*BPP]/RATIO;
281
yrow[x*BPP+1] += ytoleft * data[(sourcerow * *width + x)*BPP+1]/RATIO;
282
yrow[x*BPP+2] += ytoleft * data[(sourcerow * *width + x)*BPP+2]/RATIO;
284
/* Alpha is a bit special - we don't want to blend it -
285
* we want to take whatever is the more opaque value.
287
if (data[(sourcerow * *width + x)*BPP+3] > yrow[x*BPP+3])
288
yrow[x*BPP+3] = data[(sourcerow * *width + x)*BPP+3];
292
if (sourcerow < *height)
296
for (x=0; x < *width; ++x) {
297
if (data[(sourcerow * *width + x)*BPP+3] > 0 ) {
298
xrow[x*BPP] = yrow[x*BPP] + ytofill * data[(sourcerow * *width + x)*BPP] / RATIO;
299
xrow[x*BPP+1] = yrow[x*BPP+1] + ytofill * data[(sourcerow * *width + x)*BPP+1] / RATIO;
300
xrow[x*BPP+2] = yrow[x*BPP+2] + ytofill * data[(sourcerow * *width + x)*BPP+2] / RATIO;
302
if (data[(sourcerow * *width + x)*BPP+3] > xrow[x*BPP+3])
303
xrow[x*BPP+3] = data[(sourcerow * *width + x)*BPP+3];
304
yrow[x*BPP]=0; yrow[x*BPP+1]=0; yrow[x*BPP+2]=0; yrow[x*BPP+3]=0;
310
if (sourcerow < *height)
321
for (x=0; x< *width; x++) {
324
while (xtoleft >= xtofill) {
330
if (xrow[source_column*BPP+3] > 0) {
331
r += xtofill * xrow[source_column*BPP] / RATIO;
332
g += xtofill * xrow[1+source_column*BPP] / RATIO;
333
b += xtofill * xrow[2+source_column*BPP] / RATIO;
335
if (xrow[3+source_column*BPP] > a)
336
a = xrow[3+source_column*BPP];
338
nrows[destrow][dest_column * BPP] = r;
339
nrows[destrow][1+dest_column * BPP] = g;
340
nrows[destrow][2+dest_column * BPP] = b;
341
nrows[destrow][3+dest_column * BPP] = a;
354
if (xrow[3+source_column*BPP] > 0) {
355
r += xtoleft * xrow[source_column*BPP] / RATIO;
356
g += xtoleft * xrow[1+source_column*BPP] / RATIO;
357
b += xtoleft * xrow[2+source_column*BPP] / RATIO;
359
if (xrow[3+source_column*BPP] > a)
360
a = xrow[3+source_column*BPP];
369
if (xrow[3+source_column*BPP] > 0) {
370
r += xtofill * xrow[source_column*BPP] / RATIO;
371
g += xtofill * xrow[1+source_column*BPP] / RATIO;
372
b += xtofill * xrow[2+source_column*BPP] / RATIO;
374
if (xrow[3+source_column*BPP] > a)
375
a = xrow[3+source_column*BPP];
378
/* Not positve, but without the bound checking for dest_column,
379
* we were overrunning the buffer. My guess is this only really
380
* showed up if when the images are being scaled - there is probably
381
* something like half a pixel left over.
383
if (!needcol && (dest_column < new_width)) {
384
nrows[destrow][dest_column * BPP] = r;
385
nrows[destrow][1+dest_column * BPP] = g;
386
nrows[destrow][2+dest_column * BPP] = b;
387
nrows[destrow][3+dest_column * BPP] = a;
392
*height = new_height;
397
static XImage *ximage;
398
static int rmask=0, bmask=0,gmask=0,need_color_alloc=0, rshift=16, bshift=0, gshift=8,
399
rev_rshift=0, rev_gshift=0, rev_bshift=0;
400
static int colors_alloced=0, private_cmap=0, colormap_size;
401
struct Pngx_Color_Values {
402
unsigned char red, green, blue;
406
#define COLOR_FACTOR 3
407
#define BRIGHTNESS_FACTOR 1
409
/* This function is used to find the pixel and return it
410
* to the caller. We store what pixels we have already allocated
411
* and try to find a match against that. The reason for this is that
412
* XAllocColor is a very slow routine. Before my optimizations,
413
* png loading took about 140 seconds, of which 60 seconds of that
414
* was in XAllocColor calls.
416
long pngx_find_color(Display *display, Colormap *cmap, int red, int green, int blue)
419
int i, closeness=0xffffff, close_entry=-1, tmpclose;
422
for (i=0; i<colors_alloced; i++) {
423
if ((color_values[i].red == red) && (color_values[i].green == green) &&
424
(color_values[i].blue == blue)) return color_values[i].pixel_value;
426
tmpclose = COLOR_FACTOR * (abs(red - color_values[i].red) +
427
abs(green - color_values[i].green) +
428
abs(blue - color_values[i].blue)) +
429
BRIGHTNESS_FACTOR * abs((red + green + blue) -
430
(color_values[i].red + color_values[i].green + color_values[i].blue));
432
/* I already know that 8 bit is not enough to hold all the PNG colors,
433
* so lets do some early optimization
435
if (tmpclose < 3) return color_values[i].pixel_value;
436
if (tmpclose < closeness) {
437
closeness = tmpclose;
442
/* If the colormap is full, no reason to do anything more */
443
if (colors_alloced == colormap_size)
444
return color_values[close_entry].pixel_value;
447
/* If we get here, we haven't cached the color */
449
scolor.red = (red << 8) + red;
450
scolor.green = (green << 8) + green;
451
scolor.blue = (blue << 8) + blue;
455
if (!XAllocColor(display, *cmap, &scolor)) {
457
fprintf(stderr,"Going to private colormap after %d allocs\n", colors_alloced);
458
*cmap = XCopyColormapAndFree(display, *cmap);
464
fprintf(stderr,"Unable to allocate color %d %d %d, %d colors alloced, will use closenss value %d\n",
465
red, green, blue, colors_alloced, closeness);
467
colors_alloced = colormap_size; /* Colormap is exhausted */
468
return color_values[close_entry].pixel_value;
471
color_values[colors_alloced].red = red;
472
color_values[colors_alloced].green = green;
473
color_values[colors_alloced].blue = blue;
474
color_values[colors_alloced].pixel_value= scolor.pixel;
482
int init_pngx_loader(Display *display)
485
XVisualInfo xvinfo, *xvret;
488
depth = DefaultDepth(display, DefaultScreen(display));
489
visual = DefaultVisual(display, DefaultScreen(display));
490
xvinfo.visualid = XVisualIDFromVisual(visual);
491
xvret = XGetVisualInfo(display, VisualIDMask, &xvinfo, &pad);
493
fprintf(stderr,"XGetVisual found %d matching visuals?\n", pad);
496
rmask = xvret -> red_mask;
497
gmask = xvret -> green_mask;
498
bmask = xvret -> blue_mask;
499
/* We need to figure out how many bits to shift. Thats what this
500
* following block of code does. We can't presume to use just
501
* 16, 8, 0 bits for RGB respectively, as if you are on 16 bit,
502
* that is not correct. There may be a much easier way to do this -
503
* it is just bit manipulation. Note that we want to preserver
504
* the most significant bits, so these shift values can very
505
* well be negative, in which case we need to know that -
506
* the shift operators don't work with negative values.
507
* An example is 5 bits for blue - in that case, we really
508
* want to shfit right (>>) by 3 bits.
512
while (!((1 << rshift) & rmask)) rshift++;
513
while (((1 << rshift) & rmask)) rshift++;
522
while (!((1 << gshift) & gmask)) gshift++;
523
while (((1 << gshift) & gmask)) gshift++;
532
while (!((1 << bshift) & bmask)) bshift++;
533
while (((1 << bshift) & bmask)) bshift++;
542
if (xvret->class==PseudoColor) {
544
if (xvret->colormap_size>256) {
545
fprintf(stderr,"One a pseudocolor visual, but colormap has %d entries?\n", xvret->colormap_size);
547
color_values=malloc(sizeof(struct Pngx_Color_Values) * xvret->colormap_size);
548
colormap_size = xvret->colormap_size-1; /* comparing # of alloced colors against this */
552
if (depth>16) pad = 32;
553
else if (depth > 8) pad = 16;
556
ximage = XCreateImage(display, visual,
559
MAX_IMAGE_SIZE, MAX_IMAGE_SIZE, pad, 0);
561
fprintf(stderr,"Failed to create Ximage\n");
564
ximage->data = malloc(ximage->bytes_per_line * MAX_IMAGE_SIZE);
566
fprintf(stderr,"Failed to create Ximage data\n");
573
int png_to_xpixmap(Display *display, Drawable draw, unsigned char *data, int len,
574
Pixmap *pix, Pixmap *mask, Colormap *cmap,
575
unsigned long *width, unsigned long *height)
577
static uint8 *pixels=NULL;
578
static int pixels_byte=0, rows_byte=0;
579
static png_bytepp rows=NULL;
581
png_structp png_ptr=NULL;
582
png_infop info_ptr=NULL;
583
int bit_depth, color_type, interlace_type, compression_type,
584
red,green,blue, lastred=-1, lastgreen=-1, lastblue=-1,alpha,bpp, x,y,
585
has_alpha, cmask, lastcmask, lastcolor;
592
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
595
return PNGX_OUTOFMEM;
597
info_ptr = png_create_info_struct (png_ptr);
600
png_destroy_read_struct (&png_ptr, NULL, NULL);
601
return PNGX_OUTOFMEM;
603
if (setjmp (png_ptr->jmpbuf)) {
604
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
607
/* put these here to prevent compiler warnings about them getting
608
* clobbered by setjmp
615
png_set_read_fn(png_ptr, NULL, user_read_data);
616
png_read_info (png_ptr, info_ptr);
618
/* re-read due to transformations just made */
619
/* Breaking these out instead of using png_get_IHDR fixes bug
620
* 1249877 - problems on 64 bit systems (amd64 at least)
622
*width = png_get_image_width(png_ptr, info_ptr);
623
*height = png_get_image_height(png_ptr, info_ptr);
624
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
625
color_type = png_get_color_type(png_ptr, info_ptr);
626
interlace_type = png_get_interlace_type(png_ptr, info_ptr);
627
compression_type = png_get_compression_type(png_ptr, info_ptr);
629
if (color_type == PNG_COLOR_TYPE_PALETTE &&
632
/* Convert indexed images to RGB */
633
png_set_expand (png_ptr);
635
} else if (color_type == PNG_COLOR_TYPE_GRAY &&
638
/* Convert grayscale to RGB */
639
png_set_expand (png_ptr);
641
} else if (png_get_valid (png_ptr,
642
info_ptr, PNG_INFO_tRNS)) {
644
/* If we have transparency header, convert it to alpha
646
png_set_expand(png_ptr);
648
} else if (bit_depth < 8) {
650
/* If we have < 8 scale it up to 8 */
651
png_set_expand(png_ptr);
654
/* Conceivably, png_set_packing() is a better idea;
655
* God only knows how libpng works
658
/* If we are 16-bit, convert to 8-bit */
659
if (bit_depth == 16) {
660
png_set_strip_16(png_ptr);
663
/* If gray scale, convert to RGB */
664
if (color_type == PNG_COLOR_TYPE_GRAY ||
665
color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
666
png_set_gray_to_rgb(png_ptr);
669
/* If interlaced, handle that */
670
if (interlace_type != PNG_INTERLACE_NONE) {
671
png_set_interlace_handling(png_ptr);
674
/* Update the info the reflect our transformations */
675
png_read_update_info(png_ptr, info_ptr);
676
/* re-read due to transformations just made */
677
/* re-read due to transformations just made */
679
/* Breaking these out instead of using png_get_IHDR fixes bug
680
* 1249877 - problems on 64 bit systems (amd64 at least)
682
*width = png_get_image_width(png_ptr, info_ptr);
683
*height = png_get_image_height(png_ptr, info_ptr);
684
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
685
color_type = png_get_color_type(png_ptr, info_ptr);
686
interlace_type = png_get_interlace_type(png_ptr, info_ptr);
687
compression_type = png_get_compression_type(png_ptr, info_ptr);
689
if (color_type & PNG_COLOR_MASK_ALPHA)
694
/* Allocate the memory we need once, and increase it if necessary.
695
* This is more efficient the allocating this block of memory every time.
697
if (pixels_byte==0) {
698
pixels_byte =*width * *height * bpp;
699
pixels = (uint8*)malloc(pixels_byte);
700
} else if ((*width * *height * bpp) > pixels_byte) {
701
pixels_byte =*width * *height * bpp;
702
pixels=realloc(pixels, pixels_byte);
707
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
708
return PNGX_OUTOFMEM;
710
if (rows_byte == 0) {
711
rows =(png_bytepp) malloc(sizeof(char*) * *height);
713
} else if (*height > rows_byte) {
714
rows =(png_bytepp) realloc(rows, sizeof(char*) * *height);
719
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
720
return PNGX_OUTOFMEM;
723
for (y=0; y<*height; y++)
724
rows[y] = pixels + y * (*width) * bpp;
726
png_read_image(png_ptr, rows);
728
fprintf(stderr,"image is %d X %d, bpp=%d, color_type=%d\n",
729
*width, *height, bpp, color_type);
732
*pix = XCreatePixmap(display, draw, *width, *height,
733
DefaultDepth(display, DefaultScreen(display)));
735
gc=XCreateGC(display, *pix, 0, NULL);
736
XSetFunction(display, gc, GXcopy);
737
XSetPlaneMask(display, gc, AllPlanes);
739
if (color_type & PNG_COLOR_MASK_ALPHA) {
740
/* The foreground/background colors are not really
741
* colors, but rather values to set in the mask.
742
* The values used below work properly on at least
743
* 8 bit and 16 bit display - using things like
744
* blackpixel & whitepixel does NO work on
745
* both types of display.
747
*mask=XCreatePixmap(display ,draw, *width, *height,1);
748
gc_alpha=XCreateGC(display, *mask, 0, NULL);
749
XSetFunction(display, gc_alpha, GXcopy);
750
XSetPlaneMask(display, gc_alpha, AllPlanes);
751
XSetForeground(display, gc_alpha, 1);
752
XFillRectangle(display, *mask, gc_alpha, 0, 0, *width, *height);
753
XSetForeground(display, gc_alpha, 0);
758
gc_alpha = None; /* Prevent compile warnings */
761
for (y=0; y<*height; y++) {
762
for (x=0; x<*width; x++) {
764
green=rows[y][x*bpp+1];
765
blue=rows[y][x*bpp+2];
767
alpha = rows[y][x*bpp+3];
768
/* Transparent bit */
770
XDrawPoint(display, *mask, gc_alpha, x, y);
773
if (need_color_alloc) {
774
/* We only use cmask to avoid calling pngx_find_color repeatedly.
775
* when the color has not changed from the last pixel.
777
if ((lastred != red) && (lastgreen != green) && (lastblue != blue)) {
778
lastcolor = pngx_find_color(display, cmap, red, green, blue);
781
XPutPixel(ximage, x, y, lastcolor);
783
if ((lastred != red) && (lastgreen != green) && (lastblue != blue)) {
784
if (rev_rshift) red >>= rshift;
786
if (rev_gshift) green >>= gshift;
787
else green <<= gshift;
788
if (rev_bshift) blue >>= bshift;
789
else blue <<= bshift;
791
cmask = (red & rmask) | (green & gmask) | (blue & bmask);
793
XPutPixel(ximage, x, y, cmask);
798
XPutImage(display, *pix, gc, ximage, 0, 0, 0, 0, 32, 32);
800
XFreeGC(display, gc_alpha);
801
XFreeGC(display, gc);
802
png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
807
/* like png_to_xpixmap above, but the data has already been decompressed
811
int rgba_to_xpixmap(Display *display, Drawable draw, uint8 *pixels,
812
Pixmap *pix, Pixmap *mask, Colormap *cmap,
813
unsigned long width, unsigned long height)
815
int red,green,blue, lastred=-1, lastgreen=-1, lastblue=-1,alpha,x,y,
816
cmask=-1, lastcmask, lastcolor=-1;
819
*pix = XCreatePixmap(display, draw, width, height,
820
DefaultDepth(display, DefaultScreen(display)));
822
gc=XCreateGC(display, *pix, 0, NULL);
823
XSetFunction(display, gc, GXcopy);
824
XSetPlaneMask(display, gc, AllPlanes);
826
/* The foreground/background colors are not really
827
* colors, but rather values to set in the mask.
828
* The values used below work properly on at least
829
* 8 bit and 16 bit display - using things like
830
* blackpixel & whitepixel does NO work on
831
* both types of display.
834
*mask=XCreatePixmap(display ,draw, width, height,1);
835
gc_alpha=XCreateGC(display, *mask, 0, NULL);
836
XSetFunction(display, gc_alpha, GXcopy);
837
XSetPlaneMask(display, gc_alpha, AllPlanes);
838
XSetForeground(display, gc_alpha, 1);
839
XFillRectangle(display, *mask, gc_alpha, 0, 0, width, height);
840
XSetForeground(display, gc_alpha, 0);
842
for (y=0; y<height; y++) {
843
for (x=0; x<width; x++) {
844
red= pixels[(y * width + x)*4];
845
green= pixels[(y * width + x)*4 + 1];
846
blue= pixels[(y * width + x)*4 + 2];
847
alpha = pixels[(y * width + x)*4 + 3];
849
XDrawPoint(display, *mask, gc_alpha, x, y);
851
if (need_color_alloc) {
852
/* We only use cmask to avoid calling pngx_find_color repeatedly.
853
* when the color has not changed from the last pixel.
855
if ((lastred != red) && (lastgreen != green) && (lastblue != blue)) {
856
lastcolor = pngx_find_color(display, cmap, red, green, blue);
859
XPutPixel(ximage, x, y, lastcolor);
861
if ((lastred != red) && (lastgreen != green) && (lastblue != blue)) {
862
if (rev_rshift) red >>= rshift;
864
if (rev_gshift) green >>= gshift;
865
else green <<= gshift;
866
if (rev_bshift) blue >>= bshift;
867
else blue <<= bshift;
869
cmask = (red & rmask) | (green & gmask) | (blue & bmask);
871
XPutPixel(ximage, x, y, cmask);
876
XPutImage(display, *pix, gc, ximage, 0, 0, 0, 0, width, height);
877
XFreeGC(display, gc_alpha);
878
XFreeGC(display, gc);
883
/* Takes the pixmap to put the data into, as well as the rgba
884
* data (ie, already loaded with png_to_data). Scales and
885
* stores the relevant data into the pixmap structure.
886
* returns 1 on failure.
888
int create_and_rescale_image_from_data(Cache_Entry *ce, int pixmap_num, uint8 *rgba_data, int width, int height)
890
struct PixmapInfo *pi;
892
if (pixmap_num <= 0 || pixmap_num >= MAXPIXMAPNUM)
895
if (pixmaps[pixmap_num] != pixmaps[0]) {
896
XFreePixmap(display, pixmaps[pixmap_num]->pixmap);
897
if (pixmaps[pixmap_num]->mask)
898
XFreePixmap(display, pixmaps[pixmap_num]->mask);
899
free(pixmaps[pixmap_num]);
900
pixmaps[pixmap_num] = pixmaps[0];
903
pi = malloc(sizeof(struct PixmapInfo));
904
if (rgba_to_xpixmap(display, win_game, rgba_data, &pi->pixmap,
905
&pi->mask, &colormap, width, height) != 0) {
910
if (!pi->pixmap || !pi->mask) {
912
XFreePixmap(display, pi->pixmap);
914
XFreePixmap(display, pi->mask);
919
pi->width = width / image_size;
920
pi->height = height / image_size;
925
pixmaps[pixmap_num] = pi;
929
void get_map_image_size(int face, uint8 *w, uint8 *h)
931
/* This function is not implemented yet, so just return default values */
932
if (face < 0 || face >= MAXPIXMAPNUM) {
937
*w = pixmaps[face]->width;
938
*h = pixmaps[face]->height;
945
int main(int argc, char *argv[])
948
char data[256],buf[1024*1024];
950
unsigned long width, height;
952
XSetWindowAttributes wattrs;
957
fprintf(stderr,"Usage: %s <filename>\n", argv[0]);
961
if (!(disp=XOpenDisplay(NULL))) {
962
fprintf(stderr,"Unable to open display\n");
966
wattrs.backing_store = WhenMapped;
967
wattrs.background_pixel = WhitePixel(disp, DefaultScreen(disp));
969
window=XCreateWindow(disp, DefaultRootWindow(disp), 0, 0,
970
32, 32, 0, CopyFromParent, InputOutput, CopyFromParent,
971
CWBackingStore|CWBackPixel, &wattrs);
973
i = open(argv[1], O_RDONLY);
974
z=read(i, buf, 1024*1024);
976
fprintf(stderr,"Read %d bytes from %s\n", z, argv[1]);
977
png_to_xpixmap(disp, window, buf, z, &pix, &mask, DefaultColormap(disp,
978
DefaultScreen(disp)), &width, &height);
979
XResizeWindow(disp, window, width, height);
981
fprintf(stderr,"Unable to create window\n");
984
if (mask) XShapeCombineMask(disp,window,ShapeBounding,0,0,mask,ShapeSet);
985
XMapWindow(disp, window);
987
gc=XCreateGC(disp, pix, 0, NULL);
989
XSetClipMask(disp, gc, mask);
991
/* A simple way to display the image without needing to worry
992
* about exposures and redraws.
994
for (i=0; i<30; i++) {
995
XCopyArea(disp, pix, window, gc, 0, 0, width, height, 0 , 0);