use FreeImage.dll if it's available

This commit is contained in:
nothings.org 2007-07-11 17:09:01 +00:00
parent 9e0f63ad87
commit 2255e9fd57
2 changed files with 264 additions and 27 deletions

281
imv.c
View File

@ -35,6 +35,25 @@
#include "resource.h"
// general configuration options
#define USE_FREEIMAGE
// size of border in pixels
#define FRAME 3
// location within frame of secondary border
#define FRAME2 (FRAME >> 1)
// color of secondary border
#define GREY 192
// all programs get the version number from the same place: version.bat
#define set static char *
#include "version.bat"
@ -64,16 +83,6 @@ void ods(char *str, ...)
#endif
// size of border in pixels
#define FRAME 3
// location within frame of secondary border
#define FRAME2 (FRAME >> 1)
// color of secondary border
#define GREY 192
// internal messages (all used for waking up main thread from tasks)
enum
{
@ -409,6 +418,8 @@ start:
return best;
}
static uint8 *imv_decode_from_memory(uint8 *mem, int len, int *x, int *y, int *n, int n_req);
void *decode_task(void *p)
{
for(;;) {
@ -428,7 +439,7 @@ void *decode_task(void *p)
// decode image
o(("DECIDE: decoding %s\n", f->filename));
data = stbi_load_from_memory(f->filedata, f->len, &x, &y, &n, BPP);
data = imv_decode_from_memory(f->filedata, f->len, &x, &y, &n, BPP);
o(("DECODE: decoded %s\n", f->filename));
// free copy of data from disk, which we don't need anymore
@ -536,9 +547,8 @@ int show_help=0;
int downsample_cubic = 0;
int upsample_cubic = TRUE;
// declare with extra bytes so we can print the version number into it
char helptext_center[88] =
char helptext_center[104] =
"imv(stb)\n"
"Copyright 2007 Sean Barrett\n"
"http://code.google.com/p/stb-imv\n"
@ -546,7 +556,7 @@ char helptext_center[88] =
;
char helptext_left[] =
"\n\n\n\n"
"\n\n\n\n\n"
" ESC: exit\n"
" ALT-ENTER: toggle size\n"
" CTRL-PLUS: zoom in\n"
@ -563,7 +573,7 @@ char helptext_left[] =
;
char helptext_right[] =
"\n\n\n\n\n"
"\n\n\n\n\n\n"
"right-click to exit\n"
"left drag center to move\n"
"left drag edges to resize\n"
@ -1096,6 +1106,8 @@ void free_fileinfo(void)
fileinfo = NULL;
}
char *open_filter = "Image Files\0*.jpg;*.jpeg;*.png;*.bmp\0";
// build a filelist for the current directory
void init_filelist(void)
{
@ -1109,7 +1121,7 @@ void init_filelist(void)
free_fileinfo();
}
image_files = stb_readdir_files_mask(path_to_file, "*.jpg;*.jpeg;*.png;*.bmp");
image_files = stb_readdir_files_mask(path_to_file, open_filter + 12);
if (image_files == NULL) { error("Error: couldn't read directory."); exit(0); }
// given the array of filenames, build an equivalent fileinfo array
@ -1365,12 +1377,13 @@ void advance(int dir)
// the filelist, and force it to load (and prefetch)
// with 'advance'
static char filenamebuffer[4096];
void open_file(void)
{
OPENFILENAME o;
memset(&o, 0, sizeof(o));
o.lStructSize = sizeof(o);
o.lpstrFilter = "Image Files\0*.jpg;*.jpeg;*.png;*.bmp\0";
o.lpstrFilter = open_filter;
o.lpstrFile = filenamebuffer;
filenamebuffer[0] = 0;
o.nMaxFile = sizeof(filenamebuffer);
@ -1639,6 +1652,8 @@ int reg_set(char *str, void *data, int len)
return (ERROR_SUCCESS == RegSetValueEx(zreg, str, 0, REG_BINARY, data, len));
}
int only_stbi=FALSE;
// we use very short strings for these to avoid wasting space, since
// people shouldn't be mucking with them directly anyway!
void reg_save(void)
@ -1651,6 +1666,7 @@ void reg_save(void)
reg_set("cache", &temp, 4);
reg_set("lfs", &label_font_height, 4);
reg_set("label", &show_label, 4);
reg_set("stbi", &only_stbi, 4);
RegCloseKey(zreg);
}
}
@ -1666,6 +1682,7 @@ void reg_load(void)
reg_get("label", &show_label, 4);
if (reg_get("cache", &temp, 4))
max_cache_bytes = temp << 20;
reg_get("stbi", &only_stbi, 4);
RegCloseKey(zreg);
}
}
@ -1730,6 +1747,7 @@ BOOL CALLBACK PrefDlgProc(HWND hdlg, UINT imsg, WPARAM wparam, LPARAM lparam)
// copy preferences into dialog
SendMessage(GetDlgItem(hdlg, DIALOG_upsample), BM_SETCHECK, upsample_cubic, 0);
SendMessage(GetDlgItem(hdlg, DIALOG_showlabel), BM_SETCHECK, show_label, 0);
SendMessage(GetDlgItem(hdlg, DIALOG_stbi_only), BM_SETCHECK, only_stbi, 0);
for (i=0; i < 6; ++i)
set_dialog_number(DIALOG_r1+i, alpha_background[0][i]);
set_dialog_number(DIALOG_cachesize, max_cache_bytes >> 20);
@ -1780,6 +1798,7 @@ BOOL CALLBACK PrefDlgProc(HWND hdlg, UINT imsg, WPARAM wparam, LPARAM lparam)
label_font_height = get_dialog_number(DIALOG_labelheight);
upsample_cubic = BST_CHECKED == SendMessage(GetDlgItem(hdlg,DIALOG_upsample ), BM_GETCHECK,0,0);
show_label = BST_CHECKED == SendMessage(GetDlgItem(hdlg,DIALOG_showlabel), BM_GETCHECK,0,0);
only_stbi = BST_CHECKED == SendMessage(GetDlgItem(hdlg,DIALOG_stbi_only), BM_GETCHECK,0,0);
// if alpha_background changed, clear the cache of any images that used it
if (memcmp(alpha_background, cur, 6)) {
@ -1828,6 +1847,33 @@ BOOL CALLBACK PrefDlgProc(HWND hdlg, UINT imsg, WPARAM wparam, LPARAM lparam)
return FALSE;
}
#ifdef PERFTEST
void performance_test(void)
{
int t1,t2;
int len,i;
uint8 *buffer = stb_file(cur_filename, &len);
if (buffer == NULL) return;
t1 = timeGetTime();
for (i=0; i < 50; ++i) {
int x,y,n;
uint8 *result = imv_decode_from_memory(buffer, len, &x, &y, &n, 4);
free(result);
}
t2 = timeGetTime();
free(buffer);
{
char buffer[512];
sprintf(buffer, "Decode time: %f ms\n", (t2-t1)/50.0);
error(buffer);
}
}
#endif
// missing VK definitions in old compiler
#ifndef VK_OEM_PLUS
#define VK_OEM_PLUS 0xbb
@ -2017,6 +2063,11 @@ int WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
extra_border = show_frame;
if (cur) frame(cur);
break;
#ifdef PERFTEST
case 'D' | MY_CTRL:
performance_test();
break;
#endif
case 'P':
case 'P' | MY_CTRL:
@ -2066,6 +2117,11 @@ int cur_is_current(void)
return !strcmp(cur_filename, source_c->filename);
}
#ifdef USE_FREEIMAGE
static int FreeImagePresent;
static int LoadFreeImage(void);
#endif
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
int argc;
@ -2083,10 +2139,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
inst = hInstance;
// concatenate the version number onto the help text, because
// we can't do this statically with the current build process
strcat(helptext_center, VERSION);
// determine the number of threads to use in the resizer
resize_threads = stb_min(stb_processor_count(), 16);
resize_threads = 8;
@ -2101,6 +2153,20 @@ resize_threads = 8;
// load the registry preferences, if they're there (AFTER the above)
reg_load();
// concatenate the version number onto the help text, because
// we can't do this statically with the current build process
strcat(helptext_center, VERSION);
// now try to LoadFreeImage _after_ we've already loaded the prefs;
// that way only_stbi can be used to suppress errors
#ifdef USE_FREEIMAGE
if (LoadFreeImage()) {
strcat(helptext_center, "\nUsing FreeImage.dll");
open_filter = "Image Files\0*.jpg;*.jpeg;*.png;*.bmp;*.dds;*.gif;*.ico;*.jng;*.lbm;*.pcx;*.ppm;*.psd;*.tga;*.tiff\0";
}
#endif
assert(helptext_center[sizeof(helptext_center)-1]==0);
// create the main window class
memset(&wndclass, 0, sizeof(wndclass));
wndclass.cbSize = sizeof(wndclass);
@ -2132,7 +2198,7 @@ resize_threads = 8;
OPENFILENAME o;
memset(&o, 0, sizeof(o));
o.lStructSize = sizeof(o);
o.lpstrFilter = "Image Files\0*.jpg;*.jpeg;*.png;*.bmp\0";
o.lpstrFilter = open_filter;
o.lpstrFile = filenamebuffer;
filenamebuffer[0] = 0;
o.nMaxFile = sizeof(filenamebuffer);
@ -2156,7 +2222,7 @@ resize_threads = 8;
if (!data)
why = "Couldn't open file";
else {
image_data = stbi_load_from_memory(data, len, &image_x, &image_y, &image_n, BPP);
image_data = imv_decode_from_memory(data, len, &image_x, &image_y, &image_n, BPP);
if (image_data == NULL)
why = stbi_failure_reason();
}
@ -2935,3 +3001,172 @@ void image_resize(Image *dest, Image *src)
}
#endif
}
#ifdef USE_FREEIMAGE
// FreeImage types
typedef int FREE_IMAGE_FORMAT;
typedef struct FIBITMAP FIBITMAP;
typedef struct FIMEMORY FIMEMORY;
typedef void (*FreeImage_OutputMessageFunction)(FREE_IMAGE_FORMAT fif, const char *msg);
#define fitype(x) typedef __declspec(dllimport) x __stdcall
// FreeImage functions that we're going to import;
fitype(void) freeimage_setoutputmessage(FreeImage_OutputMessageFunction omf);
static freeimage_setoutputmessage *FreeImage_SetOutputMessage;
fitype(FIMEMORY *) freeimage_openmemory(uint8 *data, unsigned size);
static freeimage_openmemory *FreeImage_OpenMemory;
fitype(void) freeimage_closememory(FIMEMORY *stream);
static freeimage_closememory *FreeImage_CloseMemory;
fitype(int) freeimage_seekmemory(FIMEMORY *stream, long offset, int origin);
static freeimage_seekmemory *FreeImage_SeekMemory;
fitype(FIBITMAP *) freeimage_loadfrommemory(FREE_IMAGE_FORMAT fif, FIMEMORY *fi, int flags);
static freeimage_loadfrommemory *FreeImage_LoadFromMemory;
fitype(void) freeimage_converttorawbits(BYTE *bits, FIBITMAP *dib, int pitch, unsigned bpp, unsigned red_mask, unsigned green_mask, unsigned blue_mask, BOOL topdown);
static freeimage_converttorawbits *FreeImage_ConvertToRawBits;
typedef __declspec(dllimport) void __stdcall freeimage_unload(FIBITMAP *dib);
static freeimage_unload *FreeImage_Unload;
typedef __declspec(dllimport) unsigned __stdcall freeimage_getwidth(FIBITMAP *dib);
static freeimage_getwidth *FreeImage_GetWidth;
typedef __declspec(dllimport) unsigned __stdcall freeimage_getheight(FIBITMAP *dib);
static freeimage_getheight *FreeImage_GetHeight;
typedef __declspec(dllimport) FREE_IMAGE_FORMAT __stdcall freeimage_getfiletypefrommemory(FIMEMORY *fi, int size);
static freeimage_getfiletypefrommemory *FreeImage_GetFileTypeFromMemory;
typedef __declspec(dllimport) FREE_IMAGE_FORMAT __stdcall freeimage_getfiffromfilename(const char *filename);
static freeimage_getfiffromfilename *FreeImage_GetFIFFromFilename;
typedef __declspec(dllimport) BYTE *__stdcall freeimage_getbits(FIBITMAP *dib);
static freeimage_getbits *FreeImage_GetBits;
typedef __declspec(dllimport) int __stdcall freeimage_istransparent(FIBITMAP *dib);
static freeimage_istransparent *FreeImage_IsTransparent;
static void
FreeImageErrorHandler(FREE_IMAGE_FORMAT fif, const char *message)
{
assert(!"FreeImage failure");
}
static HINSTANCE FreeImageDLL;
FARPROC fifunc(char *str)
{
FARPROC p = GetProcAddress(FreeImageDLL, str);
if (p == NULL)
FreeImagePresent = FALSE; // if something doesn't load, bail!
return p;
}
static int LoadFreeImage(void)
{
static int InitializationAttempted;
if(!InitializationAttempted)
{
FreeImageDLL = LoadLibrary("FreeImage.dll");
if(FreeImageDLL)
{
FreeImagePresent = TRUE;
FreeImage_ConvertToRawBits = (freeimage_converttorawbits *)fifunc("_FreeImage_ConvertToRawBits@32");
FreeImage_GetBits = (freeimage_getbits *)fifunc("_FreeImage_GetBits@4");
FreeImage_GetFIFFromFilename = (freeimage_getfiffromfilename *)fifunc("_FreeImage_GetFIFFromFilename@4");
FreeImage_GetFileTypeFromMemory = (freeimage_getfiletypefrommemory *)fifunc("_FreeImage_GetFileTypeFromMemory@8");
FreeImage_GetHeight = (freeimage_getheight *)fifunc("_FreeImage_GetHeight@4");
FreeImage_GetWidth = (freeimage_getwidth *)fifunc("_FreeImage_GetWidth@4");
FreeImage_LoadFromMemory = (freeimage_loadfrommemory *)fifunc("_FreeImage_LoadFromMemory@12");
FreeImage_SetOutputMessage = (freeimage_setoutputmessage *)fifunc("_FreeImage_SetOutputMessage@4");
FreeImage_Unload = (freeimage_unload *)fifunc("_FreeImage_Unload@4");
FreeImage_OpenMemory = (freeimage_openmemory *)fifunc("_FreeImage_OpenMemory@8");
FreeImage_CloseMemory = (freeimage_closememory *)fifunc("_FreeImage_CloseMemory@4");
FreeImage_SeekMemory = (freeimage_seekmemory *)fifunc("_FreeImage_SeekMemory@12");
FreeImage_IsTransparent = (freeimage_istransparent *)fifunc("_FreeImage_IsTransparent@4");
if (!FreeImagePresent) {
if (!only_stbi)
error("Invalid FreeImage.dll; disabling FreeImage support.");
} else
FreeImage_SetOutputMessage(FreeImageErrorHandler);
}
InitializationAttempted = TRUE;
}
return(FreeImagePresent);
}
uint8 *LoadImageWithFreeImage(FIMEMORY *fi, int *x, int *y, int *n, int n_req)
{
uint8 *Result = 0;
FREE_IMAGE_FORMAT FileFormat = FreeImage_GetFileTypeFromMemory(fi, 0);
FIBITMAP *Bitmap;
if(FileFormat == -1)
{
// @TODO: propogate the filename to here
// bail!
return NULL;
// FileFormat = FreeImage_GetFIFFromFilename(FromFilename);
}
FreeImage_SeekMemory(fi, 0, SEEK_SET);
Bitmap = FreeImage_LoadFromMemory(FileFormat, fi, 0);
if(Bitmap)
{
int32 Width = FreeImage_GetWidth(Bitmap);
int32 Height = FreeImage_GetHeight(Bitmap);
Result = (uint8 *) malloc(Width * Height * BPP);
if(Result)
{
int i;
FreeImage_ConvertToRawBits(Result, Bitmap, BPP*Width, BPP*8, 0xff0000,0x00ff00,0xff, FALSE);
#ifndef PERFTEST
for (i=0; i < Width*Height*BPP; i += BPP) {
uint8 t = Result[i];
Result[i] = Result[i+2];
Result[i+2] = t;
}
#endif
*x = Width;
*y = Height;
*n = FreeImage_IsTransparent(Bitmap) ? 4 : 3;
}
FreeImage_Unload(Bitmap);
}
return(Result);
}
#endif
static uint8 *imv_decode_from_memory(uint8 *mem, int len, int *x, int *y, int *n, int n_req)
{
uint8 *res = NULL;
#ifdef USE_FREEIMAGE
if (!only_stbi) {
if (res == NULL && FreeImagePresent) {
FIMEMORY *fi = FreeImage_OpenMemory(mem,len);
res = LoadImageWithFreeImage(fi, x, y, n, n_req);
FreeImage_CloseMemory(fi);
}
if (res) return res;
}
#endif
res = stbi_load_from_memory(mem, len, x, y, n, n_req);
return res;
}

10
pref.rc
View File

@ -52,13 +52,13 @@ END
// Dialog
//
IDD_pref DIALOG DISCARDABLE 0, 0, 161, 171
IDD_pref DIALOG DISCARDABLE 0, 0, 161, 196
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "imv(stb) preferences"
FONT 8, "MS Sans Serif"
BEGIN
DEFPUSHBUTTON "OK",IDOK,23,149,50,14
PUSHBUTTON "Cancel",IDCANCEL,83,149,50,14
DEFPUSHBUTTON "OK",IDOK,23,172,50,14
PUSHBUTTON "Cancel",IDCANCEL,83,172,50,14
CONTROL "High-quality resizing",DIALOG_upsample,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,23,116,76,10
EDITTEXT DIALOG_r1,57,50,19,12,ES_RIGHT | ES_AUTOHSCROLL
@ -79,6 +79,8 @@ BEGIN
LTEXT "Label font height",IDC_STATIC,35,101,104,10
CONTROL "Show filename label",DIALOG_showlabel,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,23,87,120,10
CONTROL "Only use stb_image loaders",DIALOG_stbi_only,"Button",
BS_AUTOCHECKBOX | WS_TABSTOP,23,149,111,10
END
@ -95,7 +97,7 @@ BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 154
TOPMARGIN, 7
BOTTOMMARGIN, 164
BOTTOMMARGIN, 189
END
END
#endif // APSTUDIO_INVOKED