1
/* $XConsortium: Xpmscan.c /main/6 1996/09/20 08:16:12 pascale $ */
3
* Copyright (C) 1989-95 GROUPE BULL
5
* Permission is hereby granted, free of charge, to any person obtaining a copy
6
* of this software and associated documentation files (the "Software"), to
7
* deal in the Software without restriction, including without limitation the
8
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9
* sell copies of the Software, and to permit persons to whom the Software is
10
* furnished to do so, subject to the following conditions:
12
* The above copyright notice and this permission notice shall be included in
13
* all copies or substantial portions of the Software.
15
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
* GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
* Except as contained in this notice, the name of GROUPE BULL shall not be
23
* used in advertising or otherwise to promote the sale, use or other dealings
24
* in this Software without prior written authorization from GROUPE BULL.
27
/*****************************************************************************\
31
* Scanning utility for XPM file format *
33
* Developed by Arnaud Le Hors *
34
\*****************************************************************************/
37
* The code related to FOR_MSW has been added by
38
* HeDu (hedu@cul-ipn.uni-kiel.de) 4/94
46
/* October 2004, source code review by Thomas Biege <thomas@suse.de> */
50
#define MAXPRINTABLE 92 /* number of printable ascii chars
51
* minus \ and " for string compat
52
* and ? to avoid ANSI trigraphs. */
54
static char *printable =
55
" .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjklzxcvbnmMNBVCZ\
56
ASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
59
* printable begin with a space, so in most case, due to my algorithm, when
60
* the number of different colors is less than MAXPRINTABLE, it will give a
61
* char follow by "nothing" (a space) in the readable xpm file
67
unsigned int *pixelindex;
70
unsigned int mask_pixel; /* whether there is or not */
73
LFUNC(storePixel, int, (Pixel pixel, PixelsMap *pmap,
74
unsigned int *index_return));
76
LFUNC(storeMaskPixel, int, (Pixel pixel, PixelsMap *pmap,
77
unsigned int *index_return));
80
LFUNC(GetImagePixels, int, (XImage *image, unsigned int width,
81
unsigned int height, PixelsMap *pmap));
83
LFUNC(GetImagePixels32, int, (XImage *image, unsigned int width,
84
unsigned int height, PixelsMap *pmap));
86
LFUNC(GetImagePixels16, int, (XImage *image, unsigned int width,
87
unsigned int height, PixelsMap *pmap));
89
LFUNC(GetImagePixels8, int, (XImage *image, unsigned int width,
90
unsigned int height, PixelsMap *pmap));
92
LFUNC(GetImagePixels1, int, (XImage *image, unsigned int width,
93
unsigned int height, PixelsMap *pmap,
94
int (*storeFunc) ()));
95
#else /* ndef FOR_MSW */
96
LFUNC(MSWGetImagePixels, int, (Display *d, XImage *image, unsigned int width,
97
unsigned int height, PixelsMap *pmap,
98
int (*storeFunc) ()));
100
LFUNC(ScanTransparentColor, int, (XpmColor *color, unsigned int cpp,
101
XpmAttributes *attributes));
103
LFUNC(ScanOtherColors, int, (Display *display, XpmColor *colors,
104
unsigned int ncolors,
105
Pixel *pixels, unsigned int mask,
106
unsigned int cpp, XpmAttributes *attributes));
109
* This function stores the given pixel in the given arrays which are grown
110
* if not large enough.
113
storePixel(pixel, pmap, index_return)
116
unsigned int *index_return;
120
unsigned int ncolors;
122
if (*index_return) { /* this is a transparent pixel! */
126
ncolors = pmap->ncolors;
127
p = pmap->pixels + pmap->mask_pixel;
128
for (i = pmap->mask_pixel; i < ncolors; i++, p++)
132
if (ncolors >= pmap->size) {
134
p = (Pixel *) XpmRealloc(pmap->pixels, sizeof(Pixel) * pmap->size);
140
(pmap->pixels)[ncolors] = pixel;
148
storeMaskPixel(pixel, pmap, index_return)
151
unsigned int *index_return;
154
if (!pmap->ncolors) {
156
(pmap->pixels)[0] = 0;
157
pmap->mask_pixel = 1;
165
/* function call in case of error, frees only locally allocated variables */
167
#define RETURN(status) \
169
if (pmap.pixelindex) XpmFree(pmap.pixelindex); \
170
if (pmap.pixels) XpmFree(pmap.pixels); \
171
if (colorTable) xpmFreeColorTable(colorTable, pmap.ncolors); \
176
* This function scans the given image and stores the found informations in
177
* the given XpmImage structure.
180
XpmCreateXpmImageFromImage(display, image, shapeimage,
181
xpmimage, attributes)
186
XpmAttributes *attributes;
188
/* variables stored in the XpmAttributes structure */
191
/* variables to return */
193
XpmColor *colorTable = NULL;
196
/* calculation variables */
197
unsigned int width = 0;
198
unsigned int height = 0;
199
unsigned int cppm; /* minimum chars per pixel */
202
/* initialize pmap */
204
pmap.pixelindex = NULL;
205
pmap.size = 256; /* should be enough most of the time */
213
width = image->width;
214
height = image->height;
215
} else if (shapeimage) {
216
width = shapeimage->width;
217
height = shapeimage->height;
221
* retrieve information from the XpmAttributes
223
if (attributes && (attributes->valuemask & XpmCharsPerPixel
224
/* 3.2 backward compatibility code */
225
|| attributes->valuemask & XpmInfos))
227
cpp = attributes->cpp;
231
if ((height > 0 && width >= UINT_MAX / height) ||
232
width * height >= UINT_MAX / sizeof(unsigned int))
235
(unsigned int *) XpmCalloc(width * height, sizeof(unsigned int));
236
if (!pmap.pixelindex)
239
if (pmap.size >= UINT_MAX / sizeof(Pixel))
242
pmap.pixels = (Pixel *) XpmMalloc(sizeof(Pixel) * pmap.size);
247
* scan shape mask if any
251
ErrorStatus = GetImagePixels1(shapeimage, width, height, &pmap,
254
ErrorStatus = MSWGetImagePixels(display, shapeimage, width, height,
255
&pmap, storeMaskPixel);
257
if (ErrorStatus != XpmSuccess)
262
* scan the image data
264
* In case depth is 1 or bits_per_pixel is 4, 6, 8, 24 or 32 use optimized
265
* functions, otherwise use slower but sure general one.
271
if (((image->bits_per_pixel | image->depth) == 1) &&
272
(image->byte_order == image->bitmap_bit_order))
273
ErrorStatus = GetImagePixels1(image, width, height, &pmap,
275
else if (image->format == ZPixmap) {
276
if (image->bits_per_pixel == 8)
277
ErrorStatus = GetImagePixels8(image, width, height, &pmap);
278
else if (image->bits_per_pixel == 16)
279
ErrorStatus = GetImagePixels16(image, width, height, &pmap);
280
else if (image->bits_per_pixel == 32)
281
ErrorStatus = GetImagePixels32(image, width, height, &pmap);
283
ErrorStatus = GetImagePixels(image, width, height, &pmap);
285
ErrorStatus = MSWGetImagePixels(display, image, width, height, &pmap,
288
if (ErrorStatus != XpmSuccess)
293
* get rgb values and a string of char, and possibly a name for each
296
if (pmap.ncolors >= UINT_MAX / sizeof(XpmColor))
298
colorTable = (XpmColor *) XpmCalloc(pmap.ncolors, sizeof(XpmColor));
302
/* compute the minimal cpp */
303
for (cppm = 1, c = MAXPRINTABLE; pmap.ncolors > c; cppm++)
308
if (pmap.mask_pixel) {
309
ErrorStatus = ScanTransparentColor(colorTable, cpp, attributes);
310
if (ErrorStatus != XpmSuccess)
314
ErrorStatus = ScanOtherColors(display, colorTable, pmap.ncolors,
315
pmap.pixels, pmap.mask_pixel, cpp,
317
if (ErrorStatus != XpmSuccess)
321
* store found informations in the XpmImage structure
323
xpmimage->width = width;
324
xpmimage->height = height;
326
xpmimage->ncolors = pmap.ncolors;
327
xpmimage->colorTable = colorTable;
328
xpmimage->data = pmap.pixelindex;
330
XpmFree(pmap.pixels);
335
ScanTransparentColor(color, cpp, attributes)
338
XpmAttributes *attributes;
341
unsigned int a, b, c;
343
/* first get a character string */
345
if (cpp >= UINT_MAX - 1)
346
return (XpmNoMemory);
347
if (!(s = color->string = (char *) XpmMalloc(cpp + 1)))
348
return (XpmNoMemory);
349
*s++ = printable[c = a % MAXPRINTABLE];
350
for (b = 1; b < cpp; b++, s++)
351
*s = printable[c = ((a - c) / MAXPRINTABLE) % MAXPRINTABLE];
354
/* then retreive related info from the attributes if any */
355
if (attributes && (attributes->valuemask & XpmColorTable
356
/* 3.2 backward compatibility code */
357
|| attributes->valuemask & XpmInfos)
359
&& attributes->mask_pixel != XpmUndefPixel) {
362
char **defaults = (char **) color;
363
char **mask_defaults;
365
/* 3.2 backward compatibility code */
366
if (attributes->valuemask & XpmColorTable)
368
mask_defaults = (char **) (
369
attributes->colorTable + attributes->mask_pixel);
370
/* 3.2 backward compatibility code */
372
mask_defaults = (char **)
373
((XpmColor **) attributes->colorTable)[attributes->mask_pixel];
375
for (key = 1; key <= NKEYS; key++) {
376
if ((s = mask_defaults[key])) {
377
defaults[key] = (char *) xpmstrdup(s);
379
return (XpmNoMemory);
383
color->c_color = (char *) xpmstrdup(TRANSPARENT_COLOR);
385
return (XpmNoMemory);
391
ScanOtherColors(display, colors, ncolors, pixels, mask, cpp, attributes)
394
unsigned int ncolors;
398
XpmAttributes *attributes;
400
/* variables stored in the XpmAttributes structure */
405
xpmRgbName rgbn[MAX_RGBNAMES];
407
xpmRgbName *rgbn = NULL;
410
unsigned int i, j, c, i2;
412
XColor *xcolors = NULL, *xcolor;
414
XpmColor *colorTable = NULL, **oldColorTable = NULL;
415
unsigned int ancolors = 0;
416
Pixel *apixels = NULL;
417
unsigned int mask_pixel = 0;
420
/* retrieve information from the XpmAttributes */
421
if (attributes && (attributes->valuemask & XpmColormap))
422
colormap = attributes->colormap;
424
colormap = XDefaultColormap(display, XDefaultScreen(display));
425
if (attributes && (attributes->valuemask & XpmRgbFilename))
426
rgb_fname = attributes->rgb_fname;
430
/* start from the right element */
437
/* first get character strings and rgb values */
438
if (ncolors >= UINT_MAX / sizeof(XColor) || cpp >= UINT_MAX - 1)
439
return (XpmNoMemory);
440
xcolors = (XColor *) XpmMalloc(sizeof(XColor) * ncolors);
442
return (XpmNoMemory);
444
for (i = 0, i2 = mask, color = colors, xcolor = xcolors;
445
i < ncolors; i++, i2++, color++, xcolor++, pixels++) {
447
if (!(s = color->string = (char *) XpmMalloc(cpp + 1))) {
449
return (XpmNoMemory);
451
*s++ = printable[c = i2 % MAXPRINTABLE];
452
for (j = 1; j < cpp; j++, s++)
453
*s = printable[c = ((i2 - c) / MAXPRINTABLE) % MAXPRINTABLE];
456
xcolor->pixel = *pixels;
458
XQueryColors(display, colormap, xcolors, ncolors);
461
/* read the rgb file if any was specified */
463
rgbn_max = xpmReadRgbNames(attributes->rgb_fname, rgbn);
465
/* FOR_MSW: rgb names and values are hardcoded in rgbtab.h */
466
rgbn_max = xpmReadRgbNames(NULL, NULL);
469
if (attributes && attributes->valuemask & XpmColorTable) {
470
colorTable = attributes->colorTable;
471
ancolors = attributes->ncolors;
472
apixels = attributes->pixels;
473
mask_pixel = attributes->mask_pixel;
475
/* 3.2 backward compatibility code */
476
else if (attributes && attributes->valuemask & XpmInfos) {
477
oldColorTable = (XpmColor **) attributes->colorTable;
478
ancolors = attributes->ncolors;
479
apixels = attributes->pixels;
480
mask_pixel = attributes->mask_pixel;
484
for (i = 0, color = colors, xcolor = xcolors; i < ncolors;
485
i++, color++, xcolor++) {
487
/* look for related info from the attributes if any */
490
unsigned int offset = 0;
492
for (j = 0; j < ancolors; j++) {
493
if (j == mask_pixel) {
497
if (apixels[j - offset] == xcolor->pixel)
502
char **defaults = (char **) color;
505
/* 3.2 backward compatibility code */
507
adefaults = (char **) oldColorTable[j];
510
adefaults = (char **) (colorTable + j);
513
for (key = 1; key <= NKEYS; key++) {
514
if ((s = adefaults[key]))
515
defaults[key] = (char *) xpmstrdup(s);
520
/* if nothing found look for a color name */
523
colorname = xpmGetRgbName(rgbn, rgbn_max, xcolor->red,
524
xcolor->green, xcolor->blue);
526
color->c_color = (char *) xpmstrdup(colorname);
528
/* at last store the rgb value */
531
sprintf(buf, "#%04X%04X%04X",
532
xcolor->red, xcolor->green, xcolor->blue);
534
sprintf(buf, "#%02x%02x%02x",
535
xcolor->red, xcolor->green, xcolor->blue);
537
color->c_color = (char *) xpmstrdup(buf);
539
if (!color->c_color) {
541
xpmFreeRgbNames(rgbn, rgbn_max);
542
return (XpmNoMemory);
548
xpmFreeRgbNames(rgbn, rgbn_max);
554
* The functions below are written from X11R5 MIT's code (XImUtil.c)
556
* The idea is to have faster functions than the standard XGetPixel function
557
* to scan the image data. Indeed we can speed up things by suppressing tests
558
* performed for each pixel. We do exactly the same tests but at the image
562
static unsigned long Const low_bits_table[] = {
563
0x00000000, 0x00000001, 0x00000003, 0x00000007,
564
0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
565
0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
566
0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
567
0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
568
0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
569
0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
570
0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
575
* Default method to scan pixels of an image data structure.
576
* The algorithm used is:
578
* copy the source bitmap_unit or Zpixel into temp
579
* normalize temp if needed
580
* extract the pixel bits into return value
585
GetImagePixels(image, width, height, pmap)
596
int bits, depth, ibu, ibpp, offset, i;
601
iptr = pmap->pixelindex;
602
depth = image->depth;
603
lbt = low_bits_table[depth];
604
ibpp = image->bits_per_pixel;
605
offset = image->xoffset;
607
if (image->bitmap_unit < 0)
608
return (XpmNoMemory);
610
if ((image->bits_per_pixel | image->depth) == 1) {
611
ibu = image->bitmap_unit;
612
for (y = 0; y < height; y++)
613
for (x = 0; x < width; x++, iptr++) {
614
src = &data[XYINDEX(x, y, image)];
615
dst = (char *) &pixel;
617
for (i = ibu >> 3; --i >= 0;)
619
XYNORMALIZE(&pixel, image);
620
bits = (x + offset) % ibu;
621
pixel = ((((char *) &pixel)[bits >> 3]) >> (bits & 7)) & 1;
624
if (storePixel(pixel, pmap, iptr))
625
return (XpmNoMemory);
627
} else if (image->format == XYPixmap) {
630
ibu = image->bitmap_unit;
632
bpl = image->bytes_per_line;
633
for (y = 0; y < height; y++)
634
for (x = 0; x < width; x++, iptr++) {
637
for (i = depth; --i >= 0;) {
638
src = &data[XYINDEX(x, y, image) + plane];
641
for (j = nbytes; --j >= 0;)
643
XYNORMALIZE(&px, image);
644
bits = (x + offset) % ibu;
645
pixel = (pixel << 1) |
646
(((((char *) &px)[bits >> 3]) >> (bits & 7)) & 1);
647
plane = plane + (bpl * height);
651
if (storePixel(pixel, pmap, iptr))
652
return (XpmNoMemory);
654
} else if (image->format == ZPixmap) {
655
for (y = 0; y < height; y++)
656
for (x = 0; x < width; x++, iptr++) {
657
src = &data[ZINDEX(x, y, image)];
660
for (i = (ibpp + 7) >> 3; --i >= 0;)
662
ZNORMALIZE(&px, image);
664
for (i = sizeof(unsigned long); --i >= 0;)
665
pixel = (pixel << 8) | ((unsigned char *) &px)[i];
674
if (storePixel(pixel, pmap, iptr))
675
return (XpmNoMemory);
678
return (XpmColorError); /* actually a bad image */
683
* scan pixels of a 32-bits Z image data structure
686
#if !defined(WORD64) && !defined(LONG64)
687
static unsigned long byteorderpixel = MSBFirst << 24;
691
GetImagePixels32(image, width, height, pmap)
705
data = (unsigned char *) image->data;
706
iptr = pmap->pixelindex;
707
depth = image->depth;
708
lbt = low_bits_table[depth];
709
#if !defined(WORD64) && !defined(LONG64)
710
if (*((char *) &byteorderpixel) == image->byte_order) {
711
for (y = 0; y < height; y++)
712
for (x = 0; x < width; x++, iptr++) {
713
addr = &data[ZINDEX32(x, y, image)];
714
pixel = *((unsigned long *) addr);
717
if (storePixel(pixel, pmap, iptr))
718
return (XpmNoMemory);
722
if (image->byte_order == MSBFirst)
723
for (y = 0; y < height; y++)
724
for (x = 0; x < width; x++, iptr++) {
725
addr = &data[ZINDEX32(x, y, image)];
726
pixel = ((unsigned long) addr[0] << 24 |
727
(unsigned long) addr[1] << 16 |
728
(unsigned long) addr[2] << 8 |
732
if (storePixel(pixel, pmap, iptr))
733
return (XpmNoMemory);
736
for (y = 0; y < height; y++)
737
for (x = 0; x < width; x++, iptr++) {
738
addr = &data[ZINDEX32(x, y, image)];
740
(unsigned long) addr[1] << 8 |
741
(unsigned long) addr[2] << 16 |
742
(unsigned long) addr[3] << 24);
745
if (storePixel(pixel, pmap, iptr))
746
return (XpmNoMemory);
752
* scan pixels of a 16-bits Z image data structure
756
GetImagePixels16(image, width, height, pmap)
770
data = (unsigned char *) image->data;
771
iptr = pmap->pixelindex;
772
depth = image->depth;
773
lbt = low_bits_table[depth];
774
if (image->byte_order == MSBFirst)
775
for (y = 0; y < height; y++)
776
for (x = 0; x < width; x++, iptr++) {
777
addr = &data[ZINDEX16(x, y, image)];
778
pixel = addr[0] << 8 | addr[1];
781
if (storePixel(pixel, pmap, iptr))
782
return (XpmNoMemory);
785
for (y = 0; y < height; y++)
786
for (x = 0; x < width; x++, iptr++) {
787
addr = &data[ZINDEX16(x, y, image)];
788
pixel = addr[0] | addr[1] << 8;
791
if (storePixel(pixel, pmap, iptr))
792
return (XpmNoMemory);
798
* scan pixels of a 8-bits Z image data structure
802
GetImagePixels8(image, width, height, pmap)
815
data = (unsigned char *) image->data;
816
iptr = pmap->pixelindex;
817
depth = image->depth;
818
lbt = low_bits_table[depth];
819
for (y = 0; y < height; y++)
820
for (x = 0; x < width; x++, iptr++) {
821
pixel = data[ZINDEX8(x, y, image)];
824
if (storePixel(pixel, pmap, iptr))
825
return (XpmNoMemory);
831
* scan pixels of a 1-bit depth Z image data structure
835
GetImagePixels1(image, width, height, pmap, storeFunc)
846
int xoff, yoff, offset, bpl;
849
iptr = pmap->pixelindex;
850
offset = image->xoffset;
851
bpl = image->bytes_per_line;
853
if (image->bitmap_bit_order == MSBFirst)
854
for (y = 0; y < height; y++)
855
for (x = 0; x < width; x++, iptr++) {
857
yoff = y * bpl + (xoff >> 3);
859
pixel = (data[yoff] & (0x80 >> xoff)) ? 1 : 0;
860
if ((*storeFunc) (pixel, pmap, iptr))
861
return (XpmNoMemory);
864
for (y = 0; y < height; y++)
865
for (x = 0; x < width; x++, iptr++) {
867
yoff = y * bpl + (xoff >> 3);
869
pixel = (data[yoff] & (1 << xoff)) ? 1 : 0;
870
if ((*storeFunc) (pixel, pmap, iptr))
871
return (XpmNoMemory);
876
#else /* ndef FOR_MSW */
878
MSWGetImagePixels(display, image, width, height, pmap, storeFunc)
890
iptr = pmap->pixelindex;
892
SelectObject(*display, image->bitmap);
893
for (y = 0; y < height; y++) {
894
for (x = 0; x < width; x++, iptr++) {
895
pixel = GetPixel(*display, x, y);
896
if ((*storeFunc) (pixel, pmap, iptr))
897
return (XpmNoMemory);
907
XpmCreateXpmImageFromPixmap(display, pixmap, shapemask,
908
xpmimage, attributes)
913
XpmAttributes *attributes;
915
XImage *ximage = NULL;
916
XImage *shapeimage = NULL;
917
unsigned int width = 0;
918
unsigned int height = 0;
922
if (attributes && attributes->valuemask & XpmSize) {
923
width = attributes->width;
924
height = attributes->height;
926
/* get the ximages */
928
xpmCreateImageFromPixmap(display, pixmap, &ximage, &width, &height);
930
xpmCreateImageFromPixmap(display, shapemask, &shapeimage,
933
/* create the related XpmImage */
934
ErrorStatus = XpmCreateXpmImageFromImage(display, ximage, shapeimage,
935
xpmimage, attributes);
937
/* destroy the ximages */
939
XDestroyImage(ximage);
941
XDestroyImage(shapeimage);
943
return (ErrorStatus);
946
#endif /* ndef FOR_MSW */