]>
Commit | Line | Data |
---|---|---|
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 | #include "xpmi.h" | |
46 | ||
47 | #define MAXPRINTABLE 92 /* number of printable ascii chars | |
48 | * minus \ and " for string compat | |
49 | * and ? to avoid ANSI trigraphs. */ | |
50 | ||
51 | static char *printable = | |
52 | " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjklzxcvbnmMNBVCZ\ | |
53 | ASDFGHJKLPIUYTREWQ!~^/()_`'][{}|"; | |
54 | ||
55 | /* | |
56 | * printable begin with a space, so in most case, due to my algorithm, when | |
57 | * the number of different colors is less than MAXPRINTABLE, it will give a | |
58 | * char follow by "nothing" (a space) in the readable xpm file | |
59 | */ | |
60 | ||
61 | ||
62 | typedef struct { | |
63 | Pixel *pixels; | |
64 | unsigned int *pixelindex; | |
65 | unsigned int size; | |
66 | unsigned int ncolors; | |
67 | unsigned int mask_pixel; /* whether there is or not */ | |
68 | } PixelsMap; | |
69 | ||
70 | LFUNC(storePixel, int, (Pixel pixel, PixelsMap *pmap, | |
71 | unsigned int *index_return)); | |
72 | ||
73 | LFUNC(storeMaskPixel, int, (Pixel pixel, PixelsMap *pmap, | |
74 | unsigned int *index_return)); | |
75 | ||
76 | LFUNC(PlatformGetImagePixels, int, (Display *d, XImage *image, unsigned int width, | |
77 | unsigned int height, PixelsMap *pmap, | |
78 | int (*storeFunc) ())); | |
79 | LFUNC(ScanTransparentColor, int, (XpmColor *color, unsigned int cpp, | |
80 | XpmAttributes *attributes)); | |
81 | ||
82 | LFUNC(ScanOtherColors, int, (Display *display, XpmColor *colors, int ncolors, | |
83 | Pixel *pixels, unsigned int mask, | |
84 | unsigned int cpp, XpmAttributes *attributes)); | |
85 | ||
86 | /* | |
87 | * This function stores the given pixel in the given arrays which are grown | |
88 | * if not large enough. | |
89 | */ | |
90 | static int | |
91 | storePixel(pixel, pmap, index_return) | |
92 | Pixel pixel; | |
93 | PixelsMap *pmap; | |
94 | unsigned int *index_return; | |
95 | { | |
96 | unsigned int i; | |
97 | Pixel *p; | |
98 | unsigned int ncolors; | |
99 | ||
100 | if (*index_return) { /* this is a transparent pixel! */ | |
101 | *index_return = 0; | |
102 | return 0; | |
103 | } | |
104 | ncolors = pmap->ncolors; | |
105 | p = pmap->pixels + pmap->mask_pixel; | |
106 | for (i = pmap->mask_pixel; i < ncolors; i++, p++) | |
107 | if ( IS_EQUAL_PIXEL(*p , pixel) ) | |
108 | break; | |
109 | if (i == ncolors) { | |
110 | if (ncolors >= pmap->size) { | |
111 | pmap->size *= 2; | |
112 | p = (Pixel *) XpmRealloc(pmap->pixels, sizeof(Pixel) * pmap->size); | |
113 | if (!p) | |
114 | return (1); | |
115 | pmap->pixels = p; | |
116 | ||
117 | } | |
118 | (pmap->pixels)[ncolors] = pixel; | |
119 | pmap->ncolors++; | |
120 | } | |
121 | *index_return = i; | |
122 | return 0; | |
123 | } | |
124 | ||
125 | static int | |
126 | storeMaskPixel(pixel, pmap, index_return) | |
127 | Pixel pixel; | |
128 | PixelsMap *pmap; | |
129 | unsigned int *index_return; | |
130 | { | |
131 | if (IS_ZERO_PIXEL(pixel)) { | |
132 | if (!pmap->ncolors) { | |
133 | pmap->ncolors = 1; | |
134 | SET_ZERO_PIXEL((pmap->pixels)[0]); | |
135 | pmap->mask_pixel = 1; | |
136 | } | |
137 | *index_return = 1; | |
138 | } else | |
139 | *index_return = 0; | |
140 | return 0; | |
141 | } | |
142 | ||
143 | /* function call in case of error */ | |
144 | #undef RETURN | |
145 | #define RETURN(status) \ | |
146 | { \ | |
147 | ErrorStatus = status; \ | |
148 | goto error; \ | |
149 | } | |
150 | ||
151 | /* | |
152 | * This function scans the given image and stores the found informations in | |
153 | * the given XpmImage structure. | |
154 | */ | |
155 | int | |
156 | XpmCreateXpmImageFromImage(display, image, shapeimage, | |
157 | xpmimage, attributes) | |
158 | Display *display; | |
159 | XImage *image; | |
160 | XImage *shapeimage; | |
161 | XpmImage *xpmimage; | |
162 | XpmAttributes *attributes; | |
163 | { | |
164 | /* variables stored in the XpmAttributes structure */ | |
165 | unsigned int cpp; | |
166 | ||
167 | /* variables to return */ | |
168 | PixelsMap pmap; | |
169 | XpmColor *colorTable = NULL; | |
170 | int ErrorStatus; | |
171 | ||
172 | /* calculation variables */ | |
173 | unsigned int width = 0; | |
174 | unsigned int height = 0; | |
175 | unsigned int cppm; /* minimum chars per pixel */ | |
176 | unsigned int c; | |
177 | ||
178 | /* initialize pmap */ | |
179 | pmap.pixels = NULL; | |
180 | pmap.pixelindex = NULL; | |
181 | pmap.size = 256; /* should be enough most of the time */ | |
182 | pmap.ncolors = 0; | |
183 | pmap.mask_pixel = 0; | |
184 | ||
185 | /* | |
186 | * get geometry | |
187 | */ | |
188 | if (image) { | |
189 | width = image->width; | |
190 | height = image->height; | |
191 | } else if (shapeimage) { | |
192 | width = shapeimage->width; | |
193 | height = shapeimage->height; | |
194 | } | |
195 | ||
196 | /* | |
197 | * retrieve information from the XpmAttributes | |
198 | */ | |
199 | if (attributes && (attributes->valuemask & XpmCharsPerPixel | |
200 | /* 3.2 backward compatibility code */ | |
201 | || attributes->valuemask & XpmInfos)) | |
202 | /* end 3.2 bc */ | |
203 | cpp = attributes->cpp; | |
204 | else | |
205 | cpp = 0; | |
206 | ||
207 | pmap.pixelindex = | |
208 | (unsigned int *) XpmCalloc(width * height, sizeof(unsigned int)); | |
209 | if (!pmap.pixelindex) | |
210 | RETURN(XpmNoMemory); | |
211 | ||
212 | pmap.pixels = (Pixel *) XpmMalloc(sizeof(Pixel) * pmap.size); | |
213 | if (!pmap.pixels) | |
214 | RETURN(XpmNoMemory); | |
215 | ||
216 | /* | |
217 | * scan shape mask if any | |
218 | */ | |
219 | if (shapeimage) { | |
220 | ||
221 | ErrorStatus = PlatformGetImagePixels(display, shapeimage, width, height, | |
222 | &pmap, storeMaskPixel); | |
223 | ||
224 | if (ErrorStatus != XpmSuccess) | |
225 | RETURN(ErrorStatus); | |
226 | } | |
227 | ||
228 | /* | |
229 | * scan the image data | |
230 | * | |
231 | * In case depth is 1 or bits_per_pixel is 4, 6, 8, 24 or 32 use optimized | |
232 | * functions, otherwise use slower but sure general one. | |
233 | * | |
234 | */ | |
235 | ||
236 | if (image) { | |
237 | ||
238 | ErrorStatus = PlatformGetImagePixels(display, image, width, height, &pmap, | |
239 | storePixel); | |
240 | ||
241 | if (ErrorStatus != XpmSuccess) | |
242 | RETURN(ErrorStatus); | |
243 | } | |
244 | ||
245 | /* | |
246 | * get rgb values and a string of char, and possibly a name for each | |
247 | * color | |
248 | */ | |
249 | ||
250 | colorTable = (XpmColor *) XpmCalloc(pmap.ncolors, sizeof(XpmColor)); | |
251 | if (!colorTable) | |
252 | RETURN(XpmNoMemory); | |
253 | ||
254 | /* compute the minimal cpp */ | |
255 | for (cppm = 1, c = MAXPRINTABLE; pmap.ncolors > c; cppm++) | |
256 | c *= MAXPRINTABLE; | |
257 | if (cpp < cppm) | |
258 | cpp = cppm; | |
259 | ||
260 | if (pmap.mask_pixel) { | |
261 | ErrorStatus = ScanTransparentColor(colorTable, cpp, attributes); | |
262 | if (ErrorStatus != XpmSuccess) | |
263 | RETURN(ErrorStatus); | |
264 | } | |
265 | ||
266 | ErrorStatus = ScanOtherColors(display, colorTable, pmap.ncolors, | |
267 | pmap.pixels, pmap.mask_pixel, cpp, | |
268 | attributes); | |
269 | if (ErrorStatus != XpmSuccess) | |
270 | RETURN(ErrorStatus); | |
271 | ||
272 | /* | |
273 | * store found informations in the XpmImage structure | |
274 | */ | |
275 | xpmimage->width = width; | |
276 | xpmimage->height = height; | |
277 | xpmimage->cpp = cpp; | |
278 | xpmimage->ncolors = pmap.ncolors; | |
279 | xpmimage->colorTable = colorTable; | |
280 | xpmimage->data = pmap.pixelindex; | |
281 | ||
282 | XpmFree(pmap.pixels); | |
283 | return (XpmSuccess); | |
284 | ||
285 | /* exit point in case of error, free only locally allocated variables */ | |
286 | error: | |
287 | if (pmap.pixelindex) | |
288 | XpmFree(pmap.pixelindex); | |
289 | if (pmap.pixels) | |
290 | XpmFree(pmap.pixels); | |
291 | if (colorTable) | |
292 | xpmFreeColorTable(colorTable, pmap.ncolors); | |
293 | ||
294 | return (ErrorStatus); | |
295 | } | |
296 | ||
297 | static int | |
298 | ScanTransparentColor(color, cpp, attributes) | |
299 | XpmColor *color; | |
300 | unsigned int cpp; | |
301 | XpmAttributes *attributes; | |
302 | { | |
303 | char *s; | |
304 | unsigned int a, b, c; | |
305 | ||
306 | /* first get a character string */ | |
307 | a = 0; | |
308 | if (!(s = color->string = (char *) XpmMalloc(cpp + 1))) | |
309 | return (XpmNoMemory); | |
310 | *s++ = printable[c = a % MAXPRINTABLE]; | |
311 | for (b = 1; b < cpp; b++, s++) | |
312 | *s = printable[c = ((a - c) / MAXPRINTABLE) % MAXPRINTABLE]; | |
313 | *s = '\0'; | |
314 | ||
315 | /* then retreive related info from the attributes if any */ | |
316 | if (attributes && (attributes->valuemask & XpmColorTable | |
317 | /* 3.2 backward compatibility code */ | |
318 | || attributes->valuemask & XpmInfos) | |
319 | /* end 3.2 bc */ | |
320 | && attributes->mask_pixel != XpmUndefPixel) { | |
321 | ||
322 | unsigned int key; | |
323 | char **defaults = (char **) color; | |
324 | char **mask_defaults; | |
325 | ||
326 | /* 3.2 backward compatibility code */ | |
327 | if (attributes->valuemask & XpmColorTable) | |
328 | /* end 3.2 bc */ | |
329 | mask_defaults = (char **) ( | |
330 | attributes->colorTable + attributes->mask_pixel); | |
331 | /* 3.2 backward compatibility code */ | |
332 | else | |
333 | mask_defaults = (char **) | |
334 | ((XpmColor **) attributes->colorTable)[attributes->mask_pixel]; | |
335 | /* end 3.2 bc */ | |
336 | for (key = 1; key <= NKEYS; key++) { | |
337 | if (s = mask_defaults[key]) { | |
338 | defaults[key] = (char *) xpmstrdup(s); | |
339 | if (!defaults[key]) | |
340 | return (XpmNoMemory); | |
341 | } | |
342 | } | |
343 | } else { | |
344 | color->c_color = (char *) xpmstrdup(TRANSPARENT_COLOR); | |
345 | if (!color->c_color) | |
346 | return (XpmNoMemory); | |
347 | } | |
348 | return (XpmSuccess); | |
349 | } | |
350 | ||
351 | static int | |
352 | ScanOtherColors(display, colors, ncolors, pixels, mask, cpp, attributes) | |
353 | Display *display; | |
354 | XpmColor *colors; | |
355 | int ncolors; | |
356 | Pixel *pixels; | |
357 | unsigned int mask; | |
358 | unsigned int cpp; | |
359 | XpmAttributes *attributes; | |
360 | { | |
361 | /* variables stored in the XpmAttributes structure */ | |
362 | Colormap colormap; | |
363 | char *rgb_fname; | |
364 | ||
365 | xpmRgbName *rgbn = NULL; | |
366 | ||
367 | int rgbn_max = 0; | |
368 | unsigned int i, j, c, i2; | |
369 | XpmColor *color; | |
370 | XColor *xcolors = NULL, *xcolor; | |
371 | char *colorname, *s; | |
372 | XpmColor *colorTable, **oldColorTable = NULL; | |
373 | unsigned int ancolors = 0; | |
374 | Pixel *apixels; | |
375 | unsigned int mask_pixel; | |
376 | Bool found; | |
377 | ||
378 | /* retrieve information from the XpmAttributes */ | |
379 | if (attributes && (attributes->valuemask & XpmColormap)) | |
380 | colormap = attributes->colormap; | |
381 | else | |
382 | colormap = XDefaultColormap(display, XDefaultScreen(display)); | |
383 | if (attributes && (attributes->valuemask & XpmRgbFilename)) | |
384 | rgb_fname = attributes->rgb_fname; | |
385 | else | |
386 | rgb_fname = NULL; | |
387 | ||
388 | /* start from the right element */ | |
389 | if (mask) { | |
390 | colors++; | |
391 | ncolors--; | |
392 | pixels++; | |
393 | } | |
394 | ||
395 | /* first get character strings and rgb values */ | |
396 | xcolors = (XColor *) XpmMalloc(sizeof(XColor) * ncolors); | |
397 | if (!xcolors) | |
398 | return (XpmNoMemory); | |
399 | ||
400 | for (i = 0, i2 = mask, color = colors, xcolor = xcolors; | |
401 | i < ncolors; i++, i2++, color++, xcolor++, pixels++) { | |
402 | ||
403 | if (!(s = color->string = (char *) XpmMalloc(cpp + 1))) { | |
404 | XpmFree(xcolors); | |
405 | return (XpmNoMemory); | |
406 | } | |
407 | *s++ = printable[c = i2 % MAXPRINTABLE]; | |
408 | for (j = 1; j < cpp; j++, s++) | |
409 | *s = printable[c = ((i2 - c) / MAXPRINTABLE) % MAXPRINTABLE]; | |
410 | *s = '\0'; | |
411 | ||
412 | xcolor->pixel = *pixels; | |
413 | } | |
414 | XQueryColors(display, colormap, xcolors, ncolors); | |
415 | ||
416 | rgbn_max = xpmReadRgbNames(NULL, NULL); | |
417 | ||
418 | if (attributes && attributes->valuemask & XpmColorTable) { | |
419 | colorTable = attributes->colorTable; | |
420 | ancolors = attributes->ncolors; | |
421 | apixels = attributes->pixels; | |
422 | mask_pixel = attributes->mask_pixel; | |
423 | } | |
424 | /* 3.2 backward compatibility code */ | |
425 | else if (attributes && attributes->valuemask & XpmInfos) { | |
426 | oldColorTable = (XpmColor **) attributes->colorTable; | |
427 | ancolors = attributes->ncolors; | |
428 | apixels = attributes->pixels; | |
429 | mask_pixel = attributes->mask_pixel; | |
430 | } | |
431 | /* end 3.2 bc */ | |
432 | ||
433 | for (i = 0, color = colors, xcolor = xcolors; i < ncolors; | |
434 | i++, color++, xcolor++) { | |
435 | ||
436 | /* look for related info from the attributes if any */ | |
437 | found = False; | |
438 | if (ancolors) { | |
439 | unsigned int offset = 0; | |
440 | ||
441 | for (j = 0; j < ancolors; j++) { | |
442 | if (j == mask_pixel) { | |
443 | offset = 1; | |
444 | continue; | |
445 | } | |
446 | if (IS_EQUAL_PIXEL( apixels[j - offset] , xcolor->pixel) ) | |
447 | break; | |
448 | } | |
449 | if (j != ancolors) { | |
450 | unsigned int key; | |
451 | char **defaults = (char **) color; | |
452 | char **adefaults; | |
453 | ||
454 | /* 3.2 backward compatibility code */ | |
455 | if (oldColorTable) | |
456 | adefaults = (char **) oldColorTable[j]; | |
457 | else | |
458 | /* end 3.2 bc */ | |
459 | adefaults = (char **) (colorTable + j); | |
460 | ||
461 | found = True; | |
462 | for (key = 1; key <= NKEYS; key++) { | |
463 | if (s = adefaults[key]) | |
464 | defaults[key] = (char *) xpmstrdup(s); | |
465 | } | |
466 | } | |
467 | } | |
468 | if (!found) { | |
469 | /* if nothing found look for a color name */ | |
470 | colorname = NULL; | |
471 | if (rgbn_max) | |
472 | colorname = xpmGetRgbName(rgbn, rgbn_max, xcolor->red, | |
473 | xcolor->green, xcolor->blue); | |
474 | if (colorname) | |
475 | color->c_color = (char *) xpmstrdup(colorname); | |
476 | else { | |
477 | /* at last store the rgb value */ | |
478 | char buf[BUFSIZ]; | |
479 | // sprintf(buf, "#%04X%04X%04X", | |
480 | sprintf(buf, "#%02x%02x%02x", | |
481 | xcolor->red, xcolor->green, xcolor->blue); | |
482 | ||
483 | color->c_color = (char *) xpmstrdup(buf); | |
484 | } | |
485 | if (!color->c_color) { | |
486 | XpmFree(xcolors); | |
487 | xpmFreeRgbNames(rgbn, rgbn_max); | |
488 | return (XpmNoMemory); | |
489 | } | |
490 | } | |
491 | } | |
492 | ||
493 | XpmFree(xcolors); | |
494 | xpmFreeRgbNames(rgbn, rgbn_max); | |
495 | return (XpmSuccess); | |
496 | } | |
497 | ||
498 | ||
499 | static int | |
500 | PlatformGetImagePixels(display, image, width, height, pmap, storeFunc) | |
501 | Display *display; | |
502 | XImage *image; | |
503 | unsigned int width; | |
504 | unsigned int height; | |
505 | PixelsMap *pmap; | |
506 | int (*storeFunc) (); | |
507 | { | |
508 | #if FOR_MSW | |
509 | unsigned int *iptr; | |
510 | unsigned int x, y; | |
511 | Pixel pixel; | |
512 | ||
513 | iptr = pmap->pixelindex; | |
514 | ||
515 | SelectObject(*display, image->bitmap); | |
516 | for (y = 0; y < height; y++) { | |
517 | for (x = 0; x < width; x++, iptr++) { | |
518 | pixel = GetPixel(*display, x, y); | |
519 | if ((*storeFunc) (pixel, pmap, iptr)) | |
520 | return (XpmNoMemory); | |
521 | } | |
522 | } | |
523 | #elif macintosh | |
524 | #endif | |
525 | return (XpmSuccess); | |
526 | } |