mirror of
https://github.com/nothings/stb-imv
synced 2024-11-21 21:11:51 +03:00
stb_image fixes; gdi+ fixes merged from Won
This commit is contained in:
parent
f7468cec5c
commit
3b167d592c
91
imv.c
91
imv.c
@ -231,6 +231,26 @@ typedef struct
|
||||
// there can only be one pending command in flight
|
||||
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
|
||||
void *diskload_task(void *p)
|
||||
{
|
||||
@ -1972,7 +1992,7 @@ void performance_test(void)
|
||||
{
|
||||
int t1,t2;
|
||||
int len,i;
|
||||
uint8 *buffer = stb_file(cur_filename, &len);
|
||||
uint8 *buffer = stb_file2(cur_filename, &len);
|
||||
if (buffer == NULL) return;
|
||||
|
||||
t1 = timeGetTime();
|
||||
@ -2304,7 +2324,10 @@ int cur_is_current(void)
|
||||
}
|
||||
|
||||
#ifdef USE_GDIPLUS
|
||||
typedef ULONG ULONG_PTR;
|
||||
|
||||
static Bool GdiplusPresent;
|
||||
static ULONG_PTR GpToken;
|
||||
static Bool LoadGdiplus(void);
|
||||
#define ICM_SUFFIX ""
|
||||
// use this definition to enable color management
|
||||
@ -2414,7 +2437,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
||||
{
|
||||
char *why=NULL;
|
||||
int len;
|
||||
uint8 *data = stb_file(filename, &len);
|
||||
uint8 *data = stb_file2(filename, &len);
|
||||
if (!data)
|
||||
why = "Couldn't open file";
|
||||
else {
|
||||
@ -3213,6 +3236,7 @@ static char *imv_failure_reason(void)
|
||||
|
||||
#ifdef USE_GDIPLUS
|
||||
|
||||
|
||||
#pragma pack(push,8)
|
||||
|
||||
// from GdiplusTypes.h
|
||||
@ -3246,20 +3270,19 @@ typedef enum
|
||||
|
||||
typedef enum
|
||||
{
|
||||
DebugEventLevelFatal,
|
||||
DebugEventLevelWarning
|
||||
GpDebugEventLevelFatal,
|
||||
GpDebugEventLevelWarning
|
||||
} GpDebugEventLevel;
|
||||
|
||||
typedef VOID (WINAPI *GpDebugEventProc)(GpDebugEventLevel level, CHAR *message);
|
||||
|
||||
typedef ULONG ULONG_PTR;
|
||||
typedef GpStatus (WINAPI *GpNotificationHookProc)(ULONG_PTR *token);
|
||||
typedef VOID (WINAPI *GpNotificationUnhookProc)(ULONG_PTR token);
|
||||
|
||||
typedef struct {
|
||||
UINT32 GdiplusVersion;
|
||||
GpDebugEventProc DebugEventCallback;
|
||||
BOOL SuppressBackgroundThread; // TODO: manually call hook/unhook
|
||||
BOOL SuppressBackgroundThread;
|
||||
BOOL SuppressExternalCodecs;
|
||||
} GdiplusStartupInput;
|
||||
|
||||
@ -3271,9 +3294,6 @@ typedef struct {
|
||||
static HINSTANCE GdiplusDLL;
|
||||
static GdiplusStartupOutput gpStartupOutput;
|
||||
|
||||
typedef __declspec(dllimport) GpStatus (WINAPI *GdiplusStartupProc)(ULONG_PTR *token, const GdiplusStartupInput* input, GdiplusStartupOutput* output);
|
||||
static GdiplusStartupProc GdiplusStartup;
|
||||
|
||||
// from GdiplusHeaders.h
|
||||
typedef void GpImage; // opaque type
|
||||
|
||||
@ -3321,6 +3341,12 @@ typedef enum
|
||||
GpImageLockModeUserInputBuf= 0x0004
|
||||
} 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);
|
||||
static GdipCreateBitmapFromStreamProc GdipCreateBitmapFromStream;
|
||||
|
||||
@ -3333,6 +3359,8 @@ static GdipBitmapLockBitsProc GdipBitmapLockBits;
|
||||
typedef __declspec(dllimport) GpStatus (WINAPI *GdipBitmapUnlockBitsProc)(GpBitmap* bitmap, GpBitmapData* lockedBitmapData);
|
||||
static GdipBitmapUnlockBitsProc GdipBitmapUnlockBits;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
FARPROC GpFunc(char *str)
|
||||
{
|
||||
FARPROC p = GetProcAddress(GdiplusDLL, str);
|
||||
@ -3355,6 +3383,7 @@ static Bool LoadGdiplus(void)
|
||||
|
||||
GdiplusPresent = TRUE;
|
||||
GdiplusStartup = (GdiplusStartupProc)GpFunc("GdiplusStartup");
|
||||
//GdiplusShutdown = (GdiplusShutdownProc)GpFunc("GdiplusShutdown");
|
||||
GdipCreateBitmapFromStream = (GdipCreateBitmapFromStreamProc)GpFunc("GdipCreateBitmapFromStream" ICM_SUFFIX);
|
||||
GdipDisposeImage = (GdipDisposeImageProc)GpFunc("GdipDisposeImage");
|
||||
GdipBitmapLockBits = (GdipBitmapLockBitsProc)GpFunc("GdipBitmapLockBits");
|
||||
@ -3363,9 +3392,9 @@ static Bool LoadGdiplus(void)
|
||||
if (!only_stbi)
|
||||
error("Invalid GdiPlus.dll; disabling GDI+ support.");
|
||||
} else {
|
||||
ULONG token;
|
||||
GdiplusStartupInput gpStartupInput = { 1, NULL, FALSE, FALSE };
|
||||
if (GdiplusStartup(&token, &gpStartupInput, &gpStartupOutput) != GpOk) {
|
||||
// no need to use GDI+ backup thread, or to call the hook methods in gpStartupOutput
|
||||
GdiplusStartupInput gpStartupInput = { 1, NULL, TRUE, FALSE };
|
||||
if (GdiplusStartup(&GpToken, &gpStartupInput, &gpStartupOutput) != GpOk) {
|
||||
GdiplusPresent = FALSE;
|
||||
if (!only_stbi)
|
||||
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) {
|
||||
// TODO: implement an IStream that does this in-place, to avoid the copy and allocations
|
||||
IStream* stream;
|
||||
GpBitmap* bitmap;
|
||||
HGLOBAL hMem = NULL;
|
||||
IStream* stream = NULL;
|
||||
GpBitmap* bitmap = NULL;
|
||||
GpBitmapData data;
|
||||
HGLOBAL hmem;
|
||||
GpPixelFormat pixelFormat;
|
||||
size_t i, image_sz;
|
||||
uint8* buf, *ret = NULL;
|
||||
size_t i, image_sz = 0;
|
||||
uint8 *buf = NULL, *ret = NULL;
|
||||
image_sz = 0;
|
||||
*x = 0;
|
||||
*y = 0;
|
||||
*n = n_req;
|
||||
bitmap = NULL;
|
||||
data.Scan0 = NULL;
|
||||
|
||||
hmem = GlobalAlloc(GMEM_MOVEABLE, len);
|
||||
if (!hmem)
|
||||
hMem = GlobalAlloc(GMEM_MOVEABLE, len);
|
||||
if (!hMem)
|
||||
goto liwgExit;
|
||||
|
||||
buf = GlobalLock(hmem);
|
||||
if (!buf)
|
||||
goto liwgExit;
|
||||
buf = GlobalLock(hMem);
|
||||
if (!buf) goto liwgExit;
|
||||
|
||||
memcpy(buf, mem, len);
|
||||
if (GlobalUnlock(hMem))
|
||||
goto liwgExit;
|
||||
|
||||
if (CreateStreamOnHGlobal(buf, FALSE, &stream) != S_OK)
|
||||
goto liwgExit;
|
||||
|
||||
if (GdipCreateBitmapFromStream(stream, &bitmap) != GpOk)
|
||||
goto liwgExit;
|
||||
|
||||
if (n_req == 3)
|
||||
#if BPP == 3
|
||||
assert(n_req == 3);
|
||||
pixelFormat = GpPixelFormat24bppRGB;
|
||||
else
|
||||
#else
|
||||
assert(n_req == 4);
|
||||
pixelFormat = GpPixelFormat32bppARGB;
|
||||
#endif
|
||||
|
||||
if (GdipBitmapLockBits(bitmap, NULL, GpImageLockModeRead, pixelFormat, &data) != GpOk)
|
||||
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);
|
||||
|
||||
liwgExit:
|
||||
if (buf) GlobalUnlock(hmem);
|
||||
if (hmem) GlobalFree(hmem);
|
||||
if (data.Scan0) GdipBitmapUnlockBits(bitmap, &data);
|
||||
if (bitmap) GdipDisposeImage(bitmap);
|
||||
if (stream) stream->lpVtbl->Release(stream);
|
||||
if (hMem) GlobalFree(hMem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
QUICK NOTES:
|
||||
@ -16,6 +16,8 @@
|
||||
PSD loader
|
||||
|
||||
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.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same
|
||||
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");
|
||||
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].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");
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
@ -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].h2 = img_mcu_y * img_comp[i].v * 8;
|
||||
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;
|
||||
@ -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
|
||||
// currently)
|
||||
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) {
|
||||
int tx = (img_x+1)>>1;
|
||||
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;
|
||||
if (!first) return e("multiple IHDR","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_y = get32(); if (img_y > (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","Very large image (corrupt?)");
|
||||
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");
|
||||
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 (!pal_img_n) {
|
||||
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;
|
||||
} else {
|
||||
// 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