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,
32 #include "imgformat.h"
35 * Restricted support for XPM images.
37 * The images must be in the following "normalized" format:
42 * 2 ignored ( normally "static char *xpm[] = {" )
43 * 3 "width height color_count chars" where chars is 1 or 2
44 * 4 color definitions. Only c values with #rrggbb or #rrrrggggbbb
48 * - no comments or blank lines are allowed, except for the signature
49 * - all lines must have at most 256 characters
50 * - no white spaces allowed at left of each line
57 static void free_color_symbol_table(unsigned char *color_table
[],
58 unsigned short *symbol_table
)
72 RImage
*RGetImageFromXPMData(RContext
* context
, char **data
)
75 unsigned char *color_table
[4] = { NULL
, NULL
, NULL
, NULL
};
76 unsigned short *symbol_table
= NULL
;
77 unsigned char *r
, *g
, *b
, *a
;
78 int i
, j
, k
, line
= 0;
82 int w
, h
, ccount
, csize
;
84 if (sscanf(data
[line
++], "%i %i %i %i", &w
, &h
, &ccount
, &csize
) != 4
85 || w
<= 0 || h
<= 0 || ccount
<= 0 || csize
<= 0)
88 if (csize
!= 1 && csize
!= 2)
91 color_table
[0] = malloc(ccount
);
92 color_table
[1] = malloc(ccount
);
93 color_table
[2] = malloc(ccount
);
94 color_table
[3] = malloc(ccount
);
95 symbol_table
= malloc(ccount
* sizeof(unsigned short));
97 bsize
= csize
* w
+ 16;
99 if (!color_table
[0] || !color_table
[1] || !color_table
[2] || !color_table
[3] || !symbol_table
|| !bsize
) {
100 RErrorCode
= RERR_NOMEMORY
;
101 free_color_symbol_table(color_table
, symbol_table
);
106 /* get color table */
107 for (i
= 0; i
< ccount
; i
++) {
108 symbol_table
[i
] = data
[line
][0];
110 symbol_table
[i
] |= data
[line
][1] << 8;
113 while (data
[line
][j
] != '#' && data
[line
][j
] != 0 && data
[line
][j
] != 'N')
116 if (data
[line
][j
] == '#') {
117 unsigned int red
, green
, blue
;
121 while (data
[line
][j
+ k
] != 0)
124 if (sscanf(&(data
[line
][j
]), "%2x%2x%2x", &red
, &green
, &blue
) != 3)
126 } else if (k
== 12) {
127 if (sscanf(&(data
[line
][j
]), "%4x%4x%4x", &red
, &green
, &blue
) != 3)
135 color_table
[0][i
] = red
;
136 color_table
[1][i
] = green
;
137 color_table
[2][i
] = blue
;
138 color_table
[3][i
] = 255;
139 } else if (strncmp(&(data
[line
][j
]), "None", 4) == 0 || strncmp(&(data
[line
][j
]), "none", 4) == 0) {
140 color_table
[3][i
] = 0;
148 image
= RCreateImage(w
, h
, transp
);
150 free_color_symbol_table(color_table
, symbol_table
);
157 if (image
->format
== RRGBAFormat
)
162 for (i
= 0; i
< h
; i
++) {
164 for (j
= 0; j
< w
; j
++) {
165 color
= data
[line
][j
];
167 for (k
= 0; k
< ccount
; k
++) {
168 if (symbol_table
[k
] == color
)
174 *r
= color_table
[0][k
];
175 *g
= color_table
[1][k
];
176 *b
= color_table
[2][k
];
178 *a
= color_table
[3][k
];
190 for (j
= 0; j
< w
* 2; j
++) {
191 color
= data
[line
][j
++];
192 color
|= data
[line
][j
];
194 for (k
= 0; k
< ccount
; k
++) {
195 if (symbol_table
[k
] == color
)
201 *r
= color_table
[0][k
];
202 *g
= color_table
[1][k
];
203 *b
= color_table
[2][k
];
205 *a
= color_table
[3][k
];
220 free_color_symbol_table(color_table
, symbol_table
);
224 RErrorCode
= RERR_BADIMAGEFILE
;
225 free_color_symbol_table(color_table
, symbol_table
);
227 RReleaseImage(image
);
231 RImage
*RLoadXPM(RContext
* context
, const char *file
)
233 RImage
*image
= NULL
;
234 char line
[LINEWIDTH
+ 1];
236 unsigned char *color_table
[4] = { NULL
, NULL
, NULL
, NULL
};
237 unsigned short *symbol_table
= NULL
;
238 unsigned char *r
, *g
, *b
, *a
;
241 unsigned short color
;
243 int w
, h
, ccount
, csize
;
246 f
= fopen(file
, "rb");
248 RErrorCode
= RERR_OPEN
;
252 if (!fgets(line
, LINEWIDTH
, f
))
255 if (!fgets(line
, LINEWIDTH
, f
))
259 if (!fgets(line
, LINEWIDTH
, f
))
263 if (!fgets(line
, LINEWIDTH
, f
))
266 if (sscanf(line
, "\"%i %i %i %i\"", &w
, &h
, &ccount
, &csize
) != 4
267 || w
<= 0 || h
<= 0 || ccount
<= 0 || csize
<= 0)
270 if (csize
!= 1 && csize
!= 2)
273 color_table
[0] = malloc(ccount
);
274 color_table
[1] = malloc(ccount
);
275 color_table
[2] = malloc(ccount
);
276 color_table
[3] = malloc(ccount
);
277 symbol_table
= malloc(ccount
* sizeof(unsigned short));
279 bsize
= csize
* w
+ 16;
280 buffer
= malloc(bsize
);
282 if (!color_table
[0] || !color_table
[1] || !color_table
[2] ||
283 !color_table
[3] || !symbol_table
|| !bsize
|| !buffer
) {
284 RErrorCode
= RERR_NOMEMORY
;
286 free_color_symbol_table(color_table
, symbol_table
);
293 /* get color table */
294 for (i
= 0; i
< ccount
; i
++) {
295 if (!fgets(line
, LINEWIDTH
, f
))
298 if (!fgets(line
, LINEWIDTH
, f
))
301 symbol_table
[i
] = line
[1];
303 symbol_table
[i
] |= line
[2] << 8;
306 while (line
[j
] != '#' && line
[j
] != '"' && line
[j
] != 0 && line
[j
] != 'N')
309 if (line
[j
] == '#') {
310 unsigned int red
, green
, blue
;
314 while (line
[j
+ k
] != '"' && line
[j
+ k
] != 0)
317 if (sscanf(&(line
[j
]), "%2x%2x%2x", &red
, &green
, &blue
) != 3)
319 } else if (k
== 12) {
320 if (sscanf(&(line
[j
]), "%4x%4x%4x", &red
, &green
, &blue
) != 3)
328 color_table
[0][i
] = red
;
329 color_table
[1][i
] = green
;
330 color_table
[2][i
] = blue
;
331 color_table
[3][i
] = 255;
332 } else if (strncmp(&(line
[j
]), "None", 4) == 0 || strncmp(&(line
[j
]), "none", 4) == 0) {
333 color_table
[3][i
] = 0;
340 image
= RCreateImage(w
, h
, transp
);
343 free_color_symbol_table(color_table
, symbol_table
);
352 if (image
->format
== RRGBAFormat
)
357 for (i
= 0; i
< h
; i
++) {
358 if (!fgets(buffer
, bsize
, f
))
360 if (buffer
[0] == '/')
361 if (!fgets(buffer
, bsize
, f
))
365 for (j
= 1; j
<= w
; j
++) {
368 for (k
= 0; k
< ccount
; k
++) {
369 if (symbol_table
[k
] == color
)
375 *r
= color_table
[0][k
];
376 *g
= color_table
[1][k
];
377 *b
= color_table
[2][k
];
379 *a
= color_table
[3][k
];
391 for (j
= 1; j
<= w
* 2; j
++) {
393 color
|= buffer
[j
] << 8;
395 for (k
= 0; k
< ccount
; k
++) {
396 if (symbol_table
[k
] == color
)
403 *r
= color_table
[0][k
];
404 *g
= color_table
[1][k
];
405 *b
= color_table
[2][k
];
407 *a
= color_table
[3][k
];
422 free_color_symbol_table(color_table
, symbol_table
);
428 RErrorCode
= RERR_BADIMAGEFILE
;
430 free_color_symbol_table(color_table
, symbol_table
);
434 RReleaseImage(image
);
438 RErrorCode
= RERR_BADIMAGEFILE
;
440 free_color_symbol_table(color_table
, symbol_table
);
444 RReleaseImage(image
);
450 typedef struct XPMColor
{
455 struct XPMColor
*next
;
458 #define I2CHAR(i) ((i)<12 ? (i)+'0' : ((i)<38 ? (i)+'A'-12 : (i)+'a'-38))
459 #define CINDEX(xpmc) (((unsigned)(xpmc)->red)<<16|((unsigned)(xpmc)->green)<<8|((unsigned)(xpmc)->blue))
461 static XPMColor
*lookfor(XPMColor
* list
, int index
)
466 for (; list
!= NULL
; list
= list
->next
) {
467 if (CINDEX(list
) == index
)
474 * Looks for the color in the colormap and inserts if it is not found.
476 * list is a binary search list. The unbalancing problem is just ignored.
478 * Returns False on error
480 static Bool
addcolor(XPMColor
** list
, unsigned r
, unsigned g
, unsigned b
, int *colors
)
486 index
= r
<< 16 | g
<< 8 | b
;
489 tmpc
= lookfor(*list
, index
);
494 newc
= malloc(sizeof(XPMColor
));
498 RErrorCode
= RERR_NOMEMORY
;
514 static char *index2str(char *buffer
, int index
, int charsPerPixel
)
518 for (i
= 0; i
< charsPerPixel
; i
++) {
519 buffer
[i
] = I2CHAR(index
& 63);
527 static void outputcolormap(FILE * file
, XPMColor
* colormap
, int charsPerPixel
)
535 for (index
= 0; colormap
!= NULL
; colormap
= colormap
->next
, index
++) {
536 colormap
->index
= index
;
537 fprintf(file
, "\"%s c #%02x%02x%02x\",\n",
538 index2str(buf
, index
, charsPerPixel
), colormap
->red
, colormap
->green
, colormap
->blue
);
542 static void freecolormap(XPMColor
* colormap
)
547 tmp
= colormap
->next
;
553 /* save routine is common to internal support and library support */
554 Bool
RSaveXPM(RImage
* image
, const char *filename
)
560 XPMColor
*colormap
= NULL
;
564 unsigned char *r
, *g
, *b
, *a
;
568 file
= fopen(filename
, "wb+");
570 RErrorCode
= RERR_OPEN
;
574 fprintf(file
, "/* XPM */\n");
576 fprintf(file
, "static char *image[] = {\n");
581 if (image
->format
== RRGBAFormat
)
586 /* first pass: make colormap for the image */
589 for (y
= 0; y
< image
->height
; y
++) {
590 for (x
= 0; x
< image
->width
; x
++) {
591 if (!a
|| *a
> 127) {
592 if (!addcolor(&colormap
, *r
, *g
, *b
, &colorCount
)) {
610 while ((1 << charsPerPixel
* 6) < colorCount
)
613 /* write header info */
614 fprintf(file
, "\"%i %i %i %i\",\n", image
->width
, image
->height
, colorCount
, charsPerPixel
);
616 /* write colormap data */
618 for (i
= 0; i
< charsPerPixel
; i
++)
622 fprintf(file
, "\"%s c None\",\n", transp
);
626 outputcolormap(file
, colormap
, charsPerPixel
);
631 if (image
->format
== RRGBAFormat
)
637 for (y
= 0; y
< image
->height
; y
++) {
641 for (x
= 0; x
< image
->width
; x
++) {
643 if (!a
|| *a
> 127) {
644 tmpc
= lookfor(colormap
, (unsigned)*r
<< 16 | (unsigned)*g
<< 8 | (unsigned)*b
);
646 fprintf(file
, "%s", index2str(buf
, tmpc
->index
, charsPerPixel
));
648 fprintf(file
, "%s", transp
);
663 if (y
< image
->height
- 1)
664 fprintf(file
, "\",\n");
666 fprintf(file
, "\"};\n");
673 if (ok
&& errno
== ENOSPC
) {
674 RErrorCode
= RERR_WRITE
;
677 freecolormap(colormap
);
679 return ok
? True
: False
;