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 || 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
];
195 for (j
=0; j
<w
*2; j
++) {
196 color
= data
[line
][j
++];
197 color
|= data
[line
][j
];
199 for (k
=0; k
<ccount
; k
++) {
200 if (symbol_table
[k
] == color
)
206 *r
= color_table
[0][k
];
207 *g
= color_table
[1][k
];
208 *b
= color_table
[2][k
];
210 *a
= color_table
[3][k
];
231 RErrorCode
= RERR_BADIMAGEFILE
;
236 RDestroyImage(image
);
243 RLoadXPM(RContext
*context
, char *file
, int index
)
245 RImage
*image
= NULL
;
246 char line
[LINEWIDTH
+1];
248 unsigned char *color_table
[4];
249 unsigned short *symbol_table
;
250 unsigned char *r
, *g
, *b
, *a
;
253 unsigned short color
;
255 int w
, h
, ccount
, csize
;
258 f
= fopen(file
, "r");
260 RErrorCode
= RERR_OPEN
;
264 if (!fgets(line
, LINEWIDTH
, f
))
267 if (!fgets(line
, LINEWIDTH
, f
))
271 if (!fgets(line
, LINEWIDTH
, f
))
275 if (!fgets(line
, LINEWIDTH
, f
))
278 if (sscanf(line
, "\"%i %i %i %i\"", &w
, &h
, &ccount
, &csize
)!=4
279 || w
<= 0 || h
<= 0 || ccount
<= 0 || csize
<= 0)
282 if (csize
!=1 && csize
!=2)
285 color_table
[0] = alloca(ccount
);
286 color_table
[1] = alloca(ccount
);
287 color_table
[2] = alloca(ccount
);
288 color_table
[3] = alloca(ccount
);
289 symbol_table
= alloca(ccount
* sizeof(unsigned short));
291 bsize
= csize
* w
+ 16;
292 buffer
= alloca(bsize
);
294 if (!color_table
[0] || !color_table
[1] || !color_table
[2] ||
295 !color_table
[3] || !symbol_table
|| !bsize
) {
296 RErrorCode
= RERR_NOMEMORY
;
303 /* get color table */
304 for (i
=0; i
<ccount
; i
++) {
305 if (!fgets(line
, LINEWIDTH
, f
))
308 if (!fgets(line
, LINEWIDTH
, f
))
311 symbol_table
[i
] = line
[1];
313 symbol_table
[i
] |= line
[2]<<8;
316 while (line
[j
]!='#' && line
[j
]!='"' && line
[j
]!=0 && line
[j
]!='N') j
++;
319 unsigned int red
, green
, blue
;
323 while (line
[j
+k
]!='"' && line
[j
+k
]!=0) k
++;
325 if (sscanf(&(line
[j
]), "%2x%2x%2x", &red
, &green
, &blue
)!=3)
328 if (sscanf(&(line
[j
]), "%4x%4x%4x", &red
, &green
, &blue
)!=3)
336 color_table
[0][i
] = red
;
337 color_table
[1][i
] = green
;
338 color_table
[2][i
] = blue
;
339 color_table
[3][i
] = 255;
340 } else if (strncmp(&(line
[j
]), "None", 4)==0
341 || strncmp(&(line
[j
]), "none", 4)==0) {
342 color_table
[3][i
] = 0;
349 image
= RCreateImage(w
, h
, transp
);
359 if (image
->format
== RRGBAFormat
)
364 for (i
=0; i
<h
; i
++) {
365 if (!fgets(buffer
, bsize
, f
))
368 if (!fgets(buffer
, bsize
, f
))
372 for (j
=1; j
<=w
; j
++) {
375 for (k
=0; k
<ccount
; k
++) {
376 if (symbol_table
[k
] == color
)
382 *(r
++) = color_table
[0][k
];
383 *(g
++) = color_table
[1][k
];
384 *(b
++) = color_table
[2][k
];
386 *(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
];
417 RErrorCode
= RERR_BADIMAGEFILE
;
423 RDestroyImage(image
);
427 RErrorCode
= RERR_BADIMAGEFILE
;
433 RDestroyImage(image
);
440 typedef struct XPMColor
{
445 struct XPMColor
*next
;
450 #define I2CHAR(i) ((i)<12 ? (i)+'0' : ((i)<38 ? (i)+'A'-12 : (i)+'a'-38))
451 #define CINDEX(xpmc) (((unsigned)(xpmc)->red)<<16|((unsigned)(xpmc)->green)<<8|((unsigned)(xpmc)->blue))
456 lookfor(XPMColor
*list
, int index
)
461 for (; list
!=NULL
; list
=list
->next
) {
462 if (CINDEX(list
) == index
)
469 * Looks for the color in the colormap and inserts if it is not found.
471 * list is a binary search list. The unbalancing problem is just ignored.
473 * Returns False on error
476 addcolor(XPMColor
**list
, unsigned r
, unsigned g
, unsigned b
, int *colors
)
482 index
= r
<<16|g
<<8|b
;
485 tmpc
= lookfor(*list
, index
);
490 newc
= malloc(sizeof(XPMColor
));
494 RErrorCode
= RERR_NOMEMORY
;
512 index2str(char *buffer
, int index
, int charsPerPixel
)
516 for (i
=0; i
<charsPerPixel
; i
++) {
517 buffer
[i
] = I2CHAR(index
&63);
527 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
,
539 colormap
->green
, colormap
->blue
);
545 freecolormap(XPMColor
*colormap
)
550 tmp
= colormap
->next
;
558 /* save routine is common to internal support and library support */
560 RSaveXPM(RImage
*image
, char *filename
)
566 XPMColor
*colormap
= NULL
;
570 unsigned char *r
, *g
, *b
, *a
;
574 file
= fopen(filename
, "w+");
576 RErrorCode
= RERR_OPEN
;
580 fprintf(file
, "/* XPM */\n");
582 fprintf(file
, "static char *image[] = {\n");
587 if (image
->format
== RRGBAFormat
)
592 /* first pass: make colormap for the image */
595 for (y
= 0; y
< image
->height
; y
++) {
596 for (x
= 0; x
< image
->width
; x
++) {
598 if (!addcolor(&colormap
, *r
, *g
, *b
, &colorCount
)) {
606 while ((1 << charsPerPixel
*6) < colorCount
)
609 /* write header info */
610 fprintf(file
, "\"%i %i %i %i\",\n", image
->width
, image
->height
,
611 colorCount
, charsPerPixel
);
613 /* write colormap data */
614 if (image
->data
[3]) {
615 for (i
=0; i
<charsPerPixel
; i
++)
619 fprintf(file
, "\"%s c None\",\n", transp
);
623 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
, index2str(buf
, tmpc
->index
, charsPerPixel
));
646 fprintf(file
, transp
);
652 if (y
< image
->height
-1)
653 fprintf(file
, "\",\n");
655 fprintf(file
, "\"};\n");
662 if (ok
&& errno
==ENOSPC
) {
663 RErrorCode
= RERR_WRITE
;
666 freecolormap(colormap
);
668 return ok
? True
: False
;