For libwraster:
[wmaker-crm.git] / wrlib / load.c
blobdde6c5a3a1358852467f673c892768190ab0208d
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>
32 #include <assert.h>
34 #ifdef USE_PNG
35 #include <png.h>
36 #endif
38 #include "wraster.h"
41 typedef struct RCachedImage {
42 RImage *image;
43 char *file;
44 time_t last_modif; /* last time file was modified */
45 time_t last_use; /* last time image was used */
46 } RCachedImage;
50 * Size of image cache
52 static int RImageCacheSize = -1;
55 * Max. size of image to store in cache
57 static int RImageCacheMaxImage = -1; /* 0 = any size */
59 #define IMAGE_CACHE_SIZE 8
61 #define IMAGE_CACHE_MAX_IMAGE 64*64
63 static RCachedImage *RImageCache;
69 #define IM_ERROR -1
70 #define IM_UNKNOWN 0
71 #define IM_XPM 1
72 #define IM_TIFF 2
73 #define IM_PNG 3
74 #define IM_PPM 4
75 #define IM_JPEG 5
76 #define IM_GIF 6
77 /* How many image types do we have. */
78 /* Increase this when adding new image types! */
79 #define IM_TYPES 6
82 static int identFile(char *path);
84 extern RImage *RLoadPPM(RContext *context, char *file_name, int index);
86 extern RImage *RLoadXPM(RContext *context, char *file, int index);
89 #ifdef USE_TIFF
90 extern RImage *RLoadTIFF(RContext *context, char *file, int index);
91 #endif
92 #ifdef USE_PNG
93 extern RImage *RLoadPNG(RContext *context, char *file, int index);
94 #endif
95 #ifdef USE_JPEG
96 extern RImage *RLoadJPEG(RContext *context, char *file_name, int index);
97 #endif
98 #ifdef USE_GIF
99 extern RImage *RLoadGIF(RContext *context, char *file_name, int index);
100 #endif
103 char**
104 RSupportedFileFormats(void)
106 static char *tmp[IM_TYPES+1];
107 int i = 0;
109 /* built-in */
110 tmp[i++] = "XPM";
111 /* built-in */
112 tmp[i++] = "PPM";
113 #ifdef USE_TIFF
114 tmp[i++] = "TIFF";
115 #endif
116 #ifdef USE_PNG
117 tmp[i++] = "PNG";
118 #endif
119 #ifdef USE_JPEG
120 tmp[i++] = "JPEG";
121 #endif
122 #ifdef USE_GIF
123 tmp[i++] = "GIF";
124 #endif
125 tmp[i] = NULL;
127 return tmp;
131 static void
132 init_cache()
134 char *tmp;
136 tmp = getenv("RIMAGE_CACHE");
137 if (!tmp || sscanf(tmp, "%i", &RImageCacheSize)!=1) {
138 RImageCacheSize = IMAGE_CACHE_SIZE;
140 if (RImageCacheSize<0)
141 RImageCacheSize = 0;
143 tmp = getenv("RIMAGE_CACHE_SIZE");
144 if (!tmp || sscanf(tmp, "%i", &RImageCacheMaxImage)!=1) {
145 RImageCacheMaxImage = IMAGE_CACHE_MAX_IMAGE;
148 if (RImageCacheSize>0) {
149 RImageCache = malloc(sizeof(RCachedImage)*RImageCacheSize);
150 if (RImageCache==NULL) {
151 printf("wrlib: out of memory for image cache\n");
152 return;
154 memset(RImageCache, 0, sizeof(RCachedImage)*RImageCacheSize);
159 RImage*
160 RLoadImage(RContext *context, char *file, int index)
162 RImage *image = NULL;
163 int i;
164 struct stat st;
166 assert(file!=NULL);
168 if (RImageCacheSize<0) {
169 init_cache();
172 if (RImageCacheSize>0) {
174 for (i=0; i<RImageCacheSize; i++) {
175 if (RImageCache[i].file
176 && strcmp(file, RImageCache[i].file)==0) {
178 if (stat(file, &st)==0
179 && st.st_mtime == RImageCache[i].last_modif) {
180 RImageCache[i].last_use = time(NULL);
182 return RCloneImage(RImageCache[i].image);
184 } else {
185 free(RImageCache[i].file);
186 RImageCache[i].file = NULL;
187 RReleaseImage(RImageCache[i].image);
193 switch (identFile(file)) {
194 case IM_ERROR:
195 return NULL;
197 case IM_UNKNOWN:
198 RErrorCode = RERR_BADFORMAT;
199 return NULL;
201 case IM_XPM:
202 image = RLoadXPM(context, file, index);
203 break;
205 #ifdef USE_TIFF
206 case IM_TIFF:
207 image = RLoadTIFF(context, file, index);
208 break;
209 #endif /* USE_TIFF */
211 #ifdef USE_PNG
212 case IM_PNG:
213 image = RLoadPNG(context, file, index);
214 break;
215 #endif /* USE_PNG */
217 #ifdef USE_JPEG
218 case IM_JPEG:
219 image = RLoadJPEG(context, file, index);
220 break;
221 #endif /* USE_JPEG */
223 #ifdef USE_GIF
224 case IM_GIF:
225 image = RLoadGIF(context, file, index);
226 break;
227 #endif /* USE_GIF */
229 case IM_PPM:
230 image = RLoadPPM(context, file, index);
231 break;
233 default:
234 RErrorCode = RERR_BADFORMAT;
235 return NULL;
239 /* store image in cache */
240 if (RImageCacheSize>0 && image &&
241 (RImageCacheMaxImage==0
242 || RImageCacheMaxImage >= image->width*image->height)) {
243 time_t oldest=time(NULL);
244 int oldest_idx = 0;
245 int done = 0;
247 for (i=0; i<RImageCacheSize; i++) {
248 if (!RImageCache[i].file) {
249 RImageCache[i].file = malloc(strlen(file)+1);
250 strcpy(RImageCache[i].file, file);
251 RImageCache[i].image = RCloneImage(image);
252 RImageCache[i].last_modif = st.st_mtime;
253 RImageCache[i].last_use = time(NULL);
254 done = 1;
255 break;
256 } else {
257 if (oldest > RImageCache[i].last_use) {
258 oldest = RImageCache[i].last_use;
259 oldest_idx = i;
264 /* if no slot available, dump least recently used one */
265 if (!done) {
266 free(RImageCache[oldest_idx].file);
267 RReleaseImage(RImageCache[oldest_idx].image);
268 RImageCache[oldest_idx].file = malloc(strlen(file)+1);
269 strcpy(RImageCache[oldest_idx].file, file);
270 RImageCache[oldest_idx].image = RCloneImage(image);
271 RImageCache[oldest_idx].last_modif = st.st_mtime;
272 RImageCache[oldest_idx].last_use = time(NULL);
276 return image;
280 char*
281 RGetImageFileFormat(char *file)
283 switch (identFile(file)) {
284 case IM_XPM:
285 return "XPM";
287 #ifdef USE_TIFF
288 case IM_TIFF:
289 return "TIFF";
290 #endif /* USE_TIFF */
292 #ifdef USE_PNG
293 case IM_PNG:
294 return "PNG";
295 #endif /* USE_PNG */
297 #ifdef USE_JPEG
298 case IM_JPEG:
299 return "JPEG";
300 #endif /* USE_JPEG */
302 #ifdef USE_GIF
303 case IM_GIF:
304 return "GIF";
305 #endif /* USE_GIF */
307 case IM_PPM:
308 return "PPM";
310 default:
311 return NULL;
316 static int
317 identFile(char *path)
319 int fd;
320 unsigned char buffer[32];
322 assert(path!=NULL);
324 fd = open(path, O_RDONLY);
325 if (fd < 0) {
326 RErrorCode = RERR_OPEN;
327 return IM_ERROR;
329 if (read(fd, buffer, 32)<1) {
330 close(fd);
331 RErrorCode = RERR_READ;
332 return IM_ERROR;
334 close(fd);
336 /* check for XPM */
337 if (strncmp((char*)buffer, "/* XPM */", 9)==0)
338 return IM_XPM;
340 /* check for TIFF */
341 if ((buffer[0]=='I' && buffer[1]=='I' && buffer[2]=='*' && buffer[3]==0)
342 ||(buffer[0]=='M' && buffer[1]=='M' && buffer[2]==0 && buffer[3]=='*'))
343 return IM_TIFF;
345 #ifdef USE_PNG
346 /* check for PNG */
347 if (png_check_sig(buffer, 8))
348 return IM_PNG;
349 #endif
351 /* check for raw PPM or PGM */
352 if (buffer[0]=='P' && (buffer[1]=='5' || buffer[1]=='6'))
353 return IM_PPM;
355 /* check for JPEG */
356 if (buffer[0] == 0xff && buffer[1] == 0xd8)
357 return IM_JPEG;
359 /* check for GIF */
360 if (buffer[0] == 'G' && buffer[1] == 'I' && buffer[2] == 'F')
361 return IM_GIF;
363 return IM_UNKNOWN;