1 /* nxpm.c - load "normalized" XPM image
3 * Raster graphics library
5 * Copyright (c) 1997 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.
24 /* AIX requires this to be the first thing in the file. */
26 # define alloca __builtin_alloca
34 # ifndef alloca /* predefined by HP cc +Olibcalls */
51 * Restricted support for XPM images.
53 * The images must be in the following "normalized" format:
58 * 2 ignored ( normally "static char *xpm[] = {" )
59 * 3 "width height color_count chars" where chars is 1 or 2
60 * 4 color definitions. Only c values with #rrggbb or #rrrrggggbbb
64 * - no comments or blank lines are allowed, except for the signature
65 * - all lines must have at most 256 characters
66 * - no white spaces allowed at left of each line
75 RGetImageFromXPMData(RContext
*context
, char **data
)
78 unsigned char *color_table
[4];
79 unsigned short *symbol_table
;
80 unsigned char *r
, *g
, *b
, *a
;
81 int i
, j
, k
, line
= 0;
85 int w
, h
, ccount
, csize
;
87 if (sscanf(data
[line
++], "%i %i %i %i", &w
, &h
, &ccount
, &csize
)!=4
88 || w
<= 0 || h
<= 0 || ccount
<= 0 || csize
<= 0)
91 if (csize
!=1 && csize
!=2)
94 color_table
[0] = alloca(ccount
);
95 color_table
[1] = alloca(ccount
);
96 color_table
[2] = alloca(ccount
);
97 color_table
[3] = alloca(ccount
);
98 symbol_table
= alloca(ccount
* sizeof(unsigned short));
100 bsize
= csize
* w
+ 16;
102 if (!color_table
[0] || !color_table
[1] || !color_table
[2] ||
103 !color_table
[3] || !symbol_table
|| !bsize
) {
104 RErrorCode
= RERR_MEMORY
;
110 /* get color table */
111 for (i
=0; i
<ccount
; i
++) {
112 symbol_table
[i
] = data
[line
][0];
114 symbol_table
[i
] |= data
[line
][1]<<8;
117 while (data
[line
][j
]!='#' && data
[line
][j
]!=0
118 && data
[line
][j
]!='N') j
++;
120 if (data
[line
][j
]=='#') {
121 unsigned int red
, green
, blue
;
125 while (data
[line
][j
+k
]!=0) k
++;
127 if (sscanf(&(data
[line
][j
]), "%2x%2x%2x", &red
, &green
, &blue
)!=3)
130 if (sscanf(&(data
[line
][j
]), "%4x%4x%4x", &red
, &green
, &blue
)!=3)
138 color_table
[0][i
] = red
;
139 color_table
[1][i
] = green
;
140 color_table
[2][i
] = blue
;
141 color_table
[3][i
] = 255;
142 } else if (strncmp(&(data
[line
][j
]), "None", 4)==0) {
143 color_table
[3][i
] = 0;
151 image
= RCreateImage(w
, h
, transp
);
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
];
181 for (j
=0; j
<w
*2; j
++) {
182 color
= data
[line
][j
++];
183 color
|= data
[line
][j
];
185 for (k
=0; k
<ccount
; k
++) {
186 if (symbol_table
[k
] == color
)
192 *(r
++) = color_table
[0][k
];
193 *(g
++) = color_table
[1][k
];
194 *(b
++) = color_table
[2][k
];
196 *(a
++) = color_table
[3][k
];
208 RErrorCode
= RERR_BADIMAGEFILE
;
213 RDestroyImage(image
);
220 RLoadXPM(RContext
*context
, char *file
, int index
)
222 RImage
*image
= NULL
;
223 char line
[LINEWIDTH
+1];
225 unsigned char *color_table
[4];
226 unsigned short *symbol_table
;
227 unsigned char *r
, *g
, *b
, *a
;
230 unsigned short color
;
232 int w
, h
, ccount
, csize
;
235 f
= fopen(file
, "r");
237 RErrorCode
= RERR_OPEN
;
241 if (!fgets(line
, LINEWIDTH
, f
))
244 if (!fgets(line
, LINEWIDTH
, f
))
248 if (!fgets(line
, LINEWIDTH
, f
))
252 if (!fgets(line
, LINEWIDTH
, f
))
255 if (sscanf(line
, "\"%i %i %i %i\"", &w
, &h
, &ccount
, &csize
)!=4
256 || w
<= 0 || h
<= 0 || ccount
<= 0 || csize
<= 0)
259 if (csize
!=1 && csize
!=2)
262 color_table
[0] = alloca(ccount
);
263 color_table
[1] = alloca(ccount
);
264 color_table
[2] = alloca(ccount
);
265 color_table
[3] = alloca(ccount
);
266 symbol_table
= alloca(ccount
* sizeof(unsigned short));
268 bsize
= csize
* w
+ 16;
269 buffer
= alloca(bsize
);
271 if (!color_table
[0] || !color_table
[1] || !color_table
[2] ||
272 !color_table
[3] || !symbol_table
|| !bsize
) {
273 RErrorCode
= RERR_MEMORY
;
280 /* get color table */
281 for (i
=0; i
<ccount
; i
++) {
282 if (!fgets(line
, LINEWIDTH
, f
))
285 if (!fgets(line
, LINEWIDTH
, f
))
288 symbol_table
[i
] = line
[1];
290 symbol_table
[i
] |= line
[2]<<8;
293 while (line
[j
]!='#' && line
[j
]!='"' && line
[j
]!=0 && line
[j
]!='N') j
++;
296 unsigned int red
, green
, blue
;
300 while (line
[j
+k
]!='"' && line
[j
+k
]!=0) k
++;
302 if (sscanf(&(line
[j
]), "%2x%2x%2x", &red
, &green
, &blue
)!=3)
305 if (sscanf(&(line
[j
]), "%4x%4x%4x", &red
, &green
, &blue
)!=3)
313 color_table
[0][i
] = red
;
314 color_table
[1][i
] = green
;
315 color_table
[2][i
] = blue
;
316 color_table
[3][i
] = 255;
317 } else if (strncmp(&(line
[j
]), "None", 4)==0) {
318 color_table
[3][i
] = 0;
325 image
= RCreateImage(w
, h
, transp
);
337 for (i
=0; i
<h
; i
++) {
338 if (!fgets(buffer
, bsize
, f
))
341 if (!fgets(buffer
, bsize
, f
))
345 for (j
=1; j
<=w
; j
++) {
348 for (k
=0; k
<ccount
; k
++) {
349 if (symbol_table
[k
] == color
)
355 *(r
++) = color_table
[0][k
];
356 *(g
++) = color_table
[1][k
];
357 *(b
++) = color_table
[2][k
];
359 *(a
++) = color_table
[3][k
];
362 for (j
=1; j
<=w
*2; j
++) {
364 color
|= buffer
[j
] << 8;
366 for (k
=0; k
<ccount
; k
++) {
367 if (symbol_table
[k
] == color
)
374 *(r
++) = color_table
[0][k
];
375 *(g
++) = color_table
[1][k
];
376 *(b
++) = color_table
[2][k
];
378 *(a
++) = color_table
[3][k
];
390 RErrorCode
= RERR_BADIMAGEFILE
;
396 RDestroyImage(image
);
400 RErrorCode
= RERR_BADIMAGEFILE
;
406 RDestroyImage(image
);
413 typedef struct XPMColor
{
418 struct XPMColor
*next
;
423 #define I2CHAR(i) ((i)<12 ? (i)+'0' : ((i)<38 ? (i)+'A'-12 : (i)+'a'-38))
424 #define CINDEX(xpmc) (((unsigned)(xpmc)->red)<<16|((unsigned)(xpmc)->green)<<8|((unsigned)(xpmc)->blue))
429 lookfor(XPMColor
*list
, int index
)
434 for (; list
!=NULL
; list
=list
->next
) {
435 if (CINDEX(list
) == index
)
442 * Looks for the color in the colormap and inserts if it is not found.
444 * list is a binary search list. The unbalancing problem is just ignored.
446 * Returns False on error
449 addcolor(XPMColor
**list
, unsigned r
, unsigned g
, unsigned b
, int *colors
)
455 index
= r
<<16|g
<<8|b
;
458 tmpc
= lookfor(*list
, index
);
463 newc
= malloc(sizeof(XPMColor
));
467 RErrorCode
= RERR_NOMEMORY
;
485 outputcolormap(FILE *file
, XPMColor
*colormap
, int colorCount
)
493 for (index
=0; colormap
!=NULL
; colormap
=colormap
->next
,index
++) {
495 for (i
=0; i
<colorCount
/64+1; i
++) {
496 colormap
->text
[i
] = I2CHAR(j
&63);
499 colormap
->text
[i
] = 0;
500 fprintf(file
, "\"%s c #%02x%02x%02x\",\n", colormap
->text
, colormap
->red
,
501 colormap
->green
, colormap
->blue
);
507 freecolormap(XPMColor
*colormap
)
512 tmp
= colormap
->next
;
520 /* save routine is common to internal support and library support */
522 RSaveXPM(RImage
*image
, char *filename
)
527 XPMColor
*colormap
= NULL
;
531 unsigned char *r
, *g
, *b
, *a
;
534 file
= fopen(filename
, "w+");
536 RErrorCode
= RERR_OPEN
;
540 fprintf(file
, "/* XPM */\n");
542 fprintf(file
, "static char *image[] = {\n");
549 /* first pass: make colormap for the image */
552 for (y
= 0; y
< image
->height
; y
++) {
553 for (x
= 0; x
< image
->width
; x
++) {
555 if (!addcolor(&colormap
, *r
, *g
, *b
, &colorCount
)) {
562 /* write header info */
563 fprintf(file
, "\"%i %i %i %i\",\n", image
->width
, image
->height
,
564 colorCount
, colorCount
/64+1);
567 /* write colormap data */
568 if (image
->data
[3]) {
569 for (i
=0; i
<colorCount
/64+1; i
++)
573 fprintf(file
, "\"%s c None\",\n", transp
);
577 outputcolormap(file
, colormap
, colorCount
);
585 for (y
= 0; y
< image
->height
; y
++) {
589 for (x
= 0; x
< image
->width
; x
++) {
591 if (!a
|| *a
++>127) {
592 tmpc
= lookfor(colormap
, (unsigned)*r
<<16|(unsigned)*g
<<8|(unsigned)*b
);
594 fprintf(file
, tmpc
->text
);
596 fprintf(file
, transp
);
602 if (y
< image
->height
-1)
603 fprintf(file
, "\",\n");
605 fprintf(file
, "\"};\n");
612 if (ok
&& errno
==ENOSPC
) {
613 RErrorCode
= RERR_WRITE
;
616 freecolormap(colormap
);
618 return ok
? True
: False
;