Partially support _NET_WM_STRUT_PARTIAL.
[wmaker-crm.git] / wrlib / nxpm.c
blob706d241b9170dafd604e9d67aea810c3635e6366
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., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include <config.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <errno.h>
30 #include "wraster.h"
33 * Restricted support for XPM images.
35 * The images must be in the following "normalized" format:
38 * line content
39 * 1 signature comment
40 * 2 ignored ( normally "static char *xpm[] = {" )
41 * 3 "width height color_count chars" where chars is 1 or 2
42 * 4 color definitions. Only c values with #rrggbb or #rrrrggggbbb
43 * format OR None
44 * n data
46 * - no comments or blank lines are allowed, except for the signature
47 * - all lines must have at most 256 characters
48 * - no white spaces allowed at left of each line
51 #define LINEWIDTH 64
53 #ifndef USE_XPM
55 static void free_color_symbol_table(unsigned char *color_table[],
56 unsigned short *symbol_table)
58 if (color_table[0])
59 free(color_table[0]);
60 if (color_table[1])
61 free(color_table[1]);
62 if (color_table[2])
63 free(color_table[2]);
64 if (color_table[3])
65 free(color_table[3]);
66 if (symbol_table)
67 free(symbol_table);
70 RImage *RGetImageFromXPMData(RContext * context, char **data)
72 RImage *image = NULL;
73 unsigned char *color_table[4] = { NULL, NULL, NULL, NULL };
74 unsigned short *symbol_table = NULL;
75 unsigned char *r, *g, *b, *a;
76 int i, j, k, line = 0;
77 int transp;
78 unsigned short color;
79 int bsize;
80 int w, h, ccount, csize;
82 if (sscanf(data[line++], "%i %i %i %i", &w, &h, &ccount, &csize) != 4
83 || w <= 0 || h <= 0 || ccount <= 0 || csize <= 0)
84 goto bad_format;
86 if (csize != 1 && csize != 2)
87 goto bad_format;
89 color_table[0] = malloc(ccount);
90 color_table[1] = malloc(ccount);
91 color_table[2] = malloc(ccount);
92 color_table[3] = malloc(ccount);
93 symbol_table = malloc(ccount * sizeof(unsigned short));
95 bsize = csize * w + 16;
97 if (!color_table[0] || !color_table[1] || !color_table[2] || !color_table[3] || !symbol_table || !bsize) {
98 RErrorCode = RERR_NOMEMORY;
99 free_color_symbol_table(color_table, symbol_table);
100 return NULL;
103 transp = 0;
104 /* get color table */
105 for (i = 0; i < ccount; i++) {
106 symbol_table[i] = data[line][0];
107 if (csize == 2)
108 symbol_table[i] |= data[line][1] << 8;
110 j = csize;
111 while (data[line][j] != '#' && data[line][j] != 0 && data[line][j] != 'N')
112 j++;
114 if (data[line][j] == '#') {
115 unsigned int red, green, blue;
117 k = 0;
118 j++;
119 while (data[line][j + k] != 0)
120 k++;
121 if (k == 6) {
122 if (sscanf(&(data[line][j]), "%2x%2x%2x", &red, &green, &blue) != 3)
123 goto bad_format;
124 } else if (k == 12) {
125 if (sscanf(&(data[line][j]), "%4x%4x%4x", &red, &green, &blue) != 3)
126 goto bad_format;
127 red >>= 8;
128 green >>= 8;
129 blue >>= 8;
130 } else
131 goto bad_format;
133 color_table[0][i] = red;
134 color_table[1][i] = green;
135 color_table[2][i] = blue;
136 color_table[3][i] = 255;
137 } else if (strncmp(&(data[line][j]), "None", 4) == 0 || strncmp(&(data[line][j]), "none", 4) == 0) {
138 color_table[3][i] = 0;
139 transp = 1;
140 } else {
141 goto bad_format;
143 line++;
146 image = RCreateImage(w, h, transp);
147 if (!image) {
148 free_color_symbol_table(color_table, symbol_table);
149 return NULL;
152 r = image->data;
153 g = image->data + 1;
154 b = image->data + 2;
155 if (image->format == RRGBAFormat)
156 a = image->data + 3;
157 else
158 a = NULL;
160 for (i = 0; i < h; i++) {
161 if (csize == 1) {
162 for (j = 0; j < w; j++) {
163 color = data[line][j];
165 for (k = 0; k < ccount; k++) {
166 if (symbol_table[k] == color)
167 break;
169 if (k == ccount)
170 k = 0;
172 *r = color_table[0][k];
173 *g = color_table[1][k];
174 *b = color_table[2][k];
175 if (a) {
176 *a = color_table[3][k];
177 r += 4;
178 g += 4;
179 b += 4;
180 a += 4;
181 } else {
182 r += 3;
183 g += 3;
184 b += 3;
187 } else {
188 for (j = 0; j < w * 2; j++) {
189 color = data[line][j++];
190 color |= data[line][j];
192 for (k = 0; k < ccount; k++) {
193 if (symbol_table[k] == color)
194 break;
196 if (k == ccount)
197 k = 0;
199 *r = color_table[0][k];
200 *g = color_table[1][k];
201 *b = color_table[2][k];
202 if (a) {
203 *a = color_table[3][k];
204 r += 4;
205 g += 4;
206 b += 4;
207 a += 4;
208 } else {
209 r += 3;
210 g += 3;
211 b += 3;
215 line++;
218 free_color_symbol_table(color_table, symbol_table);
219 return image;
221 bad_format:
222 RErrorCode = RERR_BADIMAGEFILE;
223 free_color_symbol_table(color_table, symbol_table);
224 if (image)
225 RReleaseImage(image);
226 return NULL;
229 RImage *RLoadXPM(RContext * context, char *file)
231 RImage *image = NULL;
232 char line[LINEWIDTH + 1];
233 char *buffer = NULL;
234 unsigned char *color_table[4] = { NULL, NULL, NULL, NULL };
235 unsigned short *symbol_table = NULL;
236 unsigned char *r, *g, *b, *a;
237 int i, j, k;
238 int transp;
239 unsigned short color;
240 int bsize;
241 int w, h, ccount, csize;
242 FILE *f;
244 f = fopen(file, "rb");
245 if (!f) {
246 RErrorCode = RERR_OPEN;
247 return NULL;
249 /* sig */
250 if (!fgets(line, LINEWIDTH, f))
251 goto bad_file;
252 /* declaration */
253 if (!fgets(line, LINEWIDTH, f))
254 goto bad_file;
256 /* data */
257 if (!fgets(line, LINEWIDTH, f))
258 goto bad_file;
260 if (line[0] == '/')
261 if (!fgets(line, LINEWIDTH, f))
262 goto bad_file;
264 if (sscanf(line, "\"%i %i %i %i\"", &w, &h, &ccount, &csize) != 4
265 || w <= 0 || h <= 0 || ccount <= 0 || csize <= 0)
266 goto bad_file;
268 if (csize != 1 && csize != 2)
269 goto bad_format;
271 color_table[0] = malloc(ccount);
272 color_table[1] = malloc(ccount);
273 color_table[2] = malloc(ccount);
274 color_table[3] = malloc(ccount);
275 symbol_table = malloc(ccount * sizeof(unsigned short));
277 bsize = csize * w + 16;
278 buffer = malloc(bsize);
280 if (!color_table[0] || !color_table[1] || !color_table[2] ||
281 !color_table[3] || !symbol_table || !bsize || !buffer) {
282 RErrorCode = RERR_NOMEMORY;
283 fclose(f);
284 free_color_symbol_table(color_table, symbol_table);
285 if (buffer)
286 free(buffer);
287 return NULL;
290 transp = 0;
291 /* get color table */
292 for (i = 0; i < ccount; i++) {
293 if (!fgets(line, LINEWIDTH, f))
294 goto bad_file;
295 if (line[0] == '/')
296 if (!fgets(line, LINEWIDTH, f))
297 goto bad_file;
299 symbol_table[i] = line[1];
300 if (csize == 2)
301 symbol_table[i] |= line[2] << 8;
303 j = csize + 1;
304 while (line[j] != '#' && line[j] != '"' && line[j] != 0 && line[j] != 'N')
305 j++;
307 if (line[j] == '#') {
308 unsigned int red, green, blue;
310 k = 0;
311 j++;
312 while (line[j + k] != '"' && line[j + k] != 0)
313 k++;
314 if (k == 6) {
315 if (sscanf(&(line[j]), "%2x%2x%2x", &red, &green, &blue) != 3)
316 goto bad_format;
317 } else if (k == 12) {
318 if (sscanf(&(line[j]), "%4x%4x%4x", &red, &green, &blue) != 3)
319 goto bad_format;
320 red >>= 8;
321 green >>= 8;
322 blue >>= 8;
323 } else
324 goto bad_format;
326 color_table[0][i] = red;
327 color_table[1][i] = green;
328 color_table[2][i] = blue;
329 color_table[3][i] = 255;
330 } else if (strncmp(&(line[j]), "None", 4) == 0 || strncmp(&(line[j]), "none", 4) == 0) {
331 color_table[3][i] = 0;
332 transp = 1;
333 } else {
334 goto bad_format;
338 image = RCreateImage(w, h, transp);
339 if (!image) {
340 fclose(f);
341 free_color_symbol_table(color_table, symbol_table);
342 if (buffer)
343 free(buffer);
344 return NULL;
347 r = image->data;
348 g = image->data + 1;
349 b = image->data + 2;
350 if (image->format == RRGBAFormat)
351 a = image->data + 3;
352 else
353 a = NULL;
355 for (i = 0; i < h; i++) {
356 if (!fgets(buffer, bsize, f))
357 goto bad_file;
358 if (buffer[0] == '/')
359 if (!fgets(buffer, bsize, f))
360 goto bad_file;
362 if (csize == 1) {
363 for (j = 1; j <= w; j++) {
364 color = buffer[j];
366 for (k = 0; k < ccount; k++) {
367 if (symbol_table[k] == color)
368 break;
370 if (k == ccount)
371 k = 0;
373 *r = color_table[0][k];
374 *g = color_table[1][k];
375 *b = color_table[2][k];
376 if (a) {
377 *a = color_table[3][k];
378 r += 4;
379 g += 4;
380 b += 4;
381 a += 4;
382 } else {
383 r += 3;
384 g += 3;
385 b += 3;
388 } else {
389 for (j = 1; j <= w * 2; j++) {
390 color = buffer[j++];
391 color |= buffer[j] << 8;
393 for (k = 0; k < ccount; k++) {
394 if (symbol_table[k] == color)
395 break;
397 if (k == ccount) {
398 k = 0;
401 *r = color_table[0][k];
402 *g = color_table[1][k];
403 *b = color_table[2][k];
404 if (a) {
405 *a = color_table[3][k];
406 r += 4;
407 g += 4;
408 b += 4;
409 a += 4;
410 } else {
411 r += 3;
412 g += 3;
413 b += 3;
419 fclose(f);
420 free_color_symbol_table(color_table, symbol_table);
421 if (buffer)
422 free(buffer);
423 return image;
425 bad_format:
426 RErrorCode = RERR_BADIMAGEFILE;
427 fclose(f);
428 free_color_symbol_table(color_table, symbol_table);
429 if (buffer)
430 free(buffer);
431 if (image)
432 RReleaseImage(image);
433 return NULL;
435 bad_file:
436 RErrorCode = RERR_BADIMAGEFILE;
437 fclose(f);
438 free_color_symbol_table(color_table, symbol_table);
439 if (buffer)
440 free(buffer);
441 if (image)
442 RReleaseImage(image);
443 return NULL;
446 #endif
448 typedef struct XPMColor {
449 unsigned char red;
450 unsigned char green;
451 unsigned char blue;
452 int index;
453 struct XPMColor *next;
454 } XPMColor;
456 #define I2CHAR(i) ((i)<12 ? (i)+'0' : ((i)<38 ? (i)+'A'-12 : (i)+'a'-38))
457 #define CINDEX(xpmc) (((unsigned)(xpmc)->red)<<16|((unsigned)(xpmc)->green)<<8|((unsigned)(xpmc)->blue))
459 static XPMColor *lookfor(XPMColor * list, int index)
461 if (!list)
462 return NULL;
464 for (; list != NULL; list = list->next) {
465 if (CINDEX(list) == index)
466 return list;
468 return NULL;
472 * Looks for the color in the colormap and inserts if it is not found.
474 * list is a binary search list. The unbalancing problem is just ignored.
476 * Returns False on error
478 static Bool addcolor(XPMColor ** list, unsigned r, unsigned g, unsigned b, int *colors)
480 XPMColor *tmpc;
481 XPMColor *newc;
482 int index;
484 index = r << 16 | g << 8 | b;
485 tmpc = *list;
487 tmpc = lookfor(*list, index);
489 if (tmpc)
490 return True;
492 newc = malloc(sizeof(XPMColor));
494 if (!newc) {
496 RErrorCode = RERR_NOMEMORY;
498 return False;
501 newc->red = r;
502 newc->green = g;
503 newc->blue = b;
504 newc->next = *list;
505 *list = newc;
507 (*colors)++;
509 return True;
512 static char *index2str(char *buffer, int index, int charsPerPixel)
514 int i;
516 for (i = 0; i < charsPerPixel; i++) {
517 buffer[i] = I2CHAR(index & 63);
518 index >>= 6;
520 buffer[i] = 0;
522 return buffer;
525 static void outputcolormap(FILE * file, XPMColor * colormap, int charsPerPixel)
527 int index;
528 char buf[128];
530 if (!colormap)
531 return;
533 for (index = 0; colormap != NULL; colormap = colormap->next, index++) {
534 colormap->index = index;
535 fprintf(file, "\"%s c #%02x%02x%02x\",\n",
536 index2str(buf, index, charsPerPixel), colormap->red, colormap->green, colormap->blue);
540 static void freecolormap(XPMColor * colormap)
542 XPMColor *tmp;
544 while (colormap) {
545 tmp = colormap->next;
546 free(colormap);
547 colormap = tmp;
551 /* save routine is common to internal support and library support */
552 Bool RSaveXPM(RImage * image, char *filename)
554 FILE *file;
555 int x, y;
556 int colorCount = 0;
557 int charsPerPixel;
558 XPMColor *colormap = NULL;
559 XPMColor *tmpc;
560 int i;
561 int ok = 0;
562 unsigned char *r, *g, *b, *a;
563 char transp[16];
564 char buf[128];
566 file = fopen(filename, "wb+");
567 if (!file) {
568 RErrorCode = RERR_OPEN;
569 return False;
572 fprintf(file, "/* XPM */\n");
574 fprintf(file, "static char *image[] = {\n");
576 r = image->data;
577 g = image->data + 1;
578 b = image->data + 2;
579 if (image->format == RRGBAFormat)
580 a = image->data + 3;
581 else
582 a = NULL;
584 /* first pass: make colormap for the image */
585 if (a)
586 colorCount = 1;
587 for (y = 0; y < image->height; y++) {
588 for (x = 0; x < image->width; x++) {
589 if (!a || *a > 127) {
590 if (!addcolor(&colormap, *r, *g, *b, &colorCount)) {
591 goto uhoh;
594 if (a) {
595 r += 4;
596 g += 4;
597 b += 4;
598 a += 4;
599 } else {
600 r += 3;
601 g += 3;
602 b += 3;
607 charsPerPixel = 1;
608 while ((1 << charsPerPixel * 6) < colorCount)
609 charsPerPixel++;
611 /* write header info */
612 fprintf(file, "\"%i %i %i %i\",\n", image->width, image->height, colorCount, charsPerPixel);
614 /* write colormap data */
615 if (a) {
616 for (i = 0; i < charsPerPixel; i++)
617 transp[i] = ' ';
618 transp[i] = 0;
620 fprintf(file, "\"%s c None\",\n", transp);
623 i = 0;
624 outputcolormap(file, colormap, charsPerPixel);
626 r = image->data;
627 g = image->data + 1;
628 b = image->data + 2;
629 if (image->format == RRGBAFormat)
630 a = image->data + 3;
631 else
632 a = NULL;
634 /* write data */
635 for (y = 0; y < image->height; y++) {
637 fprintf(file, "\"");
639 for (x = 0; x < image->width; x++) {
641 if (!a || *a > 127) {
642 tmpc = lookfor(colormap, (unsigned)*r << 16 | (unsigned)*g << 8 | (unsigned)*b);
644 fprintf(file, "%s", index2str(buf, tmpc->index, charsPerPixel));
645 } else {
646 fprintf(file, "%s", transp);
649 if (a) {
650 r += 4;
651 g += 4;
652 b += 4;
653 a += 4;
654 } else {
655 r += 3;
656 g += 3;
657 b += 3;
661 if (y < image->height - 1)
662 fprintf(file, "\",\n");
663 else
664 fprintf(file, "\"};\n");
667 ok = 1;
668 uhoh:
669 errno = 0;
670 fclose(file);
671 if (ok && errno == ENOSPC) {
672 RErrorCode = RERR_WRITE;
675 freecolormap(colormap);
677 return ok ? True : False;