Change to the linux kernel coding style
[wmaker-crm.git] / wrlib / load.c
Commit [+]AuthorDateLineData
9d2e6ef9 scottc1998-09-29 22:36:29 +00001/* load.c - load image from file
6830b057 dan2004-10-12 21:28:27 +00002 *
4153e2fd dan2003-01-16 23:30:45 +00003 * Raster graphics library
6830b057 dan2004-10-12 21:28:27 +00004 *
4153e2fd dan2003-01-16 23:30:45 +00005 * Copyright (c) 1997-2003 Alfredo K. Kojima
9d2e6ef9 scottc1998-09-29 22:36:29 +00006 *
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.
6830b057 dan2004-10-12 21:28:27 +000011 *
9d2e6ef9 scottc1998-09-29 22:36:29 +000012 * 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.
6830b057 dan2004-10-12 21:28:27 +000016 *
9d2e6ef9 scottc1998-09-29 22:36:29 +000017 * 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.
20 */
21
22#include <config.h>
23
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>
9af1c6c4 dan1998-10-21 14:43:47 +000032#include <assert.h>
9d2e6ef9 scottc1998-09-29 22:36:29 +000033
34#ifdef USE_PNG
35#include <png.h>
36#endif
37
38#include "wraster.h"
39
92b012e8 dan2002-09-15 20:37:41 +000040/* Silly hack for Windows systems with cygwin */
41#ifndef O_BINARY
42# define O_BINARY 0
43#endif
9d2e6ef9 scottc1998-09-29 22:36:29 +000044
45typedef struct RCachedImage {
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020046 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 */
9d2e6ef9 scottc1998-09-29 22:36:29 +000050} RCachedImage;
51
9d2e6ef9 scottc1998-09-29 22:36:29 +000052/*
53 * Size of image cache
54 */
55static int RImageCacheSize = -1;
56
57/*
58 * Max. size of image to store in cache
59 */
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020060static int RImageCacheMaxImage = -1; /* 0 = any size */
9d2e6ef9 scottc1998-09-29 22:36:29 +000061
62#define IMAGE_CACHE_SIZE 8
63
64#define IMAGE_CACHE_MAX_IMAGE 64*64
65
66static RCachedImage *RImageCache;
67
9d2e6ef9 scottc1998-09-29 22:36:29 +000068#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
79
9d2e6ef9 scottc1998-09-29 22:36:29 +000080static int identFile(char *path);
81
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020082extern RImage *RLoadPPM(RContext * context, char *file_name, int index);
9d2e6ef9 scottc1998-09-29 22:36:29 +000083
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020084extern RImage *RLoadXPM(RContext * context, char *file, int index);
9d2e6ef9 scottc1998-09-29 22:36:29 +000085
86#ifdef USE_TIFF
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020087extern RImage *RLoadTIFF(RContext * context, char *file, int index);
9d2e6ef9 scottc1998-09-29 22:36:29 +000088#endif
89#ifdef USE_PNG
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020090extern RImage *RLoadPNG(RContext * context, char *file, int index);
9d2e6ef9 scottc1998-09-29 22:36:29 +000091#endif
92#ifdef USE_JPEG
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020093extern RImage *RLoadJPEG(RContext * context, char *file_name, int index);
9d2e6ef9 scottc1998-09-29 22:36:29 +000094#endif
95#ifdef USE_GIF
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020096extern RImage *RLoadGIF(RContext * context, char *file_name, int index);
9d2e6ef9 scottc1998-09-29 22:36:29 +000097#endif
98
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +020099char **RSupportedFileFormats(void)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000100{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200101 static char *tmp[IM_TYPES + 1];
102 int i = 0;
e7495baf dan1999-02-17 11:06:40 +0000103
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200104 /* built-in */
105 tmp[i++] = "XPM";
106 /* built-in */
107 tmp[i++] = "PPM";
9d2e6ef9 scottc1998-09-29 22:36:29 +0000108#ifdef USE_TIFF
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200109 tmp[i++] = "TIFF";
9d2e6ef9 scottc1998-09-29 22:36:29 +0000110#endif
111#ifdef USE_PNG
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200112 tmp[i++] = "PNG";
9d2e6ef9 scottc1998-09-29 22:36:29 +0000113#endif
114#ifdef USE_JPEG
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200115 tmp[i++] = "JPEG";
9d2e6ef9 scottc1998-09-29 22:36:29 +0000116#endif
117#ifdef USE_GIF
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200118 tmp[i++] = "GIF";
9d2e6ef9 scottc1998-09-29 22:36:29 +0000119#endif
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200120 tmp[i] = NULL;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000121
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200122 return tmp;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000123}
124
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200125static void init_cache()
9d2e6ef9 scottc1998-09-29 22:36:29 +0000126{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200127 char *tmp;
128
129 tmp = getenv("RIMAGE_CACHE");
130 if (!tmp || sscanf(tmp, "%i", &RImageCacheSize) != 1) {
131 RImageCacheSize = IMAGE_CACHE_SIZE;
132 }
133 if (RImageCacheSize < 0)
134 RImageCacheSize = 0;
135
136 tmp = getenv("RIMAGE_CACHE_SIZE");
137 if (!tmp || sscanf(tmp, "%i", &RImageCacheMaxImage) != 1) {
138 RImageCacheMaxImage = IMAGE_CACHE_MAX_IMAGE;
139 }
140
141 if (RImageCacheSize > 0) {
142 RImageCache = malloc(sizeof(RCachedImage) * RImageCacheSize);
143 if (RImageCache == NULL) {
144 printf("wrlib: out of memory for image cache\n");
145 return;
146 }
147 memset(RImageCache, 0, sizeof(RCachedImage) * RImageCacheSize);
148 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000149}
150
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200151RImage *RLoadImage(RContext * context, char *file, int index)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000152{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200153 RImage *image = NULL;
154 int i;
155 struct stat st;
9af1c6c4 dan1998-10-21 14:43:47 +0000156
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200157 assert(file != NULL);
9af1c6c4 dan1998-10-21 14:43:47 +0000158
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200159 if (RImageCacheSize < 0) {
160 init_cache();
161 }
9af1c6c4 dan1998-10-21 14:43:47 +0000162
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200163 if (RImageCacheSize > 0) {
6830b057 dan2004-10-12 21:28:27 +0000164
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200165 for (i = 0; i < RImageCacheSize; i++) {
166 if (RImageCache[i].file && strcmp(file, RImageCache[i].file) == 0) {
6830b057 dan2004-10-12 21:28:27 +0000167
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200168 if (stat(file, &st) == 0 && st.st_mtime == RImageCache[i].last_modif) {
169 RImageCache[i].last_use = time(NULL);
6830b057 dan2004-10-12 21:28:27 +0000170
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200171 return RCloneImage(RImageCache[i].image);
6830b057 dan2004-10-12 21:28:27 +0000172
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200173 } else {
174 free(RImageCache[i].file);
175 RImageCache[i].file = NULL;
176 RReleaseImage(RImageCache[i].image);
177 }
178 }
179 }
180 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000181
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200182 switch (identFile(file)) {
183 case IM_ERROR:
184 return NULL;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000185
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200186 case IM_UNKNOWN:
187 RErrorCode = RERR_BADFORMAT;
188 return NULL;
6830b057 dan2004-10-12 21:28:27 +0000189
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200190 case IM_XPM:
191 image = RLoadXPM(context, file, index);
192 break;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000193
9d2e6ef9 scottc1998-09-29 22:36:29 +0000194#ifdef USE_TIFF
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200195 case IM_TIFF:
196 image = RLoadTIFF(context, file, index);
197 break;
198#endif /* USE_TIFF */
9d2e6ef9 scottc1998-09-29 22:36:29 +0000199
200#ifdef USE_PNG
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200201 case IM_PNG:
202 image = RLoadPNG(context, file, index);
203 break;
204#endif /* USE_PNG */
9d2e6ef9 scottc1998-09-29 22:36:29 +0000205
206#ifdef USE_JPEG
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200207 case IM_JPEG:
208 image = RLoadJPEG(context, file, index);
209 break;
210#endif /* USE_JPEG */
9d2e6ef9 scottc1998-09-29 22:36:29 +0000211
212#ifdef USE_GIF
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200213 case IM_GIF:
214 image = RLoadGIF(context, file, index);
215 break;
216#endif /* USE_GIF */
217
218 case IM_PPM:
219 image = RLoadPPM(context, file, index);
220 break;
221
222 default:
223 RErrorCode = RERR_BADFORMAT;
224 return NULL;
225 }
226
227 /* store image in cache */
228 if (RImageCacheSize > 0 && image &&
229 (RImageCacheMaxImage == 0 || RImageCacheMaxImage >= image->width * image->height)) {
230 time_t oldest = time(NULL);
231 int oldest_idx = 0;
232 int done = 0;
233
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);
241 done = 1;
242 break;
243 } else {
244 if (oldest > RImageCache[i].last_use) {
245 oldest = RImageCache[i].last_use;
246 oldest_idx = i;
247 }
248 }
249 }
250
251 /* if no slot available, dump least recently used one */
252 if (!done) {
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);
260 }
261 }
262
263 return image;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000264}
265
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200266char *RGetImageFileFormat(char *file)
088c0ac2 dan1999-03-09 14:58:01 +0000267{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200268 switch (identFile(file)) {
269 case IM_XPM:
270 return "XPM";
088c0ac2 dan1999-03-09 14:58:01 +0000271
272#ifdef USE_TIFF
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200273 case IM_TIFF:
274 return "TIFF";
275#endif /* USE_TIFF */
088c0ac2 dan1999-03-09 14:58:01 +0000276
277#ifdef USE_PNG
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200278 case IM_PNG:
279 return "PNG";
280#endif /* USE_PNG */
088c0ac2 dan1999-03-09 14:58:01 +0000281
282#ifdef USE_JPEG
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200283 case IM_JPEG:
284 return "JPEG";
285#endif /* USE_JPEG */
088c0ac2 dan1999-03-09 14:58:01 +0000286
287#ifdef USE_GIF
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200288 case IM_GIF:
289 return "GIF";
290#endif /* USE_GIF */
088c0ac2 dan1999-03-09 14:58:01 +0000291
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200292 case IM_PPM:
293 return "PPM";
9d2e6ef9 scottc1998-09-29 22:36:29 +0000294
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200295 default:
296 return NULL;
297 }
088c0ac2 dan1999-03-09 14:58:01 +0000298}
9d2e6ef9 scottc1998-09-29 22:36:29 +0000299
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200300static int identFile(char *path)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000301{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200302 int fd;
303 unsigned char buffer[32];
304
305 assert(path != NULL);
306
307 fd = open(path, O_RDONLY | O_BINARY);
308 if (fd < 0) {
309 RErrorCode = RERR_OPEN;
310 return IM_ERROR;
311 }
312 if (read(fd, buffer, 32) < 1) {
313 close(fd);
314 RErrorCode = RERR_READ;
315 return IM_ERROR;
316 }
317 close(fd);
318
319 /* check for XPM */
320 if (strncmp((char *)buffer, "/* XPM */", 9) == 0)
321 return IM_XPM;
322
323 /* check for TIFF */
324 if ((buffer[0] == 'I' && buffer[1] == 'I' && buffer[2] == '*' && buffer[3] == 0)
325 || (buffer[0] == 'M' && buffer[1] == 'M' && buffer[2] == 0 && buffer[3] == '*'))
326 return IM_TIFF;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000327
328#ifdef USE_PNG
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200329 /* check for PNG */
330 if (png_check_sig(buffer, 8))
331 return IM_PNG;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000332#endif
6830b057 dan2004-10-12 21:28:27 +0000333
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200334 /* check for raw PPM or PGM */
335 if (buffer[0] == 'P' && (buffer[1] == '5' || buffer[1] == '6'))
336 return IM_PPM;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000337
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200338 /* check for JPEG */
339 if (buffer[0] == 0xff && buffer[1] == 0xd8)
340 return IM_JPEG;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000341
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200342 /* check for GIF */
343 if (buffer[0] == 'G' && buffer[1] == 'I' && buffer[2] == 'F')
344 return IM_GIF;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000345
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200346 return IM_UNKNOWN;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000347}