wmaker: Replaced local 'extern' definition of wPreferences by proper header usage
[wmaker-crm.git] / wrlib / load.c
blob5e1bde615623ba6e6cd2c75b6376a7722a82e0ae
1 /* load.c - load image from file
3 * Raster graphics library
5 * Copyright (c) 1997-2003 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., 51 Franklin St, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
23 #include <config.h>
25 #include <errno.h>
26 #include <X11/Xlib.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <sys/stat.h>
32 #include <string.h>
33 #include <time.h>
34 #include <assert.h>
36 #ifdef USE_PNG
37 #include <png.h>
38 #endif
40 #include "wraster.h"
41 #include "imgformat.h"
43 #define RETRY( x ) do { \
44 x; \
45 } while (errno == EINTR);
47 typedef struct RCachedImage {
48 RImage *image;
49 char *file;
50 time_t last_modif; /* last time file was modified */
51 time_t last_use; /* last time image was used */
52 } RCachedImage;
55 * Size of image cache
57 static int RImageCacheSize = -1;
60 * Max. size of image to store in cache
62 static int RImageCacheMaxImage = -1; /* 0 = any size */
64 #define IMAGE_CACHE_SIZE 8
66 #define IMAGE_CACHE_MAX_IMAGE 64*64
68 static RCachedImage *RImageCache;
71 static WRImgFormat identFile(const char *path);
74 char **RSupportedFileFormats(void)
76 static char *tmp[IM_TYPES + 1];
77 int i = 0;
79 /* built-in */
80 tmp[i++] = "XPM";
81 /* built-in */
82 tmp[i++] = "PPM";
83 #ifdef USE_TIFF
84 tmp[i++] = "TIFF";
85 #endif
86 #ifdef USE_PNG
87 tmp[i++] = "PNG";
88 #endif
89 #ifdef USE_JPEG
90 tmp[i++] = "JPEG";
91 #endif
92 #ifdef USE_GIF
93 tmp[i++] = "GIF";
94 #endif
95 tmp[i] = NULL;
97 return tmp;
100 static void init_cache(void)
102 char *tmp;
104 tmp = getenv("RIMAGE_CACHE");
105 if (!tmp || sscanf(tmp, "%i", &RImageCacheSize) != 1) {
106 RImageCacheSize = IMAGE_CACHE_SIZE;
108 if (RImageCacheSize < 0)
109 RImageCacheSize = 0;
111 tmp = getenv("RIMAGE_CACHE_SIZE");
112 if (!tmp || sscanf(tmp, "%i", &RImageCacheMaxImage) != 1) {
113 RImageCacheMaxImage = IMAGE_CACHE_MAX_IMAGE;
116 if (RImageCacheSize > 0) {
117 RImageCache = malloc(sizeof(RCachedImage) * RImageCacheSize);
118 if (RImageCache == NULL) {
119 printf("wrlib: out of memory for image cache\n");
120 return;
122 memset(RImageCache, 0, sizeof(RCachedImage) * RImageCacheSize);
126 RImage *RLoadImage(RContext * context, const char *file, int index)
128 RImage *image = NULL;
129 int i;
130 struct stat st;
132 assert(file != NULL);
134 if (RImageCacheSize < 0) {
135 init_cache();
138 if (RImageCacheSize > 0) {
140 for (i = 0; i < RImageCacheSize; i++) {
141 if (RImageCache[i].file && strcmp(file, RImageCache[i].file) == 0) {
143 if (stat(file, &st) == 0 && st.st_mtime == RImageCache[i].last_modif) {
144 RImageCache[i].last_use = time(NULL);
146 return RCloneImage(RImageCache[i].image);
148 } else {
149 free(RImageCache[i].file);
150 RImageCache[i].file = NULL;
151 RReleaseImage(RImageCache[i].image);
157 switch (identFile(file)) {
158 case IM_ERROR:
159 return NULL;
161 case IM_UNKNOWN:
162 RErrorCode = RERR_BADFORMAT;
163 return NULL;
165 case IM_XPM:
166 image = RLoadXPM(context, file);
167 break;
169 #ifdef USE_TIFF
170 case IM_TIFF:
171 image = RLoadTIFF(file, index);
172 break;
173 #endif /* USE_TIFF */
175 #ifdef USE_PNG
176 case IM_PNG:
177 image = RLoadPNG(context, file);
178 break;
179 #endif /* USE_PNG */
181 #ifdef USE_JPEG
182 case IM_JPEG:
183 image = RLoadJPEG(context, file);
184 break;
185 #endif /* USE_JPEG */
187 #ifdef USE_GIF
188 case IM_GIF:
189 image = RLoadGIF(file, index);
190 break;
191 #endif /* USE_GIF */
193 case IM_PPM:
194 image = RLoadPPM(file);
195 break;
197 default:
198 RErrorCode = RERR_BADFORMAT;
199 return NULL;
202 /* store image in cache */
203 if (RImageCacheSize > 0 && image &&
204 (RImageCacheMaxImage == 0 || RImageCacheMaxImage >= image->width * image->height)) {
205 time_t oldest = time(NULL);
206 int oldest_idx = 0;
207 int done = 0;
209 for (i = 0; i < RImageCacheSize; i++) {
210 if (!RImageCache[i].file) {
211 RImageCache[i].file = malloc(strlen(file) + 1);
212 strcpy(RImageCache[i].file, file);
213 RImageCache[i].image = RCloneImage(image);
214 RImageCache[i].last_modif = st.st_mtime;
215 RImageCache[i].last_use = time(NULL);
216 done = 1;
217 break;
218 } else {
219 if (oldest > RImageCache[i].last_use) {
220 oldest = RImageCache[i].last_use;
221 oldest_idx = i;
226 /* if no slot available, dump least recently used one */
227 if (!done) {
228 free(RImageCache[oldest_idx].file);
229 RReleaseImage(RImageCache[oldest_idx].image);
230 RImageCache[oldest_idx].file = malloc(strlen(file) + 1);
231 strcpy(RImageCache[oldest_idx].file, file);
232 RImageCache[oldest_idx].image = RCloneImage(image);
233 RImageCache[oldest_idx].last_modif = st.st_mtime;
234 RImageCache[oldest_idx].last_use = time(NULL);
238 return image;
241 char *RGetImageFileFormat(const char *file)
243 switch (identFile(file)) {
244 case IM_XPM:
245 return "XPM";
247 #ifdef USE_TIFF
248 case IM_TIFF:
249 return "TIFF";
250 #endif /* USE_TIFF */
252 #ifdef USE_PNG
253 case IM_PNG:
254 return "PNG";
255 #endif /* USE_PNG */
257 #ifdef USE_JPEG
258 case IM_JPEG:
259 return "JPEG";
260 #endif /* USE_JPEG */
262 #ifdef USE_GIF
263 case IM_GIF:
264 return "GIF";
265 #endif /* USE_GIF */
267 case IM_PPM:
268 return "PPM";
270 default:
271 return NULL;
275 static WRImgFormat identFile(const char *path)
277 FILE *file;
278 unsigned char buffer[32];
279 size_t nread;
281 assert(path != NULL);
283 RETRY( file = fopen(path, "rb") )
284 if (file == NULL) {
285 RErrorCode = RERR_OPEN;
286 return IM_ERROR;
289 RETRY( nread = fread(buffer, 1, sizeof(buffer), file) )
290 if (nread < sizeof(buffer) || ferror(file)) {
291 RETRY( fclose(file) )
292 RErrorCode = RERR_READ;
293 return IM_ERROR;
295 RETRY( fclose(file) )
297 /* check for XPM */
298 if (strncmp((char *)buffer, "/* XPM */", 9) == 0)
299 return IM_XPM;
301 /* check for TIFF */
302 if ((buffer[0] == 'I' && buffer[1] == 'I' && buffer[2] == '*' && buffer[3] == 0)
303 || (buffer[0] == 'M' && buffer[1] == 'M' && buffer[2] == 0 && buffer[3] == '*'))
304 return IM_TIFF;
306 #ifdef USE_PNG
307 /* check for PNG */
308 if (!png_sig_cmp(buffer, 0, 8))
309 return IM_PNG;
310 #endif
312 /* check for raw PPM or PGM */
313 if (buffer[0] == 'P' && (buffer[1] == '5' || buffer[1] == '6'))
314 return IM_PPM;
316 /* check for JPEG */
317 if (buffer[0] == 0xff && buffer[1] == 0xd8)
318 return IM_JPEG;
320 /* check for GIF */
321 if (buffer[0] == 'G' && buffer[1] == 'I' && buffer[2] == 'F')
322 return IM_GIF;
324 return IM_UNKNOWN;