added nana stuff
[wmaker-crm.git] / wrlib / nxpm.c
blob4bd0e151f3e61b4bbb00b882566f01ddd358ff76
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>
46 #include <errno.h>
48 #include "wraster.h"
52 * Restricted support for XPM images.
54 * The images must be in the following "normalized" format:
57 * line content
58 * 1 signature comment
59 * 2 ignored ( normally "static char *xpm[] = {" )
60 * 3 "width height color_count chars" where chars is 1 or 2
61 * 4 color definitions. Only c values with #rrggbb or #rrrrggggbbb
62 * format OR None
63 * n data
65 * - no comments or blank lines are allowed, except for the signature
66 * - all lines must have at most 256 characters
67 * - no white spaces allowed at left of each line
70 #define LINEWIDTH 64
72 #ifndef USE_XPM
75 RImage*
76 RGetImageFromXPMData(RContext *context, char **data)
78 RImage *image = NULL;
79 unsigned char *color_table[4];
80 unsigned short *symbol_table;
81 unsigned char *r, *g, *b, *a;
82 int i, j, k, line = 0;
83 int transp;
84 unsigned short color;
85 int bsize;
86 int w, h, ccount, csize;
88 if (sscanf(data[line++], "%i %i %i %i", &w, &h, &ccount, &csize)!=4
89 || w <= 0 || h <= 0 || ccount <= 0 || csize <= 0)
90 goto bad_format;
92 if (csize!=1 && csize!=2)
93 goto bad_format;
95 color_table[0] = alloca(ccount);
96 color_table[1] = alloca(ccount);
97 color_table[2] = alloca(ccount);
98 color_table[3] = alloca(ccount);
99 symbol_table = alloca(ccount * sizeof(unsigned short));
101 bsize = csize * w + 16;
103 if (!color_table[0] || !color_table[1] || !color_table[2] ||
104 !color_table[3] || !symbol_table || !bsize) {
105 RErrorCode = RERR_NOMEMORY;
106 alloca(0);
107 return NULL;
110 transp = 0;
111 /* get color table */
112 for (i=0; i<ccount; i++) {
113 symbol_table[i] = data[line][0];
114 if (csize==2)
115 symbol_table[i] |= data[line][1]<<8;
117 j = csize;
118 while (data[line][j]!='#' && data[line][j]!=0
119 && data[line][j]!='N') j++;
121 if (data[line][j]=='#') {
122 unsigned int red, green, blue;
124 k = 0;
125 j++;
126 while (data[line][j+k]!=0) k++;
127 if (k==6) {
128 if (sscanf(&(data[line][j]), "%2x%2x%2x", &red, &green, &blue)!=3)
129 goto bad_format;
130 } else if (k==12) {
131 if (sscanf(&(data[line][j]), "%4x%4x%4x", &red, &green, &blue)!=3)
132 goto bad_format;
133 red >>= 8;
134 green >>= 8;
135 blue >>= 8;
136 } else
137 goto bad_format;
139 color_table[0][i] = red;
140 color_table[1][i] = green;
141 color_table[2][i] = blue;
142 color_table[3][i] = 255;
143 } else if (strncmp(&(data[line][j]), "None", 4)==0
144 || strncmp(&(data[line][j]), "none", 4)==0) {
145 color_table[3][i] = 0;
146 transp = 1;
147 } else {
148 goto bad_format;
150 line++;
153 image = RCreateImage(w, h, transp);
154 if (!image) {
155 alloca(0);
156 return NULL;
159 r = image->data[0];
160 g = image->data[1];
161 b = image->data[2];
162 a = image->data[3];
164 for (i=0; i<h; i++) {
165 if (csize==1) {
166 for (j=0; j<w; j++) {
167 color = data[line][j];
169 for (k=0; k<ccount; k++) {
170 if (symbol_table[k] == color)
171 break;
173 if (k==ccount)
174 k = 0;
176 *(r++) = color_table[0][k];
177 *(g++) = color_table[1][k];
178 *(b++) = color_table[2][k];
179 if (a)
180 *(a++) = color_table[3][k];
182 } else {
183 for (j=0; j<w*2; j++) {
184 color = data[line][j++];
185 color |= data[line][j];
187 for (k=0; k<ccount; k++) {
188 if (symbol_table[k] == color)
189 break;
191 if (k==ccount)
192 k = 0;
194 *(r++) = color_table[0][k];
195 *(g++) = color_table[1][k];
196 *(b++) = color_table[2][k];
197 if (a)
198 *(a++) = color_table[3][k];
201 line++;
204 #ifdef C_ALLOCA
205 alloca(0);
206 #endif
207 return image;
209 bad_format:
210 RErrorCode = RERR_BADIMAGEFILE;
211 #ifdef C_ALLOCA
212 alloca(0);
213 #endif
214 if (image)
215 RDestroyImage(image);
216 return NULL;
221 RImage*
222 RLoadXPM(RContext *context, char *file, int index)
224 RImage *image = NULL;
225 char line[LINEWIDTH+1];
226 char *buffer;
227 unsigned char *color_table[4];
228 unsigned short *symbol_table;
229 unsigned char *r, *g, *b, *a;
230 int i, j, k;
231 int transp;
232 unsigned short color;
233 int bsize;
234 int w, h, ccount, csize;
235 FILE *f;
237 f = fopen(file, "r");
238 if (!f) {
239 RErrorCode = RERR_OPEN;
240 return NULL;
242 /* sig */
243 if (!fgets(line, LINEWIDTH, f))
244 goto bad_file;
245 /* declaration */
246 if (!fgets(line, LINEWIDTH, f))
247 goto bad_file;
249 /* data */
250 if (!fgets(line, LINEWIDTH, f))
251 goto bad_file;
253 if (line[0]=='/')
254 if (!fgets(line, LINEWIDTH, f))
255 goto bad_file;
257 if (sscanf(line, "\"%i %i %i %i\"", &w, &h, &ccount, &csize)!=4
258 || w <= 0 || h <= 0 || ccount <= 0 || csize <= 0)
259 goto bad_file;
261 if (csize!=1 && csize!=2)
262 goto bad_format;
264 color_table[0] = alloca(ccount);
265 color_table[1] = alloca(ccount);
266 color_table[2] = alloca(ccount);
267 color_table[3] = alloca(ccount);
268 symbol_table = alloca(ccount * sizeof(unsigned short));
270 bsize = csize * w + 16;
271 buffer = alloca(bsize);
273 if (!color_table[0] || !color_table[1] || !color_table[2] ||
274 !color_table[3] || !symbol_table || !bsize) {
275 RErrorCode = RERR_NOMEMORY;
276 fclose(f);
277 alloca(0);
278 return NULL;
281 transp = 0;
282 /* get color table */
283 for (i=0; i<ccount; i++) {
284 if (!fgets(line, LINEWIDTH, f))
285 goto bad_file;
286 if (line[0]=='/')
287 if (!fgets(line, LINEWIDTH, f))
288 goto bad_file;
290 symbol_table[i] = line[1];
291 if (csize==2)
292 symbol_table[i] |= line[2]<<8;
294 j = csize+1;
295 while (line[j]!='#' && line[j]!='"' && line[j]!=0 && line[j]!='N') j++;
297 if (line[j]=='#') {
298 unsigned int red, green, blue;
300 k = 0;
301 j++;
302 while (line[j+k]!='"' && line[j+k]!=0) k++;
303 if (k==6) {
304 if (sscanf(&(line[j]), "%2x%2x%2x", &red, &green, &blue)!=3)
305 goto bad_format;
306 } else if (k==12) {
307 if (sscanf(&(line[j]), "%4x%4x%4x", &red, &green, &blue)!=3)
308 goto bad_format;
309 red >>= 8;
310 green >>= 8;
311 blue >>= 8;
312 } else
313 goto bad_format;
315 color_table[0][i] = red;
316 color_table[1][i] = green;
317 color_table[2][i] = blue;
318 color_table[3][i] = 255;
319 } else if (strncmp(&(line[j]), "None", 4)==0
320 || strncmp(&(line[j]), "none", 4)==0) {
321 color_table[3][i] = 0;
322 transp = 1;
323 } else {
324 goto bad_format;
328 image = RCreateImage(w, h, transp);
329 if (!image) {
330 fclose(f);
331 alloca(0);
332 return NULL;
335 r = image->data[0];
336 g = image->data[1];
337 b = image->data[2];
338 a = image->data[3];
340 for (i=0; i<h; i++) {
341 if (!fgets(buffer, bsize, f))
342 goto bad_file;
343 if (buffer[0]=='/')
344 if (!fgets(buffer, bsize, f))
345 goto bad_file;
347 if (csize==1) {
348 for (j=1; j<=w; j++) {
349 color = buffer[j];
351 for (k=0; k<ccount; k++) {
352 if (symbol_table[k] == color)
353 break;
355 if (k==ccount)
356 k = 0;
358 *(r++) = color_table[0][k];
359 *(g++) = color_table[1][k];
360 *(b++) = color_table[2][k];
361 if (a)
362 *(a++) = color_table[3][k];
364 } else {
365 for (j=1; j<=w*2; j++) {
366 color = buffer[j++];
367 color |= buffer[j] << 8;
369 for (k=0; k<ccount; k++) {
370 if (symbol_table[k] == color)
371 break;
373 if (k==ccount) {
374 k = 0;
377 *(r++) = color_table[0][k];
378 *(g++) = color_table[1][k];
379 *(b++) = color_table[2][k];
380 if (a)
381 *(a++) = color_table[3][k];
386 fclose(f);
387 #ifdef C_ALLOCA
388 alloca(0);
389 #endif
390 return image;
392 bad_format:
393 RErrorCode = RERR_BADIMAGEFILE;
394 fclose(f);
395 #ifdef C_ALLOCA
396 alloca(0);
397 #endif
398 if (image)
399 RDestroyImage(image);
400 return NULL;
402 bad_file:
403 RErrorCode = RERR_BADIMAGEFILE;
404 fclose(f);
405 #ifdef C_ALLOCA
406 alloca(0);
407 #endif
408 if (image)
409 RDestroyImage(image);
410 return NULL;
413 #endif
416 typedef struct XPMColor {
417 unsigned char red;
418 unsigned char green;
419 unsigned char blue;
420 int index;
421 struct XPMColor *next;
422 } XPMColor;
426 #define I2CHAR(i) ((i)<12 ? (i)+'0' : ((i)<38 ? (i)+'A'-12 : (i)+'a'-38))
427 #define CINDEX(xpmc) (((unsigned)(xpmc)->red)<<16|((unsigned)(xpmc)->green)<<8|((unsigned)(xpmc)->blue))
431 static XPMColor*
432 lookfor(XPMColor *list, int index)
434 if (!list)
435 return NULL;
437 for (; list!=NULL; list=list->next) {
438 if (CINDEX(list) == index)
439 return list;
441 return NULL;
445 * Looks for the color in the colormap and inserts if it is not found.
447 * list is a binary search list. The unbalancing problem is just ignored.
449 * Returns False on error
451 static Bool
452 addcolor(XPMColor **list, unsigned r, unsigned g, unsigned b, int *colors)
454 XPMColor *tmpc;
455 XPMColor *newc;
456 int index;
458 index = r<<16|g<<8|b;
459 tmpc = *list;
461 tmpc = lookfor(*list, index);
463 if (tmpc)
464 return True;
466 newc = malloc(sizeof(XPMColor));
468 if (!newc) {
470 RErrorCode = RERR_NOMEMORY;
472 return False;
475 newc->red = r;
476 newc->green = g;
477 newc->blue = b;
478 newc->next = *list;
479 *list = newc;
481 (*colors)++;
483 return True;
487 static char*
488 index2str(char *buffer, int index, int charsPerPixel)
490 int i;
492 for (i=0; i<charsPerPixel; i++) {
493 buffer[i] = I2CHAR(index&63);
494 index >>= 6;
496 buffer[i] = 0;
498 return buffer;
502 static void
503 outputcolormap(FILE *file, XPMColor *colormap, int charsPerPixel)
505 int index;
506 char buf[128];
508 if (!colormap)
509 return;
511 for (index=0; colormap!=NULL; colormap=colormap->next,index++) {
512 colormap->index = index;
513 fprintf(file, "\"%s c #%02x%02x%02x\",\n",
514 index2str(buf, index, charsPerPixel), colormap->red,
515 colormap->green, colormap->blue);
520 static void
521 freecolormap(XPMColor *colormap)
523 XPMColor *tmp;
525 while (colormap) {
526 tmp = colormap->next;
527 free(colormap);
528 colormap = tmp;
534 /* save routine is common to internal support and library support */
535 Bool
536 RSaveXPM(RImage *image, char *filename)
538 FILE *file;
539 int x, y;
540 int colorCount=0;
541 int charsPerPixel;
542 XPMColor *colormap = NULL;
543 XPMColor *tmpc;
544 int i;
545 int ok = 0;
546 unsigned char *r, *g, *b, *a;
547 char transp[16];
548 char buf[128];
550 file = fopen(filename, "w+");
551 if (!file) {
552 RErrorCode = RERR_OPEN;
553 return False;
556 fprintf(file, "/* XPM */\n");
558 fprintf(file, "static char *image[] = {\n");
560 r = image->data[0];
561 g = image->data[1];
562 b = image->data[2];
563 a = image->data[3];
565 /* first pass: make colormap for the image */
566 if (a)
567 colorCount = 1;
568 for (y = 0; y < image->height; y++) {
569 for (x = 0; x < image->width; x++) {
570 if (!a || *a++>127)
571 if (!addcolor(&colormap, *r, *g, *b, &colorCount)) {
572 goto uhoh;
574 r++; g++; b++;
578 charsPerPixel = 1;
579 while ((1 << charsPerPixel*6) < colorCount)
580 charsPerPixel++;
582 /* write header info */
583 fprintf(file, "\"%i %i %i %i\",\n", image->width, image->height,
584 colorCount, charsPerPixel);
586 /* write colormap data */
587 if (image->data[3]) {
588 for (i=0; i<charsPerPixel; i++)
589 transp[i] = ' ';
590 transp[i] = 0;
592 fprintf(file, "\"%s c None\",\n", transp);
595 i = 0;
596 outputcolormap(file, colormap, charsPerPixel);
598 r = image->data[0];
599 g = image->data[1];
600 b = image->data[2];
601 a = image->data[3];
604 /* write data */
605 for (y = 0; y < image->height; y++) {
607 fprintf(file, "\"");
609 for (x = 0; x < image->width; x++) {
611 if (!a || *a++>127) {
612 tmpc = lookfor(colormap, (unsigned)*r<<16|(unsigned)*g<<8|(unsigned)*b);
614 fprintf(file, index2str(buf, tmpc->index, charsPerPixel));
615 } else {
616 fprintf(file, transp);
619 r++; g++; b++;
622 if (y < image->height-1)
623 fprintf(file, "\",\n");
624 else
625 fprintf(file, "\"};\n");
628 ok = 1;
629 uhoh:
630 errno = 0;
631 fclose(file);
632 if (ok && errno==ENOSPC) {
633 RErrorCode = RERR_WRITE;
636 freecolormap(colormap);
638 return ok ? True : False;