Initial revision
[wmaker-crm.git] / wrlib / load.c
blob1e23a5dde78d0bf5e09961f3892d90f094c735fb
1 /* load.c - load image from file
2 *
3 * Raster graphics library
4 *
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.
22 #include <config.h>
24 #include <X11/Xlib.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <sys/stat.h>
30 #include <string.h>
31 #include <time.h>
33 #ifdef USE_PNG
34 #include <png.h>
35 #endif
37 #include "wraster.h"
40 typedef struct RCachedImage {
41 RImage *image;
42 char *file;
43 time_t last_modif; /* last time file was modified */
44 time_t last_use; /* last time image was used */
45 } RCachedImage;
49 * Size of image cache
51 static int RImageCacheSize = -1;
54 * Max. size of image to store in cache
56 static int RImageCacheMaxImage = -1; /* 0 = any size */
58 #define IMAGE_CACHE_SIZE 8
60 #define IMAGE_CACHE_MAX_IMAGE 64*64
62 static RCachedImage *RImageCache;
68 #define IM_ERROR -1
69 #define IM_UNKNOWN 0
70 #define IM_XPM 1
71 #define IM_TIFF 2
72 #define IM_PNG 3
73 #define IM_PPM 4
74 #define IM_JPEG 5
75 #define IM_GIF 6
76 /* How many image types do we have. */
77 /* Increase this when adding new image types! */
78 #define IM_TYPES 6
81 static int identFile(char *path);
83 extern RImage *RLoadPPM(RContext *context, char *file_name, int index);
85 extern RImage *RLoadXPM(RContext *context, char *file, int index);
88 #ifdef USE_TIFF
89 extern RImage *RLoadTIFF(RContext *context, char *file, int index);
90 #endif
91 #ifdef USE_PNG
92 extern RImage *RLoadPNG(RContext *context, char *file, int index);
93 #endif
94 #ifdef USE_JPEG
95 extern RImage *RLoadJPEG(RContext *context, char *file_name, int index);
96 #endif
97 #ifdef USE_GIF
98 extern RImage *RLoadGIF(RContext *context, char *file_name, int index);
99 #endif
102 static char*
103 wstrdup(char *s)
105 char *tmp;
107 tmp = malloc(strlen(s)+1);
108 if (!tmp)
109 return NULL;
110 return strcpy(tmp, s);
113 char**
114 RSupportedFileFormats(void)
116 char **tmp;
117 int i = 0;
119 tmp = malloc(sizeof(char*)*(IM_TYPES+1));
120 if (!tmp)
121 return NULL;
122 memset(tmp, 0, sizeof(char*)*(IM_TYPES+1));
124 /* built-in */
125 tmp[i++] = wstrdup("XPM");
126 if (!tmp[i-1]) {
127 RFreeStringList(tmp);
128 return NULL;
130 /* built-in */
131 tmp[i++] = wstrdup("PPM");
132 if (!tmp[i-1]) {
133 RFreeStringList(tmp);
134 return NULL;
136 #ifdef USE_TIFF
137 tmp[i++] = wstrdup("TIFF");
138 if (!tmp[i-1]) {
139 RFreeStringList(tmp);
140 return NULL;
142 #endif
143 #ifdef USE_PNG
144 tmp[i++] = wstrdup("PNG");
145 if (!tmp[i-1]) {
146 RFreeStringList(tmp);
147 return NULL;
149 #endif
150 #ifdef USE_JPEG
151 tmp[i++] = wstrdup("JPEG");
152 if (!tmp[i-1]) {
153 RFreeStringList(tmp);
154 return NULL;
156 #endif
157 #ifdef USE_GIF
158 tmp[i++] = wstrdup("GIF");
159 if (!tmp[i-1]) {
160 RFreeStringList(tmp);
161 return NULL;
163 #endif
164 tmp[i] = NULL;
166 return tmp;
170 void
171 RFreeStringList(char **list)
173 int i;
175 for (i = 0; list[i]!=NULL; i++) {
176 free(list[i]);
178 free(list);
182 static void
183 init_cache()
185 char *tmp;
187 tmp = getenv("RIMAGE_CACHE");
188 if (!tmp || sscanf(tmp, "%i", &RImageCacheSize)!=1) {
189 RImageCacheSize = IMAGE_CACHE_SIZE;
191 if (RImageCacheSize<0)
192 RImageCacheSize = 0;
194 tmp = getenv("RIMAGE_CACHE_SIZE");
195 if (!tmp || sscanf(tmp, "%i", &RImageCacheMaxImage)!=1) {
196 RImageCacheMaxImage = IMAGE_CACHE_MAX_IMAGE;
199 if (RImageCacheSize>0) {
200 RImageCache = malloc(sizeof(RCachedImage)*RImageCacheSize);
201 if (RImageCache==NULL) {
202 printf("wrlib: out of memory for image cache\n");
203 return;
205 memset(RImageCache, 0, sizeof(RCachedImage)*RImageCacheSize);
210 RImage*
211 RLoadImage(RContext *context, char *file, int index)
213 RImage *image = NULL;
214 int i;
215 struct stat st;
217 RErrorString[0] = 0;
219 if (RImageCacheSize<0) {
220 init_cache();
223 if (RImageCacheSize>0) {
225 for (i=0; i<RImageCacheSize; i++) {
226 if (RImageCache[i].file
227 && strcmp(file, RImageCache[i].file)==0) {
229 if (stat(file, &st)==0
230 && st.st_mtime == RImageCache[i].last_modif) {
231 RImageCache[i].last_use = time(NULL);
233 return RCloneImage(RImageCache[i].image);
235 } else {
236 free(RImageCache[i].file);
237 RImageCache[i].file = NULL;
238 RDestroyImage(RImageCache[i].image);
244 switch (identFile(file)) {
245 case IM_ERROR:
246 sprintf(RErrorString, "error opening file");
247 return NULL;
249 case IM_UNKNOWN:
250 sprintf(RErrorString, "unknown image format");
251 return NULL;
253 case IM_XPM:
254 image = RLoadXPM(context, file, index);
255 break;
257 #ifdef USE_TIFF
258 case IM_TIFF:
259 image = RLoadTIFF(context, file, index);
260 break;
261 #endif /* USE_TIFF */
263 #ifdef USE_PNG
264 case IM_PNG:
265 image = RLoadPNG(context, file, index);
266 break;
267 #endif /* USE_PNG */
269 #ifdef USE_JPEG
270 case IM_JPEG:
271 image = RLoadJPEG(context, file, index);
272 break;
273 #endif /* USE_JPEG */
275 #ifdef USE_GIF
276 case IM_GIF:
277 image = RLoadGIF(context, file, index);
278 break;
279 #endif /* USE_GIF */
281 case IM_PPM:
282 image = RLoadPPM(context, file, index);
283 break;
285 default:
286 sprintf(RErrorString, "unsupported image format");
287 return NULL;
291 /* store image in cache */
292 if (RImageCacheSize>0 && image &&
293 (RImageCacheMaxImage==0
294 || RImageCacheMaxImage >= image->width*image->height)) {
295 time_t oldest=time(NULL);
296 int oldest_idx = 0;
297 int done = 0;
299 for (i=0; i<RImageCacheSize; i++) {
300 if (!RImageCache[i].file) {
301 RImageCache[i].file = malloc(strlen(file)+1);
302 strcpy(RImageCache[i].file, file);
303 RImageCache[i].image = RCloneImage(image);
304 RImageCache[i].last_modif = st.st_mtime;
305 RImageCache[i].last_use = time(NULL);
306 done = 1;
307 break;
308 } else {
309 if (oldest > RImageCache[i].last_use) {
310 oldest = RImageCache[i].last_use;
311 oldest_idx = i;
316 /* if no slot available, dump least recently used one */
317 if (!done) {
318 free(RImageCache[oldest_idx].file);
319 RDestroyImage(RImageCache[oldest_idx].image);
320 RImageCache[oldest_idx].file = malloc(strlen(file)+1);
321 strcpy(RImageCache[oldest_idx].file, file);
322 RImageCache[oldest_idx].image = RCloneImage(image);
323 RImageCache[oldest_idx].last_modif = st.st_mtime;
324 RImageCache[oldest_idx].last_use = time(NULL);
328 return image;
335 static int
336 identFile(char *path)
338 int fd;
339 unsigned char buffer[32];
341 if (!path)
342 return IM_ERROR;
344 fd = open(path, O_RDONLY);
345 if (fd < 0)
346 return IM_ERROR;
347 if (read(fd, buffer, 32)<1) {
348 close(fd);
349 return IM_ERROR;
351 close(fd);
353 /* check for XPM */
354 if (strncmp((char*)buffer, "/* XPM */", 9)==0)
355 return IM_XPM;
357 /* check for TIFF */
358 if ((buffer[0]=='I' && buffer[1]=='I' && buffer[2]=='*' && buffer[3]==0)
359 ||(buffer[0]=='M' && buffer[1]=='M' && buffer[2]==0 && buffer[3]=='*'))
360 return IM_TIFF;
362 #ifdef USE_PNG
363 /* check for PNG */
364 if (png_check_sig(buffer, 8))
365 return IM_PNG;
366 #endif
368 /* check for raw PPM or PGM */
369 if (buffer[0]=='P' && (buffer[1]=='5' || buffer[1]=='6'))
370 return IM_PPM;
372 /* check for JPEG */
373 if (buffer[0] == 0xff && buffer[1] == 0xd8)
374 return IM_JPEG;
376 /* check for GIF */
377 if (buffer[0] == 'G' && buffer[1] == 'I' && buffer[2] == 'F')
378 return IM_GIF;
380 return IM_UNKNOWN;