WRaster: add functions to save image on disk
[wmaker-crm.git] / wrlib / load_xpm_normalized.c
blob82be3c4ea029b5bdf84e15f6fdeae3b1d89e56b0
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"
32 #include "imgformat.h"
33 #include "wr_i18n.h"
37 * Restricted support for XPM images.
39 * The images must be in the following "normalized" format:
42 * line content
43 * 1 signature comment
44 * 2 ignored ( normally "static char *xpm[] = {" )
45 * 3 "width height color_count chars" where chars is 1 or 2
46 * 4 color definitions. Only c values with #rrggbb or #rrrrggggbbb
47 * format OR None
48 * n data
50 * - no comments or blank lines are allowed, except for the signature
51 * - all lines must have at most 256 characters
52 * - no white spaces allowed at left of each line
55 #define LINEWIDTH 64
58 static void free_color_symbol_table(unsigned char *color_table[],
59 unsigned short *symbol_table)
61 if (color_table[0])
62 free(color_table[0]);
63 if (color_table[1])
64 free(color_table[1]);
65 if (color_table[2])
66 free(color_table[2]);
67 if (color_table[3])
68 free(color_table[3]);
69 if (symbol_table)
70 free(symbol_table);
73 RImage *RGetImageFromXPMData(RContext * context, char **data)
75 RImage *image = NULL;
76 unsigned char *color_table[4] = { NULL, NULL, NULL, NULL };
77 unsigned short *symbol_table = NULL;
78 unsigned char *r, *g, *b, *a;
79 int i, j, k, line = 0;
80 int transp;
81 unsigned short color;
82 int bsize;
83 int w, h, ccount, csize;
86 * When using libXpm we need the context argument but the code here does
87 * not, so tell the compiler to not warn about it
89 (void) context;
91 if (sscanf(data[line++], "%i %i %i %i", &w, &h, &ccount, &csize) != 4
92 || w <= 0 || h <= 0 || ccount <= 0 || csize <= 0)
93 goto bad_format;
95 if (csize != 1 && csize != 2)
96 goto bad_format;
98 color_table[0] = malloc(ccount);
99 color_table[1] = malloc(ccount);
100 color_table[2] = malloc(ccount);
101 color_table[3] = malloc(ccount);
102 symbol_table = malloc(ccount * sizeof(unsigned short));
104 bsize = csize * w + 16;
106 if (!color_table[0] || !color_table[1] || !color_table[2] || !color_table[3] || !symbol_table || !bsize) {
107 RErrorCode = RERR_NOMEMORY;
108 free_color_symbol_table(color_table, symbol_table);
109 return NULL;
112 transp = 0;
113 /* get color table */
114 for (i = 0; i < ccount; i++) {
115 symbol_table[i] = data[line][0];
116 if (csize == 2)
117 symbol_table[i] |= data[line][1] << 8;
119 j = csize;
120 while (data[line][j] != '#' && data[line][j] != 0 && data[line][j] != 'N')
121 j++;
123 if (data[line][j] == '#') {
124 unsigned int red, green, blue;
126 k = 0;
127 j++;
128 while (data[line][j + k] != 0)
129 k++;
130 if (k == 6) {
131 if (sscanf(&(data[line][j]), "%2x%2x%2x", &red, &green, &blue) != 3)
132 goto bad_format;
133 } else if (k == 12) {
134 if (sscanf(&(data[line][j]), "%4x%4x%4x", &red, &green, &blue) != 3)
135 goto bad_format;
136 red >>= 8;
137 green >>= 8;
138 blue >>= 8;
139 } else
140 goto bad_format;
142 color_table[0][i] = red;
143 color_table[1][i] = green;
144 color_table[2][i] = blue;
145 color_table[3][i] = 255;
146 } else if (strncmp(&(data[line][j]), "None", 4) == 0 || strncmp(&(data[line][j]), "none", 4) == 0) {
147 color_table[3][i] = 0;
148 transp = 1;
149 } else {
150 goto bad_format;
152 line++;
155 image = RCreateImage(w, h, transp);
156 if (!image) {
157 free_color_symbol_table(color_table, symbol_table);
158 return NULL;
161 r = image->data;
162 g = image->data + 1;
163 b = image->data + 2;
164 if (image->format == RRGBAFormat)
165 a = image->data + 3;
166 else
167 a = NULL;
169 for (i = 0; i < h; i++) {
170 if (csize == 1) {
171 for (j = 0; j < w; j++) {
172 color = data[line][j];
174 for (k = 0; k < ccount; k++) {
175 if (symbol_table[k] == color)
176 break;
178 if (k == ccount)
179 k = 0;
181 *r = color_table[0][k];
182 *g = color_table[1][k];
183 *b = color_table[2][k];
184 if (a) {
185 *a = color_table[3][k];
186 r += 4;
187 g += 4;
188 b += 4;
189 a += 4;
190 } else {
191 r += 3;
192 g += 3;
193 b += 3;
196 } else {
197 for (j = 0; j < w * 2; j++) {
198 color = data[line][j++];
199 color |= data[line][j];
201 for (k = 0; k < ccount; k++) {
202 if (symbol_table[k] == color)
203 break;
205 if (k == ccount)
206 k = 0;
208 *r = color_table[0][k];
209 *g = color_table[1][k];
210 *b = color_table[2][k];
211 if (a) {
212 *a = color_table[3][k];
213 r += 4;
214 g += 4;
215 b += 4;
216 a += 4;
217 } else {
218 r += 3;
219 g += 3;
220 b += 3;
224 line++;
227 free_color_symbol_table(color_table, symbol_table);
228 return image;
230 bad_format:
231 RErrorCode = RERR_BADIMAGEFILE;
232 free_color_symbol_table(color_table, symbol_table);
233 if (image)
234 RReleaseImage(image);
235 return NULL;
238 RImage *RLoadXPM(RContext * context, const char *file)
240 RImage *image = NULL;
241 char line[LINEWIDTH + 1];
242 char *buffer = NULL;
243 unsigned char *color_table[4] = { NULL, NULL, NULL, NULL };
244 unsigned short *symbol_table = NULL;
245 unsigned char *r, *g, *b, *a;
246 int i, j, k;
247 int transp;
248 unsigned short color;
249 int bsize;
250 int w, h, ccount, csize;
251 FILE *f;
254 * When using libXpm we need the context argument but the code here does
255 * not, so tell the compiler to not warn about it
257 (void) context;
259 f = fopen(file, "rb");
260 if (!f) {
261 RErrorCode = RERR_OPEN;
262 return NULL;
264 /* sig */
265 if (!fgets(line, LINEWIDTH, f))
266 goto bad_file;
267 /* declaration */
268 if (!fgets(line, LINEWIDTH, f))
269 goto bad_file;
271 /* data */
272 if (!fgets(line, LINEWIDTH, f))
273 goto bad_file;
275 if (line[0] == '/')
276 if (!fgets(line, LINEWIDTH, f))
277 goto bad_file;
279 if (sscanf(line, "\"%i %i %i %i\"", &w, &h, &ccount, &csize) != 4
280 || w <= 0 || h <= 0 || ccount <= 0 || csize <= 0)
281 goto bad_file;
283 if (csize != 1 && csize != 2)
284 goto bad_format;
286 color_table[0] = malloc(ccount);
287 color_table[1] = malloc(ccount);
288 color_table[2] = malloc(ccount);
289 color_table[3] = malloc(ccount);
290 symbol_table = malloc(ccount * sizeof(unsigned short));
292 bsize = csize * w + 16;
293 buffer = malloc(bsize);
295 if (!color_table[0] || !color_table[1] || !color_table[2] ||
296 !color_table[3] || !symbol_table || !bsize || !buffer) {
297 RErrorCode = RERR_NOMEMORY;
298 fclose(f);
299 free_color_symbol_table(color_table, symbol_table);
300 if (buffer)
301 free(buffer);
302 return NULL;
305 transp = 0;
306 /* get color table */
307 for (i = 0; i < ccount; i++) {
308 if (!fgets(line, LINEWIDTH, f))
309 goto bad_file;
310 if (line[0] == '/')
311 if (!fgets(line, LINEWIDTH, f))
312 goto bad_file;
314 symbol_table[i] = line[1];
315 if (csize == 2)
316 symbol_table[i] |= line[2] << 8;
318 j = csize + 1;
319 while (line[j] != '#' && line[j] != '"' && line[j] != 0 && line[j] != 'N')
320 j++;
322 if (line[j] == '#') {
323 unsigned int red, green, blue;
325 k = 0;
326 j++;
327 while (line[j + k] != '"' && line[j + k] != 0)
328 k++;
329 if (k == 6) {
330 if (sscanf(&(line[j]), "%2x%2x%2x", &red, &green, &blue) != 3)
331 goto bad_format;
332 } else if (k == 12) {
333 if (sscanf(&(line[j]), "%4x%4x%4x", &red, &green, &blue) != 3)
334 goto bad_format;
335 red >>= 8;
336 green >>= 8;
337 blue >>= 8;
338 } else
339 goto bad_format;
341 color_table[0][i] = red;
342 color_table[1][i] = green;
343 color_table[2][i] = blue;
344 color_table[3][i] = 255;
345 } else if (strncmp(&(line[j]), "None", 4) == 0 || strncmp(&(line[j]), "none", 4) == 0) {
346 color_table[3][i] = 0;
347 transp = 1;
348 } else {
349 goto bad_format;
353 image = RCreateImage(w, h, transp);
354 if (!image) {
355 fclose(f);
356 free_color_symbol_table(color_table, symbol_table);
357 if (buffer)
358 free(buffer);
359 return NULL;
362 r = image->data;
363 g = image->data + 1;
364 b = image->data + 2;
365 if (image->format == RRGBAFormat)
366 a = image->data + 3;
367 else
368 a = NULL;
370 for (i = 0; i < h; i++) {
371 if (!fgets(buffer, bsize, f))
372 goto bad_file;
373 if (buffer[0] == '/')
374 if (!fgets(buffer, bsize, f))
375 goto bad_file;
377 if (csize == 1) {
378 for (j = 1; j <= w; j++) {
379 color = buffer[j];
381 for (k = 0; k < ccount; k++) {
382 if (symbol_table[k] == color)
383 break;
385 if (k == ccount)
386 k = 0;
388 *r = color_table[0][k];
389 *g = color_table[1][k];
390 *b = color_table[2][k];
391 if (a) {
392 *a = color_table[3][k];
393 r += 4;
394 g += 4;
395 b += 4;
396 a += 4;
397 } else {
398 r += 3;
399 g += 3;
400 b += 3;
403 } else {
404 for (j = 1; j <= w * 2; j++) {
405 color = buffer[j++];
406 color |= buffer[j] << 8;
408 for (k = 0; k < ccount; k++) {
409 if (symbol_table[k] == color)
410 break;
412 if (k == ccount) {
413 k = 0;
416 *r = color_table[0][k];
417 *g = color_table[1][k];
418 *b = color_table[2][k];
419 if (a) {
420 *a = color_table[3][k];
421 r += 4;
422 g += 4;
423 b += 4;
424 a += 4;
425 } else {
426 r += 3;
427 g += 3;
428 b += 3;
434 fclose(f);
435 free_color_symbol_table(color_table, symbol_table);
436 if (buffer)
437 free(buffer);
438 return image;
440 bad_format:
441 RErrorCode = RERR_BADIMAGEFILE;
442 fclose(f);
443 free_color_symbol_table(color_table, symbol_table);
444 if (buffer)
445 free(buffer);
446 if (image)
447 RReleaseImage(image);
448 return NULL;
450 bad_file:
451 RErrorCode = RERR_BADIMAGEFILE;
452 fclose(f);
453 free_color_symbol_table(color_table, symbol_table);
454 if (buffer)
455 free(buffer);
456 if (image)
457 RReleaseImage(image);
458 return NULL;