0.51.1 pre snapshot. Be careful, it may be buggy. It fixes some bugs though.
[wmaker-crm.git] / wrlib / nxpm.c
blobc62c8db7fe658fffa89a2244c8b3b489b12d52ff
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 color_table[3][i] = 0;
145 transp = 1;
146 } else {
147 goto bad_format;
149 line++;
152 image = RCreateImage(w, h, transp);
153 if (!image) {
154 alloca(0);
155 return NULL;
158 r = image->data[0];
159 g = image->data[1];
160 b = image->data[2];
161 a = image->data[3];
163 for (i=0; i<h; i++) {
164 if (csize==1) {
165 for (j=0; j<w; j++) {
166 color = data[line][j];
168 for (k=0; k<ccount; k++) {
169 if (symbol_table[k] == color)
170 break;
172 if (k==ccount)
173 k = 0;
175 *(r++) = color_table[0][k];
176 *(g++) = color_table[1][k];
177 *(b++) = color_table[2][k];
178 if (a)
179 *(a++) = color_table[3][k];
181 } else {
182 for (j=0; j<w*2; j++) {
183 color = data[line][j++];
184 color |= data[line][j];
186 for (k=0; k<ccount; k++) {
187 if (symbol_table[k] == color)
188 break;
190 if (k==ccount)
191 k = 0;
193 *(r++) = color_table[0][k];
194 *(g++) = color_table[1][k];
195 *(b++) = color_table[2][k];
196 if (a)
197 *(a++) = color_table[3][k];
200 line++;
203 #ifdef C_ALLOCA
204 alloca(0);
205 #endif
206 return image;
208 bad_format:
209 RErrorCode = RERR_BADIMAGEFILE;
210 #ifdef C_ALLOCA
211 alloca(0);
212 #endif
213 if (image)
214 RDestroyImage(image);
215 return NULL;
220 RImage*
221 RLoadXPM(RContext *context, char *file, int index)
223 RImage *image = NULL;
224 char line[LINEWIDTH+1];
225 char *buffer;
226 unsigned char *color_table[4];
227 unsigned short *symbol_table;
228 unsigned char *r, *g, *b, *a;
229 int i, j, k;
230 int transp;
231 unsigned short color;
232 int bsize;
233 int w, h, ccount, csize;
234 FILE *f;
236 f = fopen(file, "r");
237 if (!f) {
238 RErrorCode = RERR_OPEN;
239 return NULL;
241 /* sig */
242 if (!fgets(line, LINEWIDTH, f))
243 goto bad_file;
244 /* declaration */
245 if (!fgets(line, LINEWIDTH, f))
246 goto bad_file;
248 /* data */
249 if (!fgets(line, LINEWIDTH, f))
250 goto bad_file;
252 if (line[0]=='/')
253 if (!fgets(line, LINEWIDTH, f))
254 goto bad_file;
256 if (sscanf(line, "\"%i %i %i %i\"", &w, &h, &ccount, &csize)!=4
257 || w <= 0 || h <= 0 || ccount <= 0 || csize <= 0)
258 goto bad_file;
260 if (csize!=1 && csize!=2)
261 goto bad_format;
263 color_table[0] = alloca(ccount);
264 color_table[1] = alloca(ccount);
265 color_table[2] = alloca(ccount);
266 color_table[3] = alloca(ccount);
267 symbol_table = alloca(ccount * sizeof(unsigned short));
269 bsize = csize * w + 16;
270 buffer = alloca(bsize);
272 if (!color_table[0] || !color_table[1] || !color_table[2] ||
273 !color_table[3] || !symbol_table || !bsize) {
274 RErrorCode = RERR_NOMEMORY;
275 fclose(f);
276 alloca(0);
277 return NULL;
280 transp = 0;
281 /* get color table */
282 for (i=0; i<ccount; i++) {
283 if (!fgets(line, LINEWIDTH, f))
284 goto bad_file;
285 if (line[0]=='/')
286 if (!fgets(line, LINEWIDTH, f))
287 goto bad_file;
289 symbol_table[i] = line[1];
290 if (csize==2)
291 symbol_table[i] |= line[2]<<8;
293 j = csize+1;
294 while (line[j]!='#' && line[j]!='"' && line[j]!=0 && line[j]!='N') j++;
296 if (line[j]=='#') {
297 unsigned int red, green, blue;
299 k = 0;
300 j++;
301 while (line[j+k]!='"' && line[j+k]!=0) k++;
302 if (k==6) {
303 if (sscanf(&(line[j]), "%2x%2x%2x", &red, &green, &blue)!=3)
304 goto bad_format;
305 } else if (k==12) {
306 if (sscanf(&(line[j]), "%4x%4x%4x", &red, &green, &blue)!=3)
307 goto bad_format;
308 red >>= 8;
309 green >>= 8;
310 blue >>= 8;
311 } else
312 goto bad_format;
314 color_table[0][i] = red;
315 color_table[1][i] = green;
316 color_table[2][i] = blue;
317 color_table[3][i] = 255;
318 } else if (strncmp(&(line[j]), "None", 4)==0) {
319 color_table[3][i] = 0;
320 transp = 1;
321 } else {
322 goto bad_format;
326 image = RCreateImage(w, h, transp);
327 if (!image) {
328 fclose(f);
329 alloca(0);
330 return NULL;
333 r = image->data[0];
334 g = image->data[1];
335 b = image->data[2];
336 a = image->data[3];
338 for (i=0; i<h; i++) {
339 if (!fgets(buffer, bsize, f))
340 goto bad_file;
341 if (buffer[0]=='/')
342 if (!fgets(buffer, bsize, f))
343 goto bad_file;
345 if (csize==1) {
346 for (j=1; j<=w; j++) {
347 color = buffer[j];
349 for (k=0; k<ccount; k++) {
350 if (symbol_table[k] == color)
351 break;
353 if (k==ccount)
354 k = 0;
356 *(r++) = color_table[0][k];
357 *(g++) = color_table[1][k];
358 *(b++) = color_table[2][k];
359 if (a)
360 *(a++) = color_table[3][k];
362 } else {
363 for (j=1; j<=w*2; j++) {
364 color = buffer[j++];
365 color |= buffer[j] << 8;
367 for (k=0; k<ccount; k++) {
368 if (symbol_table[k] == color)
369 break;
371 if (k==ccount) {
372 k = 0;
375 *(r++) = color_table[0][k];
376 *(g++) = color_table[1][k];
377 *(b++) = color_table[2][k];
378 if (a)
379 *(a++) = color_table[3][k];
384 fclose(f);
385 #ifdef C_ALLOCA
386 alloca(0);
387 #endif
388 return image;
390 bad_format:
391 RErrorCode = RERR_BADIMAGEFILE;
392 fclose(f);
393 #ifdef C_ALLOCA
394 alloca(0);
395 #endif
396 if (image)
397 RDestroyImage(image);
398 return NULL;
400 bad_file:
401 RErrorCode = RERR_BADIMAGEFILE;
402 fclose(f);
403 #ifdef C_ALLOCA
404 alloca(0);
405 #endif
406 if (image)
407 RDestroyImage(image);
408 return NULL;
411 #endif
414 typedef struct XPMColor {
415 unsigned char red;
416 unsigned char green;
417 unsigned char blue;
418 int index;
419 struct XPMColor *next;
420 } XPMColor;
424 #define I2CHAR(i) ((i)<12 ? (i)+'0' : ((i)<38 ? (i)+'A'-12 : (i)+'a'-38))
425 #define CINDEX(xpmc) (((unsigned)(xpmc)->red)<<16|((unsigned)(xpmc)->green)<<8|((unsigned)(xpmc)->blue))
429 static XPMColor*
430 lookfor(XPMColor *list, int index)
432 if (!list)
433 return NULL;
435 for (; list!=NULL; list=list->next) {
436 if (CINDEX(list) == index)
437 return list;
439 return NULL;
443 * Looks for the color in the colormap and inserts if it is not found.
445 * list is a binary search list. The unbalancing problem is just ignored.
447 * Returns False on error
449 static Bool
450 addcolor(XPMColor **list, unsigned r, unsigned g, unsigned b, int *colors)
452 XPMColor *tmpc;
453 XPMColor *newc;
454 int index;
456 index = r<<16|g<<8|b;
457 tmpc = *list;
459 tmpc = lookfor(*list, index);
461 if (tmpc)
462 return True;
464 newc = malloc(sizeof(XPMColor));
466 if (!newc) {
468 RErrorCode = RERR_NOMEMORY;
470 return False;
473 newc->red = r;
474 newc->green = g;
475 newc->blue = b;
476 newc->next = *list;
477 *list = newc;
479 (*colors)++;
481 return True;
485 static char*
486 index2str(char *buffer, int index, int colorCount)
488 int i;
490 for (i=0; i<colorCount/64+1; i++) {
491 buffer[i] = I2CHAR(index&63);
492 index >>= 5;
494 buffer[i] = 0;
496 return buffer;
500 static void
501 outputcolormap(FILE *file, XPMColor *colormap, int colorCount)
503 int index;
504 char buf[128];
506 if (!colormap)
507 return;
509 for (index=0; colormap!=NULL; colormap=colormap->next,index++) {
510 colormap->index = index;
511 fprintf(file, "\"%s c #%02x%02x%02x\",\n",
512 index2str(buf, index, colorCount), colormap->red,
513 colormap->green, colormap->blue);
518 static void
519 freecolormap(XPMColor *colormap)
521 XPMColor *tmp;
523 while (colormap) {
524 tmp = colormap->next;
525 free(colormap);
526 colormap = tmp;
532 /* save routine is common to internal support and library support */
533 Bool
534 RSaveXPM(RImage *image, char *filename)
536 FILE *file;
537 int x, y;
538 int colorCount=0;
539 XPMColor *colormap = NULL;
540 XPMColor *tmpc;
541 int i;
542 int ok = 0;
543 unsigned char *r, *g, *b, *a;
544 char transp[16];
545 char buf[128];
547 file = fopen(filename, "w+");
548 if (!file) {
549 RErrorCode = RERR_OPEN;
550 return False;
553 fprintf(file, "/* XPM */\n");
555 fprintf(file, "static char *image[] = {\n");
557 r = image->data[0];
558 g = image->data[1];
559 b = image->data[2];
560 a = image->data[3];
562 /* first pass: make colormap for the image */
563 if (a)
564 colorCount = 1;
565 for (y = 0; y < image->height; y++) {
566 for (x = 0; x < image->width; x++) {
567 if (!a || *a++>127)
568 if (!addcolor(&colormap, *r, *g, *b, &colorCount)) {
569 goto uhoh;
571 r++; g++; b++;
575 /* write header info */
576 fprintf(file, "\"%i %i %i %i\",\n", image->width, image->height,
577 colorCount, colorCount/64+1);
579 /* write colormap data */
580 if (image->data[3]) {
581 for (i=0; i<colorCount/64+1; i++)
582 transp[i] = ' ';
583 transp[i] = 0;
585 fprintf(file, "\"%s c None\",\n", transp);
588 i = 0;
589 outputcolormap(file, colormap, colorCount);
591 r = image->data[0];
592 g = image->data[1];
593 b = image->data[2];
594 a = image->data[3];
597 /* write data */
598 for (y = 0; y < image->height; y++) {
600 fprintf(file, "\"");
602 for (x = 0; x < image->width; x++) {
604 if (!a || *a++>127) {
605 tmpc = lookfor(colormap, (unsigned)*r<<16|(unsigned)*g<<8|(unsigned)*b);
607 fprintf(file, index2str(buf, tmpc->index, colorCount));
608 } else {
609 fprintf(file, transp);
612 r++; g++; b++;
615 if (y < image->height-1)
616 fprintf(file, "\",\n");
617 else
618 fprintf(file, "\"};\n");
621 ok = 1;
622 uhoh:
623 errno = 0;
624 fclose(file);
625 if (ok && errno==ENOSPC) {
626 RErrorCode = RERR_WRITE;
629 freecolormap(colormap);
631 return ok ? True : False;