This commit is contained in:
nothings.org 2008-10-20 06:20:45 +00:00
parent 33491d6a7e
commit eb8babe4db
4 changed files with 162 additions and 24 deletions

75
imv.c
View File

@ -53,6 +53,8 @@
#define ALLOW_RECOLORING 1 #define ALLOW_RECOLORING 1
#endif #endif
//#define MONO2
// implement USE_STBI // implement USE_STBI
#if USE_STBI #if USE_STBI
@ -388,8 +390,12 @@ void make_image(Image *z, int image_x, int image_y, uint8 *image_data, BOOL imag
#if ALLOW_RECOLORING #if ALLOW_RECOLORING
if (mono) { if (mono) {
#ifdef MONO2
int p = image_data[k+2];
#else
int y = image_data[k+0]*5 + image_data[k+1]*9 + image_data[k+2]*2; int y = image_data[k+0]*5 + image_data[k+1]*9 + image_data[k+2]*2;
int p = (int) stb_linear_remap(y, ymin, ymax, 0,255); int p = (int) stb_linear_remap(y, ymin, ymax, 0,255);
#endif
image_data[k+0] = p; image_data[k+0] = p;
image_data[k+1] = p; image_data[k+1] = p;
image_data[k+2] = p; image_data[k+2] = p;
@ -641,6 +647,7 @@ char helptext_left[] =
" CTRL-B: toggle white stripe in border\n" " CTRL-B: toggle white stripe in border\n"
" L: toggle filename label\n" " L: toggle filename label\n"
" S: slideshow in current directory\n" " S: slideshow in current directory\n"
" CTRL-S: sharpen when upscaling\n"
; ;
char helptext_right[] = char helptext_right[] =
@ -957,6 +964,8 @@ void GetAdjustedWindowRect(HWND win, RECT *rect)
} }
} }
int allow_fullsize;
// compute the size we'd prefer this window to be at for 1:1-ness // compute the size we'd prefer this window to be at for 1:1-ness
void ideal_window_size(int w, int h, int *w_ideal, int *h_ideal, int *x, int *y) void ideal_window_size(int w, int h, int *w_ideal, int *h_ideal, int *x, int *y)
{ {
@ -967,7 +976,7 @@ void ideal_window_size(int w, int h, int *w_ideal, int *h_ideal, int *x, int *y)
int cx2 = GetSystemMetrics(SM_CXSCREEN); int cx2 = GetSystemMetrics(SM_CXSCREEN);
int cy2 = GetSystemMetrics(SM_CYSCREEN); int cy2 = GetSystemMetrics(SM_CYSCREEN);
if (w <= cx2 && h <= cy2) { if (allow_fullsize || (w <= cx2 && h <= cy2)) {
// if the image fits on the primary monitor, go for it // if the image fits on the primary monitor, go for it
*w_ideal = w; *w_ideal = w;
*h_ideal = h; *h_ideal = h;
@ -1193,10 +1202,11 @@ void free_fileinfo(void)
// food.jpg // food.jpg
// use upper, not lower, to get better sorting versus '_' // use upper, not lower, to get better sorting versus '_'
// no, use lower not upper, to get sorting that matches explorer
__forceinline char tupper(char b) __forceinline char tupper(char b)
{ {
//if (b >= 'A' && b <= 'Z') return b - 'A' + 'a'; if (b >= 'A' && b <= 'Z') return b - 'A' + 'a';
if (b >= 'a' && b <= 'z') return b - 'a' + 'A'; //if (b >= 'a' && b <= 'z') return b - 'a' + 'A';
return b; return b;
} }
@ -2004,7 +2014,7 @@ BOOL CALLBACK PrefDlgProc(HWND hdlg, UINT imsg, WPARAM wparam, LPARAM lparam)
#else #else
int channels; int channels;
Bool loaded_as_rgb; Bool loaded_as_rgb;
uint8 *data = imv_decode_from_memory(rom_images[n], 2000, &x, &y, &loaded_as_rgb, &channels, BPP); uint8 *data = imv_decode_from_memory(rom_images[n], 2000, &x, &y, &loaded_as_rgb, &channels, BPP, "");
assert(channels == BPP); assert(channels == BPP);
pref_image = bmp_alloc(x, y); pref_image = bmp_alloc(x, y);
pref_image->pixels = data; pref_image->pixels = data;
@ -2169,9 +2179,11 @@ void performance_test(void)
#define WM_APPCOMMAND 0x0319 #define WM_APPCOMMAND 0x0319
#define APPCOMMAND_BROWSER_BACKWARD 1 #define APPCOMMAND_BROWSER_BACKWARD 1
#define APPCOMMAND_BROWSER_FORWARD 2 #define APPCOMMAND_BROWSER_FORWARD 2
#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK))
#endif
#ifndef APPCOMMAND_OPEN
#define APPCOMMAND_OPEN 30 #define APPCOMMAND_OPEN 30
#define FAPPCOMMAND_MASK 0xF000 #define FAPPCOMMAND_MASK 0xF000
#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK))
#endif #endif
// ok, surely windows doesn't BY DESIGN require you to store your // ok, surely windows doesn't BY DESIGN require you to store your
@ -2179,6 +2191,7 @@ void performance_test(void)
// or some such to tell you what instance a thread came from. But the // or some such to tell you what instance a thread came from. But the
// HINSTANCE is needed to launch the preferences dialog. Oh well! // HINSTANCE is needed to launch the preferences dialog. Oh well!
HINSTANCE inst; HINSTANCE inst;
int sharpen=0;
int WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) int WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ {
@ -2503,11 +2516,26 @@ int WINAPI MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
resize(-1); resize(-1);
break; break;
case 'S' | MY_CTRL:
sharpen = !sharpen;
--cur->y;
--cur->x;
size_to_current(0);
break;
case 'O': case 'O':
case MY_CTRL | 'O': case MY_CTRL | 'O':
open_file(); open_file();
break; break;
case MY_CTRL | 'F':
allow_fullsize = !allow_fullsize;
if (allow_fullsize)
display_mode = DISPLAY_current;
else
display_mode = !display_mode;
toggle_display();
break;
case MY_ALT | '\r': case MY_ALT | '\r':
toggle_display(); toggle_display();
break; break;
@ -3052,7 +3080,7 @@ typedef uint32 Color;
// lerp() is just blend() that also "blends" alpha // lerp() is just blend() that also "blends" alpha
// put a/256 of src over dest, including alpha // put a/256 of src over dest, including alpha
// again, cannot be used for a=256 ;// again, cannot be used for a=256
static Color lerp(Color dest, Color src, uint8 a) static Color lerp(Color dest, Color src, uint8 a)
{ {
int rb_src = src & 0xff00ff; int rb_src = src & 0xff00ff;
@ -3413,6 +3441,36 @@ Image *downsample_two_thirds(Image *src)
return res; return res;
} }
void do_sharpen(uint8 *data, int stride, int x, int y)
{
int i,j,k;
uint8 prev[3200*4];
if (x > 3200) return;
memcpy(prev, data, x*BPP);
for (j=1; j < y-1; ++j) {
uint8 *next = data + stride*(j+1);
unsigned char left[4];
memcpy(left, data+stride*j+BPP, BPP);
for (i=1; i < x-1; ++i) {
unsigned char temp[4];
memcpy(temp, data+stride*j+i*BPP,BPP);
for (k=0; k < BPP; ++k) {
int v = data[stride*j+i*BPP+k] * 16;
v -= (prev[i*BPP+k-4] + prev[i*BPP+k] + prev[i*BPP+k+4]);
v -= (next[i*BPP+k-4] + next[i*BPP+k] + next[i*BPP+k+4]);
v -= (left[k] + data[stride*j+i*BPP+4+k]);
v >>= 3;
if (v < 0) v = 0; else if (v > 255) v = 255;
data[stride*j+i*BPP+k] = v;
}
// now temp becomes the new left
// but first:
memcpy(prev+(i-1)*BPP, left, BPP);
memcpy(left, temp, BPP);
}
}
}
Image *grScaleBitmap(Image *src, int gx, int gy, Image *dest) Image *grScaleBitmap(Image *src, int gx, int gy, Image *dest)
{ {
Image *to_free, *res; Image *to_free, *res;
@ -3423,6 +3481,9 @@ Image *grScaleBitmap(Image *src, int gx, int gy, Image *dest)
if (gx > src->x || gy > src->y) { if (gx > src->x || gy > src->y) {
upsample = TRUE; upsample = TRUE;
} else { } else {
// current biggest problem perf-wise is on scaling down, we don't
// use threads
// maybe should do something smarter here, like find the // maybe should do something smarter here, like find the
// nearest box size, instead of repetitive powers of two // nearest box size, instead of repetitive powers of two
while (gx <= (src->x >> 1) && gy <= (src->y >> 1)) { while (gx <= (src->x >> 1) && gy <= (src->y >> 1)) {
@ -3465,6 +3526,8 @@ Image *grScaleBitmap(Image *src, int gx, int gy, Image *dest)
imfree(to_free); imfree(to_free);
#endif #endif
} }
if (upsample && sharpen)
do_sharpen(res->pixels, res->stride, res->x, res->y);
return res; return res;
} }
#endif // BPP==4 #endif // BPP==4

View File

@ -1,3 +1,8 @@
Version 1.0: Release 1
* feature: open a directory
* feature: sharpen when upscaling
* secret feature: toggle use of full-size virtual desktop
Version 0.991: Beta 12 Version 0.991: Beta 12
* bugfix: .spk file recursion issues, security * bugfix: .spk file recursion issues, security

View File

@ -1,4 +1,4 @@
/* stbi-1.15 - public domain JPEG/PNG reader - http://nothings.org/stb_image.c /* stbi-1.17 - 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:
@ -6,7 +6,7 @@
avoid problematic images and only need the trivial interface avoid problematic images and only need the trivial interface
JPEG baseline (no JPEG progressive, no oddball channel decimations) JPEG baseline (no JPEG progressive, no oddball channel decimations)
PNG non-interlaced PNG 8-bit only
BMP non-1bpp, non-RLE BMP non-1bpp, non-RLE
TGA (not sure what subset, if a subset) TGA (not sure what subset, if a subset)
PSD (composited view only, no extra channels) PSD (composited view only, no extra channels)
@ -19,6 +19,8 @@
stbi_info_* stbi_info_*
history: history:
1.17 support interlaced PNG
1.16 major bugfix - convert_format converted one too many pixels
1.15 initialize some fields for thread safety 1.15 initialize some fields for thread safety
1.14 fix threadsafe conversion bug; header-file-only version (#define STBI_HEADER_FILE_ONLY before including) 1.14 fix threadsafe conversion bug; header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
1.13 threadsafe 1.13 threadsafe
@ -1388,7 +1390,7 @@ static int process_marker(jpeg *z, int m)
z->dequant[t][dezigzag[i]] = get8u(&z->s); z->dequant[t][dezigzag[i]] = get8u(&z->s);
#if STBI_SIMD #if STBI_SIMD
for (i=0; i < 64; ++i) for (i=0; i < 64; ++i)
z->dequant2[t][i] = dequant[t][i]; z->dequant2[t][i] = z->dequant[t][i];
#endif #endif
L -= 65; L -= 65;
} }
@ -1654,7 +1656,7 @@ static uint8 *resample_row_generic(uint8 *out, uint8 *in_near, uint8 *in_far, in
// 0.38 seconds on 3*anemones.jpg (0.25 with processor = Pro) // 0.38 seconds on 3*anemones.jpg (0.25 with processor = Pro)
// VC6 without processor=Pro is generating multiple LEAs per multiply! // VC6 without processor=Pro is generating multiple LEAs per multiply!
static void YCbCr_to_RGB_row(uint8 *out, uint8 *y, uint8 *pcb, uint8 *pcr, int count, int step) static void YCbCr_to_RGB_row(uint8 *out, const uint8 *y, const uint8 *pcb, const uint8 *pcr, int count, int step)
{ {
int i; int i;
for (i=0; i < count; ++i) { for (i=0; i < count; ++i) {
@ -2185,6 +2187,7 @@ static void init_defaults(void)
for (i=0; i <= 31; ++i) default_distance[i] = 5; for (i=0; i <= 31; ++i) default_distance[i] = 5;
} }
int stbi_png_partial; // a quick hack to only allow decoding some of a PNG... I should implement real streaming support instead
static int parse_zlib(zbuf *a, int parse_header) static int parse_zlib(zbuf *a, int parse_header)
{ {
int final, type; int final, type;
@ -2210,6 +2213,8 @@ static int parse_zlib(zbuf *a, int parse_header)
} }
if (!parse_huffman_block(a)) return 0; if (!parse_huffman_block(a)) return 0;
} }
if (stbi_png_partial && a->zout - a->zout_start > 65536)
break;
} while (!final); } while (!final);
return 1; return 1;
} }
@ -2348,17 +2353,23 @@ static int paeth(int a, int b, int c)
} }
// create the png data from post-deflated data // create the png data from post-deflated data
static int create_png_image(png *a, uint8 *raw, uint32 raw_len, int out_n) static int create_png_image_raw(png *a, uint8 *raw, uint32 raw_len, int out_n, uint32 x, uint32 y)
{ {
stbi *s = &a->s; stbi *s = &a->s;
uint32 i,j,stride = s->img_x*out_n; uint32 i,j,stride = x*out_n;
int k; int k;
int img_n = s->img_n; // copy it into a local for later int img_n = s->img_n; // copy it into a local for later
assert(out_n == s->img_n || out_n == s->img_n+1); assert(out_n == s->img_n || out_n == s->img_n+1);
a->out = (uint8 *) malloc(s->img_x * s->img_y * out_n); if (stbi_png_partial) y = 1;
a->out = (uint8 *) malloc(x * y * out_n);
if (!a->out) return e("outofmem", "Out of memory"); if (!a->out) return e("outofmem", "Out of memory");
if (raw_len != (img_n * s->img_x + 1) * s->img_y) return e("not enough pixels","Corrupt PNG"); if (!stbi_png_partial) {
for (j=0; j < s->img_y; ++j) { if (s->img_x == x && s->img_y == y)
if (raw_len != (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG");
else // interlaced:
if (raw_len < (img_n * x + 1) * y) return e("not enough pixels","Corrupt PNG");
}
for (j=0; j < y; ++j) {
uint8 *cur = a->out + stride*j; uint8 *cur = a->out + stride*j;
uint8 *prior = cur - stride; uint8 *prior = cur - stride;
int filter = *raw++; int filter = *raw++;
@ -2385,7 +2396,7 @@ static int create_png_image(png *a, uint8 *raw, uint32 raw_len, int out_n)
if (img_n == out_n) { if (img_n == out_n) {
#define CASE(f) \ #define CASE(f) \
case f: \ case f: \
for (i=s->img_x-1; i >= 1; --i, raw+=img_n,cur+=img_n,prior+=img_n) \ for (i=x-1; i >= 1; --i, raw+=img_n,cur+=img_n,prior+=img_n) \
for (k=0; k < img_n; ++k) for (k=0; k < img_n; ++k)
switch(filter) { switch(filter) {
CASE(F_none) cur[k] = raw[k]; break; CASE(F_none) cur[k] = raw[k]; break;
@ -2401,7 +2412,7 @@ static int create_png_image(png *a, uint8 *raw, uint32 raw_len, int out_n)
assert(img_n+1 == out_n); assert(img_n+1 == out_n);
#define CASE(f) \ #define CASE(f) \
case f: \ case f: \
for (i=s->img_x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \ for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \
for (k=0; k < img_n; ++k) for (k=0; k < img_n; ++k)
switch(filter) { switch(filter) {
CASE(F_none) cur[k] = raw[k]; break; CASE(F_none) cur[k] = raw[k]; break;
@ -2418,6 +2429,47 @@ static int create_png_image(png *a, uint8 *raw, uint32 raw_len, int out_n)
return 1; return 1;
} }
static int create_png_image(png *a, uint8 *raw, uint32 raw_len, int out_n, int interlaced)
{
uint8 *final;
int p;
int save;
if (!interlaced)
return create_png_image_raw(a, raw, raw_len, out_n, a->s.img_x, a->s.img_y);
save = stbi_png_partial;
stbi_png_partial = 0;
// deinterlacing
final = malloc(a->s.img_x * a->s.img_y * out_n);
for (p=0; p < 7; ++p) {
int xorig[] = { 0,4,0,2,0,1,0 };
int yorig[] = { 0,0,4,0,2,0,1 };
int xspc[] = { 8,8,4,4,2,2,1 };
int yspc[] = { 8,8,8,4,4,2,2 };
int i,j,x,y;
// pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1
x = (a->s.img_x - xorig[p] + xspc[p]-1) / xspc[p];
y = (a->s.img_y - yorig[p] + yspc[p]-1) / yspc[p];
if (x && y) {
if (!create_png_image_raw(a, raw, raw_len, out_n, x, y)) {
free(final);
return 0;
}
for (j=0; j < y; ++j)
for (i=0; i < x; ++i)
memcpy(final + (j*yspc[p]+yorig[p])*a->s.img_x*out_n + (i*xspc[p]+xorig[p])*out_n,
a->out + (j*x+i)*out_n, out_n);
free(a->out);
raw += (x*out_n+1)*y;
raw_len -= (x*out_n+1)*y;
}
}
a->out = final;
stbi_png_partial = save;
return 1;
}
static int compute_transparency(png *z, uint8 tc[3], int out_n) static int compute_transparency(png *z, uint8 tc[3], int out_n)
{ {
stbi *s = &z->s; stbi *s = &z->s;
@ -2482,7 +2534,7 @@ static int parse_png_file(png *z, int scan, int req_comp)
uint8 palette[1024], pal_img_n=0; uint8 palette[1024], pal_img_n=0;
uint8 has_trans=0, tc[3]; uint8 has_trans=0, tc[3];
uint32 ioff=0, idata_limit=0, i, pal_len=0; uint32 ioff=0, idata_limit=0, i, pal_len=0;
int first=1,k; int first=1,k,interlace=0;
stbi *s = &z->s; stbi *s = &z->s;
if (!check_png_header(s)) return 0; if (!check_png_header(s)) return 0;
@ -2495,7 +2547,7 @@ static int parse_png_file(png *z, int scan, int req_comp)
return e("first not IHDR","Corrupt PNG"); return e("first not IHDR","Corrupt PNG");
switch (c.type) { switch (c.type) {
case PNG_TYPE('I','H','D','R'): { case PNG_TYPE('I','H','D','R'): {
int depth,color,interlace,comp,filter; int depth,color,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");
s->img_x = get32(s); if (s->img_x > (1 << 24)) return e("too large","Very large image (corrupt?)"); s->img_x = get32(s); if (s->img_x > (1 << 24)) return e("too large","Very large image (corrupt?)");
@ -2505,7 +2557,7 @@ static int parse_png_file(png *z, int scan, int req_comp)
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");
comp = get8(s); if (comp) return e("bad comp method","Corrupt PNG"); comp = get8(s); if (comp) return e("bad comp method","Corrupt PNG");
filter= get8(s); if (filter) return e("bad filter method","Corrupt PNG"); filter= get8(s); if (filter) return e("bad filter method","Corrupt PNG");
interlace = get8(s); if (interlace) return e("interlaced","PNG not supported: interlaced mode"); interlace = get8(s); if (interlace>1) return e("bad interlace method","Corrupt PNG");
if (!s->img_x || !s->img_y) return e("0-pixel image","Corrupt PNG"); if (!s->img_x || !s->img_y) return e("0-pixel image","Corrupt PNG");
if (!pal_img_n) { if (!pal_img_n) {
s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
@ -2590,7 +2642,7 @@ static int parse_png_file(png *z, int scan, int req_comp)
s->img_out_n = s->img_n+1; s->img_out_n = s->img_n+1;
else else
s->img_out_n = s->img_n; s->img_out_n = s->img_n;
if (!create_png_image(z, z->expanded, raw_len, s->img_out_n)) return 0; if (!create_png_image(z, z->expanded, raw_len, s->img_out_n, interlace)) return 0;
if (has_trans) if (has_trans)
if (!compute_transparency(z, tc, s->img_out_n)) return 0; if (!compute_transparency(z, tc, s->img_out_n)) return 0;
if (pal_img_n) { if (pal_img_n) {
@ -2700,7 +2752,23 @@ int stbi_png_test_memory(stbi_uc const *buffer, int len)
// TODO: load header from png // TODO: load header from png
#ifndef STBI_NO_STDIO #ifndef STBI_NO_STDIO
extern int stbi_png_info (char const *filename, int *x, int *y, int *comp); int stbi_png_info (char const *filename, int *x, int *y, int *comp)
{
png p;
FILE *f = fopen(filename, "rb");
if (!f) return 0;
start_file(&p.s, f);
if (parse_png_file(&p, SCAN_header, 0)) {
if(x) *x = p.s.img_x;
if(y) *y = p.s.img_y;
if (comp) *comp = p.s.img_n;
fclose(f);
return 1;
}
fclose(f);
return 0;
}
extern int stbi_png_info_from_file (FILE *f, int *x, int *y, int *comp); extern int stbi_png_info_from_file (FILE *f, int *x, int *y, int *comp);
#endif #endif
extern int stbi_png_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp); extern int stbi_png_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp);
@ -2783,7 +2851,7 @@ static int shiftsigned(int v, int shift, int bits)
static stbi_uc *bmp_load(stbi *s, int *x, int *y, int *comp, int req_comp) static stbi_uc *bmp_load(stbi *s, int *x, int *y, int *comp, int req_comp)
{ {
uint8 *out; uint8 *out;
unsigned int mr=0,mg=0,mb=0,ma=0; unsigned int mr=0,mg=0,mb=0,ma=0, fake_a=0;
stbi_uc pal[256][4]; stbi_uc pal[256][4];
int psize=0,i,j,compress=0,width; int psize=0,i,j,compress=0,width;
int bpp, flip_vertically, pad, target, offset, hsz; int bpp, flip_vertically, pad, target, offset, hsz;
@ -2832,6 +2900,8 @@ static stbi_uc *bmp_load(stbi *s, int *x, int *y, int *comp, int req_comp)
mr = 0xff << 16; mr = 0xff << 16;
mg = 0xff << 8; mg = 0xff << 8;
mb = 0xff << 0; mb = 0xff << 0;
ma = 0xff << 24;
fake_a = 1; // @TODO: check for cases like alpha value is all 0 and switch it to 255
} else { } else {
mr = 31 << 10; mr = 31 << 10;
mg = 31 << 5; mg = 31 << 5;

View File

@ -1 +1 @@
set VERSION="0.99" set VERSION="1.0"