Updating to version 0.20.2
[wmaker-crm.git] / wrlib / nxpm.c
blobcae055c48d7a87f3f65b8c6ab67bbdd22e221829
1 /* nxpm.c - load "normalized" XPM image
2 *
3 * Raster graphics library
4 *
5 * Copyright (c) 1997 Alfredo K. Kojima
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <config.h>
24 /* AIX requires this to be the first thing in the file. */
25 #ifdef __GNUC__
26 # define alloca __builtin_alloca
27 #else
28 # if HAVE_ALLOCA_H
29 # include <alloca.h>
30 # else
31 # ifdef _AIX
32 # pragma alloca
33 # else
34 # ifndef alloca /* predefined by HP cc +Olibcalls */
35 char *alloca ();
36 # endif
37 # endif
38 # endif
39 #endif
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <assert.h>
47 #include "wraster.h"
51 * Restricted support for XPM images.
53 * The images must be in the following "normalized" format:
56 * line content
57 * 1 signature comment
58 * 2 ignored ( normally "static char *xpm[] = {" )
59 * 3 "width height color_count chars" where chars is 1 or 2
60 * 4 color definitions. Only c values with #rrggbb or #rrrrggggbbb
61 * format OR None
62 * n data
64 * - no comments or blank lines are allowed, except for the signature
65 * - all lines must have at most 256 characters
66 * - no white spaces allowed at left of each line
69 #define LINEWIDTH 64
71 #ifndef USE_XPM
74 RImage*
75 RGetImageFromXPMData(RContext *context, char **data)
77 RImage *image = NULL;
78 unsigned char *color_table[4];
79 unsigned short *symbol_table;
80 unsigned char *r, *g, *b, *a;
81 int i, j, k, line = 0;
82 int transp;
83 unsigned short color;
84 int bsize;
85 int w, h, ccount, csize;
87 if (sscanf(data[line++], "%i %i %i %i", &w, &h, &ccount, &csize)!=4
88 || w <= 0 || h <= 0 || ccount <= 0 || csize <= 0)
89 goto bad_format;
91 if (csize!=1 && csize!=2)
92 goto bad_format;
94 color_table[0] = alloca(ccount);
95 color_table[1] = alloca(ccount);
96 color_table[2] = alloca(ccount);
97 color_table[3] = alloca(ccount);
98 symbol_table = alloca(ccount * sizeof(unsigned short));
100 bsize = csize * w + 16;
102 if (!color_table[0] || !color_table[1] || !color_table[2] ||
103 !color_table[3] || !symbol_table || !bsize) {
104 RErrorCode = RERR_MEMORY;
105 alloca(0);
106 return NULL;
109 transp = 0;
110 /* get color table */
111 for (i=0; i<ccount; i++) {
112 symbol_table[i] = data[line][0];
113 if (csize==2)
114 symbol_table[i] |= data[line][1]<<8;
116 j = csize;
117 while (data[line][j]!='#' && data[line][j]!=0
118 && data[line][j]!='N') j++;
120 if (data[line][j]=='#') {
121 unsigned int red, green, blue;
123 k = 0;
124 j++;
125 while (data[line][j+k]!=0) k++;
126 if (k==6) {
127 if (sscanf(&(data[line][j]), "%2x%2x%2x", &red, &green, &blue)!=3)
128 goto bad_format;
129 } else if (k==12) {
130 if (sscanf(&(data[line][j]), "%4x%4x%4x", &red, &green, &blue)!=3)
131 goto bad_format;
132 red >>= 8;
133 green >>= 8;
134 blue >>= 8;
135 } else
136 goto bad_format;
138 color_table[0][i] = red;
139 color_table[1][i] = green;
140 color_table[2][i] = blue;
141 color_table[3][i] = 255;
142 } else if (strncmp(&(data[line][j]), "None", 4)==0) {
143 color_table[3][i] = 0;
144 transp = 1;
145 } else {
146 goto bad_format;
148 line++;
151 image = RCreateImage(w, h, transp);
152 if (!image) {
153 alloca(0);
154 return NULL;
157 r = image->data[0];
158 g = image->data[1];
159 b = image->data[2];
160 a = image->data[3];
162 for (i=0; i<h; i++) {
163 if (csize==1) {
164 for (j=0; j<w; j++) {
165 color = data[line][j];
167 for (k=0; k<ccount; k++) {
168 if (symbol_table[k] == color)
169 break;
171 if (k==ccount)
172 k = 0;
174 *(r++) = color_table[0][k];
175 *(g++) = color_table[1][k];
176 *(b++) = color_table[2][k];
177 if (a)
178 *(a++) = color_table[3][k];
180 } else {
181 for (j=0; j<w*2; j++) {
182 color = data[line][j++];
183 color |= data[line][j];
185 for (k=0; k<ccount; k++) {
186 if (symbol_table[k] == color)
187 break;
189 if (k==ccount)
190 k = 0;
192 *(r++) = color_table[0][k];
193 *(g++) = color_table[1][k];
194 *(b++) = color_table[2][k];
195 if (a)
196 *(a++) = color_table[3][k];
199 line++;
202 #ifdef C_ALLOCA
203 alloca(0);
204 #endif
205 return image;
207 bad_format:
208 RErrorCode = RERR_BADIMAGEFILE;
209 #ifdef C_ALLOCA
210 alloca(0);
211 #endif
212 if (image)
213 RDestroyImage(image);
214 return NULL;
219 RImage*
220 RLoadXPM(RContext *context, char *file, int index)
222 RImage *image = NULL;
223 char line[LINEWIDTH+1];
224 char *buffer;
225 unsigned char *color_table[4];
226 unsigned short *symbol_table;
227 unsigned char *r, *g, *b, *a;
228 int i, j, k;
229 int transp;
230 unsigned short color;
231 int bsize;
232 int w, h, ccount, csize;
233 FILE *f;
235 f = fopen(file, "r");
236 if (!f) {
237 RErrorCode = RERR_OPEN;
238 return NULL;
240 /* sig */
241 if (!fgets(line, LINEWIDTH, f))
242 goto bad_file;
243 /* declaration */
244 if (!fgets(line, LINEWIDTH, f))
245 goto bad_file;
247 /* data */
248 if (!fgets(line, LINEWIDTH, f))
249 goto bad_file;
251 if (line[0]=='/')
252 if (!fgets(line, LINEWIDTH, f))
253 goto bad_file;
255 if (sscanf(line, "\"%i %i %i %i\"", &w, &h, &ccount, &csize)!=4
256 || w <= 0 || h <= 0 || ccount <= 0 || csize <= 0)
257 goto bad_file;
259 if (csize!=1 && csize!=2)
260 goto bad_format;
262 color_table[0] = alloca(ccount);
263 color_table[1] = alloca(ccount);
264 color_table[2] = alloca(ccount);
265 color_table[3] = alloca(ccount);
266 symbol_table = alloca(ccount * sizeof(unsigned short));
268 bsize = csize * w + 16;
269 buffer = alloca(bsize);
271 if (!color_table[0] || !color_table[1] || !color_table[2] ||
272 !color_table[3] || !symbol_table || !bsize) {
273 RErrorCode = RERR_MEMORY;
274 fclose(f);
275 alloca(0);
276 return NULL;
279 transp = 0;
280 /* get color table */
281 for (i=0; i<ccount; i++) {
282 if (!fgets(line, LINEWIDTH, f))
283 goto bad_file;
284 if (line[0]=='/')
285 if (!fgets(line, LINEWIDTH, f))
286 goto bad_file;
288 symbol_table[i] = line[1];
289 if (csize==2)
290 symbol_table[i] |= line[2]<<8;
292 j = csize+1;
293 while (line[j]!='#' && line[j]!='"' && line[j]!=0 && line[j]!='N') j++;
295 if (line[j]=='#') {
296 unsigned int red, green, blue;
298 k = 0;
299 j++;
300 while (line[j+k]!='"' && line[j+k]!=0) k++;
301 if (k==6) {
302 if (sscanf(&(line[j]), "%2x%2x%2x", &red, &green, &blue)!=3)
303 goto bad_format;
304 } else if (k==12) {
305 if (sscanf(&(line[j]), "%4x%4x%4x", &red, &green, &blue)!=3)
306 goto bad_format;
307 red >>= 8;
308 green >>= 8;
309 blue >>= 8;
310 } else
311 goto bad_format;
313 color_table[0][i] = red;
314 color_table[1][i] = green;
315 color_table[2][i] = blue;
316 color_table[3][i] = 255;
317 } else if (strncmp(&(line[j]), "None", 4)==0) {
318 color_table[3][i] = 0;
319 transp = 1;
320 } else {
321 goto bad_format;
325 image = RCreateImage(w, h, transp);
326 if (!image) {
327 fclose(f);
328 alloca(0);
329 return NULL;
332 r = image->data[0];
333 g = image->data[1];
334 b = image->data[2];
335 a = image->data[3];
337 for (i=0; i<h; i++) {
338 if (!fgets(buffer, bsize, f))
339 goto bad_file;
340 if (buffer[0]=='/')
341 if (!fgets(buffer, bsize, f))
342 goto bad_file;
344 if (csize==1) {
345 for (j=1; j<=w; j++) {
346 color = buffer[j];
348 for (k=0; k<ccount; k++) {
349 if (symbol_table[k] == color)
350 break;
352 if (k==ccount)
353 k = 0;
355 *(r++) = color_table[0][k];
356 *(g++) = color_table[1][k];
357 *(b++) = color_table[2][k];
358 if (a)
359 *(a++) = color_table[3][k];
361 } else {
362 for (j=1; j<=w*2; j++) {
363 color = buffer[j++];
364 color |= buffer[j] << 8;
366 for (k=0; k<ccount; k++) {
367 if (symbol_table[k] == color)
368 break;
370 if (k==ccount) {
371 k = 0;
374 *(r++) = color_table[0][k];
375 *(g++) = color_table[1][k];
376 *(b++) = color_table[2][k];
377 if (a)
378 *(a++) = color_table[3][k];
383 fclose(f);
384 #ifdef C_ALLOCA
385 alloca(0);
386 #endif
387 return image;
389 bad_format:
390 RErrorCode = RERR_BADIMAGEFILE;
391 fclose(f);
392 #ifdef C_ALLOCA
393 alloca(0);
394 #endif
395 if (image)
396 RDestroyImage(image);
397 return NULL;
399 bad_file:
400 RErrorCode = RERR_BADIMAGEFILE;
401 fclose(f);
402 #ifdef C_ALLOCA
403 alloca(0);
404 #endif
405 if (image)
406 RDestroyImage(image);
407 return NULL;
410 #endif
413 typedef struct XPMColor {
414 unsigned char red;
415 unsigned char green;
416 unsigned char blue;
417 char text[12];
418 struct XPMColor *next;
419 } XPMColor;
423 #define I2CHAR(i) ((i)<12 ? (i)+'0' : ((i)<38 ? (i)+'A'-12 : (i)+'a'-38))
424 #define CINDEX(xpmc) (((unsigned)(xpmc)->red)<<16|((unsigned)(xpmc)->green)<<8|((unsigned)(xpmc)->blue))
428 static XPMColor*
429 lookfor(XPMColor *list, int index)
431 if (!list)
432 return NULL;
434 for (; list!=NULL; list=list->next) {
435 if (CINDEX(list) == index)
436 return list;
438 return NULL;
442 * Looks for the color in the colormap and inserts if it is not found.
444 * list is a binary search list. The unbalancing problem is just ignored.
446 * Returns False on error
448 static Bool
449 addcolor(XPMColor **list, unsigned r, unsigned g, unsigned b, int *colors)
451 XPMColor *tmpc;
452 XPMColor *newc;
453 int index;
455 index = r<<16|g<<8|b;
456 tmpc = *list;
458 tmpc = lookfor(*list, index);
460 if (tmpc)
461 return True;
463 newc = malloc(sizeof(XPMColor));
465 if (!newc) {
467 RErrorCode = RERR_NOMEMORY;
469 return False;
472 newc->red = r;
473 newc->green = g;
474 newc->blue = b;
475 newc->next = *list;
476 *list = newc;
478 (*colors)++;
480 return True;
484 static void
485 outputcolormap(FILE *file, XPMColor *colormap, int colorCount)
487 int j;
488 int i,index;
490 if (!colormap)
491 return;
493 for (index=0; colormap!=NULL; colormap=colormap->next,index++) {
494 j = index;
495 for (i=0; i<colorCount/64+1; i++) {
496 colormap->text[i] = I2CHAR(j&63);
497 j >>= 5;
499 colormap->text[i] = 0;
500 fprintf(file, "\"%s c #%02x%02x%02x\",\n", colormap->text, colormap->red,
501 colormap->green, colormap->blue);
506 static void
507 freecolormap(XPMColor *colormap)
509 XPMColor *tmp;
511 while (colormap) {
512 tmp = colormap->next;
513 free(colormap);
514 colormap = tmp;
520 /* save routine is common to internal support and library support */
521 Bool
522 RSaveXPM(RImage *image, char *filename)
524 FILE *file;
525 int x, y;
526 int colorCount=0;
527 XPMColor *colormap = NULL;
528 XPMColor *tmpc;
529 int i;
530 int ok = 0;
531 unsigned char *r, *g, *b, *a;
532 char transp[16];
534 file = fopen(filename, "w+");
535 if (!file) {
536 RErrorCode = RERR_OPEN;
537 return False;
540 fprintf(file, "/* XPM */\n");
542 fprintf(file, "static char *image[] = {\n");
544 r = image->data[0];
545 g = image->data[1];
546 b = image->data[2];
547 a = image->data[3];
549 /* first pass: make colormap for the image */
550 if (a)
551 colorCount = 1;
552 for (y = 0; y < image->height; y++) {
553 for (x = 0; x < image->width; x++) {
554 if (!a || *a++>127)
555 if (!addcolor(&colormap, *r, *g, *b, &colorCount)) {
556 goto uhoh;
558 r++; g++; b++;
562 /* write header info */
563 fprintf(file, "\"%i %i %i %i\",\n", image->width, image->height,
564 colorCount, colorCount/64+1);
567 /* write colormap data */
568 if (image->data[3]) {
569 for (i=0; i<colorCount/64+1; i++)
570 transp[i] = ' ';
571 transp[i] = 0;
573 fprintf(file, "\"%s c None\",\n", transp);
576 i = 0;
577 outputcolormap(file, colormap, colorCount);
579 r = image->data[0];
580 g = image->data[1];
581 b = image->data[2];
582 a = image->data[3];
584 /* write data */
585 for (y = 0; y < image->height; y++) {
587 fprintf(file, "\"");
589 for (x = 0; x < image->width; x++) {
591 if (!a || *a++>127) {
592 tmpc = lookfor(colormap, (unsigned)*r<<16|(unsigned)*g<<8|(unsigned)*b);
594 fprintf(file, tmpc->text);
595 } else {
596 fprintf(file, transp);
599 r++; g++; b++;
602 if (y < image->height-1)
603 fprintf(file, "\",\n");
604 else
605 fprintf(file, "\"};\n");
608 ok = 1;
609 uhoh:
610 errno = 0;
611 fclose(file);
612 if (ok && errno==ENOSPC) {
613 RErrorCode = RERR_WRITE;
616 freecolormap(colormap);
618 return ok ? True : False;