From a5facf66d3e2f534a40a459a8691cff250ea4812 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Fri, 12 May 2006 05:08:03 +0000 Subject: [PATCH] Added support for dynamically loading libjpeg, libpng, and libtiff. --- CHANGES | 2 + IMG_jpg.c | 159 +++++++++++++++++++++++++++++++--- IMG_png.c | 239 +++++++++++++++++++++++++++++++++++++++++++++++---- IMG_tif.c | 119 +++++++++++++++++++++++-- configure.in | 100 ++++++++++++++++++--- 5 files changed, 569 insertions(+), 50 deletions(-) diff --git a/CHANGES b/CHANGES index 9cd53472..24dfc587 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,6 @@ 1.2.5: +Sam Lantinga - Thu May 11 21:51:19 PDT 2006 + * Added support for dynamically loading libjpeg, libpng, and libtiff. Sam Lantinga - Sun Apr 30 01:48:40 PDT 2006 * Added gcc-fat.sh for generating Universal binaries on Mac OS X * Updated libtool support to version 1.5.22 diff --git a/IMG_jpg.c b/IMG_jpg.c index c7e2c49d..2dfb47e7 100644 --- a/IMG_jpg.c +++ b/IMG_jpg.c @@ -38,6 +38,133 @@ /* Define this for quicker (but less perfect) JPEG identification */ #define FAST_IS_JPEG +static struct { + int loaded; + void *handle; + void (*jpeg_calc_output_dimensions) (j_decompress_ptr cinfo); + void (*jpeg_CreateDecompress) (j_decompress_ptr cinfo, int version, size_t structsize); + void (*jpeg_destroy_decompress) (j_decompress_ptr cinfo); + boolean (*jpeg_finish_decompress) (j_decompress_ptr cinfo); + int (*jpeg_read_header) (j_decompress_ptr cinfo, boolean require_image); + JDIMENSION (*jpeg_read_scanlines) (j_decompress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION max_lines); + boolean (*jpeg_resync_to_restart) (j_decompress_ptr cinfo, int desired); + boolean (*jpeg_start_decompress) (j_decompress_ptr cinfo); + struct jpeg_error_mgr * (*jpeg_std_error) (struct jpeg_error_mgr * err); +} lib; + +#ifdef LOAD_JPG_DYNAMIC +int IMG_InitJPG() +{ + if ( lib.loaded == 0 ) { + lib.handle = SDL_LoadObject(LOAD_JPG_DYNAMIC); + if ( lib.handle == NULL ) { + return -1; + } + lib.jpeg_calc_output_dimensions = + (void (*) (j_decompress_ptr)) + SDL_LoadFunction(lib.handle, "jpeg_calc_output_dimensions"); + if ( lib.jpeg_calc_output_dimensions == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.jpeg_CreateDecompress = + (void (*) (j_decompress_ptr, int, size_t)) + SDL_LoadFunction(lib.handle, "jpeg_CreateDecompress"); + if ( lib.jpeg_CreateDecompress == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.jpeg_destroy_decompress = + (void (*) (j_decompress_ptr)) + SDL_LoadFunction(lib.handle, "jpeg_destroy_decompress"); + if ( lib.jpeg_destroy_decompress == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.jpeg_finish_decompress = + (boolean (*) (j_decompress_ptr)) + SDL_LoadFunction(lib.handle, "jpeg_finish_decompress"); + if ( lib.jpeg_finish_decompress == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.jpeg_read_header = + (int (*) (j_decompress_ptr, boolean)) + SDL_LoadFunction(lib.handle, "jpeg_read_header"); + if ( lib.jpeg_read_header == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.jpeg_read_scanlines = + (JDIMENSION (*) (j_decompress_ptr, JSAMPARRAY, JDIMENSION)) + SDL_LoadFunction(lib.handle, "jpeg_read_scanlines"); + if ( lib.jpeg_read_scanlines == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.jpeg_resync_to_restart = + (boolean (*) (j_decompress_ptr, int)) + SDL_LoadFunction(lib.handle, "jpeg_resync_to_restart"); + if ( lib.jpeg_resync_to_restart == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.jpeg_start_decompress = + (boolean (*) (j_decompress_ptr)) + SDL_LoadFunction(lib.handle, "jpeg_start_decompress"); + if ( lib.jpeg_start_decompress == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.jpeg_std_error = + (struct jpeg_error_mgr * (*) (struct jpeg_error_mgr *)) + SDL_LoadFunction(lib.handle, "jpeg_std_error"); + if ( lib.jpeg_std_error == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + } + ++lib.loaded; + + return 0; +} +void IMG_QuitJPG() +{ + if ( lib.loaded == 0 ) { + return; + } + if ( lib.loaded == 1 ) { + SDL_UnloadObject(lib.handle); + } + --lib.loaded; +} +#else +int IMG_InitJPG() +{ + if ( lib.loaded == 0 ) { + lib.jpeg_calc_output_dimensions = jpeg_calc_output_dimensions; + lib.jpeg_CreateDecompress = jpeg_CreateDecompress; + lib.jpeg_destroy_decompress = jpeg_destroy_decompress; + lib.jpeg_finish_decompress = jpeg_finish_decompress; + lib.jpeg_read_header = jpeg_read_header; + lib.jpeg_read_scanlines = jpeg_read_scanlines; + lib.jpeg_resync_to_restart = jpeg_resync_to_restart; + lib.jpeg_start_decompress = jpeg_start_decompress; + lib.jpeg_std_error = jpeg_std_error; + } + ++lib.loaded; +} +void IMG_QuitJPG() +{ + if ( lib.loaded == 0 ) { + return; + } + if ( lib.loaded == 1 ) { + } + --lib.loaded; +} +#endif /* LOAD_JPG_DYNAMIC */ + /* See if an image is contained in a data source */ int IMG_isJPG(SDL_RWops *src) { @@ -210,7 +337,7 @@ static void jpeg_SDL_RW_src (j_decompress_ptr cinfo, SDL_RWops *ctx) src->pub.init_source = init_source; src->pub.fill_input_buffer = fill_input_buffer; src->pub.skip_input_data = skip_input_data; - src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.resync_to_restart = lib.jpeg_resync_to_restart; /* use default method */ src->pub.term_source = term_source; src->ctx = ctx; src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ @@ -248,30 +375,35 @@ SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src) } start = SDL_RWtell(src); + if ( IMG_InitJPG() < 0 ) { + return NULL; + } + /* Create a decompression structure and load the JPEG header */ - cinfo.err = jpeg_std_error(&jerr.errmgr); + cinfo.err = lib.jpeg_std_error(&jerr.errmgr); jerr.errmgr.error_exit = my_error_exit; jerr.errmgr.output_message = output_no_message; if(setjmp(jerr.escape)) { /* If we get here, libjpeg found an error */ - jpeg_destroy_decompress(&cinfo); + lib.jpeg_destroy_decompress(&cinfo); if ( surface != NULL ) { SDL_FreeSurface(surface); } SDL_RWseek(src, start, SEEK_SET); + IMG_QuitJPG(); IMG_SetError("JPEG loading error"); return NULL; } - jpeg_create_decompress(&cinfo); + lib.jpeg_create_decompress(&cinfo); jpeg_SDL_RW_src(&cinfo, src); - jpeg_read_header(&cinfo, TRUE); + lib.jpeg_read_header(&cinfo, TRUE); if(cinfo.num_components == 4) { /* Set 32-bit Raw output */ cinfo.out_color_space = JCS_CMYK; cinfo.quantize_colors = FALSE; - jpeg_calc_output_dimensions(&cinfo); + lib.jpeg_calc_output_dimensions(&cinfo); /* Allocate an output surface to hold the image */ surface = SDL_AllocSurface(SDL_SWSURFACE, @@ -291,7 +423,7 @@ SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src) cinfo.dct_method = JDCT_FASTEST; cinfo.do_fancy_upsampling = FALSE; #endif - jpeg_calc_output_dimensions(&cinfo); + lib.jpeg_calc_output_dimensions(&cinfo); /* Allocate an output surface to hold the image */ surface = SDL_AllocSurface(SDL_SWSURFACE, @@ -305,21 +437,24 @@ SDL_Surface *IMG_LoadJPG_RW(SDL_RWops *src) } if ( surface == NULL ) { - jpeg_destroy_decompress(&cinfo); + lib.jpeg_destroy_decompress(&cinfo); SDL_RWseek(src, start, SEEK_SET); + IMG_QuitJPG(); IMG_SetError("Out of memory"); return NULL; } /* Decompress the image */ - jpeg_start_decompress(&cinfo); + lib.jpeg_start_decompress(&cinfo); while ( cinfo.output_scanline < cinfo.output_height ) { rowptr[0] = (JSAMPROW)(Uint8 *)surface->pixels + cinfo.output_scanline * surface->pitch; - jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1); + lib.jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1); } - jpeg_finish_decompress(&cinfo); - jpeg_destroy_decompress(&cinfo); + lib.jpeg_finish_decompress(&cinfo); + lib.jpeg_destroy_decompress(&cinfo); + + IMG_QuitJPG(); return(surface); } diff --git a/IMG_png.c b/IMG_png.c index b1c9dc74..6406f36a 100644 --- a/IMG_png.c +++ b/IMG_png.c @@ -71,6 +71,196 @@ #define PNG_BYTES_TO_CHECK 4 +static struct { + int loaded; + void *handle; + png_infop (*png_create_info_struct) (png_structp png_ptr); + png_structp (*png_create_read_struct) (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn); + void (*png_destroy_read_struct) (png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr); + png_uint_32 (*png_get_IHDR) (png_structp png_ptr, png_infop info_ptr, png_uint_32 *width, png_uint_32 *height, int *bit_depth, int *color_type, int *interlace_method, int *compression_method, int *filter_method); + png_voidp (*png_get_io_ptr) (png_structp png_ptr); + png_uint_32 (*png_get_tRNS) (png_structp png_ptr, png_infop info_ptr, png_bytep *trans, int *num_trans, png_color_16p *trans_values); + png_uint_32 (*png_get_valid) (png_structp png_ptr, png_infop info_ptr, png_uint_32 flag); + void (*png_read_image) (png_structp png_ptr, png_bytepp image); + void (*png_read_info) (png_structp png_ptr, png_infop info_ptr); + void (*png_read_update_info) (png_structp png_ptr, png_infop info_ptr); + void (*png_set_expand) (png_structp png_ptr); + void (*png_set_gray_to_rgb) (png_structp png_ptr); + void (*png_set_packing) (png_structp png_ptr); + void (*png_set_read_fn) (png_structp png_ptr, png_voidp io_ptr, png_rw_ptr read_data_fn); + void (*png_set_strip_16) (png_structp png_ptr); + int (*png_sig_cmp) (png_bytep sig, png_size_t start, png_size_t num_to_check); +} lib; + +#ifdef LOAD_PNG_DYNAMIC +int IMG_InitPNG() +{ + if ( lib.loaded == 0 ) { + lib.handle = SDL_LoadObject(LOAD_PNG_DYNAMIC); + if ( lib.handle == NULL ) { + return -1; + } + lib.png_create_info_struct = + (png_infop (*) (png_structp)) + SDL_LoadFunction(lib.handle, "png_create_info_struct"); + if ( lib.png_create_info_struct == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_create_read_struct = + (png_structp (*) (png_const_charp, png_voidp, png_error_ptr, png_error_ptr)) + SDL_LoadFunction(lib.handle, "png_create_read_struct"); + if ( lib.png_create_read_struct == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_destroy_read_struct = + (void (*) (png_structpp, png_infopp, png_infopp)) + SDL_LoadFunction(lib.handle, "png_destroy_read_struct"); + if ( lib.png_destroy_read_struct == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_get_IHDR = + (png_uint_32 (*) (png_structp, png_infop, png_uint_32 *, png_uint_32 *, int *, int *, int *, int *, int *)) + SDL_LoadFunction(lib.handle, "png_get_IHDR"); + if ( lib.png_get_IHDR == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_get_io_ptr = + (png_voidp (*) (png_structp)) + SDL_LoadFunction(lib.handle, "png_get_io_ptr"); + if ( lib.png_get_io_ptr == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_get_tRNS = + (png_uint_32 (*) (png_structp, png_infop, png_bytep *, int *, png_color_16p *)) + SDL_LoadFunction(lib.handle, "png_get_tRNS"); + if ( lib.png_get_tRNS == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_get_valid = + (png_uint_32 (*) (png_structp, png_infop, png_uint_32)) + SDL_LoadFunction(lib.handle, "png_get_valid"); + if ( lib.png_get_valid == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_read_image = + (void (*) (png_structp, png_bytepp)) + SDL_LoadFunction(lib.handle, "png_read_image"); + if ( lib.png_read_image == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_read_info = + (void (*) (png_structp, png_infop)) + SDL_LoadFunction(lib.handle, "png_read_info"); + if ( lib.png_read_info == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_read_update_info = + (void (*) (png_structp, png_infop)) + SDL_LoadFunction(lib.handle, "png_read_update_info"); + if ( lib.png_read_update_info == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_set_expand = + (void (*) (png_structp)) + SDL_LoadFunction(lib.handle, "png_set_expand"); + if ( lib.png_set_expand == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_set_gray_to_rgb = + (void (*) (png_structp)) + SDL_LoadFunction(lib.handle, "png_set_gray_to_rgb"); + if ( lib.png_set_gray_to_rgb == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_set_packing = + (void (*) (png_structp)) + SDL_LoadFunction(lib.handle, "png_set_packing"); + if ( lib.png_set_packing == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_set_read_fn = + (void (*) (png_structp, png_voidp, png_rw_ptr)) + SDL_LoadFunction(lib.handle, "png_set_read_fn"); + if ( lib.png_set_read_fn == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_set_strip_16 = + (void (*) (png_structp)) + SDL_LoadFunction(lib.handle, "png_set_strip_16"); + if ( lib.png_set_strip_16 == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.png_sig_cmp = + (int (*) (png_bytep, png_size_t, png_size_t)) + SDL_LoadFunction(lib.handle, "png_sig_cmp"); + if ( lib.png_sig_cmp == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + } + ++lib.loaded; + + return 0; +} +void IMG_QuitPNG() +{ + if ( lib.loaded == 0 ) { + return; + } + if ( lib.loaded == 1 ) { + SDL_UnloadObject(lib.handle); + } + --lib.loaded; +} +#else +int IMG_InitPNG() +{ + if ( lib.loaded == 0 ) { + lib.png_create_info_struct = png_create_info_struct; + lib.png_create_read_struct = png_create_read_struct; + lib.png_destroy_read_struct = png_destroy_read_struct; + lib.png_get_IHDR = png_get_IHDR; + lib.png_get_io_ptr = png_get_io_ptr; + lib.png_get_tRNS = png_get_tRNS; + lib.png_get_valid = png_get_valid; + lib.png_read_image = png_read_image; + lib.png_read_info = png_read_info; + lib.png_read_update_info = png_read_update_info; + lib.png_set_expand = png_set_expand; + lib.png_set_gray_to_rgb = png_set_gray_to_rgb; + lib.png_set_packing = png_set_packing; + lib.png_set_read_fn = png_set_read_fn; + lib.png_set_strip_16 = png_set_strip_16; + lib.png_sig_cmp = png_sig_cmp; + } + ++lib.loaded; +} +void IMG_QuitPNG() +{ + if ( lib.loaded == 0 ) { + return; + } + if ( lib.loaded == 1 ) { + } + --lib.loaded; +} +#endif /* LOAD_PNG_DYNAMIC */ + /* See if an image is contained in a data source */ int IMG_isPNG(SDL_RWops *src) { @@ -78,12 +268,16 @@ int IMG_isPNG(SDL_RWops *src) int is_PNG; unsigned char buf[PNG_BYTES_TO_CHECK]; + if ( IMG_InitPNG() < 0 ) { + return 0; + } start = SDL_RWtell(src); is_PNG = 0; if ( SDL_RWread(src, buf, 1, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK ) { - is_PNG = (png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK) == 0); + is_PNG = (lib.png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK) == 0); } SDL_RWseek(src, start, SEEK_SET); + IMG_QuitPNG(); return(is_PNG); } @@ -92,7 +286,7 @@ static void png_read_data(png_structp ctx, png_bytep area, png_size_t size) { SDL_RWops *src; - src = (SDL_RWops *)png_get_io_ptr(ctx); + src = (SDL_RWops *)lib.png_get_io_ptr(ctx); SDL_RWread(src, area, size, 1); } SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src) @@ -120,12 +314,16 @@ SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src) } start = SDL_RWtell(src); + if ( IMG_InitPNG() < 0 ) { + return NULL; + } + /* Initialize the data we will clean up when we're done */ error = NULL; png_ptr = NULL; info_ptr = NULL; row_pointers = NULL; surface = NULL; /* Create the PNG loading context structure */ - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, + png_ptr = lib.png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,NULL,NULL); if (png_ptr == NULL){ error = "Couldn't allocate memory for PNG file or incompatible PNG dll"; @@ -133,7 +331,7 @@ SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src) } /* Allocate/initialize the memory for image information. REQUIRED. */ - info_ptr = png_create_info_struct(png_ptr); + info_ptr = lib.png_create_info_struct(png_ptr); if (info_ptr == NULL) { error = "Couldn't create image information for PNG file"; goto done; @@ -149,32 +347,32 @@ SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src) } /* Set up the input control */ - png_set_read_fn(png_ptr, src, png_read_data); + lib.png_set_read_fn(png_ptr, src, png_read_data); /* Read PNG header info */ - png_read_info(png_ptr, info_ptr); - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, + lib.png_read_info(png_ptr, info_ptr); + lib.png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); /* tell libpng to strip 16 bit/color files down to 8 bits/color */ - png_set_strip_16(png_ptr) ; + lib.png_set_strip_16(png_ptr) ; /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ - png_set_packing(png_ptr); + lib.png_set_packing(png_ptr); /* scale greyscale values to the range 0..255 */ if(color_type == PNG_COLOR_TYPE_GRAY) - png_set_expand(png_ptr); + lib.png_set_expand(png_ptr); /* For images with a single "transparent colour", set colour key; if more than one index has transparency, or if partially transparent entries exist, use full alpha channel */ - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + if (lib.png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { int num_trans; Uint8 *trans; - png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, + lib.png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, &transv); if(color_type == PNG_COLOR_TYPE_PALETTE) { /* Check if all tRNS entries are opaque except one */ @@ -191,18 +389,18 @@ SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src) ckey = t; } else { /* more than one transparent index, or translucency */ - png_set_expand(png_ptr); + lib.png_set_expand(png_ptr); } } else ckey = 0; /* actual value will be set later */ } if ( color_type == PNG_COLOR_TYPE_GRAY_ALPHA ) - png_set_gray_to_rgb(png_ptr); + lib.png_set_gray_to_rgb(png_ptr); - png_read_update_info(png_ptr, info_ptr); + lib.png_read_update_info(png_ptr, info_ptr); - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, + lib.png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, NULL, NULL); /* Allocate the SDL surface to hold the image */ @@ -250,14 +448,14 @@ SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src) } /* Read the entire image in one go */ - png_read_image(png_ptr, row_pointers); + lib.png_read_image(png_ptr, row_pointers); /* and we're done! (png_read_end() can be omitted if no processing of * post-IDAT text/time/etc. is desired) * In some cases it can't read PNG's created by some popular programs (ACDSEE), * we do not want to process comments, so we omit png_read_end - png_read_end(png_ptr, info_ptr); + lib.png_read_end(png_ptr, info_ptr); */ /* Load the palette, if any */ @@ -282,7 +480,7 @@ SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src) done: /* Clean up and return */ if ( png_ptr ) { - png_destroy_read_struct(&png_ptr, + lib.png_destroy_read_struct(&png_ptr, info_ptr ? &info_ptr : (png_infopp)0, (png_infopp)0); } @@ -295,7 +493,10 @@ SDL_Surface *IMG_LoadPNG_RW(SDL_RWops *src) SDL_FreeSurface(surface); surface = NULL; } + IMG_QuitPNG(); IMG_SetError(error); + } else { + IMG_QuitPNG(); } return(surface); } diff --git a/IMG_tif.c b/IMG_tif.c index 091a82c7..d2e636cc 100644 --- a/IMG_tif.c +++ b/IMG_tif.c @@ -30,6 +30,97 @@ #include +static struct { + int loaded; + void *handle; + TIFF* (*TIFFClientOpen)(const char*, const char*, thandle_t, TIFFReadWriteProc, TIFFReadWriteProc, TIFFSeekProc, TIFFCloseProc, TIFFSizeProc, TIFFMapFileProc, TIFFUnmapFileProc); + void (*TIFFClose)(TIFF*); + int (*TIFFGetField)(TIFF*, ttag_t, ...); + int (*TIFFReadRGBAImage)(TIFF*, uint32, uint32, uint32*, int); + TIFFErrorHandler (*TIFFSetErrorHandler)(TIFFErrorHandler); +} lib; + +#ifdef LOAD_TIF_DYNAMIC +int IMG_InitTIF() +{ + if ( lib.loaded == 0 ) { + lib.handle = SDL_LoadObject(LOAD_TIF_DYNAMIC); + if ( lib.handle == NULL ) { + return -1; + } + lib.TIFFClientOpen = + (TIFF* (*)(const char*, const char*, thandle_t, TIFFReadWriteProc, TIFFReadWriteProc, TIFFSeekProc, TIFFCloseProc, TIFFSizeProc, TIFFMapFileProc, TIFFUnmapFileProc)) + SDL_LoadFunction(lib.handle, "TIFFClientOpen"); + if ( lib.TIFFClientOpen == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.TIFFClose = + (void (*)(TIFF*)) + SDL_LoadFunction(lib.handle, "TIFFClose"); + if ( lib.TIFFClose == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.TIFFGetField = + (int (*)(TIFF*, ttag_t, ...)) + SDL_LoadFunction(lib.handle, "TIFFGetField"); + if ( lib.TIFFGetField == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.TIFFReadRGBAImage = + (int (*)(TIFF*, uint32, uint32, uint32*, int)) + SDL_LoadFunction(lib.handle, "TIFFReadRGBAImage"); + if ( lib.TIFFReadRGBAImage == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + lib.TIFFSetErrorHandler = + (TIFFErrorHandler (*)(TIFFErrorHandler)) + SDL_LoadFunction(lib.handle, "TIFFSetErrorHandler"); + if ( lib.TIFFSetErrorHandler == NULL ) { + SDL_UnloadObject(lib.handle); + return -1; + } + } + ++lib.loaded; + + return 0; +} +void IMG_QuitTIF() +{ + if ( lib.loaded == 0 ) { + return; + } + if ( lib.loaded == 1 ) { + SDL_UnloadObject(lib.handle); + } + --lib.loaded; +} +#else +int IMG_InitTIF() +{ + if ( lib.loaded == 0 ) { + lib.TIFFClientOpen = TIFFClientOpen; + lib.TIFFClose = TIFFClose; + lib.TIFFGetField = TIFFGetField; + lib.TIFFReadRGBAImage = TIFFReadRGBAImage; + lib.TIFFSetErrorHandler = TIFFSetErrorHandler; + } + ++lib.loaded; +} +void IMG_QuitTIF() +{ + if ( lib.loaded == 0 ) { + return; + } + if ( lib.loaded == 1 ) { + } + --lib.loaded; +} +#endif /* LOAD_TIF_DYNAMIC */ + /* * These are the thunking routine to use the SDL_RWops* routines from * libtiff's internals. @@ -78,28 +169,32 @@ int IMG_isTIF(SDL_RWops* src) TIFF* tiff; TIFFErrorHandler prev_handler; + if ( IMG_InitTIF() < 0 ) { + return 0; + } start = SDL_RWtell(src); is_TIF = 0; /* Suppress output from libtiff */ - prev_handler = TIFFSetErrorHandler(NULL); + prev_handler = lib.TIFFSetErrorHandler(NULL); /* Attempt to process the given file data */ /* turn off memory mapped access with the m flag */ - tiff = TIFFClientOpen("SDL_image", "rm", (thandle_t)src, + tiff = lib.TIFFClientOpen("SDL_image", "rm", (thandle_t)src, tiff_read, tiff_write, tiff_seek, tiff_close, tiff_size, NULL, NULL); /* Reset the default error handler, since it can be useful for info */ - TIFFSetErrorHandler(prev_handler); + lib.TIFFSetErrorHandler(prev_handler); /* If it's not a TIFF, then tiff will be NULL. */ if ( tiff ) { is_TIF = 1; /* Free up any dynamically allocated memory libtiff uses */ - TIFFClose(tiff); + lib.TIFFClose(tiff); } SDL_RWseek(src, start, SEEK_SET); + IMG_QuitTIF(); return(is_TIF); } @@ -119,15 +214,19 @@ SDL_Surface* IMG_LoadTIF_RW(SDL_RWops* src) } start = SDL_RWtell(src); + if ( IMG_InitTIF() < 0 ) { + return NULL; + } + /* turn off memory mapped access with the m flag */ - tiff = TIFFClientOpen("SDL_image", "rm", (thandle_t)src, + tiff = lib.TIFFClientOpen("SDL_image", "rm", (thandle_t)src, tiff_read, tiff_write, tiff_seek, tiff_close, tiff_size, NULL, NULL); if(!tiff) goto error; /* Retrieve the dimensions of the image from the TIFF tags */ - TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &img_width); - TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &img_height); + lib.TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &img_width); + lib.TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &img_height); Rmask = 0x000000FF; Gmask = 0x0000FF00; @@ -138,7 +237,7 @@ SDL_Surface* IMG_LoadTIF_RW(SDL_RWops* src) if(!surface) goto error; - if(!TIFFReadRGBAImage(tiff, img_width, img_height, surface->pixels, 0)) + if(!lib.TIFFReadRGBAImage(tiff, img_width, img_height, surface->pixels, 0)) goto error; /* libtiff loads the image upside-down, flip it back */ @@ -155,7 +254,8 @@ SDL_Surface* IMG_LoadTIF_RW(SDL_RWops* src) bot[x] = tmp; } } - TIFFClose(tiff); + lib.TIFFClose(tiff); + IMG_QuitTIF(); return surface; @@ -164,6 +264,7 @@ SDL_Surface* IMG_LoadTIF_RW(SDL_RWops* src) if ( surface ) { SDL_FreeSurface(surface); } + IMG_QuitTIF(); return NULL; } diff --git a/configure.in b/configure.in index a65d210b..0ebfb2ae 100644 --- a/configure.in +++ b/configure.in @@ -89,18 +89,24 @@ AC_ARG_ENABLE([gif], [AC_HELP_STRING([--enable-gif], [support loading GIF images [], [enable_gif=yes]) AC_ARG_ENABLE([jpg], [AC_HELP_STRING([--enable-jpg], [support loading JPG images [default=yes]])], [], [enable_jpg=yes]) +AC_ARG_ENABLE([jpg-shared], AC_HELP_STRING([--enable-jpg-shared], [dynamically load JPG support [[default=yes]]]), + [], [enable_jpg_shared=yes]) AC_ARG_ENABLE([lbm], [AC_HELP_STRING([--enable-lbm], [support loading LBM images [default=yes]])], [], [enable_lbm=yes]) AC_ARG_ENABLE([pcx], [AC_HELP_STRING([--enable-pcx], [support loading PCX images [default=yes]])], [], [enable_pcx=yes]) -AC_ARG_ENABLE([png], [AC_HELP_STRING([--enable-bmp], [support loading PNG images [default=yes]])], +AC_ARG_ENABLE([png], [AC_HELP_STRING([--enable-png], [support loading PNG images [default=yes]])], [], [enable_png=yes]) +AC_ARG_ENABLE([png-shared], AC_HELP_STRING([--enable-png-shared], [dynamically load PNG support [[default=yes]]]), + [], [enable_png_shared=yes]) AC_ARG_ENABLE([pnm], [AC_HELP_STRING([--enable-pnm], [support loading PNM images [default=yes]])], [], [enable_pnm=yes]) AC_ARG_ENABLE([tga], [AC_HELP_STRING([--enable-tga], [support loading TGA images [default=yes]])], [], [enable_tga=yes]) -AC_ARG_ENABLE([tif], [AC_HELP_STRING([--enable-tif], [support loading TIFF images [default=no]])], - [], [enable_tif=no]) +AC_ARG_ENABLE([tif], [AC_HELP_STRING([--enable-tif], [support loading TIFF images [default=yes]])], + [], [enable_tif=yes]) +AC_ARG_ENABLE([tif-shared], AC_HELP_STRING([--enable-tif-shared], [dynamically load TIFF support [[default=yes]]]), + [], [enable_tif_shared=yes]) AC_ARG_ENABLE([xcf], [AC_HELP_STRING([--enable-xcf], [support loading XCF images [default=yes]])], [], [enable_xcf=yes]) AC_ARG_ENABLE([xpm], [AC_HELP_STRING([--enable-xpm], [support loading XPM images [default=yes]])], @@ -108,21 +114,35 @@ AC_ARG_ENABLE([xpm], [AC_HELP_STRING([--enable-xpm], [support loading XPM images AC_ARG_ENABLE([xv], [AC_HELP_STRING([--enable-xv], [support loading XV images [default=yes]])], [], [enable_xv=yes]) -if test x$enable_png = xyes || x$enable_tif = xyes; then +if test x$enable_png = xyes || test x$enable_tif = xyes; then AC_CHECK_LIB([z], [uncompress], [ LIBS="-lz $LIBS" - IMG_LIBS="-lz $IMG_LIBS" ]) fi -if test x$enable_jpg = xyes || x$enable_tif = xyes; then +if test x$enable_jpg = xyes || test x$enable_tif = xyes; then AC_CHECK_LIB([jpeg], [jpeg_CreateDecompress], [have_libjpeg=yes]) if test x$have_libjpeg = xyes; then if test x$enable_jpg = xyes; then AC_DEFINE(LOAD_JPG) fi LIBS="-ljpeg $LIBS" - IMG_LIBS="-ljpeg $IMG_LIBS" + + case "$host" in + *-*-darwin*) # FIXME when Mac OS X ships with libjpeg + jpg_lib='' + ;; + *-*-cygwin* | *-*-mingw32*) + jpg_lib='jpeg.dll' + ;; + *) + for path in /usr/lib /usr/local/lib; do + if test x$jpg_lib = x; then + jpg_lib=[`ls -- $path/libjpeg.so.[0-9][0-9] 2>/dev/null | sort -r | sed 's/.*\/\(.*\)/\1/; q'`] + fi + done + ;; + esac elif test x$enable_jpg = xyes; then AC_MSG_WARN([*** Unable to find JPEG library (http://www.ijg.org/)]) AC_MSG_WARN([JPG image loading disabled]) @@ -133,7 +153,22 @@ if test x$enable_png = xyes; then AC_CHECK_LIB([png], [png_create_read_struct], [have_libpng=yes]) if test x$have_libpng = xyes; then AC_DEFINE([LOAD_PNG]) - IMG_LIBS="-lpng $IMG_LIBS" + + case "$host" in + *-*-darwin*) # FIXME when Mac OS X ships with libpng + png_lib='' + ;; + *-*-cygwin* | *-*-mingw32*) + png_lib='libpng13.dll' + ;; + *) + for path in /usr/lib /usr/local/lib; do + if test x$png_lib = x; then + png_lib=[`ls -- $path/libpng.so.[0-9] 2>/dev/null | sort -r | sed 's/.*\/\(.*\)/\1/; q'`] + fi + done + ;; + esac else AC_MSG_WARN([*** Unable to find PNG library (http://www.libpng.org/pub/png/libpng.html)]) AC_MSG_WARN([PNG image loading disabled]) @@ -144,9 +179,24 @@ if test x$enable_tif = xyes; then AC_CHECK_LIB([tiff], [TIFFClientOpen], [have_libtiff=yes]) if test x$have_libtiff = xyes; then AC_DEFINE([LOAD_TIF]) - IMG_LIBS="-ltiff $IMG_LIBS" + + case "$host" in + *-*-darwin*) # FIXME when Mac OS X ships with libtiff + tif_lib='' + ;; + *-*-cygwin* | *-*-mingw32*) + tif_lib='libtiff.dll' + ;; + *) + for path in /usr/lib /usr/local/lib; do + if test x$tif_lib = x; then + tif_lib=[`ls -- $path/libtiff.so.[0-9] 2>/dev/null | sort -r | sed 's/.*\/\(.*\)/\1/; q'`] + fi + done + ;; + esac else - AC_MSG_WARN([*** Unable to find Tiff library (ftp://ftp.sgi.com/graphics/tiff/)]) + AC_MSG_WARN([*** Unable to find Tiff library (http://www.remotesensing.org/libtiff/)]) AC_MSG_WARN([TIF image loading disabled]) fi fi @@ -187,6 +237,36 @@ if test x$enable_xv = xyes; then AC_DEFINE([LOAD_XV]) fi +if test x$enable_tif = xyes; then + if test x$enable_tif_shared = xyes && test x$tif_lib != x; then + echo "-- dynamic libtiff -> $tif_lib" + AC_DEFINE_UNQUOTED(LOAD_TIF_DYNAMIC, "$tif_lib") + else + if test x$have_libjpeg = xyes; then + # Disable dynamic jpeg since we're linking it explicitly + jpg_lib='' + IMG_LIBS="-ljpeg $IMG_LIBS" + fi + IMG_LIBS="-ltiff -lz" + fi +fi +if test x$enable_jpg = xyes; then + if test x$enable_jpg_shared = xyes && test x$jpg_lib != x; then + echo "-- dynamic libjpeg -> $jpg_lib" + AC_DEFINE_UNQUOTED(LOAD_JPG_DYNAMIC, "$jpg_lib") + else + IMG_LIBS="-ljpeg $IMG_LIBS" + fi +fi +if test x$enable_png = xyes; then + if test x$enable_png_shared = xyes && test x$png_lib != x; then + echo "-- dynamic libpng -> $png_lib" + AC_DEFINE_UNQUOTED(LOAD_PNG_DYNAMIC, "$png_lib") + else + IMG_LIBS="-lpng -lz $IMG_LIBS" + fi +fi + LIBS="$saved_LIBS" AC_SUBST([IMG_LIBS])