display errors

This commit is contained in:
nothings.org 2007-06-26 21:22:01 +00:00
parent bd5433ae3c
commit 81a01c806f
6 changed files with 203 additions and 88 deletions

213
imv.c
View File

@ -32,7 +32,11 @@
#include "stb_image.c" /* http://nothings.org/stb_image.c */ #include "stb_image.c" /* http://nothings.org/stb_image.c */
#define VERSION "0.53" // all programs get the version number from the same place: version.bat
#define set static char *
#include "version.bat"
;
#undef set
void error(char *str) { MessageBox(NULL, str, "imv(stb) error", MB_OK); } void error(char *str) { MessageBox(NULL, str, "imv(stb) error", MB_OK); }
@ -64,6 +68,8 @@ void ods(char *str, ...)
enum enum
{ {
WM_APP_DECODED = WM_APP, WM_APP_DECODED = WM_APP,
WM_APP_LOAD_ERROR,
WM_APP_DECODE_ERROR,
}; };
@ -233,6 +239,7 @@ o(("READ: Loading file %s\n", dc.files[i]->filename));
dc.files[i]->len = 0; dc.files[i]->len = 0;
barrier(); barrier();
dc.files[i]->status = LOAD_error_reading; dc.files[i]->status = LOAD_error_reading;
wake(WM_APP_LOAD_ERROR);
} else { } else {
dc.files[i]->error = NULL; dc.files[i]->error = NULL;
assert(dc.files[i]->filedata == NULL); assert(dc.files[i]->filedata == NULL);
@ -308,6 +315,7 @@ o(("DECODE: decoded %s\n", f->filename));
f->error = strdup(stbi_failure_reason()); f->error = strdup(stbi_failure_reason());
barrier(); barrier();
f->status = LOAD_error_reading; f->status = LOAD_error_reading;
wake(WM_APP_DECODE_ERROR);
} else { } else {
f->image = (Image *) malloc(sizeof(*f->image)); f->image = (Image *) malloc(sizeof(*f->image));
make_image(f->image, x,y,data,n); make_image(f->image, x,y,data,n);
@ -340,7 +348,7 @@ Image *bmp_alloc(int x, int y)
void make_image(Image *z, int image_x, int image_y, uint8 *image_data, int image_n) void make_image(Image *z, int image_x, int image_y, uint8 *image_data, int image_n)
{ {
int i; int i,j,k=0;
z->pixels = image_data; z->pixels = image_data;
z->x = image_x; z->x = image_x;
z->y = image_y; z->y = image_y;
@ -348,20 +356,29 @@ void make_image(Image *z, int image_x, int image_y, uint8 *image_data, int image
z->frame = 0; z->frame = 0;
// swap RGB to BGR // swap RGB to BGR
for (i=0; i < image_x*image_y*BPP; i += BPP) { for (j=0; j < image_y; ++j) {
unsigned char t = image_data[i+0]; for (i=0; i < image_x; ++i) {
image_data[i+0] = image_data[i+2]; unsigned char t = image_data[k+0];
image_data[i+2] = t; image_data[k+0] = image_data[k+2];
#if BPP==4 image_data[k+2] = t;
if (image_n == 4) { #if BPP==4
// apply alpha if (image_n == 4) {
unsigned char *p = image_data+i; // apply alpha
int a = (255-p[3]); unsigned char *p = image_data+k;
p[0] += (((200 - (int) p[0])*a)>>8); int a = (255-p[3]);
p[1] += (((100 - (int) p[1])*a)>>8); if ((i ^ j) & 8) {
p[2] += (((200 - (int) p[2])*a)>>8); p[0] += (((200 - (int) p[0])*a)>>8);
p[1] += ((( 40 - (int) p[1])*a)>>8);
p[2] += (((200 - (int) p[2])*a)>>8);
} else {
p[0] += (((150 - (int) p[0])*a)>>8);
p[1] += ((( 30 - (int) p[1])*a)>>8);
p[2] += (((150 - (int) p[2])*a)>>8);
}
}
#endif
k += BPP;
} }
#endif
} }
} }
@ -389,8 +406,10 @@ void frame(Image *z)
void imfree(Image *x) void imfree(Image *x)
{ {
free(x->pixels); if (x) {
free(x); free(x->pixels);
free(x);
}
} }
Image image_region(Image *p, int x, int y, int w, int h) Image image_region(Image *p, int x, int y, int w, int h)
@ -409,8 +428,8 @@ Image *cur;
char *cur_filename; char *cur_filename;
int show_help=0; int show_help=0;
char helptext_center[] = char helptext_center[128] =
"imv(stb) version " VERSION "imv(stb) version "
; ;
char helptext_left[] = char helptext_left[] =
@ -454,6 +473,19 @@ void draw_nice(HDC hdc, char *text, RECT *rect, uint flags)
DrawText(hdc, text, -1, rect, flags); DrawText(hdc, text, -1, rect, flags);
} }
char display_error[1024];
void set_error(volatile ImageFile *z)
{
sprintf(display_error, "File:\n%s\nError:\n%s\n", z->filename, z->error);
InvalidateRect(win, NULL, FALSE);
imfree(cur);
cur = NULL;
free(cur_filename);
cur_filename = strdup(z->filename);
source_c = (ImageFile *) z;
source = NULL;
}
void display(HWND win, HDC hdc) void display(HWND win, HDC hdc)
{ {
RECT rect,r2; RECT rect,r2;
@ -462,6 +494,14 @@ void display(HWND win, HDC hdc)
GetClientRect(win, &rect); GetClientRect(win, &rect);
w = rect.right - rect.left; w = rect.right - rect.left;
h = rect.bottom - rect.top; h = rect.bottom - rect.top;
SetBkMode(hdc, TRANSPARENT);
if (display_error[0]) {
FillRect(hdc, &rect, b);
if (rect.bottom > rect.top + 100) rect.top += 50;
draw_nice(hdc, display_error, &rect, DT_CENTER);
return;
}
x = (w - cur->x) >> 1; x = (w - cur->x) >> 1;
y = (h - cur->y) >> 1; y = (h - cur->y) >> 1;
@ -484,7 +524,6 @@ void display(HWND win, HDC hdc)
h2 = box.bottom - box.top; h2 = box.bottom - box.top;
box = rect; box = rect;
box.left -= 200; box.right += 200; box.left -= 200; box.right += 200;
SetBkMode(hdc, TRANSPARENT);
box.top = stb_max((h - h2) >> 1, 0); box.top = stb_max((h - h2) >> 1, 0);
box.bottom = box.top + h2; box.bottom = box.top + h2;
draw_nice(hdc, helptext_center, &box, DT_CENTER); draw_nice(hdc, helptext_center, &box, DT_CENTER);
@ -549,6 +588,7 @@ void queue_resize(int w, int h, ImageFile *src_c, int immediate)
int w2,h2; int w2,h2;
if (!immediate) assert(pending_resize.size.w); if (!immediate) assert(pending_resize.size.w);
if (src_c == NULL) return;
// create (w2,h2) matching aspect ratio of w/h // create (w2,h2) matching aspect ratio of w/h
w -= FRAME*2; w -= FRAME*2;
@ -582,7 +622,7 @@ void queue_resize(int w, int h, ImageFile *src_c, int immediate)
void enqueue_resize(int left, int top, int width, int height) void enqueue_resize(int left, int top, int width, int height)
{ {
if ((width == cur->x && height >= cur->y) || (height == cur->y && width >= cur->x)) { if (cur && ((width == cur->x && height >= cur->y) || (height == cur->y && width >= cur->x))) {
// no resize necessary, just a variant of the current shape // no resize necessary, just a variant of the current shape
MoveWindow(win, left, top, width, height, TRUE); MoveWindow(win, left, top, width, height, TRUE);
InvalidateRect(win, NULL, FALSE); InvalidateRect(win, NULL, FALSE);
@ -614,9 +654,21 @@ void size_to_current(int maximize)
w2 = source->x+FRAME*2, h2 = source->y+FRAME*2; w2 = source->x+FRAME*2, h2 = source->y+FRAME*2;
switch (display_mode) { switch (display_mode) {
case DISPLAY_actual: case DISPLAY_actual: {
int cx,cy;
RECT rect;
ideal_window_size(w2,h2, &w,&h, &x,&y); ideal_window_size(w2,h2, &w,&h, &x,&y);
cx = GetSystemMetrics(SM_CXSCREEN);
cy = GetSystemMetrics(SM_CYSCREEN);
if (w <= cx && h <= cy) {
GetWindowRect(win, &rect);
x = (rect.right + rect.left - w) >> 1;
y = (rect.top + rect.bottom - h) >> 1;
x = stb_clamp(x,0,cx-w);
y = stb_clamp(y,0,cy-h);
}
break; break;
}
case DISPLAY_current: case DISPLAY_current:
if (maximize) { if (maximize) {
x = y = -FRAME; x = y = -FRAME;
@ -639,6 +691,7 @@ void size_to_current(int maximize)
imfree(cur); imfree(cur);
free(cur_filename); free(cur_filename);
cur = bmp_alloc(z->x + FRAME*2, z->y + FRAME*2); cur = bmp_alloc(z->x + FRAME*2, z->y + FRAME*2);
display_error[0] = 0;
cur_filename = strdup(source_c->filename); cur_filename = strdup(source_c->filename);
frame(cur); frame(cur);
{ {
@ -665,13 +718,16 @@ void update_source(ImageFile *q)
source = z; source = z;
source_c = q; source_c = q;
size_to_current(FALSE); if (z)
size_to_current(FALSE);
} }
void toggle_display(void) void toggle_display(void)
{ {
display_mode = (display_mode + 1) % DISPLAY__num; if (source) {
size_to_current(TRUE); display_mode = (display_mode + 1) % DISPLAY__num;
size_to_current(TRUE);
}
} }
char path_to_file[4096], *filename; char path_to_file[4096], *filename;
@ -821,7 +877,9 @@ void queue_disk_command(DiskCommand *dc, int which, int make_current)
return; return;
} }
if (z->status != LOAD_inactive) { if (z->status != LOAD_inactive) {
// there was an error loading it... @todo, display the error if (make_current) {
set_error(z);
}
return; return;
} }
// it's a go, use z // it's a go, use z
@ -923,34 +981,47 @@ void resize(int step)
float s; float s;
int x2,y2; int x2,y2;
int zoom=0; int zoom=0;
if (cur->x > source->x + FRAME*2 || cur->y > source->y + FRAME*2) {
for(;;) { if (cur) {
s = (float) pow(2, zoom/2.0f + 0.25f); if (cur->x > source->x + FRAME*2 || cur->y > source->y + FRAME*2) {
x2 = int(x*s); for(;;) {
y2 = int(y*s); s = (float) pow(2, zoom/2.0f + 0.25f);
if (cur->x < x2 + FRAME*2 || cur->y < y2 + FRAME*2) x2 = int(x*s);
break; y2 = int(y*s);
++zoom; if (cur->x < x2 + FRAME*2 || cur->y < y2 + FRAME*2)
break;
++zoom;
}
} else {
for(;;) {
s = (float) pow(2, zoom/2.0f - 0.25f);
x2 = int(x*s);
y2 = int(y*s);
if (cur->x > x2 + FRAME*2 || cur->y > y2 + FRAME*2)
break;
--zoom;
}
} }
// now resize
do {
zoom += step;
s = (float) pow(2, zoom/2.0);
if (x*s < 4 || y*s < 4 || x*s > 4000 || y*s > 3000)
return;
x2 = int(x*s) + 2*FRAME;
y2 = int(y*s) + 2*FRAME;
} while (x2 == cur->x || y2 == cur->y);
} else { } else {
for(;;) { RECT rect;
s = (float) pow(2, zoom/2.0f - 0.25f); GetWindowRect(win, &rect);
x2 = int(x*s); x2 = rect.right - rect.left;
y2 = int(y*s); y2 = rect.bottom - rect.top;
if (cur->x > x2 + FRAME*2 || cur->y > y2 + FRAME*2) if (step > 0 && x2 <= 1200 && y2 <= 1024)
break; x2 <<= 1, y2 <<= 1;
--zoom; if (step < 0 && x2 >= 64 && y2 >= 64)
} x2 >>= 1, y2 >>= 1;
} }
// now resize
do {
zoom += step;
s = (float) pow(2, zoom/2.0);
if (x*s < 4 || y*s < 4 || x*s > 4000 || y*s > 3000)
return;
x2 = int(x*s) + 2*FRAME;
y2 = int(y*s) + 2*FRAME;
} while (x2 == cur->x || y2 == cur->y);
{ {
RECT rect; RECT rect;
@ -962,7 +1033,7 @@ void resize(int step)
enqueue_resize(x,y,x2,y2); enqueue_resize(x,y,x2,y2);
} }
display_mode = zoom==1 ? DISPLAY_actual : DISPLAY_current; display_mode = zoom==0 ? DISPLAY_actual : DISPLAY_current;
} }
enum enum
@ -1108,6 +1179,27 @@ int WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
break; break;
} }
case WM_APP_LOAD_ERROR:
case WM_APP_DECODE_ERROR:
{
int best_lru=0,i;
volatile ImageFile *best = NULL;
for (i=0; i < MAX_CACHED_IMAGES; ++i) {
if (cache[i].lru > best_lru) {
if (MAIN_OWNS(&cache[i])) {
if (cache[i].status >= LOAD_error_reading) {
best_lru = cache[i].lru;
best = &cache[i];
}
}
}
}
if (best->status == LOAD_error_reading || best->status == LOAD_error_decoding) {
set_error(best);
}
break;
}
case WM_APP_DECODED: { case WM_APP_DECODED: {
// scan the filelist for the highest-lru, decoded image // scan the filelist for the highest-lru, decoded image
int i; int i;
@ -1129,6 +1221,14 @@ int WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
break; break;
} }
case WM_MOUSEWHEEL: {
int zdelta = (short) HIWORD(wParam);
// ignore scaling factor and step 1 by 1
if (zdelta > 0) resize(1);
if (zdelta < 0) resize(-1);
break;
}
case WM_MOUSEMOVE: case WM_MOUSEMOVE:
case WM_LBUTTONDOWN: case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN: case WM_RBUTTONDOWN:
@ -1310,6 +1410,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
hInst = hInstance; hInst = hInstance;
GlobalMemoryStatus(&mem); GlobalMemoryStatus(&mem);
physmem = mem.dwTotalPhys; physmem = mem.dwTotalPhys;
max_cache_bytes = physmem / 6;
if (max_cache_bytes > 256 << 20) max_cache_bytes = 256 << 20;
strcat(helptext_center, VERSION);
/* Register the frame class */ /* Register the frame class */
memset(&wndclass, 0, sizeof(wndclass)); memset(&wndclass, 0, sizeof(wndclass));
@ -1385,6 +1489,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
ideal_window_size(w2,h2, &w,&h, &x,&y); ideal_window_size(w2,h2, &w,&h, &x,&y);
if (w == source->x+FRAME*2 && h == source->y+FRAME*2) { if (w == source->x+FRAME*2 && h == source->y+FRAME*2) {
display_error[0] = 0;
cur = bmp_alloc(image_x + FRAME*2, image_y + FRAME*2); cur = bmp_alloc(image_x + FRAME*2, image_y + FRAME*2);
frame(cur); frame(cur);
{ {
@ -1400,6 +1505,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
} else { } else {
// size is not an exact match // size is not an exact match
queue_resize(w,h, (ImageFile *) &cache[0], TRUE); queue_resize(w,h, (ImageFile *) &cache[0], TRUE);
display_error[0] = 0;
cur = pending_resize.image; cur = pending_resize.image;
pending_resize.image = NULL; pending_resize.image = NULL;
} }
@ -1423,7 +1529,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
for(;;) { for(;;) {
// if we're not currently resizing, start a resize // if we're not currently resizing, start a resize
if (qs.w && pending_resize.size.w == 0) { if (qs.w && pending_resize.size.w == 0) {
if (cur_is_current() && ((qs.w == cur->x && qs.h >= cur->y) || (qs.h == cur->y && qs.w >= cur->x))) { if (cur_is_current() && (!cur || (qs.w == cur->x && qs.h >= cur->y) || (qs.h == cur->y && qs.w >= cur->x))) {
// no resize necessary, just a variant of the current shape // no resize necessary, just a variant of the current shape
MoveWindow(win, qs.x,qs.y,qs.w,qs.h, TRUE); MoveWindow(win, qs.x,qs.y,qs.w,qs.h, TRUE);
InvalidateRect(win, NULL, FALSE); InvalidateRect(win, NULL, FALSE);
@ -1445,6 +1551,7 @@ o(("Enqueueing resize\n"));
o(("Finished resize\n")); o(("Finished resize\n"));
imfree(cur); imfree(cur);
cur = pending_resize.image; cur = pending_resize.image;
display_error[0] = 0;
cur_filename = pending_resize.filename; cur_filename = pending_resize.filename;
pending_resize.filename = NULL; pending_resize.filename = NULL;
SetWindowPos(hWnd,NULL,pending_resize.size.x, pending_resize.size.y, pending_resize.size.w, pending_resize.size.h, SWP_NOZORDER); SetWindowPos(hWnd,NULL,pending_resize.size.x, pending_resize.size.y, pending_resize.size.w, pending_resize.size.h, SWP_NOZORDER);

View File

@ -1,12 +1,18 @@
Version 0.54 () Version 0.55 [todo]
* resizing with ctrl- and ctrl+ correctly sets the actual-size-mode * bugfix: display error message for files that don't load
* integrated help with F1/h/?
Version 0.54 (2007-06-26)
* bugfix: keep current window position while switching windows in actual-size mode
* feature: mousewheel to resize
* feature: checkerboard border behind alpha - but image sized, not zoom-independent
* feature: integrated help with F1/h/?
* bugfix: resizing with ctrl- and ctrl+ correctly sets the actual-size-mode
Version 0.53 (2007-06-25) Version 0.53 (2007-06-25)
* added Open File dialog if you run without a commandline * feature: double-click, alt-enter to toggle actual-size vs. fullscreen
* ctrl-O lets you open an arbitrary file * feature: ctrl-O lets you open an arbitrary file
* double-click, alt-enter to toggle actual-size vs. fullscreen * feature: added Open File dialog if you run without a commandline
* changing images doesn't change window size except in actual-size mode * bugfix: changing images doesn't change window size except in actual-size mode
Version 0.52 (2007-06-25) Version 0.52 (2007-06-25)
* fixed a bug with resizing * bugfix: hang when resizing first image

View File

@ -2,7 +2,7 @@
= Release = = Release =
The current version is 0.53. The current version is 0.54.
= Release Notes = = Release Notes =

View File

@ -1,4 +1,4 @@
*| imv(stb) windows image viewer. copyright 2007 Sean Barrett. GPL 2.0. |* *| imv(stb) windows image viewer. copyright 2007 Sean Barrett. GPL 2.0. |*
This program comes with NO WARRANTY. See the GNU GPL for details. This program comes with NO WARRANTY. See the GNU GPL for details.
http://www.gnu.org/licenses/gpl.html http://www.gnu.org/licenses/gpl.html
@ -7,6 +7,7 @@ SOURCE
http://code.google.com/p/stb-imv/ http://code.google.com/p/stb-imv/
INSTALLING INSTALLING
Put it somewhere on your path. Put it somewhere on your path.
@ -15,7 +16,7 @@ INSTALLING
LAUNCHING LAUNCHING
Run on the commandline as: Run on the commandline as:
imv {imagefile} imv [imagefile]
You can use 'open with' and it will do the right thing. You can You can use 'open with' and it will do the right thing. You can
even set it as the default for JPG/PNG/BMP filetypes, but since even set it as the default for JPG/PNG/BMP filetypes, but since
@ -24,33 +25,12 @@ LAUNCHING
USER INTERFACE USER INTERFACE
General: Press F1 while running imv for documentation.
ESC exit application
ALT F4 exit application
right-click exit application
Single images:
drag image move image
drag corners resize
drag edges resize
CTRL + resize larger (doubles every two presses)
CTRL - resize smaller (halves every two presses)
Multiple images:
RIGHT ARROW go to next image in directory
LEFT ARROW go to previous image in directory
SPACE go to next image in directory
BACKSPACE go to previous image in directory
UNINSTALLING UNINSTALLING
Delete it. Delete the executable.
RELEASE NOTES RELEASE NOTES

View File

@ -95,10 +95,32 @@ SOURCE=..\imv.c
# Begin Source File # Begin Source File
SOURCE=..\notes.txt SOURCE=..\notes.txt
!IF "$(CFG)" == "stb_imv - Win32 Release"
# PROP Exclude_From_Build 1
!ELSEIF "$(CFG)" == "stb_imv - Win32 Debug"
!ENDIF
# End Source File # End Source File
# Begin Source File # Begin Source File
SOURCE=..\stb.h SOURCE=..\stb.h
# End Source File
# Begin Source File
SOURCE=..\version.bat
!IF "$(CFG)" == "stb_imv - Win32 Release"
# PROP Exclude_From_Build 1
!ELSEIF "$(CFG)" == "stb_imv - Win32 Debug"
!ENDIF
# End Source File # End Source File
# End Target # End Target
# End Project # End Project

View File

@ -1 +1 @@
set VERSION=0.53 set VERSION="0.54"