mirror of
https://github.com/nothings/stb-imv
synced 2024-11-22 13:31:19 +03:00
stb_image fixes; gdi+ fixes merged from Won
This commit is contained in:
parent
f7468cec5c
commit
3b167d592c
95
imv.c
95
imv.c
@ -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
|
||||||
|
23
stb_image.c
23
stb_image.c
@ -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
|
||||||
|
@ -1 +1 @@
|
|||||||
set VERSION="0.94"
|
set VERSION="0.95"
|
||||||
|
Loading…
Reference in New Issue
Block a user