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.
41 #define RETRY( x ) do { \
43 } while (errno == EINTR);
45 typedef struct RCachedImage
{
48 time_t last_modif
; /* last time file was modified */
49 time_t last_use
; /* last time image was used */
55 static int RImageCacheSize
= -1;
58 * Max. size of image to store in cache
60 static int RImageCacheMaxImage
= -1; /* 0 = any size */
62 #define IMAGE_CACHE_SIZE 8
64 #define IMAGE_CACHE_MAX_IMAGE 64*64
66 static RCachedImage
*RImageCache
;
76 /* How many image types do we have. */
77 /* Increase this when adding new image types! */
80 static int identFile(char *path
);
82 extern RImage
*RLoadPPM(char *file_name
);
84 extern RImage
*RLoadXPM(RContext
* context
, char *file
);
87 extern RImage
*RLoadTIFF(char *file
, int index
);
90 extern RImage
*RLoadPNG(RContext
* context
, char *file
);
93 extern RImage
*RLoadJPEG(RContext
* context
, char *file_name
);
96 extern RImage
*RLoadGIF(char *file_name
, int index
);
99 char **RSupportedFileFormats(void)
101 static char *tmp
[IM_TYPES
+ 1];
125 static void init_cache()
129 tmp
= getenv("RIMAGE_CACHE");
130 if (!tmp
|| sscanf(tmp
, "%i", &RImageCacheSize
) != 1) {
131 RImageCacheSize
= IMAGE_CACHE_SIZE
;
133 if (RImageCacheSize
< 0)
136 tmp
= getenv("RIMAGE_CACHE_SIZE");
137 if (!tmp
|| sscanf(tmp
, "%i", &RImageCacheMaxImage
) != 1) {
138 RImageCacheMaxImage
= IMAGE_CACHE_MAX_IMAGE
;
141 if (RImageCacheSize
> 0) {
142 RImageCache
= malloc(sizeof(RCachedImage
) * RImageCacheSize
);
143 if (RImageCache
== NULL
) {
144 printf("wrlib: out of memory for image cache\n");
147 memset(RImageCache
, 0, sizeof(RCachedImage
) * RImageCacheSize
);
151 RImage
*RLoadImage(RContext
* context
, char *file
, int index
)
153 RImage
*image
= NULL
;
157 assert(file
!= NULL
);
159 if (RImageCacheSize
< 0) {
163 if (RImageCacheSize
> 0) {
165 for (i
= 0; i
< RImageCacheSize
; i
++) {
166 if (RImageCache
[i
].file
&& strcmp(file
, RImageCache
[i
].file
) == 0) {
168 if (stat(file
, &st
) == 0 && st
.st_mtime
== RImageCache
[i
].last_modif
) {
169 RImageCache
[i
].last_use
= time(NULL
);
171 return RCloneImage(RImageCache
[i
].image
);
174 free(RImageCache
[i
].file
);
175 RImageCache
[i
].file
= NULL
;
176 RReleaseImage(RImageCache
[i
].image
);
182 switch (identFile(file
)) {
187 RErrorCode
= RERR_BADFORMAT
;
191 image
= RLoadXPM(context
, file
);
196 image
= RLoadTIFF(file
, index
);
198 #endif /* USE_TIFF */
202 image
= RLoadPNG(context
, file
);
208 image
= RLoadJPEG(context
, file
);
210 #endif /* USE_JPEG */
214 image
= RLoadGIF(file
, index
);
219 image
= RLoadPPM(file
);
223 RErrorCode
= RERR_BADFORMAT
;
227 /* store image in cache */
228 if (RImageCacheSize
> 0 && image
&&
229 (RImageCacheMaxImage
== 0 || RImageCacheMaxImage
>= image
->width
* image
->height
)) {
230 time_t oldest
= time(NULL
);
234 for (i
= 0; i
< RImageCacheSize
; i
++) {
235 if (!RImageCache
[i
].file
) {
236 RImageCache
[i
].file
= malloc(strlen(file
) + 1);
237 strcpy(RImageCache
[i
].file
, file
);
238 RImageCache
[i
].image
= RCloneImage(image
);
239 RImageCache
[i
].last_modif
= st
.st_mtime
;
240 RImageCache
[i
].last_use
= time(NULL
);
244 if (oldest
> RImageCache
[i
].last_use
) {
245 oldest
= RImageCache
[i
].last_use
;
251 /* if no slot available, dump least recently used one */
253 free(RImageCache
[oldest_idx
].file
);
254 RReleaseImage(RImageCache
[oldest_idx
].image
);
255 RImageCache
[oldest_idx
].file
= malloc(strlen(file
) + 1);
256 strcpy(RImageCache
[oldest_idx
].file
, file
);
257 RImageCache
[oldest_idx
].image
= RCloneImage(image
);
258 RImageCache
[oldest_idx
].last_modif
= st
.st_mtime
;
259 RImageCache
[oldest_idx
].last_use
= time(NULL
);
266 char *RGetImageFileFormat(char *file
)
268 switch (identFile(file
)) {
275 #endif /* USE_TIFF */
285 #endif /* USE_JPEG */
300 static int identFile(char *path
)
303 unsigned char buffer
[32];
306 assert(path
!= NULL
);
308 RETRY( file
= fopen(path
, "rb") )
310 RErrorCode
= RERR_OPEN
;
314 RETRY( nread
= fread(buffer
, 1, sizeof(buffer
), file
) )
315 if (nread
< sizeof(buffer
) || ferror(file
)) {
316 RETRY( fclose(file
) )
317 RErrorCode
= RERR_READ
;
320 RETRY( fclose(file
) )
323 if (strncmp((char *)buffer
, "/* XPM */", 9) == 0)
327 if ((buffer
[0] == 'I' && buffer
[1] == 'I' && buffer
[2] == '*' && buffer
[3] == 0)
328 || (buffer
[0] == 'M' && buffer
[1] == 'M' && buffer
[2] == 0 && buffer
[3] == '*'))
333 if (!png_sig_cmp(buffer
, 0, 8))
337 /* check for raw PPM or PGM */
338 if (buffer
[0] == 'P' && (buffer
[1] == '5' || buffer
[1] == '6'))
342 if (buffer
[0] == 0xff && buffer
[1] == 0xd8)
346 if (buffer
[0] == 'G' && buffer
[1] == 'I' && buffer
[2] == 'F')