From 81a01c806fa35895fa9e6d40bef020f6f33783ab Mon Sep 17 00:00:00 2001 From: "nothings.org" Date: Tue, 26 Jun 2007 21:22:01 +0000 Subject: [PATCH] display errors --- imv.c | 213 ++++++++++++++++++++++++++++++++++------------ notes.txt | 22 +++-- notes_header.wiki | 2 +- readme_binary.txt | 30 ++----- vc6/stb_imv.dsp | 22 +++++ version.bat | 2 +- 6 files changed, 203 insertions(+), 88 deletions(-) diff --git a/imv.c b/imv.c index e09cea8..55e43ed 100644 --- a/imv.c +++ b/imv.c @@ -32,7 +32,11 @@ #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); } @@ -64,6 +68,8 @@ void ods(char *str, ...) enum { 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; barrier(); dc.files[i]->status = LOAD_error_reading; + wake(WM_APP_LOAD_ERROR); } else { dc.files[i]->error = NULL; assert(dc.files[i]->filedata == NULL); @@ -308,6 +315,7 @@ o(("DECODE: decoded %s\n", f->filename)); f->error = strdup(stbi_failure_reason()); barrier(); f->status = LOAD_error_reading; + wake(WM_APP_DECODE_ERROR); } else { f->image = (Image *) malloc(sizeof(*f->image)); 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) { - int i; + int i,j,k=0; z->pixels = image_data; z->x = image_x; 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; // swap RGB to BGR - for (i=0; i < image_x*image_y*BPP; i += BPP) { - unsigned char t = image_data[i+0]; - image_data[i+0] = image_data[i+2]; - image_data[i+2] = t; - #if BPP==4 - if (image_n == 4) { - // apply alpha - unsigned char *p = image_data+i; - int a = (255-p[3]); - p[0] += (((200 - (int) p[0])*a)>>8); - p[1] += (((100 - (int) p[1])*a)>>8); - p[2] += (((200 - (int) p[2])*a)>>8); + for (j=0; j < image_y; ++j) { + for (i=0; i < image_x; ++i) { + unsigned char t = image_data[k+0]; + image_data[k+0] = image_data[k+2]; + image_data[k+2] = t; + #if BPP==4 + if (image_n == 4) { + // apply alpha + unsigned char *p = image_data+k; + int a = (255-p[3]); + if ((i ^ j) & 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) { - free(x->pixels); - free(x); + if (x) { + free(x->pixels); + free(x); + } } Image image_region(Image *p, int x, int y, int w, int h) @@ -409,8 +428,8 @@ Image *cur; char *cur_filename; int show_help=0; -char helptext_center[] = - "imv(stb) version " VERSION +char helptext_center[128] = + "imv(stb) version " ; char helptext_left[] = @@ -454,6 +473,19 @@ void draw_nice(HDC hdc, char *text, RECT *rect, uint 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) { RECT rect,r2; @@ -462,6 +494,14 @@ void display(HWND win, HDC hdc) GetClientRect(win, &rect); w = rect.right - rect.left; 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; y = (h - cur->y) >> 1; @@ -484,7 +524,6 @@ void display(HWND win, HDC hdc) h2 = box.bottom - box.top; box = rect; box.left -= 200; box.right += 200; - SetBkMode(hdc, TRANSPARENT); box.top = stb_max((h - h2) >> 1, 0); box.bottom = box.top + h2; 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; if (!immediate) assert(pending_resize.size.w); + if (src_c == NULL) return; // create (w2,h2) matching aspect ratio of w/h 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) { - 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 MoveWindow(win, left, top, width, height, TRUE); InvalidateRect(win, NULL, FALSE); @@ -614,9 +654,21 @@ void size_to_current(int maximize) w2 = source->x+FRAME*2, h2 = source->y+FRAME*2; switch (display_mode) { - case DISPLAY_actual: + case DISPLAY_actual: { + int cx,cy; + RECT rect; 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; + } case DISPLAY_current: if (maximize) { x = y = -FRAME; @@ -639,6 +691,7 @@ void size_to_current(int maximize) imfree(cur); free(cur_filename); cur = bmp_alloc(z->x + FRAME*2, z->y + FRAME*2); + display_error[0] = 0; cur_filename = strdup(source_c->filename); frame(cur); { @@ -665,13 +718,16 @@ void update_source(ImageFile *q) source = z; source_c = q; - size_to_current(FALSE); + if (z) + size_to_current(FALSE); } void toggle_display(void) { - display_mode = (display_mode + 1) % DISPLAY__num; - size_to_current(TRUE); + if (source) { + display_mode = (display_mode + 1) % DISPLAY__num; + size_to_current(TRUE); + } } char path_to_file[4096], *filename; @@ -821,7 +877,9 @@ void queue_disk_command(DiskCommand *dc, int which, int make_current) return; } if (z->status != LOAD_inactive) { - // there was an error loading it... @todo, display the error + if (make_current) { + set_error(z); + } return; } // it's a go, use z @@ -923,34 +981,47 @@ void resize(int step) float s; int x2,y2; int zoom=0; - if (cur->x > source->x + FRAME*2 || cur->y > source->y + FRAME*2) { - 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; + + if (cur) { + if (cur->x > source->x + FRAME*2 || cur->y > source->y + FRAME*2) { + 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; + } + } 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 { - 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; - } + RECT rect; + GetWindowRect(win, &rect); + x2 = rect.right - rect.left; + y2 = rect.bottom - rect.top; + if (step > 0 && x2 <= 1200 && y2 <= 1024) + x2 <<= 1, y2 <<= 1; + 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; @@ -962,7 +1033,7 @@ void resize(int step) enqueue_resize(x,y,x2,y2); } - display_mode = zoom==1 ? DISPLAY_actual : DISPLAY_current; + display_mode = zoom==0 ? DISPLAY_actual : DISPLAY_current; } enum @@ -1108,6 +1179,27 @@ int WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 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: { // scan the filelist for the highest-lru, decoded image int i; @@ -1129,6 +1221,14 @@ int WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 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_LBUTTONDOWN: case WM_RBUTTONDOWN: @@ -1310,6 +1410,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine hInst = hInstance; GlobalMemoryStatus(&mem); 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 */ 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); 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); frame(cur); { @@ -1400,6 +1505,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine } else { // size is not an exact match queue_resize(w,h, (ImageFile *) &cache[0], TRUE); + display_error[0] = 0; cur = pending_resize.image; pending_resize.image = NULL; } @@ -1423,7 +1529,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine for(;;) { // if we're not currently resizing, start a resize 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 MoveWindow(win, qs.x,qs.y,qs.w,qs.h, TRUE); InvalidateRect(win, NULL, FALSE); @@ -1445,6 +1551,7 @@ o(("Enqueueing resize\n")); o(("Finished resize\n")); imfree(cur); cur = pending_resize.image; + display_error[0] = 0; cur_filename = pending_resize.filename; 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); diff --git a/notes.txt b/notes.txt index 0da8fac..61792a9 100644 --- a/notes.txt +++ b/notes.txt @@ -1,12 +1,18 @@ - Version 0.54 () - * resizing with ctrl- and ctrl+ correctly sets the actual-size-mode - * integrated help with F1/h/? + Version 0.55 [todo] + * bugfix: display error message for files that don't load + + 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) - * added Open File dialog if you run without a commandline - * ctrl-O lets you open an arbitrary file - * double-click, alt-enter to toggle actual-size vs. fullscreen - * changing images doesn't change window size except in actual-size mode + * feature: double-click, alt-enter to toggle actual-size vs. fullscreen + * feature: ctrl-O lets you open an arbitrary file + * feature: added Open File dialog if you run without a commandline + * bugfix: changing images doesn't change window size except in actual-size mode Version 0.52 (2007-06-25) - * fixed a bug with resizing + * bugfix: hang when resizing first image diff --git a/notes_header.wiki b/notes_header.wiki index cbf6882..daf01e9 100644 --- a/notes_header.wiki +++ b/notes_header.wiki @@ -2,7 +2,7 @@ = Release = -The current version is 0.53. +The current version is 0.54. = Release Notes = diff --git a/readme_binary.txt b/readme_binary.txt index 4047c0c..5e55f9e 100644 --- a/readme_binary.txt +++ b/readme_binary.txt @@ -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. http://www.gnu.org/licenses/gpl.html @@ -7,6 +7,7 @@ SOURCE http://code.google.com/p/stb-imv/ + INSTALLING Put it somewhere on your path. @@ -15,7 +16,7 @@ INSTALLING LAUNCHING Run on the commandline as: - imv {imagefile} + imv [imagefile] 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 @@ -24,33 +25,12 @@ LAUNCHING USER INTERFACE -General: - - 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 + Press F1 while running imv for documentation. UNINSTALLING - Delete it. + Delete the executable. RELEASE NOTES diff --git a/vc6/stb_imv.dsp b/vc6/stb_imv.dsp index 6ec5f71..af927ac 100644 --- a/vc6/stb_imv.dsp +++ b/vc6/stb_imv.dsp @@ -95,10 +95,32 @@ SOURCE=..\imv.c # Begin Source File SOURCE=..\notes.txt + +!IF "$(CFG)" == "stb_imv - Win32 Release" + +# PROP Exclude_From_Build 1 + +!ELSEIF "$(CFG)" == "stb_imv - Win32 Debug" + +!ENDIF + # End Source File # Begin Source File 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 Target # End Project diff --git a/version.bat b/version.bat index 29c8ea7..3efb64b 100644 --- a/version.bat +++ b/version.bat @@ -1 +1 @@ -set VERSION=0.53 \ No newline at end of file +set VERSION="0.54"