Files
wmaker/wrlib/load.c
T

351 lines
7.2 KiB
C
Raw Normal View History

1998-09-29 22:36:29 +00:00
/* load.c - load image from file
2004-10-12 21:28:27 +00:00
*
2003-01-16 23:30:45 +00:00
* Raster graphics library
2004-10-12 21:28:27 +00:00
*
2003-01-16 23:30:45 +00:00
* Copyright (c) 1997-2003 Alfredo K. Kojima
1998-09-29 22:36:29 +00:00
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
2004-10-12 21:28:27 +00:00
*
1998-09-29 22:36:29 +00:00
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
2004-10-12 21:28:27 +00:00
*
1998-09-29 22:36:29 +00:00
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
2010-03-26 20:25:27 +01:00
#include <errno.h>
1998-09-29 22:36:29 +00:00
#include <X11/Xlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <time.h>
1998-10-21 14:43:47 +00:00
#include <assert.h>
1998-09-29 22:36:29 +00:00
#ifdef USE_PNG
#include <png.h>
#endif
#include "wraster.h"
2010-03-26 20:25:27 +01:00
#define RETRY( x ) do { \
x; \
} while (errno == EINTR);
1998-09-29 22:36:29 +00:00
typedef struct RCachedImage {
2009-08-20 00:59:40 +02:00
RImage *image;
char *file;
time_t last_modif; /* last time file was modified */
time_t last_use; /* last time image was used */
1998-09-29 22:36:29 +00:00
} RCachedImage;
/*
* Size of image cache
*/
static int RImageCacheSize = -1;
/*
* Max. size of image to store in cache
*/
2009-08-20 00:59:40 +02:00
static int RImageCacheMaxImage = -1; /* 0 = any size */
1998-09-29 22:36:29 +00:00
#define IMAGE_CACHE_SIZE 8
#define IMAGE_CACHE_MAX_IMAGE 64*64
static RCachedImage *RImageCache;
#define IM_ERROR -1
#define IM_UNKNOWN 0
#define IM_XPM 1
#define IM_TIFF 2
#define IM_PNG 3
#define IM_PPM 4
#define IM_JPEG 5
#define IM_GIF 6
/* How many image types do we have. */
/* Increase this when adding new image types! */
#define IM_TYPES 6
static int identFile(char *path);
2010-04-03 18:13:13 +02:00
extern RImage *RLoadPPM(char *file_name);
1998-09-29 22:36:29 +00:00
2010-04-03 18:13:13 +02:00
extern RImage *RLoadXPM(RContext * context, char *file);
1998-09-29 22:36:29 +00:00
#ifdef USE_TIFF
2010-04-03 18:13:13 +02:00
extern RImage *RLoadTIFF(char *file, int index);
1998-09-29 22:36:29 +00:00
#endif
#ifdef USE_PNG
2010-04-03 18:13:13 +02:00
extern RImage *RLoadPNG(RContext * context, char *file);
1998-09-29 22:36:29 +00:00
#endif
#ifdef USE_JPEG
2010-04-03 18:13:13 +02:00
extern RImage *RLoadJPEG(RContext * context, char *file_name);
1998-09-29 22:36:29 +00:00
#endif
#ifdef USE_GIF
2010-04-03 18:13:13 +02:00
extern RImage *RLoadGIF(char *file_name, int index);
1998-09-29 22:36:29 +00:00
#endif
2009-08-20 00:59:40 +02:00
char **RSupportedFileFormats(void)
1998-09-29 22:36:29 +00:00
{
2009-08-20 00:59:40 +02:00
static char *tmp[IM_TYPES + 1];
int i = 0;
2009-08-20 00:59:40 +02:00
/* built-in */
tmp[i++] = "XPM";
/* built-in */
tmp[i++] = "PPM";
1998-09-29 22:36:29 +00:00
#ifdef USE_TIFF
2009-08-20 00:59:40 +02:00
tmp[i++] = "TIFF";
1998-09-29 22:36:29 +00:00
#endif
#ifdef USE_PNG
2009-08-20 00:59:40 +02:00
tmp[i++] = "PNG";
1998-09-29 22:36:29 +00:00
#endif
#ifdef USE_JPEG
2009-08-20 00:59:40 +02:00
tmp[i++] = "JPEG";
1998-09-29 22:36:29 +00:00
#endif
#ifdef USE_GIF
2009-08-20 00:59:40 +02:00
tmp[i++] = "GIF";
1998-09-29 22:36:29 +00:00
#endif
2009-08-20 00:59:40 +02:00
tmp[i] = NULL;
1998-09-29 22:36:29 +00:00
2009-08-20 00:59:40 +02:00
return tmp;
1998-09-29 22:36:29 +00:00
}
2009-08-20 00:59:40 +02:00
static void init_cache()
1998-09-29 22:36:29 +00:00
{
2009-08-20 00:59:40 +02:00
char *tmp;
tmp = getenv("RIMAGE_CACHE");
if (!tmp || sscanf(tmp, "%i", &RImageCacheSize) != 1) {
RImageCacheSize = IMAGE_CACHE_SIZE;
}
if (RImageCacheSize < 0)
RImageCacheSize = 0;
tmp = getenv("RIMAGE_CACHE_SIZE");
if (!tmp || sscanf(tmp, "%i", &RImageCacheMaxImage) != 1) {
RImageCacheMaxImage = IMAGE_CACHE_MAX_IMAGE;
}
if (RImageCacheSize > 0) {
RImageCache = malloc(sizeof(RCachedImage) * RImageCacheSize);
if (RImageCache == NULL) {
printf("wrlib: out of memory for image cache\n");
return;
}
memset(RImageCache, 0, sizeof(RCachedImage) * RImageCacheSize);
}
1998-09-29 22:36:29 +00:00
}
2009-08-20 00:59:40 +02:00
RImage *RLoadImage(RContext * context, char *file, int index)
1998-09-29 22:36:29 +00:00
{
2009-08-20 00:59:40 +02:00
RImage *image = NULL;
int i;
struct stat st;
1998-10-21 14:43:47 +00:00
2009-08-20 00:59:40 +02:00
assert(file != NULL);
1998-10-21 14:43:47 +00:00
2009-08-20 00:59:40 +02:00
if (RImageCacheSize < 0) {
init_cache();
}
1998-10-21 14:43:47 +00:00
2009-08-20 00:59:40 +02:00
if (RImageCacheSize > 0) {
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
for (i = 0; i < RImageCacheSize; i++) {
if (RImageCache[i].file && strcmp(file, RImageCache[i].file) == 0) {
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
if (stat(file, &st) == 0 && st.st_mtime == RImageCache[i].last_modif) {
RImageCache[i].last_use = time(NULL);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
return RCloneImage(RImageCache[i].image);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
} else {
free(RImageCache[i].file);
RImageCache[i].file = NULL;
RReleaseImage(RImageCache[i].image);
}
}
}
}
1998-09-29 22:36:29 +00:00
2009-08-20 00:59:40 +02:00
switch (identFile(file)) {
case IM_ERROR:
return NULL;
1998-09-29 22:36:29 +00:00
2009-08-20 00:59:40 +02:00
case IM_UNKNOWN:
RErrorCode = RERR_BADFORMAT;
return NULL;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
case IM_XPM:
2010-04-03 18:13:13 +02:00
image = RLoadXPM(context, file);
2009-08-20 00:59:40 +02:00
break;
1998-09-29 22:36:29 +00:00
#ifdef USE_TIFF
2009-08-20 00:59:40 +02:00
case IM_TIFF:
2010-04-03 18:13:13 +02:00
image = RLoadTIFF(file, index);
2009-08-20 00:59:40 +02:00
break;
#endif /* USE_TIFF */
1998-09-29 22:36:29 +00:00
#ifdef USE_PNG
2009-08-20 00:59:40 +02:00
case IM_PNG:
2010-04-03 18:13:13 +02:00
image = RLoadPNG(context, file);
2009-08-20 00:59:40 +02:00
break;
#endif /* USE_PNG */
1998-09-29 22:36:29 +00:00
#ifdef USE_JPEG
2009-08-20 00:59:40 +02:00
case IM_JPEG:
2010-04-03 18:13:13 +02:00
image = RLoadJPEG(context, file);
2009-08-20 00:59:40 +02:00
break;
#endif /* USE_JPEG */
1998-09-29 22:36:29 +00:00
#ifdef USE_GIF
2009-08-20 00:59:40 +02:00
case IM_GIF:
2010-04-03 18:13:13 +02:00
image = RLoadGIF(file, index);
2009-08-20 00:59:40 +02:00
break;
#endif /* USE_GIF */
case IM_PPM:
2010-04-03 18:13:13 +02:00
image = RLoadPPM(file);
2009-08-20 00:59:40 +02:00
break;
default:
RErrorCode = RERR_BADFORMAT;
return NULL;
}
/* store image in cache */
if (RImageCacheSize > 0 && image &&
(RImageCacheMaxImage == 0 || RImageCacheMaxImage >= image->width * image->height)) {
time_t oldest = time(NULL);
int oldest_idx = 0;
int done = 0;
for (i = 0; i < RImageCacheSize; i++) {
if (!RImageCache[i].file) {
RImageCache[i].file = malloc(strlen(file) + 1);
strcpy(RImageCache[i].file, file);
RImageCache[i].image = RCloneImage(image);
RImageCache[i].last_modif = st.st_mtime;
RImageCache[i].last_use = time(NULL);
done = 1;
break;
} else {
if (oldest > RImageCache[i].last_use) {
oldest = RImageCache[i].last_use;
oldest_idx = i;
}
}
}
/* if no slot available, dump least recently used one */
if (!done) {
free(RImageCache[oldest_idx].file);
RReleaseImage(RImageCache[oldest_idx].image);
RImageCache[oldest_idx].file = malloc(strlen(file) + 1);
strcpy(RImageCache[oldest_idx].file, file);
RImageCache[oldest_idx].image = RCloneImage(image);
RImageCache[oldest_idx].last_modif = st.st_mtime;
RImageCache[oldest_idx].last_use = time(NULL);
}
}
return image;
1998-09-29 22:36:29 +00:00
}
2009-08-20 00:59:40 +02:00
char *RGetImageFileFormat(char *file)
1999-03-09 14:58:01 +00:00
{
2009-08-20 00:59:40 +02:00
switch (identFile(file)) {
case IM_XPM:
return "XPM";
1999-03-09 14:58:01 +00:00
#ifdef USE_TIFF
2009-08-20 00:59:40 +02:00
case IM_TIFF:
return "TIFF";
#endif /* USE_TIFF */
1999-03-09 14:58:01 +00:00
#ifdef USE_PNG
2009-08-20 00:59:40 +02:00
case IM_PNG:
return "PNG";
#endif /* USE_PNG */
1999-03-09 14:58:01 +00:00
#ifdef USE_JPEG
2009-08-20 00:59:40 +02:00
case IM_JPEG:
return "JPEG";
#endif /* USE_JPEG */
1999-03-09 14:58:01 +00:00
#ifdef USE_GIF
2009-08-20 00:59:40 +02:00
case IM_GIF:
return "GIF";
#endif /* USE_GIF */
1999-03-09 14:58:01 +00:00
2009-08-20 00:59:40 +02:00
case IM_PPM:
return "PPM";
1998-09-29 22:36:29 +00:00
2009-08-20 00:59:40 +02:00
default:
return NULL;
}
1999-03-09 14:58:01 +00:00
}
1998-09-29 22:36:29 +00:00
2009-08-20 00:59:40 +02:00
static int identFile(char *path)
1998-09-29 22:36:29 +00:00
{
2010-03-26 20:25:27 +01:00
FILE *file;
2009-08-20 00:59:40 +02:00
unsigned char buffer[32];
2010-03-26 20:25:27 +01:00
size_t nread;
2009-08-20 00:59:40 +02:00
assert(path != NULL);
2010-03-26 20:25:27 +01:00
RETRY( file = fopen(path, "rb") )
if (file == NULL) {
2009-08-20 00:59:40 +02:00
RErrorCode = RERR_OPEN;
return IM_ERROR;
}
2010-03-26 20:25:27 +01:00
RETRY( nread = fread(buffer, 1, sizeof(buffer), file) )
if (nread < sizeof(buffer) || ferror(file)) {
RETRY( fclose(file) )
2009-08-20 00:59:40 +02:00
RErrorCode = RERR_READ;
return IM_ERROR;
}
2010-03-26 20:25:27 +01:00
RETRY( fclose(file) )
2009-08-20 00:59:40 +02:00
/* check for XPM */
if (strncmp((char *)buffer, "/* XPM */", 9) == 0)
return IM_XPM;
/* check for TIFF */
if ((buffer[0] == 'I' && buffer[1] == 'I' && buffer[2] == '*' && buffer[3] == 0)
|| (buffer[0] == 'M' && buffer[1] == 'M' && buffer[2] == 0 && buffer[3] == '*'))
return IM_TIFF;
1998-09-29 22:36:29 +00:00
#ifdef USE_PNG
2009-08-20 00:59:40 +02:00
/* check for PNG */
2010-03-29 11:30:47 +02:00
if (!png_sig_cmp(buffer, 0, 8))
2009-08-20 00:59:40 +02:00
return IM_PNG;
1998-09-29 22:36:29 +00:00
#endif
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
/* check for raw PPM or PGM */
if (buffer[0] == 'P' && (buffer[1] == '5' || buffer[1] == '6'))
return IM_PPM;
1998-09-29 22:36:29 +00:00
2009-08-20 00:59:40 +02:00
/* check for JPEG */
if (buffer[0] == 0xff && buffer[1] == 0xd8)
return IM_JPEG;
1998-09-29 22:36:29 +00:00
2009-08-20 00:59:40 +02:00
/* check for GIF */
if (buffer[0] == 'G' && buffer[1] == 'I' && buffer[2] == 'F')
return IM_GIF;
1998-09-29 22:36:29 +00:00
2009-08-20 00:59:40 +02:00
return IM_UNKNOWN;
1998-09-29 22:36:29 +00:00
}