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 */
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 color_table
[3][i
] = 0;
152 image
= RCreateImage(w
, h
, transp
);
163 for (i
=0; i
<h
; i
++) {
165 for (j
=0; j
<w
; j
++) {
166 color
= data
[line
][j
];
168 for (k
=0; k
<ccount
; k
++) {
169 if (symbol_table
[k
] == color
)
175 *(r
++) = color_table
[0][k
];
176 *(g
++) = color_table
[1][k
];
177 *(b
++) = color_table
[2][k
];
179 *(a
++) = color_table
[3][k
];
182 for (j
=0; j
<w
*2; j
++) {
183 color
= data
[line
][j
++];
184 color
|= data
[line
][j
];
186 for (k
=0; k
<ccount
; k
++) {
187 if (symbol_table
[k
] == color
)
193 *(r
++) = color_table
[0][k
];
194 *(g
++) = color_table
[1][k
];
195 *(b
++) = color_table
[2][k
];
197 *(a
++) = color_table
[3][k
];
209 RErrorCode
= RERR_BADIMAGEFILE
;
214 RDestroyImage(image
);
221 RLoadXPM(RContext
*context
, char *file
, int index
)
223 RImage
*image
= NULL
;
224 char line
[LINEWIDTH
+1];
226 unsigned char *color_table
[4];
227 unsigned short *symbol_table
;
228 unsigned char *r
, *g
, *b
, *a
;
231 unsigned short color
;
233 int w
, h
, ccount
, csize
;
236 f
= fopen(file
, "r");
238 RErrorCode
= RERR_OPEN
;
242 if (!fgets(line
, LINEWIDTH
, f
))
245 if (!fgets(line
, LINEWIDTH
, f
))
249 if (!fgets(line
, LINEWIDTH
, f
))
253 if (!fgets(line
, LINEWIDTH
, f
))
256 if (sscanf(line
, "\"%i %i %i %i\"", &w
, &h
, &ccount
, &csize
)!=4
257 || w
<= 0 || h
<= 0 || ccount
<= 0 || csize
<= 0)
260 if (csize
!=1 && csize
!=2)
263 color_table
[0] = alloca(ccount
);
264 color_table
[1] = alloca(ccount
);
265 color_table
[2] = alloca(ccount
);
266 color_table
[3] = alloca(ccount
);
267 symbol_table
= alloca(ccount
* sizeof(unsigned short));
269 bsize
= csize
* w
+ 16;
270 buffer
= alloca(bsize
);
272 if (!color_table
[0] || !color_table
[1] || !color_table
[2] ||
273 !color_table
[3] || !symbol_table
|| !bsize
) {
274 RErrorCode
= RERR_NOMEMORY
;
281 /* get color table */
282 for (i
=0; i
<ccount
; i
++) {
283 if (!fgets(line
, LINEWIDTH
, f
))
286 if (!fgets(line
, LINEWIDTH
, f
))
289 symbol_table
[i
] = line
[1];
291 symbol_table
[i
] |= line
[2]<<8;
294 while (line
[j
]!='#' && line
[j
]!='"' && line
[j
]!=0 && line
[j
]!='N') j
++;
297 unsigned int red
, green
, blue
;
301 while (line
[j
+k
]!='"' && line
[j
+k
]!=0) k
++;
303 if (sscanf(&(line
[j
]), "%2x%2x%2x", &red
, &green
, &blue
)!=3)
306 if (sscanf(&(line
[j
]), "%4x%4x%4x", &red
, &green
, &blue
)!=3)
314 color_table
[0][i
] = red
;
315 color_table
[1][i
] = green
;
316 color_table
[2][i
] = blue
;
317 color_table
[3][i
] = 255;
318 } else if (strncmp(&(line
[j
]), "None", 4)==0) {
319 color_table
[3][i
] = 0;
326 image
= RCreateImage(w
, h
, transp
);
338 for (i
=0; i
<h
; i
++) {
339 if (!fgets(buffer
, bsize
, f
))
342 if (!fgets(buffer
, bsize
, f
))
346 for (j
=1; j
<=w
; j
++) {
349 for (k
=0; k
<ccount
; k
++) {
350 if (symbol_table
[k
] == color
)
356 *(r
++) = color_table
[0][k
];
357 *(g
++) = color_table
[1][k
];
358 *(b
++) = color_table
[2][k
];
360 *(a
++) = color_table
[3][k
];
363 for (j
=1; j
<=w
*2; j
++) {
365 color
|= buffer
[j
] << 8;
367 for (k
=0; k
<ccount
; k
++) {
368 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 RErrorCode
= RERR_BADIMAGEFILE
;
397 RDestroyImage(image
);
401 RErrorCode
= RERR_BADIMAGEFILE
;
407 RDestroyImage(image
);
414 typedef struct XPMColor
{
419 struct XPMColor
*next
;
424 #define I2CHAR(i) ((i)<12 ? (i)+'0' : ((i)<38 ? (i)+'A'-12 : (i)+'a'-38))
425 #define CINDEX(xpmc) (((unsigned)(xpmc)->red)<<16|((unsigned)(xpmc)->green)<<8|((unsigned)(xpmc)->blue))
430 lookfor(XPMColor
*list
, int index
)
435 for (; list
!=NULL
; list
=list
->next
) {
436 if (CINDEX(list
) == index
)
443 * Looks for the color in the colormap and inserts if it is not found.
445 * list is a binary search list. The unbalancing problem is just ignored.
447 * Returns False on error
450 addcolor(XPMColor
**list
, unsigned r
, unsigned g
, unsigned b
, int *colors
)
456 index
= r
<<16|g
<<8|b
;
459 tmpc
= lookfor(*list
, index
);
464 newc
= malloc(sizeof(XPMColor
));
468 RErrorCode
= RERR_NOMEMORY
;
486 index2str(char *buffer
, int index
, int charsPerPixel
)
490 for (i
=0; i
<charsPerPixel
; i
++) {
491 buffer
[i
] = I2CHAR(index
&63);
501 outputcolormap(FILE *file
, XPMColor
*colormap
, int charsPerPixel
)
509 for (index
=0; colormap
!=NULL
; colormap
=colormap
->next
,index
++) {
510 colormap
->index
= index
;
511 fprintf(file
, "\"%s c #%02x%02x%02x\",\n",
512 index2str(buf
, index
, charsPerPixel
), colormap
->red
,
513 colormap
->green
, colormap
->blue
);
519 freecolormap(XPMColor
*colormap
)
524 tmp
= colormap
->next
;
532 /* save routine is common to internal support and library support */
534 RSaveXPM(RImage
*image
, char *filename
)
540 XPMColor
*colormap
= NULL
;
544 unsigned char *r
, *g
, *b
, *a
;
548 file
= fopen(filename
, "w+");
550 RErrorCode
= RERR_OPEN
;
554 fprintf(file
, "/* XPM */\n");
556 fprintf(file
, "static char *image[] = {\n");
563 /* first pass: make colormap for the image */
566 for (y
= 0; y
< image
->height
; y
++) {
567 for (x
= 0; x
< image
->width
; x
++) {
569 if (!addcolor(&colormap
, *r
, *g
, *b
, &colorCount
)) {
577 while ((1 << charsPerPixel
*6) < colorCount
)
580 /* write header info */
581 fprintf(file
, "\"%i %i %i %i\",\n", image
->width
, image
->height
,
582 colorCount
, charsPerPixel
);
584 /* write colormap data */
585 if (image
->data
[3]) {
586 for (i
=0; i
<charsPerPixel
; i
++)
590 fprintf(file
, "\"%s c None\",\n", transp
);
594 outputcolormap(file
, colormap
, charsPerPixel
);
603 for (y
= 0; y
< image
->height
; y
++) {
607 for (x
= 0; x
< image
->width
; x
++) {
609 if (!a
|| *a
++>127) {
610 tmpc
= lookfor(colormap
, (unsigned)*r
<<16|(unsigned)*g
<<8|(unsigned)*b
);
612 fprintf(file
, index2str(buf
, tmpc
->index
, charsPerPixel
));
614 fprintf(file
, transp
);
620 if (y
< image
->height
-1)
621 fprintf(file
, "\",\n");
623 fprintf(file
, "\"};\n");
630 if (ok
&& errno
==ENOSPC
) {
631 RErrorCode
= RERR_WRITE
;
634 freecolormap(colormap
);
636 return ok
? True
: False
;