📄 rpng2-win.c
字号:
}
if (!filename) {
++error;
} else if (!(infile = fopen(filename, "rb"))) {
fprintf(stderr, PROGNAME ": can't open PNG file [%s]\n", filename);
++error;
} else {
incount = fread(inbuf, 1, INBUFSIZE, infile);
if (incount < 8 || !readpng2_check_sig(inbuf, 8)) {
fprintf(stderr, PROGNAME
": [%s] is not a PNG file: incorrect signature\n",
filename);
++error;
} else if ((rc = readpng2_init(&rpng2_info)) != 0) {
switch (rc) {
case 2:
fprintf(stderr, PROGNAME
": [%s] has bad IHDR (libpng longjmp)\n",
filename);
break;
case 4:
fprintf(stderr, PROGNAME ": insufficient memory\n");
break;
default:
fprintf(stderr, PROGNAME
": unknown readpng2_init() error\n");
break;
}
++error;
}
if (error)
fclose(infile);
}
/* usage screen */
if (error) {
int ch;
fprintf(stderr, "\n%s %s: %s\n\n", PROGNAME, VERSION, appname);
readpng2_version_info();
fprintf(stderr, "\n"
"Usage: %s [-gamma exp] [-bgcolor bg | -bgpat pat] [-timing]\n"
#if (defined(__i386__) || defined(_M_IX86))
" %*s [[-nommxfilters] [-nommxcombine] [-nommxinterlace] | -nommx]\n"
#endif
" %*s file.png\n\n"
" exp \ttransfer-function exponent (``gamma'') of the display\n"
"\t\t system in floating-point format (e.g., ``%.1f''); equal\n"
"\t\t to the product of the lookup-table exponent (varies)\n"
"\t\t and the CRT exponent (usually 2.2); must be positive\n"
" bg \tdesired background color in 7-character hex RGB format\n"
"\t\t (e.g., ``#ff7700'' for orange: same as HTML colors);\n"
"\t\t used with transparent images; overrides -bgpat option\n"
" pat \tdesired background pattern number (1-%d); used with\n"
"\t\t transparent images; overrides -bgcolor option\n"
" -timing\tenables delay for every block read, to simulate modem\n"
"\t\t download of image (~36 Kbps)\n"
#if (defined(__i386__) || defined(_M_IX86))
" -nommx*\tdisable optimized MMX routines for decoding row filters,\n"
"\t\t combining rows, and expanding interlacing, respectively\n"
#endif
"\nPress Q, Esc or mouse button 1 after image is displayed to quit.\n"
"Press Q or Esc to quit this usage screen. ",
PROGNAME,
#if (defined(__i386__) || defined(_M_IX86))
strlen(PROGNAME), " ",
#endif
strlen(PROGNAME), " ", default_display_exponent, num_bgpat);
fflush(stderr);
do
ch = _getch();
while (ch != 'q' && ch != 'Q' && ch != 0x1B);
exit(1);
} else {
fprintf(stderr, "\n%s %s: %s\n", PROGNAME, VERSION, appname);
fprintf(stderr,
"\n [console window: closing this window will terminate %s]\n\n",
PROGNAME);
fflush(stderr);
}
/* set the title-bar string, but make sure buffer doesn't overflow */
alen = strlen(appname);
flen = strlen(filename);
if (alen + flen + 3 > 1023)
sprintf(titlebar, "%s: ...%s", appname, filename+(alen+flen+6-1023));
else
sprintf(titlebar, "%s: %s", appname, filename);
/* set some final rpng2_info variables before entering main data loop */
if (have_bg) {
unsigned r, g, b; /* this approach quiets compiler warnings */
sscanf(bgstr+1, "%2x%2x%2x", &r, &g, &b);
rpng2_info.bg_red = (uch)r;
rpng2_info.bg_green = (uch)g;
rpng2_info.bg_blue = (uch)b;
} else
rpng2_info.need_bgcolor = TRUE;
rpng2_info.done = FALSE;
rpng2_info.mainprog_init = rpng2_win_init;
rpng2_info.mainprog_display_row = rpng2_win_display_row;
rpng2_info.mainprog_finish_display = rpng2_win_finish_display;
/* OK, this is the fun part: call readpng2_decode_data() at the start of
* the loop to deal with our first buffer of data (read in above to verify
* that the file is a PNG image), then loop through the file and continue
* calling the same routine to handle each chunk of data. It in turn
* passes the data to libpng, which will invoke one or more of our call-
* backs as decoded data become available. We optionally call Sleep() for
* one second per iteration to simulate downloading the image via an analog
* modem. */
for (;;) {
Trace((stderr, "about to call readpng2_decode_data()\n"))
if (readpng2_decode_data(&rpng2_info, inbuf, incount))
++error;
Trace((stderr, "done with readpng2_decode_data()\n"))
if (error || feof(infile) || rpng2_info.done)
break;
if (timing)
Sleep(1000L);
incount = fread(inbuf, 1, INBUFSIZE, infile);
}
/* clean up PNG stuff and report any decoding errors */
fclose(infile);
Trace((stderr, "about to call readpng2_cleanup()\n"))
readpng2_cleanup(&rpng2_info);
if (error) {
fprintf(stderr, PROGNAME ": libpng error while decoding PNG image\n");
exit(3);
}
/* wait for the user to tell us when to quit */
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
/* we're done: clean up all image and Windows resources and go away */
Trace((stderr, "about to call rpng2_win_cleanup()\n"))
rpng2_win_cleanup();
return msg.wParam;
}
/* this function is called by readpng2_info_callback() in readpng2.c, which
* in turn is called by libpng after all of the pre-IDAT chunks have been
* read and processed--i.e., we now have enough info to finish initializing */
static void rpng2_win_init()
{
ulg i;
ulg rowbytes = rpng2_info.rowbytes;
Trace((stderr, "beginning rpng2_win_init()\n"))
Trace((stderr, " rowbytes = %ld\n", rpng2_info.rowbytes))
Trace((stderr, " width = %ld\n", rpng2_info.width))
Trace((stderr, " height = %ld\n", rpng2_info.height))
rpng2_info.image_data = (uch *)malloc(rowbytes * rpng2_info.height);
if (!rpng2_info.image_data) {
readpng2_cleanup(&rpng2_info);
return;
}
rpng2_info.row_pointers = (uch **)malloc(rpng2_info.height * sizeof(uch *));
if (!rpng2_info.row_pointers) {
free(rpng2_info.image_data);
rpng2_info.image_data = NULL;
readpng2_cleanup(&rpng2_info);
return;
}
for (i = 0; i < rpng2_info.height; ++i)
rpng2_info.row_pointers[i] = rpng2_info.image_data + i*rowbytes;
/*---------------------------------------------------------------------------
Do the basic Windows initialization stuff, make the window, and fill it
with the user-specified, file-specified or default background color.
---------------------------------------------------------------------------*/
if (rpng2_win_create_window()) {
readpng2_cleanup(&rpng2_info);
return;
}
}
static int rpng2_win_create_window()
{
uch bg_red = rpng2_info.bg_red;
uch bg_green = rpng2_info.bg_green;
uch bg_blue = rpng2_info.bg_blue;
uch *dest;
int extra_width, extra_height;
ulg i, j;
WNDCLASSEX wndclass;
RECT rect;
/*---------------------------------------------------------------------------
Allocate memory for the display-specific version of the image (round up
to multiple of 4 for Windows DIB).
---------------------------------------------------------------------------*/
wimage_rowbytes = ((3*rpng2_info.width + 3L) >> 2) << 2;
if (!(dib = (uch *)malloc(sizeof(BITMAPINFOHEADER) +
wimage_rowbytes*rpng2_info.height)))
{
return 4; /* fail */
}
/*---------------------------------------------------------------------------
Initialize the DIB. Negative height means to use top-down BMP ordering
(must be uncompressed, but that's what we want). Bit count of 1, 4 or 8
implies a colormap of RGBX quads, but 24-bit BMPs just use B,G,R values
directly => wimage_data begins immediately after BMP header.
---------------------------------------------------------------------------*/
memset(dib, 0, sizeof(BITMAPINFOHEADER));
bmih = (BITMAPINFOHEADER *)dib;
bmih->biSize = sizeof(BITMAPINFOHEADER);
bmih->biWidth = rpng2_info.width;
bmih->biHeight = -((long)rpng2_info.height);
bmih->biPlanes = 1;
bmih->biBitCount = 24;
bmih->biCompression = 0;
wimage_data = dib + sizeof(BITMAPINFOHEADER);
/*---------------------------------------------------------------------------
Fill window with the specified background color (default is black), but
defer loading faked "background image" until window is displayed (may be
slow to compute). Data are in BGR order.
---------------------------------------------------------------------------*/
if (bg_image) { /* just fill with black for now */
memset(wimage_data, 0, wimage_rowbytes*rpng2_info.height);
} else {
for (j = 0; j < rpng2_info.height; ++j) {
dest = wimage_data + j*wimage_rowbytes;
for (i = rpng2_info.width; i > 0; --i) {
*dest++ = bg_blue;
*dest++ = bg_green;
*dest++ = bg_red;
}
}
}
/*---------------------------------------------------------------------------
Set the window parameters.
---------------------------------------------------------------------------*/
memset(&wndclass, 0, sizeof(wndclass));
wndclass.cbSize = sizeof(wndclass);
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = rpng2_win_wndproc;
wndclass.hInstance = global_hInst;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = progname;
wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
RegisterClassEx(&wndclass);
/*---------------------------------------------------------------------------
Finally, create the window.
---------------------------------------------------------------------------*/
extra_width = 2*(GetSystemMetrics(SM_CXBORDER) +
GetSystemMetrics(SM_CXDLGFRAME));
extra_height = 2*(GetSystemMetrics(SM_CYBORDER) +
GetSystemMetrics(SM_CYDLGFRAME)) +
GetSystemMetrics(SM_CYCAPTION);
global_hwnd = CreateWindow(progname, titlebar, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, rpng2_info.width+extra_width,
rpng2_info.height+extra_height, NULL, NULL, global_hInst, NULL);
ShowWindow(global_hwnd, global_showmode);
UpdateWindow(global_hwnd);
/*---------------------------------------------------------------------------
Now compute the background image and display it. If it fails (memory
allocation), revert to a plain background color.
---------------------------------------------------------------------------*/
if (bg_image) {
static const char *msg = "Computing background image...";
int x, y, len = strlen(msg);
HDC hdc = GetDC(global_hwnd);
TEXTMETRIC tm;
GetTextMetrics(hdc, &tm);
x = (rpng2_info.width - len*tm.tmAveCharWidth)/2;
y = (rpng2_info.height - tm.tmHeight)/2;
SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
/* this can still begin out of bounds even if x is positive (???): */
TextOut(hdc, ((x < 0)? 0 : x), ((y < 0)? 0 : y), msg, len);
ReleaseDC(global_hwnd, hdc);
rpng2_win_load_bg_image(); /* resets bg_image if fails */
}
if (!bg_image) {
for (j = 0; j < rpng2_info.height; ++j) {
dest = wimage_data + j*wimage_rowbytes;
for (i = rpng2_info.width; i > 0; --i) {
*dest++ = bg_blue;
*dest++ = bg_green;
*dest++ = bg_red;
}
}
}
rect.left = 0L;
rect.top = 0L;
rect.right = (LONG)rpng2_info.width; /* possibly off by one? */
rect.bottom = (LONG)rpng2_info.height; /* possibly off by one? */
InvalidateRect(global_hwnd, &rect, FALSE);
UpdateWindow(global_hwnd); /* similar to XFlush() */
return 0;
} /* end function rpng2_win_create_window() */
static int rpng2_win_load_bg_image()
{
uch *src, *dest;
uch r1, r2, g1, g2, b1, b2;
uch r1_inv, r2_inv, g1_inv, g2_inv, b1_inv, b2_inv;
int k, hmax, max;
int xidx, yidx, yidx_max = (bgscale-1);
int even_odd_vert, even_odd_horiz, even_odd;
int invert_gradient2 = (bg[pat].type & 0x08);
int invert_column;
ulg i, row;
/*---------------------------------------------------------------------------
Allocate buffer for fake background image to be used with transparent
images; if this fails, revert to plain background color.
---------------------------------------------------------------------------*/
bg_rowbytes = 3 * rpng2_info.width;
bg_data = (uch *)malloc(bg_rowbytes * rpng2_info.height);
if (!bg_data) {
fprintf(stderr, PROGNAME
": unable to allocate memory for background image\n");
bg_image = 0;
return 1;
}
/*---------------------------------------------------------------------------
Vertical gradients (ramps) in NxN squares, alternating direction and
colors (N == bgscale).
---------------------------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -