Git init
[framework/uifw/xorg/lib/libxpm.git] / src / scan.c
1 /*
2  * Copyright (C) 1989-95 GROUPE BULL
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17  * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20  *
21  * Except as contained in this notice, the name of GROUPE BULL shall not be
22  * used in advertising or otherwise to promote the sale, use or other dealings
23  * in this Software without prior written authorization from GROUPE BULL.
24  */
25
26 /*****************************************************************************\
27 * scan.c:                                                                     *
28 *                                                                             *
29 *  XPM library                                                                *
30 *  Scanning utility for XPM file format                                       *
31 *                                                                             *
32 *  Developed by Arnaud Le Hors                                                *
33 \*****************************************************************************/
34
35 /*
36  * The code related to FOR_MSW has been added by
37  * HeDu (hedu@cul-ipn.uni-kiel.de) 4/94
38  */
39
40 /*
41  * The code related to AMIGA has been added by
42  * Lorens Younes (d93-hyo@nada.kth.se) 4/96
43  */
44
45 /* October 2004, source code review by Thomas Biege <thomas@suse.de> */
46
47 #ifdef HAVE_CONFIG_H
48 #include <config.h>
49 #endif
50 #include "XpmI.h"
51
52 #define MAXPRINTABLE 92                 /* number of printable ascii chars
53                                          * minus \ and " for string compat
54                                          * and ? to avoid ANSI trigraphs. */
55
56 static char *printable =
57 " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjklzxcvbnmMNBVCZ\
58 ASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
59
60 /*
61  * printable begin with a space, so in most case, due to my algorithm, when
62  * the number of different colors is less than MAXPRINTABLE, it will give a
63  * char follow by "nothing" (a space) in the readable xpm file
64  */
65
66
67 typedef struct {
68     Pixel *pixels;
69     unsigned int *pixelindex;
70     unsigned int size;
71     unsigned int ncolors;
72     unsigned int mask_pixel;            /* whether there is or not */
73 }      PixelsMap;
74
75 LFUNC(storePixel, int, (Pixel pixel, PixelsMap *pmap,
76                         unsigned int *index_return));
77
78 LFUNC(storeMaskPixel, int, (Pixel pixel, PixelsMap *pmap,
79                             unsigned int *index_return));
80
81 typedef int (*storeFuncPtr)(Pixel pixel, PixelsMap *pmap,
82                             unsigned int *index_return);
83
84 #ifndef FOR_MSW
85 # ifndef AMIGA
86 LFUNC(GetImagePixels, int, (XImage *image, unsigned int width,
87                             unsigned int height, PixelsMap *pmap));
88
89 LFUNC(GetImagePixels32, int, (XImage *image, unsigned int width,
90                               unsigned int height, PixelsMap *pmap));
91
92 LFUNC(GetImagePixels16, int, (XImage *image, unsigned int width,
93                               unsigned int height, PixelsMap *pmap));
94
95 LFUNC(GetImagePixels8, int, (XImage *image, unsigned int width,
96                              unsigned int height, PixelsMap *pmap));
97
98 LFUNC(GetImagePixels1, int, (XImage *image, unsigned int width,
99                              unsigned int height, PixelsMap *pmap,
100                              storeFuncPtr storeFunc));
101 # else /* AMIGA */
102 LFUNC(AGetImagePixels, int, (XImage *image, unsigned int width,
103                              unsigned int height, PixelsMap *pmap,
104                              storeFuncPtr storeFunc));
105 # endif/* AMIGA */
106 #else  /* ndef FOR_MSW */
107 LFUNC(MSWGetImagePixels, int, (Display *d, XImage *image, unsigned int width,
108                                unsigned int height, PixelsMap *pmap,
109                                storeFuncPtr storeFunc));
110 #endif
111 LFUNC(ScanTransparentColor, int, (XpmColor *color, unsigned int cpp,
112                                   XpmAttributes *attributes));
113
114 LFUNC(ScanOtherColors, int, (Display *display, XpmColor *colors, 
115                              unsigned int ncolors, 
116                              Pixel *pixels, unsigned int mask,
117                              unsigned int cpp, XpmAttributes *attributes));
118
119 /*
120  * This function stores the given pixel in the given arrays which are grown
121  * if not large enough.
122  */
123 static int
124 storePixel(
125     Pixel                pixel,
126     PixelsMap           *pmap,
127     unsigned int        *index_return)
128 {
129     unsigned int i;
130     Pixel *p;
131     unsigned int ncolors;
132
133     if (*index_return) {                /* this is a transparent pixel! */
134         *index_return = 0;
135         return 0;
136     }
137     ncolors = pmap->ncolors;
138     p = pmap->pixels + pmap->mask_pixel;
139     for (i = pmap->mask_pixel; i < ncolors; i++, p++)
140         if (*p == pixel)
141             break;
142     if (i == ncolors) {
143         if (ncolors >= pmap->size) {
144             pmap->size *= 2;
145             p = (Pixel *) XpmRealloc(pmap->pixels, sizeof(Pixel) * pmap->size);
146             if (!p)
147                 return (1);
148             pmap->pixels = p;
149
150         }
151         (pmap->pixels)[ncolors] = pixel;
152         pmap->ncolors++;
153     }
154     *index_return = i;
155     return 0;
156 }
157
158 static int
159 storeMaskPixel(
160     Pixel                pixel,
161     PixelsMap           *pmap,
162     unsigned int        *index_return)
163 {
164     if (!pixel) {
165         if (!pmap->ncolors) {
166             pmap->ncolors = 1;
167             (pmap->pixels)[0] = 0;
168             pmap->mask_pixel = 1;
169         }
170         *index_return = 1;
171     } else
172         *index_return = 0;
173     return 0;
174 }
175
176 /* function call in case of error */
177 #undef RETURN
178 #define RETURN(status) \
179 do { \
180       ErrorStatus = status; \
181       goto error; \
182 } while(0)
183
184 /*
185  * This function scans the given image and stores the found informations in
186  * the given XpmImage structure.
187  */
188 int
189 XpmCreateXpmImageFromImage(
190     Display             *display,
191     XImage              *image,
192     XImage              *shapeimage,
193     XpmImage            *xpmimage,
194     XpmAttributes       *attributes)
195 {
196     /* variables stored in the XpmAttributes structure */
197     unsigned int cpp;
198
199     /* variables to return */
200     PixelsMap pmap;
201     XpmColor *colorTable = NULL;
202     int ErrorStatus = 0;
203
204     /* calculation variables */
205     unsigned int width = 0;
206     unsigned int height = 0;
207     unsigned int cppm;                  /* minimum chars per pixel */
208     unsigned int c;
209
210     /* initialize pmap */
211     pmap.pixels = NULL;
212     pmap.pixelindex = NULL;
213     pmap.size = 256;                    /* should be enough most of the time */
214     pmap.ncolors = 0;
215     pmap.mask_pixel = 0;
216
217     /*
218      * get geometry
219      */
220     if (image) {
221         width = image->width;
222         height = image->height;
223     } else if (shapeimage) {
224         width = shapeimage->width;
225         height = shapeimage->height;
226     }
227
228     /*
229      * retrieve information from the XpmAttributes
230      */
231     if (attributes && (attributes->valuemask & XpmCharsPerPixel
232 /* 3.2 backward compatibility code */
233                        || attributes->valuemask & XpmInfos))
234 /* end 3.2 bc */
235         cpp = attributes->cpp;
236     else
237         cpp = 0;
238
239     if ((height > 0 && width >= UINT_MAX / height) ||
240         width * height >= UINT_MAX / sizeof(unsigned int))
241         RETURN(XpmNoMemory);
242     pmap.pixelindex =
243         (unsigned int *) XpmCalloc(width * height, sizeof(unsigned int));
244     if (!pmap.pixelindex)
245         RETURN(XpmNoMemory);
246
247     if (pmap.size >= UINT_MAX / sizeof(Pixel)) 
248         RETURN(XpmNoMemory);
249
250     pmap.pixels = (Pixel *) XpmMalloc(sizeof(Pixel) * pmap.size);
251     if (!pmap.pixels)
252         RETURN(XpmNoMemory);
253
254     /*
255      * scan shape mask if any
256      */
257     if (shapeimage) {
258 #ifndef FOR_MSW
259 # ifndef AMIGA
260         ErrorStatus = GetImagePixels1(shapeimage, width, height, &pmap,
261                                       storeMaskPixel);
262 # else
263         ErrorStatus = AGetImagePixels(shapeimage, width, height, &pmap,
264                                       storeMaskPixel);
265 # endif
266 #else
267         ErrorStatus = MSWGetImagePixels(display, shapeimage, width, height,
268                                         &pmap, storeMaskPixel);
269 #endif
270         if (ErrorStatus != XpmSuccess)
271             RETURN(ErrorStatus);
272     }
273
274     /*
275      * scan the image data
276      * 
277      * In case depth is 1 or bits_per_pixel is 4, 6, 8, 24 or 32 use optimized
278      * functions, otherwise use slower but sure general one.
279      * 
280      */
281
282     if (image) {
283 #ifndef FOR_MSW
284 # ifndef AMIGA
285         if (((image->bits_per_pixel | image->depth) == 1)  &&
286             (image->byte_order == image->bitmap_bit_order))
287             ErrorStatus = GetImagePixels1(image, width, height, &pmap,
288                                           storePixel);
289         else if (image->format == ZPixmap) {
290             if (image->bits_per_pixel == 8)
291                 ErrorStatus = GetImagePixels8(image, width, height, &pmap);
292             else if (image->bits_per_pixel == 16)
293                 ErrorStatus = GetImagePixels16(image, width, height, &pmap);
294             else if (image->bits_per_pixel == 32)
295                 ErrorStatus = GetImagePixels32(image, width, height, &pmap);
296         } else
297             ErrorStatus = GetImagePixels(image, width, height, &pmap);
298 # else
299         ErrorStatus = AGetImagePixels(image, width, height, &pmap,
300                                       storePixel);
301 # endif
302 #else
303         ErrorStatus = MSWGetImagePixels(display, image, width, height, &pmap,
304                                         storePixel);
305 #endif
306         if (ErrorStatus != XpmSuccess)
307             RETURN(ErrorStatus);
308     }
309
310     /*
311      * get rgb values and a string of char, and possibly a name for each
312      * color
313      */
314     if (pmap.ncolors >= UINT_MAX / sizeof(XpmColor))
315         RETURN(XpmNoMemory);
316     colorTable = (XpmColor *) XpmCalloc(pmap.ncolors, sizeof(XpmColor));
317     if (!colorTable)
318         RETURN(XpmNoMemory);
319
320     /* compute the minimal cpp */
321     for (cppm = 1, c = MAXPRINTABLE; pmap.ncolors > c; cppm++)
322         c *= MAXPRINTABLE;
323     if (cpp < cppm)
324         cpp = cppm;
325
326     if (pmap.mask_pixel) {
327         ErrorStatus = ScanTransparentColor(colorTable, cpp, attributes);
328         if (ErrorStatus != XpmSuccess)
329             RETURN(ErrorStatus);
330     }
331
332     ErrorStatus = ScanOtherColors(display, colorTable, pmap.ncolors,
333                                   pmap.pixels, pmap.mask_pixel, cpp,
334                                   attributes);
335     if (ErrorStatus != XpmSuccess)
336         RETURN(ErrorStatus);
337
338     /*
339      * store found informations in the XpmImage structure
340      */
341     xpmimage->width = width;
342     xpmimage->height = height;
343     xpmimage->cpp = cpp;
344     xpmimage->ncolors = pmap.ncolors;
345     xpmimage->colorTable = colorTable;
346     xpmimage->data = pmap.pixelindex;
347
348     XpmFree(pmap.pixels);
349     return (XpmSuccess);
350
351 /* exit point in case of error, free only locally allocated variables */
352 error:
353     if (pmap.pixelindex)
354         XpmFree(pmap.pixelindex);
355     if (pmap.pixels)
356         XpmFree(pmap.pixels);
357     if (colorTable)
358         xpmFreeColorTable(colorTable, pmap.ncolors);
359
360     return (ErrorStatus);
361 }
362
363 static int
364 ScanTransparentColor(
365     XpmColor            *color,
366     unsigned int         cpp,
367     XpmAttributes       *attributes)
368 {
369     char *s;
370     unsigned int a, b, c;
371
372     /* first get a character string */
373     a = 0;
374     if (cpp >= UINT_MAX - 1)
375         return (XpmNoMemory);
376     if (!(s = color->string = (char *) XpmMalloc(cpp + 1)))
377         return (XpmNoMemory);
378     *s++ = printable[c = a % MAXPRINTABLE];
379     for (b = 1; b < cpp; b++, s++)
380         *s = printable[c = ((a - c) / MAXPRINTABLE) % MAXPRINTABLE];
381     *s = '\0';
382
383     /* then retreive related info from the attributes if any */
384     if (attributes && (attributes->valuemask & XpmColorTable
385 /* 3.2 backward compatibility code */
386                        || attributes->valuemask & XpmInfos)
387 /* end 3.2 bc */
388         && attributes->mask_pixel != XpmUndefPixel) {
389
390         unsigned int key;
391         char **defaults = (char **) color;
392         char **mask_defaults;
393
394 /* 3.2 backward compatibility code */
395         if (attributes->valuemask & XpmColorTable)
396 /* end 3.2 bc */
397             mask_defaults = (char **) (
398                 attributes->colorTable + attributes->mask_pixel);
399 /* 3.2 backward compatibility code */
400         else
401             mask_defaults = (char **)
402                 ((XpmColor **) attributes->colorTable)[attributes->mask_pixel];
403 /* end 3.2 bc */
404         for (key = 1; key <= NKEYS; key++) {
405             if ((s = mask_defaults[key])) {
406                 defaults[key] = (char *) xpmstrdup(s);
407                 if (!defaults[key])
408                     return (XpmNoMemory);
409             }
410         }
411     } else {
412         color->c_color = (char *) xpmstrdup(TRANSPARENT_COLOR);
413         if (!color->c_color)
414             return (XpmNoMemory);
415     }
416     return (XpmSuccess);
417 }
418
419 static int
420 ScanOtherColors(
421     Display             *display,
422     XpmColor            *colors,
423     unsigned int         ncolors,
424     Pixel               *pixels,
425     unsigned int         mask,
426     unsigned int         cpp,
427     XpmAttributes       *attributes)
428 {
429     /* variables stored in the XpmAttributes structure */
430     Colormap colormap;
431     char *rgb_fname;
432
433 #ifndef FOR_MSW
434     xpmRgbName rgbn[MAX_RGBNAMES];
435 #else
436     xpmRgbName *rgbn = NULL; 
437 #endif    
438     int rgbn_max = 0;
439     unsigned int i, j, c, i2;
440     XpmColor *color;
441     XColor *xcolors = NULL, *xcolor;
442     char *colorname, *s;
443     XpmColor *colorTable = NULL, **oldColorTable = NULL;
444     unsigned int ancolors = 0;
445     Pixel *apixels = NULL;
446     unsigned int mask_pixel = 0;
447     Bool found;
448
449     /* retrieve information from the XpmAttributes */
450     if (attributes && (attributes->valuemask & XpmColormap))
451         colormap = attributes->colormap;
452     else
453         colormap = XDefaultColormap(display, XDefaultScreen(display));
454     if (attributes && (attributes->valuemask & XpmRgbFilename))
455         rgb_fname = attributes->rgb_fname;
456     else
457         rgb_fname = NULL;
458
459     /* start from the right element */
460     if (mask) {
461         colors++;
462         ncolors--;
463         pixels++;
464     }
465
466     /* first get character strings and rgb values */
467     if (ncolors >= UINT_MAX / sizeof(XColor) || cpp >= UINT_MAX - 1)
468         return (XpmNoMemory);
469     xcolors = (XColor *) XpmMalloc(sizeof(XColor) * ncolors);
470     if (!xcolors)
471         return (XpmNoMemory);
472
473     for (i = 0, i2 = mask, color = colors, xcolor = xcolors;
474          i < ncolors; i++, i2++, color++, xcolor++, pixels++) {
475
476         if (!(s = color->string = (char *) XpmMalloc(cpp + 1))) {
477             XpmFree(xcolors);
478             return (XpmNoMemory);
479         }
480         *s++ = printable[c = i2 % MAXPRINTABLE];
481         for (j = 1; j < cpp; j++, s++)
482             *s = printable[c = ((i2 - c) / MAXPRINTABLE) % MAXPRINTABLE];
483         *s = '\0';
484
485         xcolor->pixel = *pixels;
486     }
487     XQueryColors(display, colormap, xcolors, ncolors);
488
489 #ifndef FOR_MSW
490     /* read the rgb file if any was specified */
491     if (rgb_fname)
492         rgbn_max = xpmReadRgbNames(attributes->rgb_fname, rgbn);
493 #else
494     /* FOR_MSW: rgb names and values are hardcoded in rgbtab.h */
495     rgbn_max = xpmReadRgbNames(NULL, NULL);
496 #endif
497
498     if (attributes && attributes->valuemask & XpmColorTable) {
499         colorTable = attributes->colorTable;
500         ancolors = attributes->ncolors;
501         apixels = attributes->pixels;
502         mask_pixel = attributes->mask_pixel;
503     }
504 /* 3.2 backward compatibility code */
505     else if (attributes && attributes->valuemask & XpmInfos) {
506         oldColorTable = (XpmColor **) attributes->colorTable;
507         ancolors = attributes->ncolors;
508         apixels = attributes->pixels;
509         mask_pixel = attributes->mask_pixel;
510     }
511 /* end 3.2 bc */
512
513     for (i = 0, color = colors, xcolor = xcolors; i < ncolors;
514                                                   i++, color++, xcolor++) {
515
516         /* look for related info from the attributes if any */
517         found = False;
518         if (ancolors) {
519             unsigned int offset = 0;
520
521             for (j = 0; j < ancolors; j++) {
522                 if (j == mask_pixel) {
523                     offset = 1;
524                     continue;
525                 }
526                 if (apixels[j - offset] == xcolor->pixel)
527                     break;
528             }
529             if (j != ancolors) {
530                 unsigned int key;
531                 char **defaults = (char **) color;
532                 char **adefaults;
533
534 /* 3.2 backward compatibility code */
535                 if (oldColorTable)
536                     adefaults = (char **) oldColorTable[j];
537                 else
538 /* end 3.2 bc */
539                     adefaults = (char **) (colorTable + j);
540
541                 found = True;
542                 for (key = 1; key <= NKEYS; key++) {
543                     if ((s = adefaults[key]))
544                         defaults[key] = (char *) xpmstrdup(s);
545                 }
546             }
547         }
548         if (!found) {
549             /* if nothing found look for a color name */
550             colorname = NULL;
551             if (rgbn_max)
552                 colorname = xpmGetRgbName(rgbn, rgbn_max, xcolor->red,
553                                           xcolor->green, xcolor->blue);
554             if (colorname)
555                 color->c_color = (char *) xpmstrdup(colorname);
556             else {
557                 /* at last store the rgb value */
558                 char buf[BUFSIZ];
559 #ifndef FOR_MSW
560                 sprintf(buf, "#%04X%04X%04X",
561                         xcolor->red, xcolor->green, xcolor->blue);
562 #else   
563                 sprintf(buf, "#%02x%02x%02x",
564                         xcolor->red, xcolor->green, xcolor->blue);
565 #endif                  
566                 color->c_color = (char *) xpmstrdup(buf);
567             }
568             if (!color->c_color) {
569                 XpmFree(xcolors);
570                 xpmFreeRgbNames(rgbn, rgbn_max);
571                 return (XpmNoMemory);
572             }
573         }
574     }
575
576     XpmFree(xcolors);
577     xpmFreeRgbNames(rgbn, rgbn_max);
578     return (XpmSuccess);
579 }
580
581 #ifndef FOR_MSW
582 # ifndef AMIGA
583 /*
584  * The functions below are written from X11R5 MIT's code (XImUtil.c)
585  *
586  * The idea is to have faster functions than the standard XGetPixel function
587  * to scan the image data. Indeed we can speed up things by suppressing tests
588  * performed for each pixel. We do exactly the same tests but at the image
589  * level.
590  */
591
592 static unsigned long Const low_bits_table[] = {
593     0x00000000, 0x00000001, 0x00000003, 0x00000007,
594     0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
595     0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
596     0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
597     0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
598     0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
599     0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
600     0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
601     0xffffffff
602 };
603
604 /*
605  * Default method to scan pixels of an image data structure.
606  * The algorithm used is:
607  *
608  *      copy the source bitmap_unit or Zpixel into temp
609  *      normalize temp if needed
610  *      extract the pixel bits into return value
611  *
612  */
613
614 static int
615 GetImagePixels(
616     XImage              *image,
617     unsigned int         width,
618     unsigned int         height,
619     PixelsMap           *pmap)
620 {
621     char *src;
622     char *dst;
623     unsigned int *iptr;
624     char *data;
625     unsigned int x, y;
626     int bits, depth, ibu, ibpp, offset, i;
627     unsigned long lbt;
628     Pixel pixel, px;
629
630     data = image->data;
631     iptr = pmap->pixelindex;
632     depth = image->depth;
633     lbt = low_bits_table[depth];
634     ibpp = image->bits_per_pixel;
635     offset = image->xoffset;
636
637     if (image->bitmap_unit < 0)
638             return (XpmNoMemory);
639
640     if ((image->bits_per_pixel | image->depth) == 1) {
641         ibu = image->bitmap_unit;
642         for (y = 0; y < height; y++)
643             for (x = 0; x < width; x++, iptr++) {
644                 src = &data[XYINDEX(x, y, image)];
645                 dst = (char *) &pixel;
646                 pixel = 0;
647                 for (i = ibu >> 3; --i >= 0;)
648                     *dst++ = *src++;
649                 XYNORMALIZE(&pixel, image);
650                 bits = (x + offset) % ibu;
651                 pixel = ((((char *) &pixel)[bits >> 3]) >> (bits & 7)) & 1;
652                 if (ibpp != depth)
653                     pixel &= lbt;
654                 if (storePixel(pixel, pmap, iptr))
655                     return (XpmNoMemory);
656             }
657     } else if (image->format == XYPixmap) {
658         int nbytes, bpl, j;
659         long plane = 0;
660         ibu = image->bitmap_unit;
661         nbytes = ibu >> 3;
662         bpl = image->bytes_per_line;
663         for (y = 0; y < height; y++)
664             for (x = 0; x < width; x++, iptr++) {
665                 pixel = 0;
666                 plane = 0;
667                 for (i = depth; --i >= 0;) {
668                     src = &data[XYINDEX(x, y, image) + plane];
669                     dst = (char *) &px;
670                     px = 0;
671                     for (j = nbytes; --j >= 0;)
672                         *dst++ = *src++;
673                     XYNORMALIZE(&px, image);
674                     bits = (x + offset) % ibu;
675                     pixel = (pixel << 1) |
676                             (((((char *) &px)[bits >> 3]) >> (bits & 7)) & 1);
677                     plane = plane + (bpl * height);
678                 }
679                 if (ibpp != depth)
680                     pixel &= lbt;
681                 if (storePixel(pixel, pmap, iptr))
682                     return (XpmNoMemory);
683             }
684     } else if (image->format == ZPixmap) {
685         for (y = 0; y < height; y++)
686             for (x = 0; x < width; x++, iptr++) {
687                 src = &data[ZINDEX(x, y, image)];
688                 dst = (char *) &px;
689                 px = 0;
690                 for (i = (ibpp + 7) >> 3; --i >= 0;)
691                     *dst++ = *src++;
692                 ZNORMALIZE(&px, image);
693                 pixel = 0;
694                 for (i = sizeof(unsigned long); --i >= 0;)
695                     pixel = (pixel << 8) | ((unsigned char *) &px)[i];
696                 if (ibpp == 4) {
697                     if (x & 1)
698                         pixel >>= 4;
699                     else
700                         pixel &= 0xf;
701                 }
702                 if (ibpp != depth)
703                     pixel &= lbt;
704                 if (storePixel(pixel, pmap, iptr))
705                     return (XpmNoMemory);
706             }
707     } else
708         return (XpmColorError); /* actually a bad image */
709     return (XpmSuccess);
710 }
711
712 /*
713  * scan pixels of a 32-bits Z image data structure
714  */
715
716 #if !defined(WORD64) && !defined(LONG64)
717 static unsigned long byteorderpixel = MSBFirst << 24;
718 #endif
719
720 static int
721 GetImagePixels32(
722     XImage               *image,
723     unsigned int         width,
724     unsigned int         height,
725     PixelsMap           *pmap)
726 {
727     unsigned char *addr;
728     unsigned char *data;
729     unsigned int *iptr;
730     unsigned int x, y;
731     unsigned long lbt;
732     Pixel pixel;
733     int depth;
734
735     data = (unsigned char *) image->data;
736     iptr = pmap->pixelindex;
737     depth = image->depth;
738     lbt = low_bits_table[depth];
739 #if !defined(WORD64) && !defined(LONG64)
740     if (*((char *) &byteorderpixel) == image->byte_order) {
741         for (y = 0; y < height; y++)
742             for (x = 0; x < width; x++, iptr++) {
743                 addr = &data[ZINDEX32(x, y, image)];
744                 pixel = *((unsigned long *) addr);
745                 if (depth != 32)
746                     pixel &= lbt;
747                 if (storePixel(pixel, pmap, iptr))
748                     return (XpmNoMemory);
749             }
750     } else
751 #endif
752     if (image->byte_order == MSBFirst)
753         for (y = 0; y < height; y++)
754             for (x = 0; x < width; x++, iptr++) {
755                 addr = &data[ZINDEX32(x, y, image)];
756                 pixel = ((unsigned long) addr[0] << 24 |
757                          (unsigned long) addr[1] << 16 |
758                          (unsigned long) addr[2] << 8 |
759                          addr[3]);
760                 if (depth != 32)
761                     pixel &= lbt;
762                 if (storePixel(pixel, pmap, iptr))
763                     return (XpmNoMemory);
764             }
765     else
766         for (y = 0; y < height; y++)
767             for (x = 0; x < width; x++, iptr++) {
768                 addr = &data[ZINDEX32(x, y, image)];
769                 pixel = (addr[0] |
770                          (unsigned long) addr[1] << 8 |
771                          (unsigned long) addr[2] << 16 |
772                          (unsigned long) addr[3] << 24);
773                 if (depth != 32)
774                     pixel &= lbt;
775                 if (storePixel(pixel, pmap, iptr))
776                     return (XpmNoMemory);
777             }
778     return (XpmSuccess);
779 }
780
781 /*
782  * scan pixels of a 16-bits Z image data structure
783  */
784
785 static int
786 GetImagePixels16(
787     XImage              *image,
788     unsigned int         width,
789     unsigned int         height,
790     PixelsMap           *pmap)
791 {
792     unsigned char *addr;
793     unsigned char *data;
794     unsigned int *iptr;
795     unsigned int x, y;
796     unsigned long lbt;
797     Pixel pixel;
798     int depth;
799
800     data = (unsigned char *) image->data;
801     iptr = pmap->pixelindex;
802     depth = image->depth;
803     lbt = low_bits_table[depth];
804     if (image->byte_order == MSBFirst)
805         for (y = 0; y < height; y++)
806             for (x = 0; x < width; x++, iptr++) {
807                 addr = &data[ZINDEX16(x, y, image)];
808                 pixel = addr[0] << 8 | addr[1];
809                 if (depth != 16)
810                     pixel &= lbt;
811                 if (storePixel(pixel, pmap, iptr))
812                     return (XpmNoMemory);
813             }
814     else
815         for (y = 0; y < height; y++)
816             for (x = 0; x < width; x++, iptr++) {
817                 addr = &data[ZINDEX16(x, y, image)];
818                 pixel = addr[0] | addr[1] << 8;
819                 if (depth != 16)
820                     pixel &= lbt;
821                 if (storePixel(pixel, pmap, iptr))
822                     return (XpmNoMemory);
823             }
824     return (XpmSuccess);
825 }
826
827 /*
828  * scan pixels of a 8-bits Z image data structure
829  */
830
831 static int
832 GetImagePixels8(
833     XImage              *image,
834     unsigned int         width,
835     unsigned int         height,
836     PixelsMap           *pmap)
837 {
838     unsigned int *iptr;
839     unsigned char *data;
840     unsigned int x, y;
841     unsigned long lbt;
842     Pixel pixel;
843     int depth;
844
845     data = (unsigned char *) image->data;
846     iptr = pmap->pixelindex;
847     depth = image->depth;
848     lbt = low_bits_table[depth];
849     for (y = 0; y < height; y++)
850         for (x = 0; x < width; x++, iptr++) {
851             pixel = data[ZINDEX8(x, y, image)];
852             if (depth != 8)
853                 pixel &= lbt;
854             if (storePixel(pixel, pmap, iptr))
855                 return (XpmNoMemory);
856         }
857     return (XpmSuccess);
858 }
859
860 /*
861  * scan pixels of a 1-bit depth Z image data structure
862  */
863
864 static int
865 GetImagePixels1(
866     XImage              *image,
867     unsigned int         width,
868     unsigned int         height,
869     PixelsMap            *pmap,
870     storeFuncPtr         storeFunc)
871 {
872     unsigned int *iptr;
873     unsigned int x, y;
874     char *data;
875     Pixel pixel;
876     int xoff, yoff, offset, bpl;
877
878     data = image->data;
879     iptr = pmap->pixelindex;
880     offset = image->xoffset;
881     bpl = image->bytes_per_line;
882
883     if (image->bitmap_bit_order == MSBFirst)
884         for (y = 0; y < height; y++)
885             for (x = 0; x < width; x++, iptr++) {
886                 xoff = x + offset;
887                 yoff = y * bpl + (xoff >> 3);
888                 xoff &= 7;
889                 pixel = (data[yoff] & (0x80 >> xoff)) ? 1 : 0;
890                 if ((*storeFunc) (pixel, pmap, iptr))
891                     return (XpmNoMemory);
892             }
893     else
894         for (y = 0; y < height; y++)
895             for (x = 0; x < width; x++, iptr++) {
896                 xoff = x + offset;
897                 yoff = y * bpl + (xoff >> 3);
898                 xoff &= 7;
899                 pixel = (data[yoff] & (1 << xoff)) ? 1 : 0;
900                 if ((*storeFunc) (pixel, pmap, iptr))
901                     return (XpmNoMemory);
902             }
903     return (XpmSuccess);
904 }
905
906 # else /* AMIGA */
907
908 #define CLEAN_UP(status) \
909 do {\
910     if (pixels) XpmFree (pixels);\
911     if (tmp_img) FreeXImage (tmp_img);\
912     return (status);\
913 } while(0)
914
915 static int
916 AGetImagePixels (
917     XImage        *image,
918     unsigned int   width,
919     unsigned int   height,
920     PixelsMap     *pmap,
921     int          (*storeFunc) (Pixel, PixelsMap *, unsigned int *))
922 {
923     unsigned int   *iptr;
924     unsigned int    x, y;
925     unsigned char  *pixels;
926     XImage         *tmp_img;
927     
928     pixels = XpmMalloc ((((width+15)>>4)<<4)*sizeof (*pixels));
929     if (pixels == NULL)
930         return XpmNoMemory;
931     
932     tmp_img = AllocXImage ((((width+15)>>4)<<4), 1, image->rp->BitMap->Depth);
933     if (tmp_img == NULL)
934         CLEAN_UP (XpmNoMemory);
935     
936     iptr = pmap->pixelindex;
937     for (y = 0; y < height; ++y)
938     {
939         ReadPixelLine8 (image->rp, 0, y, width, pixels, tmp_img->rp);
940         for (x = 0; x < width; ++x, ++iptr)
941         {
942             if ((*storeFunc) (pixels[x], pmap, iptr))
943                 CLEAN_UP (XpmNoMemory);
944         }
945     }
946     
947     CLEAN_UP (XpmSuccess);
948 }
949
950 #undef CLEAN_UP
951
952 # endif/* AMIGA */
953 #else  /* ndef FOR_MSW */
954 static int
955 MSWGetImagePixels(
956     Display      *display,
957     XImage       *image,
958     unsigned int  width,
959     unsigned int  height,
960     PixelsMap    *pmap,
961     int         (*storeFunc) (Pixel, PixelsMap*, unsigned int *))
962 {
963     unsigned int *iptr;
964     unsigned int x, y;
965     Pixel pixel;
966
967     iptr = pmap->pixelindex;
968
969     SelectObject(*display, image->bitmap);
970     for (y = 0; y < height; y++) {
971         for (x = 0; x < width; x++, iptr++) {
972             pixel = GetPixel(*display, x, y);
973             if ((*storeFunc) (pixel, pmap, iptr))
974                 return (XpmNoMemory);
975         }
976     }
977     return (XpmSuccess);
978 }
979
980 #endif
981
982 #ifndef FOR_MSW
983 # ifndef AMIGA
984 int
985 XpmCreateXpmImageFromPixmap(
986     Display             *display,
987     Pixmap               pixmap,
988     Pixmap               shapemask,
989     XpmImage            *xpmimage,
990     XpmAttributes       *attributes)
991 {
992     XImage *ximage = NULL;
993     XImage *shapeimage = NULL;
994     unsigned int width = 0;
995     unsigned int height = 0;
996     int ErrorStatus;
997
998     /* get geometry */
999     if (attributes && attributes->valuemask & XpmSize) {
1000         width = attributes->width;
1001         height = attributes->height;
1002     }
1003     /* get the ximages */
1004     if (pixmap)
1005         xpmCreateImageFromPixmap(display, pixmap, &ximage, &width, &height);
1006     if (shapemask)
1007         xpmCreateImageFromPixmap(display, shapemask, &shapeimage,
1008                                  &width, &height);
1009
1010     /* create the related XpmImage */
1011     ErrorStatus = XpmCreateXpmImageFromImage(display, ximage, shapeimage,
1012                                              xpmimage, attributes);
1013
1014     /* destroy the ximages */
1015     if (ximage)
1016         XDestroyImage(ximage);
1017     if (shapeimage)
1018         XDestroyImage(shapeimage);
1019
1020     return (ErrorStatus);
1021 }
1022
1023 # endif/* not AMIGA */
1024 #endif /* ndef FOR_MSW */