changed indentation to use spaces only
[wmaker-crm.git] / wrlib / load.c
blob320b436118147e78c8341a8600b8b3cbb47a4108
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., 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"
40 /* Silly hack for Windows systems with cygwin */
41 #ifndef O_BINARY
42 # define O_BINARY 0
43 #endif
45 typedef struct RCachedImage {
46 RImage *image;
47 char *file;
48 time_t last_modif; /* last time file was modified */
49 time_t last_use; /* last time image was used */
50 } RCachedImage;
54 * Size of image cache
56 static int RImageCacheSize = -1;
59 * Max. size of image to store in cache
61 static int RImageCacheMaxImage = -1; /* 0 = any size */
63 #define IMAGE_CACHE_SIZE 8
65 #define IMAGE_CACHE_MAX_IMAGE 64*64
67 static RCachedImage *RImageCache;
73 #define IM_ERROR -1
74 #define IM_UNKNOWN 0
75 #define IM_XPM 1
76 #define IM_TIFF 2
77 #define IM_PNG 3
78 #define IM_PPM 4
79 #define IM_JPEG 5
80 #define IM_GIF 6
81 /* How many image types do we have. */
82 /* Increase this when adding new image types! */
83 #define IM_TYPES 6
86 static int identFile(char *path);
88 extern RImage *RLoadPPM(RContext *context, char *file_name, int index);
90 extern RImage *RLoadXPM(RContext *context, char *file, int index);
93 #ifdef USE_TIFF
94 extern RImage *RLoadTIFF(RContext *context, char *file, int index);
95 #endif
96 #ifdef USE_PNG
97 extern RImage *RLoadPNG(RContext *context, char *file, int index);
98 #endif
99 #ifdef USE_JPEG
100 extern RImage *RLoadJPEG(RContext *context, char *file_name, int index);
101 #endif
102 #ifdef USE_GIF
103 extern RImage *RLoadGIF(RContext *context, char *file_name, int index);
104 #endif
107 char**
108 RSupportedFileFormats(void)
110 static char *tmp[IM_TYPES+1];
111 int i = 0;
113 /* built-in */
114 tmp[i++] = "XPM";
115 /* built-in */
116 tmp[i++] = "PPM";
117 #ifdef USE_TIFF
118 tmp[i++] = "TIFF";
119 #endif
120 #ifdef USE_PNG
121 tmp[i++] = "PNG";
122 #endif
123 #ifdef USE_JPEG
124 tmp[i++] = "JPEG";
125 #endif
126 #ifdef USE_GIF
127 tmp[i++] = "GIF";
128 #endif
129 tmp[i] = NULL;
131 return tmp;
135 static void
136 init_cache()
138 char *tmp;
140 tmp = getenv("RIMAGE_CACHE");
141 if (!tmp || sscanf(tmp, "%i", &RImageCacheSize)!=1) {
142 RImageCacheSize = IMAGE_CACHE_SIZE;
144 if (RImageCacheSize<0)
145 RImageCacheSize = 0;
147 tmp = getenv("RIMAGE_CACHE_SIZE");
148 if (!tmp || sscanf(tmp, "%i", &RImageCacheMaxImage)!=1) {
149 RImageCacheMaxImage = IMAGE_CACHE_MAX_IMAGE;
152 if (RImageCacheSize>0) {
153 RImageCache = malloc(sizeof(RCachedImage)*RImageCacheSize);
154 if (RImageCache==NULL) {
155 printf("wrlib: out of memory for image cache\n");
156 return;
158 memset(RImageCache, 0, sizeof(RCachedImage)*RImageCacheSize);
163 RImage*
164 RLoadImage(RContext *context, char *file, int index)
166 RImage *image = NULL;
167 int i;
168 struct stat st;
170 assert(file!=NULL);
172 if (RImageCacheSize<0) {
173 init_cache();
176 if (RImageCacheSize>0) {
178 for (i=0; i<RImageCacheSize; i++) {
179 if (RImageCache[i].file
180 && strcmp(file, RImageCache[i].file)==0) {
182 if (stat(file, &st)==0
183 && st.st_mtime == RImageCache[i].last_modif) {
184 RImageCache[i].last_use = time(NULL);
186 return RCloneImage(RImageCache[i].image);
188 } else {
189 free(RImageCache[i].file);
190 RImageCache[i].file = NULL;
191 RReleaseImage(RImageCache[i].image);
197 switch (identFile(file)) {
198 case IM_ERROR:
199 return NULL;
201 case IM_UNKNOWN:
202 RErrorCode = RERR_BADFORMAT;
203 return NULL;
205 case IM_XPM:
206 image = RLoadXPM(context, file, index);
207 break;
209 #ifdef USE_TIFF
210 case IM_TIFF:
211 image = RLoadTIFF(context, file, index);
212 break;
213 #endif /* USE_TIFF */
215 #ifdef USE_PNG
216 case IM_PNG:
217 image = RLoadPNG(context, file, index);
218 break;
219 #endif /* USE_PNG */
221 #ifdef USE_JPEG
222 case IM_JPEG:
223 image = RLoadJPEG(context, file, index);
224 break;
225 #endif /* USE_JPEG */
227 #ifdef USE_GIF
228 case IM_GIF:
229 image = RLoadGIF(context, file, index);
230 break;
231 #endif /* USE_GIF */
233 case IM_PPM:
234 image = RLoadPPM(context, file, index);
235 break;
237 default:
238 RErrorCode = RERR_BADFORMAT;
239 return NULL;
243 /* store image in cache */
244 if (RImageCacheSize>0 && image &&
245 (RImageCacheMaxImage==0
246 || RImageCacheMaxImage >= image->width*image->height)) {
247 time_t oldest=time(NULL);
248 int oldest_idx = 0;
249 int done = 0;
251 for (i=0; i<RImageCacheSize; i++) {
252 if (!RImageCache[i].file) {
253 RImageCache[i].file = malloc(strlen(file)+1);
254 strcpy(RImageCache[i].file, file);
255 RImageCache[i].image = RCloneImage(image);
256 RImageCache[i].last_modif = st.st_mtime;
257 RImageCache[i].last_use = time(NULL);
258 done = 1;
259 break;
260 } else {
261 if (oldest > RImageCache[i].last_use) {
262 oldest = RImageCache[i].last_use;
263 oldest_idx = i;
268 /* if no slot available, dump least recently used one */
269 if (!done) {
270 free(RImageCache[oldest_idx].file);
271 RReleaseImage(RImageCache[oldest_idx].image);
272 RImageCache[oldest_idx].file = malloc(strlen(file)+1);
273 strcpy(RImageCache[oldest_idx].file, file);
274 RImageCache[oldest_idx].image = RCloneImage(image);
275 RImageCache[oldest_idx].last_modif = st.st_mtime;
276 RImageCache[oldest_idx].last_use = time(NULL);
280 return image;
284 char*
285 RGetImageFileFormat(char *file)
287 switch (identFile(file)) {
288 case IM_XPM:
289 return "XPM";
291 #ifdef USE_TIFF
292 case IM_TIFF:
293 return "TIFF";
294 #endif /* USE_TIFF */
296 #ifdef USE_PNG
297 case IM_PNG:
298 return "PNG";
299 #endif /* USE_PNG */
301 #ifdef USE_JPEG
302 case IM_JPEG:
303 return "JPEG";
304 #endif /* USE_JPEG */
306 #ifdef USE_GIF
307 case IM_GIF:
308 return "GIF";
309 #endif /* USE_GIF */
311 case IM_PPM:
312 return "PPM";
314 default:
315 return NULL;
320 static int
321 identFile(char *path)
323 int fd;
324 unsigned char buffer[32];
326 assert(path!=NULL);
328 fd = open(path, O_RDONLY|O_BINARY);
329 if (fd < 0) {
330 RErrorCode = RERR_OPEN;
331 return IM_ERROR;
333 if (read(fd, buffer, 32)<1) {
334 close(fd);
335 RErrorCode = RERR_READ;
336 return IM_ERROR;
338 close(fd);
340 /* check for XPM */
341 if (strncmp((char*)buffer, "/* XPM */", 9)==0)
342 return IM_XPM;
344 /* check for TIFF */
345 if ((buffer[0]=='I' && buffer[1]=='I' && buffer[2]=='*' && buffer[3]==0)
346 ||(buffer[0]=='M' && buffer[1]=='M' && buffer[2]==0 && buffer[3]=='*'))
347 return IM_TIFF;
349 #ifdef USE_PNG
350 /* check for PNG */
351 if (png_check_sig(buffer, 8))
352 return IM_PNG;
353 #endif
355 /* check for raw PPM or PGM */
356 if (buffer[0]=='P' && (buffer[1]=='5' || buffer[1]=='6'))
357 return IM_PPM;
359 /* check for JPEG */
360 if (buffer[0] == 0xff && buffer[1] == 0xd8)
361 return IM_JPEG;
363 /* check for GIF */
364 if (buffer[0] == 'G' && buffer[1] == 'I' && buffer[2] == 'F')
365 return IM_GIF;
367 return IM_UNKNOWN;