stb_image fixes; gdi+ fixes merged from Won

This commit is contained in:
nothings.org 2007-08-14 17:39:54 +00:00
parent f7468cec5c
commit 3b167d592c
3 changed files with 82 additions and 38 deletions

95
imv.c
View File

@ -231,6 +231,26 @@ typedef struct
// there can only be one pending command in flight // there can only be one pending command in flight
volatile DiskCommand dc_shared; volatile DiskCommand dc_shared;
void *stb_file2(char *filename, size_t *length)
{
FILE *f = fopen(filename, "rb");
char *buffer;
size_t len;
if (!f) return NULL;
len = stb_filelen(f);
buffer = (char *) malloc(len+2); // nul + extra
if (fread(buffer, 1, len, f) == len) {
if (length) *length = len;
buffer[len] = 0;
} else {
free(buffer);
buffer = NULL;
}
fclose(f);
return buffer;
}
// the disk loader sits in this loop forever // the disk loader sits in this loop forever
void *diskload_task(void *p) void *diskload_task(void *p)
{ {
@ -1972,7 +1992,7 @@ void performance_test(void)
{ {
int t1,t2; int t1,t2;
int len,i; int len,i;
uint8 *buffer = stb_file(cur_filename, &len); uint8 *buffer = stb_file2(cur_filename, &len);
if (buffer == NULL) return; if (buffer == NULL) return;
t1 = timeGetTime(); t1 = timeGetTime();
@ -2304,7 +2324,10 @@ int cur_is_current(void)
} }
#ifdef USE_GDIPLUS #ifdef USE_GDIPLUS
typedef ULONG ULONG_PTR;
static Bool GdiplusPresent; static Bool GdiplusPresent;
static ULONG_PTR GpToken;
static Bool LoadGdiplus(void); static Bool LoadGdiplus(void);
#define ICM_SUFFIX "" #define ICM_SUFFIX ""
// use this definition to enable color management // use this definition to enable color management
@ -2414,7 +2437,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
{ {
char *why=NULL; char *why=NULL;
int len; int len;
uint8 *data = stb_file(filename, &len); uint8 *data = stb_file2(filename, &len);
if (!data) if (!data)
why = "Couldn't open file"; why = "Couldn't open file";
else { else {
@ -3213,6 +3236,7 @@ static char *imv_failure_reason(void)
#ifdef USE_GDIPLUS #ifdef USE_GDIPLUS
#pragma pack(push,8) #pragma pack(push,8)
// from GdiplusTypes.h // from GdiplusTypes.h
@ -3246,20 +3270,19 @@ typedef enum
typedef enum typedef enum
{ {
DebugEventLevelFatal, GpDebugEventLevelFatal,
DebugEventLevelWarning GpDebugEventLevelWarning
} GpDebugEventLevel; } GpDebugEventLevel;
typedef VOID (WINAPI *GpDebugEventProc)(GpDebugEventLevel level, CHAR *message); typedef VOID (WINAPI *GpDebugEventProc)(GpDebugEventLevel level, CHAR *message);
typedef ULONG ULONG_PTR;
typedef GpStatus (WINAPI *GpNotificationHookProc)(ULONG_PTR *token); typedef GpStatus (WINAPI *GpNotificationHookProc)(ULONG_PTR *token);
typedef VOID (WINAPI *GpNotificationUnhookProc)(ULONG_PTR token); typedef VOID (WINAPI *GpNotificationUnhookProc)(ULONG_PTR token);
typedef struct { typedef struct {
UINT32 GdiplusVersion; UINT32 GdiplusVersion;
GpDebugEventProc DebugEventCallback; GpDebugEventProc DebugEventCallback;
BOOL SuppressBackgroundThread; // TODO: manually call hook/unhook BOOL SuppressBackgroundThread;
BOOL SuppressExternalCodecs; BOOL SuppressExternalCodecs;
} GdiplusStartupInput; } GdiplusStartupInput;
@ -3271,9 +3294,6 @@ typedef struct {
static HINSTANCE GdiplusDLL; static HINSTANCE GdiplusDLL;
static GdiplusStartupOutput gpStartupOutput; static GdiplusStartupOutput gpStartupOutput;
typedef __declspec(dllimport) GpStatus (WINAPI *GdiplusStartupProc)(ULONG_PTR *token, const GdiplusStartupInput* input, GdiplusStartupOutput* output);
static GdiplusStartupProc GdiplusStartup;
// from GdiplusHeaders.h // from GdiplusHeaders.h
typedef void GpImage; // opaque type typedef void GpImage; // opaque type
@ -3321,6 +3341,12 @@ typedef enum
GpImageLockModeUserInputBuf= 0x0004 GpImageLockModeUserInputBuf= 0x0004
} GpImageLockMode; } GpImageLockMode;
typedef __declspec(dllimport) GpStatus (WINAPI *GdiplusStartupProc)(ULONG_PTR *token, const GdiplusStartupInput* input, GdiplusStartupOutput* output);
static GdiplusStartupProc GdiplusStartup;
typedef __declspec(dllimport) GpStatus (WINAPI *GdiplusShutdownProc)(ULONG_PTR token);
static GdiplusShutdownProc GdiplusShutdown;
typedef __declspec(dllimport) GpStatus (WINAPI *GdipCreateBitmapFromStreamProc)(IStream* stream, GpBitmap **bitmap); typedef __declspec(dllimport) GpStatus (WINAPI *GdipCreateBitmapFromStreamProc)(IStream* stream, GpBitmap **bitmap);
static GdipCreateBitmapFromStreamProc GdipCreateBitmapFromStream; static GdipCreateBitmapFromStreamProc GdipCreateBitmapFromStream;
@ -3333,6 +3359,8 @@ static GdipBitmapLockBitsProc GdipBitmapLockBits;
typedef __declspec(dllimport) GpStatus (WINAPI *GdipBitmapUnlockBitsProc)(GpBitmap* bitmap, GpBitmapData* lockedBitmapData); typedef __declspec(dllimport) GpStatus (WINAPI *GdipBitmapUnlockBitsProc)(GpBitmap* bitmap, GpBitmapData* lockedBitmapData);
static GdipBitmapUnlockBitsProc GdipBitmapUnlockBits; static GdipBitmapUnlockBitsProc GdipBitmapUnlockBits;
#pragma pack(pop)
FARPROC GpFunc(char *str) FARPROC GpFunc(char *str)
{ {
FARPROC p = GetProcAddress(GdiplusDLL, str); FARPROC p = GetProcAddress(GdiplusDLL, str);
@ -3355,6 +3383,7 @@ static Bool LoadGdiplus(void)
GdiplusPresent = TRUE; GdiplusPresent = TRUE;
GdiplusStartup = (GdiplusStartupProc)GpFunc("GdiplusStartup"); GdiplusStartup = (GdiplusStartupProc)GpFunc("GdiplusStartup");
//GdiplusShutdown = (GdiplusShutdownProc)GpFunc("GdiplusShutdown");
GdipCreateBitmapFromStream = (GdipCreateBitmapFromStreamProc)GpFunc("GdipCreateBitmapFromStream" ICM_SUFFIX); GdipCreateBitmapFromStream = (GdipCreateBitmapFromStreamProc)GpFunc("GdipCreateBitmapFromStream" ICM_SUFFIX);
GdipDisposeImage = (GdipDisposeImageProc)GpFunc("GdipDisposeImage"); GdipDisposeImage = (GdipDisposeImageProc)GpFunc("GdipDisposeImage");
GdipBitmapLockBits = (GdipBitmapLockBitsProc)GpFunc("GdipBitmapLockBits"); GdipBitmapLockBits = (GdipBitmapLockBitsProc)GpFunc("GdipBitmapLockBits");
@ -3363,9 +3392,9 @@ static Bool LoadGdiplus(void)
if (!only_stbi) if (!only_stbi)
error("Invalid GdiPlus.dll; disabling GDI+ support."); error("Invalid GdiPlus.dll; disabling GDI+ support.");
} else { } else {
ULONG token; // no need to use GDI+ backup thread, or to call the hook methods in gpStartupOutput
GdiplusStartupInput gpStartupInput = { 1, NULL, FALSE, FALSE }; GdiplusStartupInput gpStartupInput = { 1, NULL, TRUE, FALSE };
if (GdiplusStartup(&token, &gpStartupInput, &gpStartupOutput) != GpOk) { if (GdiplusStartup(&GpToken, &gpStartupInput, &gpStartupOutput) != GpOk) {
GdiplusPresent = FALSE; GdiplusPresent = FALSE;
if (!only_stbi) if (!only_stbi)
error("Failed to initialize GdiPlus.dll; disabling GDI+ support."); error("Failed to initialize GdiPlus.dll; disabling GDI+ support.");
@ -3376,39 +3405,43 @@ static Bool LoadGdiplus(void)
} }
static uint8 *LoadImageWithGdiplus(uint8 *mem, int len, int *x, int *y, int *n, int n_req) { static uint8 *LoadImageWithGdiplus(uint8 *mem, int len, int *x, int *y, int *n, int n_req) {
// TODO: implement an IStream that does this in-place, to avoid the copy and allocations HGLOBAL hMem = NULL;
IStream* stream; IStream* stream = NULL;
GpBitmap* bitmap; GpBitmap* bitmap = NULL;
GpBitmapData data; GpBitmapData data;
HGLOBAL hmem;
GpPixelFormat pixelFormat; GpPixelFormat pixelFormat;
size_t i, image_sz; size_t i, image_sz = 0;
uint8* buf, *ret = NULL; uint8 *buf = NULL, *ret = NULL;
image_sz = 0; image_sz = 0;
*x = 0; *x = 0;
*y = 0; *y = 0;
*n = n_req; *n = n_req;
bitmap = NULL;
data.Scan0 = NULL; data.Scan0 = NULL;
hmem = GlobalAlloc(GMEM_MOVEABLE, len); hMem = GlobalAlloc(GMEM_MOVEABLE, len);
if (!hmem) if (!hMem)
goto liwgExit; goto liwgExit;
buf = GlobalLock(hmem); buf = GlobalLock(hMem);
if (!buf) if (!buf) goto liwgExit;
goto liwgExit;
memcpy(buf, mem, len); memcpy(buf, mem, len);
if (GlobalUnlock(hMem))
goto liwgExit;
if (CreateStreamOnHGlobal(buf, FALSE, &stream) != S_OK) if (CreateStreamOnHGlobal(buf, FALSE, &stream) != S_OK)
goto liwgExit; goto liwgExit;
if (GdipCreateBitmapFromStream(stream, &bitmap) != GpOk) if (GdipCreateBitmapFromStream(stream, &bitmap) != GpOk)
goto liwgExit; goto liwgExit;
if (n_req == 3) #if BPP == 3
pixelFormat = GpPixelFormat24bppRGB; assert(n_req == 3);
else pixelFormat = GpPixelFormat24bppRGB;
pixelFormat = GpPixelFormat32bppARGB; #else
assert(n_req == 4);
pixelFormat = GpPixelFormat32bppARGB;
#endif
if (GdipBitmapLockBits(bitmap, NULL, GpImageLockModeRead, pixelFormat, &data) != GpOk) if (GdipBitmapLockBits(bitmap, NULL, GpImageLockModeRead, pixelFormat, &data) != GpOk)
goto liwgExit; goto liwgExit;
@ -3422,16 +3455,14 @@ static uint8 *LoadImageWithGdiplus(uint8 *mem, int len, int *x, int *y, int *n,
memcpy(&ret[i*data.Width*n_req], &((uint8*)data.Scan0)[i*data.Stride], data.Width*n_req); memcpy(&ret[i*data.Width*n_req], &((uint8*)data.Scan0)[i*data.Stride], data.Width*n_req);
liwgExit: liwgExit:
if (buf) GlobalUnlock(hmem);
if (hmem) GlobalFree(hmem);
if (data.Scan0) GdipBitmapUnlockBits(bitmap, &data); if (data.Scan0) GdipBitmapUnlockBits(bitmap, &data);
if (bitmap) GdipDisposeImage(bitmap); if (bitmap) GdipDisposeImage(bitmap);
if (stream) stream->lpVtbl->Release(stream);
if (hMem) GlobalFree(hMem);
return ret; return ret;
} }
#pragma pack(pop)
#endif #endif
#ifdef USE_FREEIMAGE #ifdef USE_FREEIMAGE

View File

@ -1,4 +1,4 @@
/* stbi-0.95 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c /* stbi-0.97 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c
when you control the images you're loading when you control the images you're loading
QUICK NOTES: QUICK NOTES:
@ -16,6 +16,8 @@
PSD loader PSD loader
history: history:
0.97 jpeg errors on too large a file; also catch another malloc failure
0.96 fix detection of invalid v value - particleman@mollyrocket forum
0.95 during header scan, seek to markers in case of padding 0.95 during header scan, seek to markers in case of padding
0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same
0.93 handle jpegtran output; verbose errors 0.93 handle jpegtran output; verbose errors
@ -1029,12 +1031,14 @@ static int process_frame_header(int scan)
return e("bad component ID","Corrupt JPEG"); return e("bad component ID","Corrupt JPEG");
z = get8(); z = get8();
img_comp[i].h = (z >> 4); if (!img_comp[i].h || img_comp[i].h > 4) return e("bad H","Corrupt JPEG"); img_comp[i].h = (z >> 4); if (!img_comp[i].h || img_comp[i].h > 4) return e("bad H","Corrupt JPEG");
img_comp[i].v = z & 15; if (!img_comp[i].h || img_comp[i].h > 4) return e("bad V","Corrupt JPEG"); img_comp[i].v = z & 15; if (!img_comp[i].v || img_comp[i].v > 4) return e("bad V","Corrupt JPEG");
img_comp[i].tq = get8(); if (img_comp[i].tq > 3) return e("bad TQ","Corrupt JPEG"); img_comp[i].tq = get8(); if (img_comp[i].tq > 3) return e("bad TQ","Corrupt JPEG");
} }
if (scan != SCAN_load) return 1; if (scan != SCAN_load) return 1;
if ((1 << 30) / img_x / img_n < img_y) return e("too large", "Image too large to decode");
for (i=0; i < img_n; ++i) { for (i=0; i < img_n; ++i) {
if (img_comp[i].h > h_max) h_max = img_comp[i].h; if (img_comp[i].h > h_max) h_max = img_comp[i].h;
if (img_comp[i].v > v_max) v_max = img_comp[i].v; if (img_comp[i].v > v_max) v_max = img_comp[i].v;
@ -1059,6 +1063,11 @@ static int process_frame_header(int scan)
img_comp[i].w2 = img_mcu_x * img_comp[i].h * 8; img_comp[i].w2 = img_mcu_x * img_comp[i].h * 8;
img_comp[i].h2 = img_mcu_y * img_comp[i].v * 8; img_comp[i].h2 = img_mcu_y * img_comp[i].v * 8;
img_comp[i].data = (uint8 *) malloc(img_comp[i].w2 * img_comp[i].h2); img_comp[i].data = (uint8 *) malloc(img_comp[i].w2 * img_comp[i].h2);
if (img_comp[i].data == NULL) {
for(--i; i >= 0; --i)
free(img_comp[i].data);
return e("outofmem", "Out of memory");
}
} }
return 1; return 1;
@ -1270,6 +1279,10 @@ static uint8 *load_jpeg_image(int *out_x, int *out_y, int *comp, int req_comp)
// the edges with upsample up to 4x4 (although we only support 2x2 // the edges with upsample up to 4x4 (although we only support 2x2
// currently) // currently)
uint8 *new_data = (uint8 *) malloc((img_x+3)*(img_y+3)); uint8 *new_data = (uint8 *) malloc((img_x+3)*(img_y+3));
if (new_data == NULL) {
cleanup_jpeg();
return ep("outofmem", "Out of memory (image too large?)");
}
if (img_comp[i].h*2 == img_h_max && img_comp[i].v*2 == img_v_max) { if (img_comp[i].h*2 == img_h_max && img_comp[i].v*2 == img_v_max) {
int tx = (img_x+1)>>1; int tx = (img_x+1)>>1;
resample_hv_2(new_data, img_comp[i].data, tx,(img_y+1)>>1, img_comp[i].w2); resample_hv_2(new_data, img_comp[i].data, tx,(img_y+1)>>1, img_comp[i].w2);
@ -1965,8 +1978,8 @@ static int parse_png_file(int scan, int req_comp)
int depth,color,interlace,comp,filter; int depth,color,interlace,comp,filter;
if (!first) return e("multiple IHDR","Corrupt PNG"); if (!first) return e("multiple IHDR","Corrupt PNG");
if (c.length != 13) return e("bad IHDR len","Corrupt PNG"); if (c.length != 13) return e("bad IHDR len","Corrupt PNG");
img_x = get32(); if (img_x > (1 << 24)) return e("too large","Corrupt PNG"); img_x = get32(); if (img_x > (1 << 24)) return e("too large","Very large image (corrupt?)");
img_y = get32(); if (img_y > (1 << 24)) return e("too large","Corrupt PNG"); img_y = get32(); if (img_y > (1 << 24)) return e("too large","Very large image (corrupt?)");
depth = get8(); if (depth != 8) return e("8bit only","PNG not supported: 8-bit only"); depth = get8(); if (depth != 8) return e("8bit only","PNG not supported: 8-bit only");
color = get8(); if (color > 6) return e("bad ctype","Corrupt PNG"); color = get8(); if (color > 6) return e("bad ctype","Corrupt PNG");
if (color == 3) pal_img_n = 3; else if (color & 1) return e("bad ctype","Corrupt PNG"); if (color == 3) pal_img_n = 3; else if (color & 1) return e("bad ctype","Corrupt PNG");
@ -1976,7 +1989,7 @@ static int parse_png_file(int scan, int req_comp)
if (!img_x || !img_y) return e("0-pixel image","Corrupt PNG"); if (!img_x || !img_y) return e("0-pixel image","Corrupt PNG");
if (!pal_img_n) { if (!pal_img_n) {
img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
if ((1 << 30) / img_x / img_n < img_y) return e("too large", "Corrupt PNG"); if ((1 << 30) / img_x / img_n < img_y) return e("too large", "Image too large to decode");
if (scan == SCAN_header) return 1; if (scan == SCAN_header) return 1;
} else { } else {
// if paletted, then pal_n is our final components, and // if paletted, then pal_n is our final components, and

View File

@ -1 +1 @@
set VERSION="0.94" set VERSION="0.95"