IMG_tif.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 18 Jul 2007 07:32:56 +0000
changeset 167 338c85983115
parent 154 201cc5c1b373
child 186 5fbbeabf647f
permissions -rw-r--r--
* PNG and TIFF images are correctly identified even if dynamic libraries
to load them aren't available.
* Fixed loading of TIFF images using libtiff 3.6
slouken@0
     1
/*
slouken@53
     2
    SDL_image:  An example image loading library for use with SDL
slouken@121
     3
    Copyright (C) 1997-2006 Sam Lantinga
slouken@0
     4
slouken@0
     5
    This library is free software; you can redistribute it and/or
slouken@121
     6
    modify it under the terms of the GNU Lesser General Public
slouken@0
     7
    License as published by the Free Software Foundation; either
slouken@121
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
    This library is distributed in the hope that it will be useful,
slouken@0
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@121
    13
    Lesser General Public License for more details.
slouken@0
    14
slouken@121
    15
    You should have received a copy of the GNU Lesser General Public
slouken@121
    16
    License along with this library; if not, write to the Free Software
slouken@121
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@0
    18
slouken@0
    19
    Sam Lantinga
slouken@53
    20
    slouken@libsdl.org
slouken@53
    21
*/
slouken@0
    22
slouken@0
    23
/* This is a TIFF image file loading framework */
slouken@0
    24
slouken@0
    25
#include <stdio.h>
slouken@0
    26
slouken@0
    27
#include "SDL_image.h"
slouken@0
    28
slouken@0
    29
#ifdef LOAD_TIF
slouken@0
    30
slouken@0
    31
#include <tiffio.h>
slouken@0
    32
slouken@143
    33
static struct {
slouken@143
    34
	int loaded;
slouken@143
    35
	void *handle;
slouken@143
    36
	TIFF* (*TIFFClientOpen)(const char*, const char*, thandle_t, TIFFReadWriteProc, TIFFReadWriteProc, TIFFSeekProc, TIFFCloseProc, TIFFSizeProc, TIFFMapFileProc, TIFFUnmapFileProc);
slouken@143
    37
	void (*TIFFClose)(TIFF*);
slouken@143
    38
	int (*TIFFGetField)(TIFF*, ttag_t, ...);
slouken@143
    39
	int (*TIFFReadRGBAImage)(TIFF*, uint32, uint32, uint32*, int);
slouken@143
    40
	TIFFErrorHandler (*TIFFSetErrorHandler)(TIFFErrorHandler);
slouken@143
    41
} lib;
slouken@143
    42
slouken@143
    43
#ifdef LOAD_TIF_DYNAMIC
slouken@143
    44
int IMG_InitTIF()
slouken@143
    45
{
slouken@143
    46
	if ( lib.loaded == 0 ) {
slouken@143
    47
		lib.handle = SDL_LoadObject(LOAD_TIF_DYNAMIC);
slouken@143
    48
		if ( lib.handle == NULL ) {
slouken@143
    49
			return -1;
slouken@143
    50
		}
slouken@143
    51
		lib.TIFFClientOpen =
slouken@143
    52
			(TIFF* (*)(const char*, const char*, thandle_t, TIFFReadWriteProc, TIFFReadWriteProc, TIFFSeekProc, TIFFCloseProc, TIFFSizeProc, TIFFMapFileProc, TIFFUnmapFileProc))
slouken@143
    53
			SDL_LoadFunction(lib.handle, "TIFFClientOpen");
slouken@143
    54
		if ( lib.TIFFClientOpen == NULL ) {
slouken@143
    55
			SDL_UnloadObject(lib.handle);
slouken@143
    56
			return -1;
slouken@143
    57
		}
slouken@143
    58
		lib.TIFFClose =
slouken@143
    59
			(void (*)(TIFF*))
slouken@143
    60
			SDL_LoadFunction(lib.handle, "TIFFClose");
slouken@143
    61
		if ( lib.TIFFClose == NULL ) {
slouken@143
    62
			SDL_UnloadObject(lib.handle);
slouken@143
    63
			return -1;
slouken@143
    64
		}
slouken@143
    65
		lib.TIFFGetField =
slouken@143
    66
			(int (*)(TIFF*, ttag_t, ...))
slouken@143
    67
			SDL_LoadFunction(lib.handle, "TIFFGetField");
slouken@143
    68
		if ( lib.TIFFGetField == NULL ) {
slouken@143
    69
			SDL_UnloadObject(lib.handle);
slouken@143
    70
			return -1;
slouken@143
    71
		}
slouken@143
    72
		lib.TIFFReadRGBAImage =
slouken@143
    73
			(int (*)(TIFF*, uint32, uint32, uint32*, int))
slouken@143
    74
			SDL_LoadFunction(lib.handle, "TIFFReadRGBAImage");
slouken@143
    75
		if ( lib.TIFFReadRGBAImage == NULL ) {
slouken@143
    76
			SDL_UnloadObject(lib.handle);
slouken@143
    77
			return -1;
slouken@143
    78
		}
slouken@143
    79
		lib.TIFFSetErrorHandler =
slouken@143
    80
			(TIFFErrorHandler (*)(TIFFErrorHandler))
slouken@143
    81
			SDL_LoadFunction(lib.handle, "TIFFSetErrorHandler");
slouken@143
    82
		if ( lib.TIFFSetErrorHandler == NULL ) {
slouken@143
    83
			SDL_UnloadObject(lib.handle);
slouken@143
    84
			return -1;
slouken@143
    85
		}
slouken@143
    86
	}
slouken@143
    87
	++lib.loaded;
slouken@143
    88
slouken@143
    89
	return 0;
slouken@143
    90
}
slouken@143
    91
void IMG_QuitTIF()
slouken@143
    92
{
slouken@143
    93
	if ( lib.loaded == 0 ) {
slouken@143
    94
		return;
slouken@143
    95
	}
slouken@143
    96
	if ( lib.loaded == 1 ) {
slouken@143
    97
		SDL_UnloadObject(lib.handle);
slouken@143
    98
	}
slouken@143
    99
	--lib.loaded;
slouken@143
   100
}
slouken@143
   101
#else
slouken@143
   102
int IMG_InitTIF()
slouken@143
   103
{
slouken@143
   104
	if ( lib.loaded == 0 ) {
slouken@143
   105
		lib.TIFFClientOpen = TIFFClientOpen;
slouken@143
   106
		lib.TIFFClose = TIFFClose;
slouken@143
   107
		lib.TIFFGetField = TIFFGetField;
slouken@143
   108
		lib.TIFFReadRGBAImage = TIFFReadRGBAImage;
slouken@143
   109
		lib.TIFFSetErrorHandler = TIFFSetErrorHandler;
slouken@143
   110
	}
slouken@143
   111
	++lib.loaded;
slouken@146
   112
slouken@146
   113
	return 0;
slouken@143
   114
}
slouken@143
   115
void IMG_QuitTIF()
slouken@143
   116
{
slouken@143
   117
	if ( lib.loaded == 0 ) {
slouken@143
   118
		return;
slouken@143
   119
	}
slouken@143
   120
	if ( lib.loaded == 1 ) {
slouken@143
   121
	}
slouken@143
   122
	--lib.loaded;
slouken@143
   123
}
slouken@143
   124
#endif /* LOAD_TIF_DYNAMIC */
slouken@143
   125
slouken@0
   126
/*
slouken@0
   127
 * These are the thunking routine to use the SDL_RWops* routines from
slouken@0
   128
 * libtiff's internals.
slouken@0
   129
*/
slouken@0
   130
slouken@0
   131
static tsize_t tiff_read(thandle_t fd, tdata_t buf, tsize_t size)
slouken@0
   132
{
slouken@0
   133
	return SDL_RWread((SDL_RWops*)fd, buf, 1, size);
slouken@0
   134
}
slouken@0
   135
slouken@0
   136
static toff_t tiff_seek(thandle_t fd, toff_t offset, int origin)
slouken@0
   137
{
slouken@0
   138
	return SDL_RWseek((SDL_RWops*)fd, offset, origin);
slouken@0
   139
}
slouken@0
   140
slouken@0
   141
static tsize_t tiff_write(thandle_t fd, tdata_t buf, tsize_t size)
slouken@0
   142
{
slouken@0
   143
	return SDL_RWwrite((SDL_RWops*)fd, buf, 1, size);
slouken@0
   144
}
slouken@0
   145
slouken@0
   146
static int tiff_close(thandle_t fd)
slouken@0
   147
{
slouken@0
   148
	/*
slouken@0
   149
	 * We don't want libtiff closing our SDL_RWops*, but if it's not given
slouken@0
   150
         * a routine to try, and if the image isn't a TIFF, it'll segfault.
slouken@0
   151
	 */
slouken@0
   152
	return 0;
slouken@0
   153
}
slouken@0
   154
slouken@167
   155
static int tiff_map(thandle_t fd, tdata_t* pbase, toff_t* psize)
slouken@167
   156
{
slouken@167
   157
	return (0);
slouken@167
   158
}
slouken@167
   159
slouken@167
   160
static void tiff_unmap(thandle_t fd, tdata_t base, toff_t size)
slouken@167
   161
{
slouken@167
   162
	return;
slouken@167
   163
}
slouken@167
   164
slouken@0
   165
static toff_t tiff_size(thandle_t fd)
slouken@0
   166
{
slouken@0
   167
	Uint32 save_pos;
slouken@0
   168
	toff_t size;
slouken@0
   169
slouken@0
   170
	save_pos = SDL_RWtell((SDL_RWops*)fd);
slouken@0
   171
	SDL_RWseek((SDL_RWops*)fd, 0, SEEK_END);
slouken@0
   172
        size = SDL_RWtell((SDL_RWops*)fd);
slouken@0
   173
	SDL_RWseek((SDL_RWops*)fd, save_pos, SEEK_SET);
slouken@0
   174
	return size;
slouken@0
   175
}
slouken@0
   176
slouken@0
   177
int IMG_isTIF(SDL_RWops* src)
slouken@0
   178
{
slouken@117
   179
	int start;
slouken@117
   180
	int is_TIF;
slouken@167
   181
	Uint8 magic[4];
slouken@0
   182
icculus@154
   183
	if ( !src )
icculus@154
   184
		return 0;
slouken@117
   185
	start = SDL_RWtell(src);
slouken@117
   186
	is_TIF = 0;
slouken@167
   187
	if ( SDL_RWread(src, magic, 1, sizeof(magic)) == sizeof(magic) ) {
slouken@167
   188
		if ( (magic[0] == 'I' &&
slouken@167
   189
                      magic[1] == 'I' &&
slouken@167
   190
		      magic[2] == 0x2a &&
slouken@167
   191
                      magic[3] == 0x00) ||
slouken@167
   192
		     (magic[0] == 'M' &&
slouken@167
   193
                      magic[1] == 'M' &&
slouken@167
   194
		      magic[2] == 0x00 &&
slouken@167
   195
                      magic[3] == 0x2a) ) {
slouken@167
   196
			is_TIF = 1;
slouken@167
   197
		}
slouken@117
   198
	}
slouken@117
   199
	SDL_RWseek(src, start, SEEK_SET);
slouken@117
   200
	return(is_TIF);
slouken@0
   201
}
slouken@0
   202
slouken@0
   203
SDL_Surface* IMG_LoadTIF_RW(SDL_RWops* src)
slouken@0
   204
{
slouken@118
   205
	int start;
slouken@0
   206
	TIFF* tiff;
slouken@0
   207
	SDL_Surface* surface = NULL;
slouken@0
   208
	Uint32 img_width, img_height;
slouken@145
   209
	Uint32 Rmask, Gmask, Bmask, Amask;
slouken@0
   210
	Uint32 x, y;
slouken@0
   211
	Uint32 half;
slouken@0
   212
slouken@98
   213
	if ( !src ) {
slouken@98
   214
		/* The error message has been set in SDL_RWFromFile */
slouken@98
   215
		return NULL;
slouken@98
   216
	}
slouken@118
   217
	start = SDL_RWtell(src);
slouken@0
   218
slouken@143
   219
	if ( IMG_InitTIF() < 0 ) {
slouken@143
   220
		return NULL;
slouken@143
   221
	}
slouken@143
   222
slouken@0
   223
	/* turn off memory mapped access with the m flag */
slouken@143
   224
	tiff = lib.TIFFClientOpen("SDL_image", "rm", (thandle_t)src, 
slouken@167
   225
		tiff_read, tiff_write, tiff_seek, tiff_close, tiff_size, tiff_map, tiff_unmap);
slouken@0
   226
	if(!tiff)
slouken@118
   227
		goto error;
slouken@0
   228
slouken@0
   229
	/* Retrieve the dimensions of the image from the TIFF tags */
slouken@143
   230
	lib.TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &img_width);
slouken@143
   231
	lib.TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &img_height);
slouken@0
   232
slouken@4
   233
	Rmask = 0x000000FF;
slouken@4
   234
	Gmask = 0x0000FF00;
slouken@4
   235
	Bmask = 0x00FF0000;
slouken@4
   236
	Amask = 0xFF000000;
slouken@0
   237
	surface = SDL_AllocSurface(SDL_SWSURFACE, img_width, img_height, 32,
slouken@0
   238
		Rmask, Gmask, Bmask, Amask);
slouken@0
   239
	if(!surface)
slouken@118
   240
		goto error;
slouken@0
   241
	
slouken@143
   242
	if(!lib.TIFFReadRGBAImage(tiff, img_width, img_height, surface->pixels, 0))
slouken@118
   243
		goto error;
slouken@0
   244
slouken@4
   245
	/* libtiff loads the image upside-down, flip it back */
slouken@0
   246
	half = img_height / 2;
slouken@4
   247
	for(y = 0; y < half; y++)
slouken@0
   248
	{
slouken@4
   249
	        Uint32 *top = (Uint32 *)surface->pixels + y * surface->pitch/4;
slouken@4
   250
	        Uint32 *bot = (Uint32 *)surface->pixels
slouken@4
   251
		              + (img_height - y - 1) * surface->pitch/4;
slouken@0
   252
		for(x = 0; x < img_width; x++)
slouken@0
   253
		{
slouken@4
   254
		        Uint32 tmp = top[x];
slouken@4
   255
			top[x] = bot[x];
slouken@4
   256
			bot[x] = tmp;
slouken@0
   257
		}
slouken@0
   258
	}
slouken@143
   259
	lib.TIFFClose(tiff);
slouken@143
   260
	IMG_QuitTIF();
slouken@0
   261
	
slouken@0
   262
	return surface;
slouken@118
   263
slouken@118
   264
error:
slouken@118
   265
	SDL_RWseek(src, start, SEEK_SET);
slouken@118
   266
	if ( surface ) {
slouken@118
   267
		SDL_FreeSurface(surface);
slouken@118
   268
	}
slouken@143
   269
	IMG_QuitTIF();
slouken@118
   270
	return NULL;
slouken@0
   271
}
slouken@0
   272
slouken@0
   273
#else
slouken@0
   274
slouken@0
   275
/* See if an image is contained in a data source */
slouken@0
   276
int IMG_isTIF(SDL_RWops *src)
slouken@0
   277
{
slouken@0
   278
	return(0);
slouken@0
   279
}
slouken@0
   280
slouken@0
   281
/* Load a TIFF type image from an SDL datasource */
slouken@0
   282
SDL_Surface *IMG_LoadTIF_RW(SDL_RWops *src)
slouken@0
   283
{
slouken@0
   284
	return(NULL);
slouken@0
   285
}
slouken@0
   286
slouken@0
   287
#endif /* LOAD_TIF */