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
];
186 for (j
=0; j
<w
*2; j
++) {
187 color
= data
[line
][j
++];
188 color
|= data
[line
][j
];
190 for (k
=0; k
<ccount
; k
++) {
191 if (symbol_table
[k
] == color
)
197 *(r
++) = color_table
[0][k
];
198 *(g
++) = color_table
[1][k
];
199 *(b
++) = color_table
[2][k
];
201 *(a
++) = color_table
[3][k
];
213 RErrorCode
= RERR_BADIMAGEFILE
;
218 RDestroyImage(image
);
225 RLoadXPM(RContext
*context
, char *file
, int index
)
227 RImage
*image
= NULL
;
228 char line
[LINEWIDTH
+1];
230 unsigned char *color_table
[4];
231 unsigned short *symbol_table
;
232 unsigned char *r
, *g
, *b
, *a
;
235 unsigned short color
;
237 int w
, h
, ccount
, csize
;
240 f
= fopen(file
, "r");
242 RErrorCode
= RERR_OPEN
;
246 if (!fgets(line
, LINEWIDTH
, f
))
249 if (!fgets(line
, LINEWIDTH
, f
))
253 if (!fgets(line
, LINEWIDTH
, f
))
257 if (!fgets(line
, LINEWIDTH
, f
))
260 if (sscanf(line
, "\"%i %i %i %i\"", &w
, &h
, &ccount
, &csize
)!=4
261 || w
<= 0 || h
<= 0 || ccount
<= 0 || csize
<= 0)
264 if (csize
!=1 && csize
!=2)
267 color_table
[0] = alloca(ccount
);
268 color_table
[1] = alloca(ccount
);
269 color_table
[2] = alloca(ccount
);
270 color_table
[3] = alloca(ccount
);
271 symbol_table
= alloca(ccount
* sizeof(unsigned short));
273 bsize
= csize
* w
+ 16;
274 buffer
= alloca(bsize
);
276 if (!color_table
[0] || !color_table
[1] || !color_table
[2] ||
277 !color_table
[3] || !symbol_table
|| !bsize
) {
278 RErrorCode
= RERR_NOMEMORY
;
285 /* get color table */
286 for (i
=0; i
<ccount
; i
++) {
287 if (!fgets(line
, LINEWIDTH
, f
))
290 if (!fgets(line
, LINEWIDTH
, f
))
293 symbol_table
[i
] = line
[1];
295 symbol_table
[i
] |= line
[2]<<8;
298 while (line
[j
]!='#' && line
[j
]!='"' && line
[j
]!=0 && line
[j
]!='N') j
++;
301 unsigned int red
, green
, blue
;
305 while (line
[j
+k
]!='"' && line
[j
+k
]!=0) k
++;
307 if (sscanf(&(line
[j
]), "%2x%2x%2x", &red
, &green
, &blue
)!=3)
310 if (sscanf(&(line
[j
]), "%4x%4x%4x", &red
, &green
, &blue
)!=3)
318 color_table
[0][i
] = red
;
319 color_table
[1][i
] = green
;
320 color_table
[2][i
] = blue
;
321 color_table
[3][i
] = 255;
322 } else if (strncmp(&(line
[j
]), "None", 4)==0
323 || strncmp(&(line
[j
]), "none", 4)==0) {
324 color_table
[3][i
] = 0;
331 image
= RCreateImage(w
, h
, transp
);
341 if (image
->format
== RRGBAFormat
)
346 for (i
=0; i
<h
; i
++) {
347 if (!fgets(buffer
, bsize
, f
))
350 if (!fgets(buffer
, bsize
, f
))
354 for (j
=1; j
<=w
; j
++) {
357 for (k
=0; k
<ccount
; k
++) {
358 if (symbol_table
[k
] == color
)
364 *(r
++) = color_table
[0][k
];
365 *(g
++) = color_table
[1][k
];
366 *(b
++) = color_table
[2][k
];
368 *(a
++) = color_table
[3][k
];
371 for (j
=1; j
<=w
*2; j
++) {
373 color
|= buffer
[j
] << 8;
375 for (k
=0; k
<ccount
; k
++) {
376 if (symbol_table
[k
] == color
)
383 *(r
++) = color_table
[0][k
];
384 *(g
++) = color_table
[1][k
];
385 *(b
++) = color_table
[2][k
];
387 *(a
++) = color_table
[3][k
];
399 RErrorCode
= RERR_BADIMAGEFILE
;
405 RDestroyImage(image
);
409 RErrorCode
= RERR_BADIMAGEFILE
;
415 RDestroyImage(image
);
422 typedef struct XPMColor
{
427 struct XPMColor
*next
;
432 #define I2CHAR(i) ((i)<12 ? (i)+'0' : ((i)<38 ? (i)+'A'-12 : (i)+'a'-38))
433 #define CINDEX(xpmc) (((unsigned)(xpmc)->red)<<16|((unsigned)(xpmc)->green)<<8|((unsigned)(xpmc)->blue))
438 lookfor(XPMColor
*list
, int index
)
443 for (; list
!=NULL
; list
=list
->next
) {
444 if (CINDEX(list
) == index
)
451 * Looks for the color in the colormap and inserts if it is not found.
453 * list is a binary search list. The unbalancing problem is just ignored.
455 * Returns False on error
458 addcolor(XPMColor
**list
, unsigned r
, unsigned g
, unsigned b
, int *colors
)
464 index
= r
<<16|g
<<8|b
;
467 tmpc
= lookfor(*list
, index
);
472 newc
= malloc(sizeof(XPMColor
));
476 RErrorCode
= RERR_NOMEMORY
;
494 index2str(char *buffer
, int index
, int charsPerPixel
)
498 for (i
=0; i
<charsPerPixel
; i
++) {
499 buffer
[i
] = I2CHAR(index
&63);
509 outputcolormap(FILE *file
, XPMColor
*colormap
, int charsPerPixel
)
517 for (index
=0; colormap
!=NULL
; colormap
=colormap
->next
,index
++) {
518 colormap
->index
= index
;
519 fprintf(file
, "\"%s c #%02x%02x%02x\",\n",
520 index2str(buf
, index
, charsPerPixel
), colormap
->red
,
521 colormap
->green
, colormap
->blue
);
527 freecolormap(XPMColor
*colormap
)
532 tmp
= colormap
->next
;
540 /* save routine is common to internal support and library support */
542 RSaveXPM(RImage
*image
, char *filename
)
548 XPMColor
*colormap
= NULL
;
552 unsigned char *r
, *g
, *b
, *a
;
556 file
= fopen(filename
, "w+");
558 RErrorCode
= RERR_OPEN
;
562 fprintf(file
, "/* XPM */\n");
564 fprintf(file
, "static char *image[] = {\n");
569 if (image
->format
== RRGBAFormat
)
574 /* first pass: make colormap for the image */
577 for (y
= 0; y
< image
->height
; y
++) {
578 for (x
= 0; x
< image
->width
; x
++) {
580 if (!addcolor(&colormap
, *r
, *g
, *b
, &colorCount
)) {
588 while ((1 << charsPerPixel
*6) < colorCount
)
591 /* write header info */
592 fprintf(file
, "\"%i %i %i %i\",\n", image
->width
, image
->height
,
593 colorCount
, charsPerPixel
);
595 /* write colormap data */
596 if (image
->data
[3]) {
597 for (i
=0; i
<charsPerPixel
; i
++)
601 fprintf(file
, "\"%s c None\",\n", transp
);
605 outputcolormap(file
, colormap
, charsPerPixel
);
611 if (image
->format
== RRGBAFormat
)
617 for (y
= 0; y
< image
->height
; y
++) {
621 for (x
= 0; x
< image
->width
; x
++) {
623 if (!a
|| *a
++>127) {
624 tmpc
= lookfor(colormap
, (unsigned)*r
<<16|(unsigned)*g
<<8|(unsigned)*b
);
626 fprintf(file
, index2str(buf
, tmpc
->index
, charsPerPixel
));
628 fprintf(file
, transp
);
634 if (y
< image
->height
-1)
635 fprintf(file
, "\",\n");
637 fprintf(file
, "\"};\n");
644 if (ok
&& errno
==ENOSPC
) {
645 RErrorCode
= RERR_WRITE
;
648 freecolormap(colormap
);
650 return ok
? True
: False
;