X-Git-Url: http://de.git.xonotic.org/?a=blobdiff_plain;f=image_png.c;h=ca090b2c57ff53113369cab8deba020deb0ae7bf;hb=8e22875426474df76c29d8ee7eb6078c7c8453f3;hp=cbaddf3e7398173d27e669a595c6b22eb3fb599e;hpb=6a75f042475ac3d601c0c85ce90f7e8cb05a11d3;p=xonotic%2Fdarkplaces.git diff --git a/image_png.c b/image_png.c index cbaddf3e..ca090b2c 100644 --- a/image_png.c +++ b/image_png.c @@ -32,7 +32,7 @@ static void (*qpng_set_sig_bytes) (void*, int); static int (*qpng_sig_cmp) (const unsigned char*, size_t, size_t); -static void* (*qpng_create_read_struct) (const char*, void*, void*, void*); +static void* (*qpng_create_read_struct) (const char*, void*, void(*)(void *png, const char *message), void(*)(void *png, const char *message)); static void* (*qpng_create_info_struct) (void*); static void (*qpng_read_info) (void*, void*); static void (*qpng_set_expand) (void*); @@ -45,12 +45,12 @@ static void (*qpng_read_update_info) (void*, void*); static void (*qpng_read_image) (void*, unsigned char**); static void (*qpng_read_end) (void*, void*); static void (*qpng_destroy_read_struct) (void**, void**, void**); -static void (*qpng_set_read_fn) (void*, void*, void*); +static void (*qpng_set_read_fn) (void*, void*, void(*)(void *png, unsigned char *data, size_t length)); static unsigned int (*qpng_get_valid) (void*, void*, unsigned int); static unsigned int (*qpng_get_rowbytes) (void*, void*); static unsigned char (*qpng_get_channels) (void*, void*); static unsigned char (*qpng_get_bit_depth) (void*, void*); -static unsigned int (*qpng_get_IHDR) (void*, void*, unsigned int*, unsigned int*, int *, int *, int *, int *, int *); +static unsigned int (*qpng_get_IHDR) (void*, void*, unsigned long*, unsigned long*, int *, int *, int *, int *, int *); static char* (*qpng_get_libpng_ver) (void*); static dllfunction_t pngfuncs[] = @@ -103,12 +103,15 @@ qboolean PNG_OpenLibrary (void) { const char* dllnames [] = { -#ifdef WIN32 +#ifdef WIN64 + "libpng12_64.dll", +#elif WIN32 "libpng12.dll", #elif defined(MACOSX) - "libpng12.dylib", + "libpng12.0.dylib", #else "libpng12.so.0", + "libpng.so", // FreeBSD #endif NULL }; @@ -118,14 +121,7 @@ qboolean PNG_OpenLibrary (void) return true; // Load the DLL - if (! Sys_LoadLibrary (dllnames, &png_dll, pngfuncs)) - { - Con_Printf ("PNG support disabled\n"); - return false; - } - - Con_Printf ("PNG support enabled\n"); - return true; + return Sys_LoadLibrary (dllnames, &png_dll, pngfuncs); } @@ -168,7 +164,7 @@ void PNG_CloseLibrary (void) #define PNG_INFO_tRNS 0x0010 // this struct is only used for status information during loading -struct +static struct { const unsigned char *tmpBuf; int tmpBuflength; @@ -186,8 +182,8 @@ struct int BitDepth; int BytesPerPixel; int ColorType; - unsigned int Height; - unsigned int Width; + unsigned long Height; // retarded libpng 1.2 pngconf.h uses long (64bit/32bit depending on arch) + unsigned long Width; // retarded libpng 1.2 pngconf.h uses long (64bit/32bit depending on arch) int Interlace; int Compression; int Filter; @@ -202,15 +198,15 @@ void PNG_fReadData(void *png, unsigned char *data, size_t length) l = my_png.tmpBuflength - my_png.tmpi; if (l < length) { - Con_Printf("PNG_fReadData: overrun by %i bytes\n", length - l); + Con_Printf("PNG_fReadData: overrun by %i bytes\n", (int)(length - l)); // a read going past the end of the file, fill in the remaining bytes // with 0 just to be consistent memset(data + l, 0, length - l); length = l; } memcpy(data, my_png.tmpBuf + my_png.tmpi, length); - my_png.tmpi += length; - Com_HexDumpToConsole(data, length); + my_png.tmpi += (int)length; + //Com_HexDumpToConsole(data, (int)length); } void PNG_error_fn(void *png, const char *message) @@ -226,11 +222,12 @@ void PNG_warning_fn(void *png, const char *message) extern int image_width; extern int image_height; -unsigned char *PNG_LoadImage (const unsigned char *raw, int filesize, int matchwidth, int matchheight) +unsigned char *PNG_LoadImage_BGRA (const unsigned char *raw, int filesize) { + unsigned int c; unsigned int y; void *png, *pnginfo; - unsigned char *imagedata; + unsigned char *imagedata = NULL; unsigned char ioBuffer[8192]; // FIXME: register an error handler so that abort() won't be called on error @@ -241,14 +238,32 @@ unsigned char *PNG_LoadImage (const unsigned char *raw, int filesize, int matchw if(qpng_sig_cmp(raw, 0, filesize)) return NULL; - png = qpng_create_read_struct(PNG_LIBPNG_VER_STRING, 0, PNG_error_fn, PNG_warning_fn); + png = (void *)qpng_create_read_struct(PNG_LIBPNG_VER_STRING, 0, PNG_error_fn, PNG_warning_fn); if(!png) return NULL; + // this must be memset before the setjmp error handler, because it relies + // on the fields in this struct for cleanup + memset(&my_png, 0, sizeof(my_png)); + // NOTE: this relies on jmp_buf being the first thing in the png structure // created by libpng! (this is correct for libpng 1.2.x) +#ifdef __cplusplus +#if defined(MACOSX) || defined(WIN32) + if (setjmp((int *)png)) +#else + if (setjmp((__jmp_buf_tag *)png)) +#endif +#else if (setjmp(png)) +#endif { + if (my_png.Data) + Mem_Free(my_png.Data); + my_png.Data = NULL; + if (my_png.FRowPtrs) + Mem_Free(my_png.FRowPtrs); + my_png.FRowPtrs = NULL; qpng_destroy_read_struct(&png, &pnginfo, 0); return NULL; } @@ -262,7 +277,6 @@ unsigned char *PNG_LoadImage (const unsigned char *raw, int filesize, int matchw } qpng_set_sig_bytes(png, 0); - memset(&my_png, 0, sizeof(my_png)); my_png.tmpBuf = raw; my_png.tmpBuflength = filesize; my_png.tmpi = 0; @@ -277,11 +291,20 @@ unsigned char *PNG_LoadImage (const unsigned char *raw, int filesize, int matchw qpng_set_read_fn(png, ioBuffer, PNG_fReadData); qpng_read_info(png, pnginfo); qpng_get_IHDR(png, pnginfo, &my_png.Width, &my_png.Height,&my_png.BitDepth, &my_png.ColorType, &my_png.Interlace, &my_png.Compression, &my_png.Filter); - if ((matchwidth && my_png.Width != (unsigned int)matchwidth) || (matchheight && my_png.Height != (unsigned int)matchheight)) + + // this check guards against pngconf.h with unsigned int *width/height parameters on big endian systems by detecting the strange values and shifting them down 32bits + // (if it's little endian the unwritten bytes are the most significant + // ones and we don't worry about that) + // + // this is only necessary because of retarded 64bit png_uint_32 types in libpng 1.2, which can (conceivably) vary by platform +#if LONG_MAX > 4000000000 + if (my_png.Width > LONG_MAX || my_png.Height > LONG_MAX) { - qpng_destroy_read_struct(&png, &pnginfo, 0); - return NULL; + my_png.Width >>= 32; + my_png.Height >>= 32; } +#endif + if (my_png.ColorType == PNG_COLOR_TYPE_PALETTE) qpng_set_palette_to_rgb(png); if (my_png.ColorType == PNG_COLOR_TYPE_GRAY || my_png.ColorType == PNG_COLOR_TYPE_GRAY_ALPHA) @@ -305,35 +328,53 @@ unsigned char *PNG_LoadImage (const unsigned char *raw, int filesize, int matchw my_png.FRowBytes = qpng_get_rowbytes(png, pnginfo); my_png.BytesPerPixel = qpng_get_channels(png, pnginfo); - my_png.FRowPtrs = Mem_Alloc(tempmempool, my_png.Height * sizeof(*my_png.FRowPtrs)); + my_png.FRowPtrs = (unsigned char **)Mem_Alloc(tempmempool, my_png.Height * sizeof(*my_png.FRowPtrs)); if (my_png.FRowPtrs) { - my_png.Data = Mem_Alloc(tempmempool, my_png.Height * my_png.FRowBytes); - if(my_png.Data) + imagedata = (unsigned char *)Mem_Alloc(tempmempool, my_png.Height * my_png.FRowBytes); + if(imagedata) { + my_png.Data = imagedata; for(y = 0;y < my_png.Height;y++) my_png.FRowPtrs[y] = my_png.Data + y * my_png.FRowBytes; qpng_read_image(png, my_png.FRowPtrs); } else - Con_DPrintf("PNG_LoadImage : not enough memory\n"); + { + Con_Printf("PNG_LoadImage : not enough memory\n"); + qpng_destroy_read_struct(&png, &pnginfo, 0); + Mem_Free(my_png.FRowPtrs); + return NULL; + } Mem_Free(my_png.FRowPtrs); + my_png.FRowPtrs = NULL; } else - Con_DPrintf("PNG_LoadImage : not enough memory\n"); + { + Con_Printf("PNG_LoadImage : not enough memory\n"); + qpng_destroy_read_struct(&png, &pnginfo, 0); + return NULL; + } qpng_read_end(png, pnginfo); qpng_destroy_read_struct(&png, &pnginfo, 0); - image_width = my_png.Width; - image_height = my_png.Height; - imagedata = my_png.Data; + image_width = (int)my_png.Width; + image_height = (int)my_png.Height; if (my_png.BitDepth != 8) { Con_Printf ("PNG_LoadImage : bad color depth\n"); Mem_Free(imagedata); - imagedata = NULL; + return NULL; + } + + // swizzle RGBA to BGRA + for (y = 0;y < (unsigned int)(image_width*image_height*4);y += 4) + { + c = imagedata[y+0]; + imagedata[y+0] = imagedata[y+2]; + imagedata[y+2] = c; } return imagedata;