mirror of
https://github.com/nothings/stb-imv
synced 2024-11-21 13:01:31 +03:00
etc
This commit is contained in:
parent
33491d6a7e
commit
eb8babe4db
75
imv.c
75
imv.c
@ -53,6 +53,8 @@
|
||||
#define ALLOW_RECOLORING 1
|
||||
#endif
|
||||
|
||||
//#define MONO2
|
||||
|
||||
// implement 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 (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 p = (int) stb_linear_remap(y, ymin, ymax, 0,255);
|
||||
#endif
|
||||
image_data[k+0] = p;
|
||||
image_data[k+1] = p;
|
||||
image_data[k+2] = p;
|
||||
@ -641,6 +647,7 @@ char helptext_left[] =
|
||||
" CTRL-B: toggle white stripe in border\n"
|
||||
" L: toggle filename label\n"
|
||||
" S: slideshow in current directory\n"
|
||||
" CTRL-S: sharpen when upscaling\n"
|
||||
;
|
||||
|
||||
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
|
||||
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 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
|
||||
*w_ideal = w;
|
||||
*h_ideal = h;
|
||||
@ -1193,10 +1202,11 @@ void free_fileinfo(void)
|
||||
// food.jpg
|
||||
|
||||
// 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)
|
||||
{
|
||||
//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;
|
||||
}
|
||||
|
||||
@ -2004,7 +2014,7 @@ BOOL CALLBACK PrefDlgProc(HWND hdlg, UINT imsg, WPARAM wparam, LPARAM lparam)
|
||||
#else
|
||||
int channels;
|
||||
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);
|
||||
pref_image = bmp_alloc(x, y);
|
||||
pref_image->pixels = data;
|
||||
@ -2169,9 +2179,11 @@ void performance_test(void)
|
||||
#define WM_APPCOMMAND 0x0319
|
||||
#define APPCOMMAND_BROWSER_BACKWARD 1
|
||||
#define APPCOMMAND_BROWSER_FORWARD 2
|
||||
#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK))
|
||||
#endif
|
||||
#ifndef APPCOMMAND_OPEN
|
||||
#define APPCOMMAND_OPEN 30
|
||||
#define FAPPCOMMAND_MASK 0xF000
|
||||
#define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK))
|
||||
#endif
|
||||
|
||||
// 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
|
||||
// HINSTANCE is needed to launch the preferences dialog. Oh well!
|
||||
HINSTANCE inst;
|
||||
int sharpen=0;
|
||||
|
||||
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);
|
||||
break;
|
||||
|
||||
case 'S' | MY_CTRL:
|
||||
sharpen = !sharpen;
|
||||
--cur->y;
|
||||
--cur->x;
|
||||
size_to_current(0);
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
case MY_CTRL | 'O':
|
||||
open_file();
|
||||
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':
|
||||
toggle_display();
|
||||
break;
|
||||
@ -3052,7 +3080,7 @@ typedef uint32 Color;
|
||||
|
||||
// lerp() is just blend() that also "blends" 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)
|
||||
{
|
||||
int rb_src = src & 0xff00ff;
|
||||
@ -3413,6 +3441,36 @@ Image *downsample_two_thirds(Image *src)
|
||||
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 *to_free, *res;
|
||||
@ -3423,6 +3481,9 @@ Image *grScaleBitmap(Image *src, int gx, int gy, Image *dest)
|
||||
if (gx > src->x || gy > src->y) {
|
||||
upsample = TRUE;
|
||||
} else {
|
||||
// current biggest problem perf-wise is on scaling down, we don't
|
||||
// use threads
|
||||
|
||||
// maybe should do something smarter here, like find the
|
||||
// nearest box size, instead of repetitive powers of two
|
||||
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);
|
||||
#endif
|
||||
}
|
||||
if (upsample && sharpen)
|
||||
do_sharpen(res->pixels, res->stride, res->x, res->y);
|
||||
return res;
|
||||
}
|
||||
#endif // BPP==4
|
||||
|
@ -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
|
||||
* bugfix: .spk file recursion issues, security
|
||||
|
||||
|
104
stb_image.c
104
stb_image.c
@ -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
|
||||
|
||||
QUICK NOTES:
|
||||
@ -6,7 +6,7 @@
|
||||
avoid problematic images and only need the trivial interface
|
||||
|
||||
JPEG baseline (no JPEG progressive, no oddball channel decimations)
|
||||
PNG non-interlaced
|
||||
PNG 8-bit only
|
||||
BMP non-1bpp, non-RLE
|
||||
TGA (not sure what subset, if a subset)
|
||||
PSD (composited view only, no extra channels)
|
||||
@ -19,6 +19,8 @@
|
||||
stbi_info_*
|
||||
|
||||
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.14 fix threadsafe conversion bug; header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
|
||||
1.13 threadsafe
|
||||
@ -1388,7 +1390,7 @@ static int process_marker(jpeg *z, int m)
|
||||
z->dequant[t][dezigzag[i]] = get8u(&z->s);
|
||||
#if STBI_SIMD
|
||||
for (i=0; i < 64; ++i)
|
||||
z->dequant2[t][i] = dequant[t][i];
|
||||
z->dequant2[t][i] = z->dequant[t][i];
|
||||
#endif
|
||||
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)
|
||||
// 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;
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int final, type;
|
||||
@ -2210,6 +2213,8 @@ static int parse_zlib(zbuf *a, int parse_header)
|
||||
}
|
||||
if (!parse_huffman_block(a)) return 0;
|
||||
}
|
||||
if (stbi_png_partial && a->zout - a->zout_start > 65536)
|
||||
break;
|
||||
} while (!final);
|
||||
return 1;
|
||||
}
|
||||
@ -2348,17 +2353,23 @@ static int paeth(int a, int b, int c)
|
||||
}
|
||||
|
||||
// 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;
|
||||
uint32 i,j,stride = s->img_x*out_n;
|
||||
uint32 i,j,stride = x*out_n;
|
||||
int k;
|
||||
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);
|
||||
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 (raw_len != (img_n * s->img_x + 1) * s->img_y) return e("not enough pixels","Corrupt PNG");
|
||||
for (j=0; j < s->img_y; ++j) {
|
||||
if (!stbi_png_partial) {
|
||||
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 *prior = cur - stride;
|
||||
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) {
|
||||
#define 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)
|
||||
switch(filter) {
|
||||
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);
|
||||
#define 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)
|
||||
switch(filter) {
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 has_trans=0, tc[3];
|
||||
uint32 ioff=0, idata_limit=0, i, pal_len=0;
|
||||
int first=1,k;
|
||||
int first=1,k,interlace=0;
|
||||
stbi *s = &z->s;
|
||||
|
||||
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");
|
||||
switch (c.type) {
|
||||
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 (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?)");
|
||||
@ -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");
|
||||
comp = get8(s); if (comp) return e("bad comp 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 (!pal_img_n) {
|
||||
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;
|
||||
else
|
||||
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 (!compute_transparency(z, tc, s->img_out_n)) return 0;
|
||||
if (pal_img_n) {
|
||||
@ -2700,7 +2752,23 @@ int stbi_png_test_memory(stbi_uc const *buffer, int len)
|
||||
|
||||
// TODO: load header from png
|
||||
#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);
|
||||
#endif
|
||||
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)
|
||||
{
|
||||
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];
|
||||
int psize=0,i,j,compress=0,width;
|
||||
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;
|
||||
mg = 0xff << 8;
|
||||
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 {
|
||||
mr = 31 << 10;
|
||||
mg = 31 << 5;
|
||||
|
@ -1 +1 @@
|
||||
set VERSION="0.99"
|
||||
set VERSION="1.0"
|
||||
|
Loading…
Reference in New Issue
Block a user