1 /* nxpm.c - load "normalized" XPM image
3 * Raster graphics library
5 * Copyright (c) 1997-2002 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 */
52 * Restricted support for XPM images.
54 * The images must be in the following "normalized" format:
59 * 2 ignored ( normally "static char *xpm[] = {" )
60 * 3 "width height color_count chars" where chars is 1 or 2
61 * 4 color definitions. Only c values with #rrggbb or #rrrrggggbbb
65 * - no comments or blank lines are allowed, except for the signature
66 * - all lines must have at most 256 characters
67 * - no white spaces allowed at left of each line
76 RGetImageFromXPMData(RContext
*context
, char **data
)
79 unsigned char *color_table
[4];
80 unsigned short *symbol_table
;
81 unsigned char *r
, *g
, *b
, *a
;
82 int i
, j
, k
, line
= 0;
86 int w
, h
, ccount
, csize
;
88 if (sscanf(data
[line
++], "%i %i %i %i", &w
, &h
, &ccount
, &csize
)!=4
89 || w
<= 0 || h
<= 0 || ccount
<= 0 || csize
<= 0)
92 if (csize
!=1 && csize
!=2)
95 color_table
[0] = alloca(ccount
);
96 color_table
[1] = alloca(ccount
);
97 color_table
[2] = alloca(ccount
);
98 color_table
[3] = alloca(ccount
);
99 symbol_table
= alloca(ccount
* sizeof(unsigned short));
101 bsize
= csize
* w
+ 16;
103 if (!color_table
[0] || !color_table
[1] || !color_table
[2] ||
104 !color_table
[3] || !symbol_table
|| !bsize
) {
105 RErrorCode
= RERR_NOMEMORY
;
111 /* get color table */
112 for (i
=0; i
<ccount
; i
++) {
113 symbol_table
[i
] = data
[line
][0];
115 symbol_table
[i
] |= data
[line
][1]<<8;
118 while (data
[line
][j
]!='#' && data
[line
][j
]!=0
119 && data
[line
][j
]!='N') j
++;
121 if (data
[line
][j
]=='#') {
122 unsigned int red
, green
, blue
;
126 while (data
[line
][j
+k
]!=0) k
++;
128 if (sscanf(&(data
[line
][j
]), "%2x%2x%2x", &red
, &green
, &blue
)!=3)
131 if (sscanf(&(data
[line
][j
]), "%4x%4x%4x", &red
, &green
, &blue
)!=3)
139 color_table
[0][i
] = red
;
140 color_table
[1][i
] = green
;
141 color_table
[2][i
] = blue
;
142 color_table
[3][i
] = 255;
143 } else if (strncmp(&(data
[line
][j
]), "None", 4)==0
144 || strncmp(&(data
[line
][j
]), "none", 4)==0) {
145 color_table
[3][i
] = 0;
153 image
= RCreateImage(w
, h
, transp
);
162 if (image
->format
== RRGBAFormat
)
167 for (i
=0; i
<h
; i
++) {
169 for (j
=0; j
<w
; j
++) {
170 color
= data
[line
][j
];
172 for (k
=0; k
<ccount
; k
++) {
173 if (symbol_table
[k
] == color
)
179 *r
= color_table
[0][k
];
180 *g
= color_table
[1][k
];
181 *b
= color_table
[2][k
];
183 *a
= color_table
[3][k
];
184 r
+= 4; g
+= 4; b
+= 4; a
+= 4;
186 r
+= 3; g
+= 3; b
+= 3;
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
];
206 r
+= 4; g
+= 4; b
+= 4; a
+= 4;
208 r
+= 3; g
+= 3; b
+= 3;
221 RErrorCode
= RERR_BADIMAGEFILE
;
226 RReleaseImage(image
);
233 RLoadXPM(RContext
*context
, char *file
, int index
)
235 RImage
*image
= NULL
;
236 char line
[LINEWIDTH
+1];
238 unsigned char *color_table
[4];
239 unsigned short *symbol_table
;
240 unsigned char *r
, *g
, *b
, *a
;
243 unsigned short color
;
245 int w
, h
, ccount
, csize
;
248 f
= fopen(file
, "rb");
250 RErrorCode
= RERR_OPEN
;
254 if (!fgets(line
, LINEWIDTH
, f
))
257 if (!fgets(line
, LINEWIDTH
, f
))
261 if (!fgets(line
, LINEWIDTH
, f
))
265 if (!fgets(line
, LINEWIDTH
, f
))
268 if (sscanf(line
, "\"%i %i %i %i\"", &w
, &h
, &ccount
, &csize
)!=4
269 || w
<= 0 || h
<= 0 || ccount
<= 0 || csize
<= 0)
272 if (csize
!=1 && csize
!=2)
275 color_table
[0] = alloca(ccount
);
276 color_table
[1] = alloca(ccount
);
277 color_table
[2] = alloca(ccount
);
278 color_table
[3] = alloca(ccount
);
279 symbol_table
= alloca(ccount
* sizeof(unsigned short));
281 bsize
= csize
* w
+ 16;
282 buffer
= alloca(bsize
);
284 if (!color_table
[0] || !color_table
[1] || !color_table
[2] ||
285 !color_table
[3] || !symbol_table
|| !bsize
) {
286 RErrorCode
= RERR_NOMEMORY
;
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') j
++;
309 unsigned int red
, green
, blue
;
313 while (line
[j
+k
]!='"' && line
[j
+k
]!=0) k
++;
315 if (sscanf(&(line
[j
]), "%2x%2x%2x", &red
, &green
, &blue
)!=3)
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
331 || strncmp(&(line
[j
]), "none", 4)==0) {
332 color_table
[3][i
] = 0;
339 image
= RCreateImage(w
, h
, transp
);
349 if (image
->format
== RRGBAFormat
)
354 for (i
=0; i
<h
; i
++) {
355 if (!fgets(buffer
, bsize
, f
))
358 if (!fgets(buffer
, bsize
, f
))
362 for (j
=1; j
<=w
; j
++) {
365 for (k
=0; k
<ccount
; k
++) {
366 if (symbol_table
[k
] == color
)
372 *r
= color_table
[0][k
];
373 *g
= color_table
[1][k
];
374 *b
= color_table
[2][k
];
376 *a
= color_table
[3][k
];
377 r
+= 4; g
+= 4; b
+= 4; a
+= 4;
379 r
+= 3; g
+= 3; b
+= 3;
383 for (j
=1; j
<=w
*2; j
++) {
385 color
|= buffer
[j
] << 8;
387 for (k
=0; k
<ccount
; k
++) {
388 if (symbol_table
[k
] == color
)
395 *r
= color_table
[0][k
];
396 *g
= color_table
[1][k
];
397 *b
= color_table
[2][k
];
399 *a
= color_table
[3][k
];
400 r
+= 4; g
+= 4; b
+= 4; a
+= 4;
402 r
+= 3; g
+= 3; b
+= 3;
415 RErrorCode
= RERR_BADIMAGEFILE
;
421 RReleaseImage(image
);
425 RErrorCode
= RERR_BADIMAGEFILE
;
431 RReleaseImage(image
);
438 typedef struct XPMColor
{
443 struct XPMColor
*next
;
448 #define I2CHAR(i) ((i)<12 ? (i)+'0' : ((i)<38 ? (i)+'A'-12 : (i)+'a'-38))
449 #define CINDEX(xpmc) (((unsigned)(xpmc)->red)<<16|((unsigned)(xpmc)->green)<<8|((unsigned)(xpmc)->blue))
454 lookfor(XPMColor
*list
, int index
)
459 for (; list
!=NULL
; list
=list
->next
) {
460 if (CINDEX(list
) == index
)
467 * Looks for the color in the colormap and inserts if it is not found.
469 * list is a binary search list. The unbalancing problem is just ignored.
471 * Returns False on error
474 addcolor(XPMColor
**list
, unsigned r
, unsigned g
, unsigned b
, int *colors
)
480 index
= r
<<16|g
<<8|b
;
483 tmpc
= lookfor(*list
, index
);
488 newc
= malloc(sizeof(XPMColor
));
492 RErrorCode
= RERR_NOMEMORY
;
510 index2str(char *buffer
, int index
, int charsPerPixel
)
514 for (i
=0; i
<charsPerPixel
; i
++) {
515 buffer
[i
] = I2CHAR(index
&63);
525 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
,
537 colormap
->green
, colormap
->blue
);
543 freecolormap(XPMColor
*colormap
)
548 tmp
= colormap
->next
;
556 /* save routine is common to internal support and library support */
558 RSaveXPM(RImage
*image
, char *filename
)
564 XPMColor
*colormap
= NULL
;
568 unsigned char *r
, *g
, *b
, *a
;
572 file
= fopen(filename
, "wb+");
574 RErrorCode
= RERR_OPEN
;
578 fprintf(file
, "/* XPM */\n");
580 fprintf(file
, "static char *image[] = {\n");
585 if (image
->format
== RRGBAFormat
)
590 /* first pass: make colormap for the image */
593 for (y
= 0; y
< image
->height
; y
++) {
594 for (x
= 0; x
< image
->width
; x
++) {
596 if (!addcolor(&colormap
, *r
, *g
, *b
, &colorCount
)) {
601 r
+= 4; g
+= 4; b
+= 4; a
+= 4;
603 r
+= 3; g
+= 3; b
+= 3;
609 while ((1 << charsPerPixel
*6) < colorCount
)
612 /* write header info */
613 fprintf(file
, "\"%i %i %i %i\",\n", image
->width
, image
->height
,
614 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
);
632 if (image
->format
== RRGBAFormat
)
638 for (y
= 0; y
< image
->height
; y
++) {
642 for (x
= 0; x
< image
->width
; x
++) {
645 tmpc
= lookfor(colormap
, (unsigned)*r
<<16|(unsigned)*g
<<8|(unsigned)*b
);
647 fprintf(file
, index2str(buf
, tmpc
->index
, charsPerPixel
));
649 fprintf(file
, transp
);
653 r
+= 4; g
+= 4; b
+= 4; a
+= 4;
655 r
+= 3; g
+= 3; b
+= 3;
659 if (y
< image
->height
-1)
660 fprintf(file
, "\",\n");
662 fprintf(file
, "\"};\n");
669 if (ok
&& errno
==ENOSPC
) {
670 RErrorCode
= RERR_WRITE
;
673 freecolormap(colormap
);
675 return ok
? True
: False
;