New function set_icon_image_from_database
[wmaker-crm.git] / wrlib / nxpm.c
blob45ace0d0f314e0dcbe2f938ee648105241afc50d
1 /* nxpm.c - load "normalized" XPM image
3 * Raster graphics library
5 * Copyright (c) 1997-2003 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., 51 Franklin St, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
23 #include <config.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <errno.h>
31 #include "wraster.h"
34 * Restricted support for XPM images.
36 * The images must be in the following "normalized" format:
39 * line content
40 * 1 signature comment
41 * 2 ignored ( normally "static char *xpm[] = {" )
42 * 3 "width height color_count chars" where chars is 1 or 2
43 * 4 color definitions. Only c values with #rrggbb or #rrrrggggbbb
44 * format OR None
45 * n data
47 * - no comments or blank lines are allowed, except for the signature
48 * - all lines must have at most 256 characters
49 * - no white spaces allowed at left of each line
52 #define LINEWIDTH 64
54 #ifndef USE_XPM
56 static void free_color_symbol_table(unsigned char *color_table[],
57 unsigned short *symbol_table)
59 if (color_table[0])
60 free(color_table[0]);
61 if (color_table[1])
62 free(color_table[1]);
63 if (color_table[2])
64 free(color_table[2]);
65 if (color_table[3])
66 free(color_table[3]);
67 if (symbol_table)
68 free(symbol_table);
71 RImage *RGetImageFromXPMData(RContext * context, char **data)
73 RImage *image = NULL;
74 unsigned char *color_table[4] = { NULL, NULL, NULL, NULL };
75 unsigned short *symbol_table = NULL;
76 unsigned char *r, *g, *b, *a;
77 int i, j, k, line = 0;
78 int transp;
79 unsigned short color;
80 int bsize;
81 int w, h, ccount, csize;
83 if (sscanf(data[line++], "%i %i %i %i", &w, &h, &ccount, &csize) != 4
84 || w <= 0 || h <= 0 || ccount <= 0 || csize <= 0)
85 goto bad_format;
87 if (csize != 1 && csize != 2)
88 goto bad_format;
90 color_table[0] = malloc(ccount);
91 color_table[1] = malloc(ccount);
92 color_table[2] = malloc(ccount);
93 color_table[3] = malloc(ccount);
94 symbol_table = malloc(ccount * sizeof(unsigned short));
96 bsize = csize * w + 16;
98 if (!color_table[0] || !color_table[1] || !color_table[2] || !color_table[3] || !symbol_table || !bsize) {
99 RErrorCode = RERR_NOMEMORY;
100 free_color_symbol_table(color_table, symbol_table);
101 return NULL;
104 transp = 0;
105 /* get color table */
106 for (i = 0; i < ccount; i++) {
107 symbol_table[i] = data[line][0];
108 if (csize == 2)
109 symbol_table[i] |= data[line][1] << 8;
111 j = csize;
112 while (data[line][j] != '#' && data[line][j] != 0 && data[line][j] != 'N')
113 j++;
115 if (data[line][j] == '#') {
116 unsigned int red, green, blue;
118 k = 0;
119 j++;
120 while (data[line][j + k] != 0)
121 k++;
122 if (k == 6) {
123 if (sscanf(&(data[line][j]), "%2x%2x%2x", &red, &green, &blue) != 3)
124 goto bad_format;
125 } else if (k == 12) {
126 if (sscanf(&(data[line][j]), "%4x%4x%4x", &red, &green, &blue) != 3)
127 goto bad_format;
128 red >>= 8;
129 green >>= 8;
130 blue >>= 8;
131 } else
132 goto bad_format;
134 color_table[0][i] = red;
135 color_table[1][i] = green;
136 color_table[2][i] = blue;
137 color_table[3][i] = 255;
138 } else if (strncmp(&(data[line][j]), "None", 4) == 0 || strncmp(&(data[line][j]), "none", 4) == 0) {
139 color_table[3][i] = 0;
140 transp = 1;
141 } else {
142 goto bad_format;
144 line++;
147 image = RCreateImage(w, h, transp);
148 if (!image) {
149 free_color_symbol_table(color_table, symbol_table);
150 return NULL;
153 r = image->data;
154 g = image->data + 1;
155 b = image->data + 2;
156 if (image->format == RRGBAFormat)
157 a = image->data + 3;
158 else
159 a = NULL;
161 for (i = 0; i < h; i++) {
162 if (csize == 1) {
163 for (j = 0; j < w; j++) {
164 color = data[line][j];
166 for (k = 0; k < ccount; k++) {
167 if (symbol_table[k] == color)
168 break;
170 if (k == ccount)
171 k = 0;
173 *r = color_table[0][k];
174 *g = color_table[1][k];
175 *b = color_table[2][k];
176 if (a) {
177 *a = color_table[3][k];
178 r += 4;
179 g += 4;
180 b += 4;
181 a += 4;
182 } else {
183 r += 3;
184 g += 3;
185 b += 3;
188 } else {
189 for (j = 0; j < w * 2; j++) {
190 color = data[line][j++];
191 color |= data[line][j];
193 for (k = 0; k < ccount; k++) {
194 if (symbol_table[k] == color)
195 break;
197 if (k == ccount)
198 k = 0;
200 *r = color_table[0][k];
201 *g = color_table[1][k];
202 *b = color_table[2][k];
203 if (a) {
204 *a = color_table[3][k];
205 r += 4;
206 g += 4;
207 b += 4;
208 a += 4;
209 } else {
210 r += 3;
211 g += 3;
212 b += 3;
216 line++;
219 free_color_symbol_table(color_table, symbol_table);
220 return image;
222 bad_format:
223 RErrorCode = RERR_BADIMAGEFILE;
224 free_color_symbol_table(color_table, symbol_table);
225 if (image)
226 RReleaseImage(image);
227 return NULL;
230 RImage *RLoadXPM(RContext * context, char *file)
232 RImage *image = NULL;
233 char line[LINEWIDTH + 1];
234 char *buffer = NULL;
235 unsigned char *color_table[4] = { NULL, NULL, NULL, NULL };
236 unsigned short *symbol_table = NULL;
237 unsigned char *r, *g, *b, *a;
238 int i, j, k;
239 int transp;
240 unsigned short color;
241 int bsize;
242 int w, h, ccount, csize;
243 FILE *f;
245 f = fopen(file, "rb");
246 if (!f) {
247 RErrorCode = RERR_OPEN;
248 return NULL;
250 /* sig */
251 if (!fgets(line, LINEWIDTH, f))
252 goto bad_file;
253 /* declaration */
254 if (!fgets(line, LINEWIDTH, f))
255 goto bad_file;
257 /* data */
258 if (!fgets(line, LINEWIDTH, f))
259 goto bad_file;
261 if (line[0] == '/')
262 if (!fgets(line, LINEWIDTH, f))
263 goto bad_file;
265 if (sscanf(line, "\"%i %i %i %i\"", &w, &h, &ccount, &csize) != 4
266 || w <= 0 || h <= 0 || ccount <= 0 || csize <= 0)
267 goto bad_file;
269 if (csize != 1 && csize != 2)
270 goto bad_format;
272 color_table[0] = malloc(ccount);
273 color_table[1] = malloc(ccount);
274 color_table[2] = malloc(ccount);
275 color_table[3] = malloc(ccount);
276 symbol_table = malloc(ccount * sizeof(unsigned short));
278 bsize = csize * w + 16;
279 buffer = malloc(bsize);
281 if (!color_table[0] || !color_table[1] || !color_table[2] ||
282 !color_table[3] || !symbol_table || !bsize || !buffer) {
283 RErrorCode = RERR_NOMEMORY;
284 fclose(f);
285 free_color_symbol_table(color_table, symbol_table);
286 if (buffer)
287 free(buffer);
288 return NULL;
291 transp = 0;
292 /* get color table */
293 for (i = 0; i < ccount; i++) {
294 if (!fgets(line, LINEWIDTH, f))
295 goto bad_file;
296 if (line[0] == '/')
297 if (!fgets(line, LINEWIDTH, f))
298 goto bad_file;
300 symbol_table[i] = line[1];
301 if (csize == 2)
302 symbol_table[i] |= line[2] << 8;
304 j = csize + 1;
305 while (line[j] != '#' && line[j] != '"' && line[j] != 0 && line[j] != 'N')
306 j++;
308 if (line[j] == '#') {
309 unsigned int red, green, blue;
311 k = 0;
312 j++;
313 while (line[j + k] != '"' && line[j + k] != 0)
314 k++;
315 if (k == 6) {
316 if (sscanf(&(line[j]), "%2x%2x%2x", &red, &green, &blue) != 3)
317 goto bad_format;
318 } else if (k == 12) {
319 if (sscanf(&(line[j]), "%4x%4x%4x", &red, &green, &blue) != 3)
320 goto bad_format;
321 red >>= 8;
322 green >>= 8;
323 blue >>= 8;
324 } else
325 goto bad_format;
327 color_table[0][i] = red;
328 color_table[1][i] = green;
329 color_table[2][i] = blue;
330 color_table[3][i] = 255;
331 } else if (strncmp(&(line[j]), "None", 4) == 0 || strncmp(&(line[j]), "none", 4) == 0) {
332 color_table[3][i] = 0;
333 transp = 1;
334 } else {
335 goto bad_format;
339 image = RCreateImage(w, h, transp);
340 if (!image) {
341 fclose(f);
342 free_color_symbol_table(color_table, symbol_table);
343 if (buffer)
344 free(buffer);
345 return NULL;
348 r = image->data;
349 g = image->data + 1;
350 b = image->data + 2;
351 if (image->format == RRGBAFormat)
352 a = image->data + 3;
353 else
354 a = NULL;
356 for (i = 0; i < h; i++) {
357 if (!fgets(buffer, bsize, f))
358 goto bad_file;
359 if (buffer[0] == '/')
360 if (!fgets(buffer, bsize, f))
361 goto bad_file;
363 if (csize == 1) {
364 for (j = 1; j <= w; j++) {
365 color = buffer[j];
367 for (k = 0; k < ccount; k++) {
368 if (symbol_table[k] == color)
369 break;
371 if (k == ccount)
372 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];
379 r += 4;
380 g += 4;
381 b += 4;
382 a += 4;
383 } else {
384 r += 3;
385 g += 3;
386 b += 3;
389 } else {
390 for (j = 1; j <= w * 2; j++) {
391 color = buffer[j++];
392 color |= buffer[j] << 8;
394 for (k = 0; k < ccount; k++) {
395 if (symbol_table[k] == color)
396 break;
398 if (k == ccount) {
399 k = 0;
402 *r = color_table[0][k];
403 *g = color_table[1][k];
404 *b = color_table[2][k];
405 if (a) {
406 *a = color_table[3][k];
407 r += 4;
408 g += 4;
409 b += 4;
410 a += 4;
411 } else {
412 r += 3;
413 g += 3;
414 b += 3;
420 fclose(f);
421 free_color_symbol_table(color_table, symbol_table);
422 if (buffer)
423 free(buffer);
424 return image;
426 bad_format:
427 RErrorCode = RERR_BADIMAGEFILE;
428 fclose(f);
429 free_color_symbol_table(color_table, symbol_table);
430 if (buffer)
431 free(buffer);
432 if (image)
433 RReleaseImage(image);
434 return NULL;
436 bad_file:
437 RErrorCode = RERR_BADIMAGEFILE;
438 fclose(f);
439 free_color_symbol_table(color_table, symbol_table);
440 if (buffer)
441 free(buffer);
442 if (image)
443 RReleaseImage(image);
444 return NULL;
447 #endif
449 typedef struct XPMColor {
450 unsigned char red;
451 unsigned char green;
452 unsigned char blue;
453 int index;
454 struct XPMColor *next;
455 } XPMColor;
457 #define I2CHAR(i) ((i)<12 ? (i)+'0' : ((i)<38 ? (i)+'A'-12 : (i)+'a'-38))
458 #define CINDEX(xpmc) (((unsigned)(xpmc)->red)<<16|((unsigned)(xpmc)->green)<<8|((unsigned)(xpmc)->blue))
460 static XPMColor *lookfor(XPMColor * list, int index)
462 if (!list)
463 return NULL;
465 for (; list != NULL; list = list->next) {
466 if (CINDEX(list) == index)
467 return list;
469 return NULL;
473 * Looks for the color in the colormap and inserts if it is not found.
475 * list is a binary search list. The unbalancing problem is just ignored.
477 * Returns False on error
479 static Bool addcolor(XPMColor ** list, unsigned r, unsigned g, unsigned b, int *colors)
481 XPMColor *tmpc;
482 XPMColor *newc;
483 int index;
485 index = r << 16 | g << 8 | b;
486 tmpc = *list;
488 tmpc = lookfor(*list, index);
490 if (tmpc)
491 return True;
493 newc = malloc(sizeof(XPMColor));
495 if (!newc) {
497 RErrorCode = RERR_NOMEMORY;
499 return False;
502 newc->red = r;
503 newc->green = g;
504 newc->blue = b;
505 newc->next = *list;
506 *list = newc;
508 (*colors)++;
510 return True;
513 static char *index2str(char *buffer, int index, int charsPerPixel)
515 int i;
517 for (i = 0; i < charsPerPixel; i++) {
518 buffer[i] = I2CHAR(index & 63);
519 index >>= 6;
521 buffer[i] = 0;
523 return buffer;
526 static void outputcolormap(FILE * file, XPMColor * colormap, int charsPerPixel)
528 int index;
529 char buf[128];
531 if (!colormap)
532 return;
534 for (index = 0; colormap != NULL; colormap = colormap->next, index++) {
535 colormap->index = index;
536 fprintf(file, "\"%s c #%02x%02x%02x\",\n",
537 index2str(buf, index, charsPerPixel), colormap->red, colormap->green, colormap->blue);
541 static void freecolormap(XPMColor * colormap)
543 XPMColor *tmp;
545 while (colormap) {
546 tmp = colormap->next;
547 free(colormap);
548 colormap = tmp;
552 /* save routine is common to internal support and library support */
553 Bool RSaveXPM(RImage * image, char *filename)
555 FILE *file;
556 int x, y;
557 int colorCount = 0;
558 int charsPerPixel;
559 XPMColor *colormap = NULL;
560 XPMColor *tmpc;
561 int i;
562 int ok = 0;
563 unsigned char *r, *g, *b, *a;
564 char transp[16];
565 char buf[128];
567 file = fopen(filename, "wb+");
568 if (!file) {
569 RErrorCode = RERR_OPEN;
570 return False;
573 fprintf(file, "/* XPM */\n");
575 fprintf(file, "static char *image[] = {\n");
577 r = image->data;
578 g = image->data + 1;
579 b = image->data + 2;
580 if (image->format == RRGBAFormat)
581 a = image->data + 3;
582 else
583 a = NULL;
585 /* first pass: make colormap for the image */
586 if (a)
587 colorCount = 1;
588 for (y = 0; y < image->height; y++) {
589 for (x = 0; x < image->width; x++) {
590 if (!a || *a > 127) {
591 if (!addcolor(&colormap, *r, *g, *b, &colorCount)) {
592 goto uhoh;
595 if (a) {
596 r += 4;
597 g += 4;
598 b += 4;
599 a += 4;
600 } else {
601 r += 3;
602 g += 3;
603 b += 3;
608 charsPerPixel = 1;
609 while ((1 << charsPerPixel * 6) < colorCount)
610 charsPerPixel++;
612 /* write header info */
613 fprintf(file, "\"%i %i %i %i\",\n", image->width, image->height, colorCount, charsPerPixel);
615 /* write colormap data */
616 if (a) {
617 for (i = 0; i < charsPerPixel; i++)
618 transp[i] = ' ';
619 transp[i] = 0;
621 fprintf(file, "\"%s c None\",\n", transp);
624 i = 0;
625 outputcolormap(file, colormap, charsPerPixel);
627 r = image->data;
628 g = image->data + 1;
629 b = image->data + 2;
630 if (image->format == RRGBAFormat)
631 a = image->data + 3;
632 else
633 a = NULL;
635 /* write data */
636 for (y = 0; y < image->height; y++) {
638 fprintf(file, "\"");
640 for (x = 0; x < image->width; x++) {
642 if (!a || *a > 127) {
643 tmpc = lookfor(colormap, (unsigned)*r << 16 | (unsigned)*g << 8 | (unsigned)*b);
645 fprintf(file, "%s", index2str(buf, tmpc->index, charsPerPixel));
646 } else {
647 fprintf(file, "%s", transp);
650 if (a) {
651 r += 4;
652 g += 4;
653 b += 4;
654 a += 4;
655 } else {
656 r += 3;
657 g += 3;
658 b += 3;
662 if (y < image->height - 1)
663 fprintf(file, "\",\n");
664 else
665 fprintf(file, "\"};\n");
668 ok = 1;
669 uhoh:
670 errno = 0;
671 fclose(file);
672 if (ok && errno == ENOSPC) {
673 RErrorCode = RERR_WRITE;
676 freecolormap(colormap);
678 return ok ? True : False;