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.
33 * Restricted support for XPM images.
35 * The images must be in the following "normalized" format:
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
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
55 static void free_color_symbol_table(unsigned char *color_table
[],
56 unsigned short *symbol_table
)
70 RImage
*RGetImageFromXPMData(RContext
* context
, char **data
)
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;
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)
86 if (csize
!= 1 && csize
!= 2)
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
);
104 /* get color table */
105 for (i
= 0; i
< ccount
; i
++) {
106 symbol_table
[i
] = data
[line
][0];
108 symbol_table
[i
] |= data
[line
][1] << 8;
111 while (data
[line
][j
] != '#' && data
[line
][j
] != 0 && data
[line
][j
] != 'N')
114 if (data
[line
][j
] == '#') {
115 unsigned int red
, green
, blue
;
119 while (data
[line
][j
+ k
] != 0)
122 if (sscanf(&(data
[line
][j
]), "%2x%2x%2x", &red
, &green
, &blue
) != 3)
124 } else if (k
== 12) {
125 if (sscanf(&(data
[line
][j
]), "%4x%4x%4x", &red
, &green
, &blue
) != 3)
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;
146 image
= RCreateImage(w
, h
, transp
);
148 free_color_symbol_table(color_table
, symbol_table
);
155 if (image
->format
== RRGBAFormat
)
160 for (i
= 0; i
< h
; i
++) {
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
)
172 *r
= color_table
[0][k
];
173 *g
= color_table
[1][k
];
174 *b
= color_table
[2][k
];
176 *a
= color_table
[3][k
];
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
)
199 *r
= color_table
[0][k
];
200 *g
= color_table
[1][k
];
201 *b
= color_table
[2][k
];
203 *a
= color_table
[3][k
];
218 free_color_symbol_table(color_table
, symbol_table
);
222 RErrorCode
= RERR_BADIMAGEFILE
;
223 free_color_symbol_table(color_table
, symbol_table
);
225 RReleaseImage(image
);
229 RImage
*RLoadXPM(RContext
* context
, char *file
)
231 RImage
*image
= NULL
;
232 char line
[LINEWIDTH
+ 1];
234 unsigned char *color_table
[4] = { NULL
, NULL
, NULL
, NULL
};
235 unsigned short *symbol_table
= NULL
;
236 unsigned char *r
, *g
, *b
, *a
;
239 unsigned short color
;
241 int w
, h
, ccount
, csize
;
244 f
= fopen(file
, "rb");
246 RErrorCode
= RERR_OPEN
;
250 if (!fgets(line
, LINEWIDTH
, f
))
253 if (!fgets(line
, LINEWIDTH
, f
))
257 if (!fgets(line
, LINEWIDTH
, f
))
261 if (!fgets(line
, LINEWIDTH
, f
))
264 if (sscanf(line
, "\"%i %i %i %i\"", &w
, &h
, &ccount
, &csize
) != 4
265 || w
<= 0 || h
<= 0 || ccount
<= 0 || csize
<= 0)
268 if (csize
!= 1 && csize
!= 2)
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
;
284 free_color_symbol_table(color_table
, symbol_table
);
291 /* get color table */
292 for (i
= 0; i
< ccount
; i
++) {
293 if (!fgets(line
, LINEWIDTH
, f
))
296 if (!fgets(line
, LINEWIDTH
, f
))
299 symbol_table
[i
] = line
[1];
301 symbol_table
[i
] |= line
[2] << 8;
304 while (line
[j
] != '#' && line
[j
] != '"' && line
[j
] != 0 && line
[j
] != 'N')
307 if (line
[j
] == '#') {
308 unsigned int red
, green
, blue
;
312 while (line
[j
+ k
] != '"' && line
[j
+ k
] != 0)
315 if (sscanf(&(line
[j
]), "%2x%2x%2x", &red
, &green
, &blue
) != 3)
317 } else if (k
== 12) {
318 if (sscanf(&(line
[j
]), "%4x%4x%4x", &red
, &green
, &blue
) != 3)
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;
338 image
= RCreateImage(w
, h
, transp
);
341 free_color_symbol_table(color_table
, symbol_table
);
350 if (image
->format
== RRGBAFormat
)
355 for (i
= 0; i
< h
; i
++) {
356 if (!fgets(buffer
, bsize
, f
))
358 if (buffer
[0] == '/')
359 if (!fgets(buffer
, bsize
, f
))
363 for (j
= 1; j
<= w
; j
++) {
366 for (k
= 0; k
< ccount
; k
++) {
367 if (symbol_table
[k
] == color
)
373 *r
= color_table
[0][k
];
374 *g
= color_table
[1][k
];
375 *b
= color_table
[2][k
];
377 *a
= color_table
[3][k
];
389 for (j
= 1; j
<= w
* 2; j
++) {
391 color
|= buffer
[j
] << 8;
393 for (k
= 0; k
< ccount
; k
++) {
394 if (symbol_table
[k
] == color
)
401 *r
= color_table
[0][k
];
402 *g
= color_table
[1][k
];
403 *b
= color_table
[2][k
];
405 *a
= color_table
[3][k
];
420 free_color_symbol_table(color_table
, symbol_table
);
426 RErrorCode
= RERR_BADIMAGEFILE
;
428 free_color_symbol_table(color_table
, symbol_table
);
432 RReleaseImage(image
);
436 RErrorCode
= RERR_BADIMAGEFILE
;
438 free_color_symbol_table(color_table
, symbol_table
);
442 RReleaseImage(image
);
448 typedef struct XPMColor
{
453 struct XPMColor
*next
;
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
)
464 for (; list
!= NULL
; list
= list
->next
) {
465 if (CINDEX(list
) == index
)
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
)
484 index
= r
<< 16 | g
<< 8 | b
;
487 tmpc
= lookfor(*list
, index
);
492 newc
= malloc(sizeof(XPMColor
));
496 RErrorCode
= RERR_NOMEMORY
;
512 static char *index2str(char *buffer
, int index
, int charsPerPixel
)
516 for (i
= 0; i
< charsPerPixel
; i
++) {
517 buffer
[i
] = I2CHAR(index
& 63);
525 static void outputcolormap(FILE * file
, XPMColor
* colormap
, int charsPerPixel
)
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
)
545 tmp
= colormap
->next
;
551 /* save routine is common to internal support and library support */
552 Bool
RSaveXPM(RImage
* image
, char *filename
)
558 XPMColor
*colormap
= NULL
;
562 unsigned char *r
, *g
, *b
, *a
;
566 file
= fopen(filename
, "wb+");
568 RErrorCode
= RERR_OPEN
;
572 fprintf(file
, "/* XPM */\n");
574 fprintf(file
, "static char *image[] = {\n");
579 if (image
->format
== RRGBAFormat
)
584 /* first pass: make colormap for the image */
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
)) {
608 while ((1 << charsPerPixel
* 6) < colorCount
)
611 /* write header info */
612 fprintf(file
, "\"%i %i %i %i\",\n", image
->width
, image
->height
, colorCount
, charsPerPixel
);
614 /* write colormap data */
616 for (i
= 0; i
< charsPerPixel
; i
++)
620 fprintf(file
, "\"%s c None\",\n", transp
);
624 outputcolormap(file
, colormap
, charsPerPixel
);
629 if (image
->format
== RRGBAFormat
)
635 for (y
= 0; y
< image
->height
; y
++) {
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
));
646 fprintf(file
, "%s", transp
);
661 if (y
< image
->height
- 1)
662 fprintf(file
, "\",\n");
664 fprintf(file
, "\"};\n");
671 if (ok
&& errno
== ENOSPC
) {
672 RErrorCode
= RERR_WRITE
;
675 freecolormap(colormap
);
677 return ok
? True
: False
;