VisualPng.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970
  1. /*------------------------------------
  2. * VisualPng.C -- Shows a PNG image
  3. *------------------------------------
  4. *
  5. * Copyright 2000, Willem van Schaik.
  6. *
  7. * This code is released under the libpng license.
  8. * For conditions of distribution and use, see the disclaimer
  9. * and license in png.h
  10. */
  11. /* switches */
  12. /* defines */
  13. #define PROGNAME "VisualPng"
  14. #define LONGNAME "Win32 Viewer for PNG-files"
  15. #define VERSION "1.0 of 2000 June 07"
  16. /* constants */
  17. #define MARGIN 8
  18. /* standard includes */
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <windows.h>
  23. /* application includes */
  24. #include "png.h"
  25. #include "pngfile.h"
  26. #include "resource.h"
  27. /* macros */
  28. /* function prototypes */
  29. LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
  30. BOOL CALLBACK AboutDlgProc (HWND, UINT, WPARAM, LPARAM) ;
  31. BOOL CenterAbout (HWND hwndChild, HWND hwndParent);
  32. BOOL BuildPngList (PTSTR pstrPathName, TCHAR **ppFileList, int *pFileCount,
  33. int *pFileIndex);
  34. BOOL SearchPngList (TCHAR *pFileList, int FileCount, int *pFileIndex,
  35. PTSTR pstrPrevName, PTSTR pstrNextName);
  36. BOOL LoadImageFile(HWND hwnd, PTSTR pstrPathName,
  37. png_byte **ppbImage, int *pxImgSize, int *pyImgSize, int *piChannels,
  38. png_color *pBkgColor);
  39. BOOL DisplayImage (HWND hwnd, BYTE **ppDib,
  40. BYTE **ppDiData, int cxWinSize, int cyWinSize,
  41. BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels,
  42. BOOL bStretched);
  43. BOOL InitBitmap (
  44. BYTE *pDiData, int cxWinSize, int cyWinSize);
  45. BOOL FillBitmap (
  46. BYTE *pDiData, int cxWinSize, int cyWinSize,
  47. BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels,
  48. BOOL bStretched);
  49. /* a few global variables */
  50. static char *szProgName = PROGNAME;
  51. static char *szAppName = LONGNAME;
  52. static char *szIconName = PROGNAME;
  53. static char szCmdFileName [MAX_PATH];
  54. /* MAIN routine */
  55. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
  56. PSTR szCmdLine, int iCmdShow)
  57. {
  58. HACCEL hAccel;
  59. HWND hwnd;
  60. MSG msg;
  61. WNDCLASS wndclass;
  62. int ixBorders, iyBorders;
  63. wndclass.style = CS_HREDRAW | CS_VREDRAW;
  64. wndclass.lpfnWndProc = WndProc;
  65. wndclass.cbClsExtra = 0;
  66. wndclass.cbWndExtra = 0;
  67. wndclass.hInstance = hInstance;
  68. wndclass.hIcon = LoadIcon (hInstance, szIconName) ;
  69. wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
  70. wndclass.hbrBackground = NULL; /* (HBRUSH) GetStockObject (GRAY_BRUSH); */
  71. wndclass.lpszMenuName = szProgName;
  72. wndclass.lpszClassName = szProgName;
  73. if (!RegisterClass (&wndclass))
  74. {
  75. MessageBox (NULL, TEXT ("Error: this program requires Windows NT!"),
  76. szProgName, MB_ICONERROR);
  77. return 0;
  78. }
  79. /* if filename given on commandline, store it */
  80. if ((szCmdLine != NULL) && (*szCmdLine != '\0'))
  81. if (szCmdLine[0] == '"')
  82. strncpy (szCmdFileName, szCmdLine + 1, strlen(szCmdLine) - 2);
  83. else
  84. strcpy (szCmdFileName, szCmdLine);
  85. else
  86. strcpy (szCmdFileName, "");
  87. /* calculate size of window-borders */
  88. ixBorders = 2 * (GetSystemMetrics (SM_CXBORDER) +
  89. GetSystemMetrics (SM_CXDLGFRAME));
  90. iyBorders = 2 * (GetSystemMetrics (SM_CYBORDER) +
  91. GetSystemMetrics (SM_CYDLGFRAME)) +
  92. GetSystemMetrics (SM_CYCAPTION) +
  93. GetSystemMetrics (SM_CYMENUSIZE) +
  94. 1; /* WvS: don't ask me why? */
  95. hwnd = CreateWindow (szProgName, szAppName,
  96. WS_OVERLAPPEDWINDOW,
  97. CW_USEDEFAULT, CW_USEDEFAULT,
  98. 512 + 2 * MARGIN + ixBorders, 384 + 2 * MARGIN + iyBorders,
  99. /* CW_USEDEFAULT, CW_USEDEFAULT, */
  100. NULL, NULL, hInstance, NULL);
  101. ShowWindow (hwnd, iCmdShow);
  102. UpdateWindow (hwnd);
  103. hAccel = LoadAccelerators (hInstance, szProgName);
  104. while (GetMessage (&msg, NULL, 0, 0))
  105. {
  106. if (!TranslateAccelerator (hwnd, hAccel, &msg))
  107. {
  108. TranslateMessage (&msg);
  109. DispatchMessage (&msg);
  110. }
  111. }
  112. return msg.wParam;
  113. }
  114. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam,
  115. LPARAM lParam)
  116. {
  117. static HINSTANCE hInstance ;
  118. static HDC hdc;
  119. static PAINTSTRUCT ps;
  120. static HMENU hMenu;
  121. static BITMAPFILEHEADER *pbmfh;
  122. static BITMAPINFOHEADER *pbmih;
  123. static BYTE *pbImage;
  124. static int cxWinSize, cyWinSize;
  125. static int cxImgSize, cyImgSize;
  126. static int cImgChannels;
  127. static png_color bkgColor = {127, 127, 127};
  128. static BOOL bStretched = TRUE;
  129. static BYTE *pDib = NULL;
  130. static BYTE *pDiData = NULL;
  131. static TCHAR szImgPathName [MAX_PATH];
  132. static TCHAR szTitleName [MAX_PATH];
  133. static TCHAR *pPngFileList = NULL;
  134. static int iPngFileCount;
  135. static int iPngFileIndex;
  136. BOOL bOk;
  137. switch (message)
  138. {
  139. case WM_CREATE:
  140. hInstance = ((LPCREATESTRUCT) lParam)->hInstance ;
  141. PngFileInitialize (hwnd);
  142. strcpy (szImgPathName, "");
  143. /* in case we process file given on command-line */
  144. if (szCmdFileName[0] != '\0')
  145. {
  146. strcpy (szImgPathName, szCmdFileName);
  147. /* read the other png-files in the directory for later */
  148. /* next/previous commands */
  149. BuildPngList (szImgPathName, &pPngFileList, &iPngFileCount,
  150. &iPngFileIndex);
  151. /* load the image from file */
  152. if (!LoadImageFile (hwnd, szImgPathName,
  153. &pbImage, &cxImgSize, &cyImgSize, &cImgChannels, &bkgColor))
  154. return 0;
  155. /* invalidate the client area for later update */
  156. InvalidateRect (hwnd, NULL, TRUE);
  157. /* display the PNG into the DIBitmap */
  158. DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
  159. pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
  160. }
  161. return 0;
  162. case WM_SIZE:
  163. cxWinSize = LOWORD (lParam);
  164. cyWinSize = HIWORD (lParam);
  165. /* invalidate the client area for later update */
  166. InvalidateRect (hwnd, NULL, TRUE);
  167. /* display the PNG into the DIBitmap */
  168. DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
  169. pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
  170. return 0;
  171. case WM_INITMENUPOPUP:
  172. hMenu = GetMenu (hwnd);
  173. if (pbImage)
  174. EnableMenuItem (hMenu, IDM_FILE_SAVE, MF_ENABLED);
  175. else
  176. EnableMenuItem (hMenu, IDM_FILE_SAVE, MF_GRAYED);
  177. return 0;
  178. case WM_COMMAND:
  179. hMenu = GetMenu (hwnd);
  180. switch (LOWORD (wParam))
  181. {
  182. case IDM_FILE_OPEN:
  183. /* show the File Open dialog box */
  184. if (!PngFileOpenDlg (hwnd, szImgPathName, szTitleName))
  185. return 0;
  186. /* read the other png-files in the directory for later */
  187. /* next/previous commands */
  188. BuildPngList (szImgPathName, &pPngFileList, &iPngFileCount,
  189. &iPngFileIndex);
  190. /* load the image from file */
  191. if (!LoadImageFile (hwnd, szImgPathName,
  192. &pbImage, &cxImgSize, &cyImgSize, &cImgChannels, &bkgColor))
  193. return 0;
  194. /* invalidate the client area for later update */
  195. InvalidateRect (hwnd, NULL, TRUE);
  196. /* display the PNG into the DIBitmap */
  197. DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
  198. pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
  199. return 0;
  200. case IDM_FILE_SAVE:
  201. /* show the File Save dialog box */
  202. if (!PngFileSaveDlg (hwnd, szImgPathName, szTitleName))
  203. return 0;
  204. /* save the PNG to a disk file */
  205. SetCursor (LoadCursor (NULL, IDC_WAIT));
  206. ShowCursor (TRUE);
  207. bOk = PngSaveImage (szImgPathName, pDiData, cxWinSize, cyWinSize,
  208. bkgColor);
  209. ShowCursor (FALSE);
  210. SetCursor (LoadCursor (NULL, IDC_ARROW));
  211. if (!bOk)
  212. MessageBox (hwnd, TEXT ("Error in saving the PNG image"),
  213. szProgName, MB_ICONEXCLAMATION | MB_OK);
  214. return 0;
  215. case IDM_FILE_NEXT:
  216. /* read next entry in the directory */
  217. if (SearchPngList (pPngFileList, iPngFileCount, &iPngFileIndex,
  218. NULL, szImgPathName))
  219. {
  220. if (strcmp (szImgPathName, "") == 0)
  221. return 0;
  222. /* load the image from file */
  223. if (!LoadImageFile (hwnd, szImgPathName, &pbImage,
  224. &cxImgSize, &cyImgSize, &cImgChannels, &bkgColor))
  225. return 0;
  226. /* invalidate the client area for later update */
  227. InvalidateRect (hwnd, NULL, TRUE);
  228. /* display the PNG into the DIBitmap */
  229. DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
  230. pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
  231. }
  232. return 0;
  233. case IDM_FILE_PREVIOUS:
  234. /* read previous entry in the directory */
  235. if (SearchPngList (pPngFileList, iPngFileCount, &iPngFileIndex,
  236. szImgPathName, NULL))
  237. {
  238. if (strcmp (szImgPathName, "") == 0)
  239. return 0;
  240. /* load the image from file */
  241. if (!LoadImageFile (hwnd, szImgPathName, &pbImage, &cxImgSize,
  242. &cyImgSize, &cImgChannels, &bkgColor))
  243. return 0;
  244. /* invalidate the client area for later update */
  245. InvalidateRect (hwnd, NULL, TRUE);
  246. /* display the PNG into the DIBitmap */
  247. DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
  248. pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
  249. }
  250. return 0;
  251. case IDM_FILE_EXIT:
  252. /* more cleanup needed... */
  253. /* free image buffer */
  254. if (pDib != NULL)
  255. {
  256. free (pDib);
  257. pDib = NULL;
  258. }
  259. /* free file-list */
  260. if (pPngFileList != NULL)
  261. {
  262. free (pPngFileList);
  263. pPngFileList = NULL;
  264. }
  265. /* let's go ... */
  266. exit (0);
  267. return 0;
  268. case IDM_OPTIONS_STRETCH:
  269. bStretched = !bStretched;
  270. if (bStretched)
  271. CheckMenuItem (hMenu, IDM_OPTIONS_STRETCH, MF_CHECKED);
  272. else
  273. CheckMenuItem (hMenu, IDM_OPTIONS_STRETCH, MF_UNCHECKED);
  274. /* invalidate the client area for later update */
  275. InvalidateRect (hwnd, NULL, TRUE);
  276. /* display the PNG into the DIBitmap */
  277. DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
  278. pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
  279. return 0;
  280. case IDM_HELP_ABOUT:
  281. DialogBox (hInstance, TEXT ("AboutBox"), hwnd, AboutDlgProc) ;
  282. return 0;
  283. } /* end switch */
  284. break;
  285. case WM_PAINT:
  286. hdc = BeginPaint (hwnd, &ps);
  287. if (pDib)
  288. SetDIBitsToDevice (hdc, 0, 0, cxWinSize, cyWinSize, 0, 0,
  289. 0, cyWinSize, pDiData, (BITMAPINFO *) pDib, DIB_RGB_COLORS);
  290. EndPaint (hwnd, &ps);
  291. return 0;
  292. case WM_DESTROY:
  293. if (pbmfh)
  294. {
  295. free (pbmfh);
  296. pbmfh = NULL;
  297. }
  298. PostQuitMessage (0);
  299. return 0;
  300. }
  301. return DefWindowProc (hwnd, message, wParam, lParam);
  302. }
  303. BOOL CALLBACK AboutDlgProc (HWND hDlg, UINT message,
  304. WPARAM wParam, LPARAM lParam)
  305. {
  306. switch (message)
  307. {
  308. case WM_INITDIALOG :
  309. ShowWindow (hDlg, SW_HIDE);
  310. CenterAbout (hDlg, GetWindow (hDlg, GW_OWNER));
  311. ShowWindow (hDlg, SW_SHOW);
  312. return TRUE ;
  313. case WM_COMMAND :
  314. switch (LOWORD (wParam))
  315. {
  316. case IDOK :
  317. case IDCANCEL :
  318. EndDialog (hDlg, 0) ;
  319. return TRUE ;
  320. }
  321. break ;
  322. }
  323. return FALSE ;
  324. }
  325. /*---------------
  326. * CenterAbout
  327. *---------------
  328. */
  329. BOOL CenterAbout (HWND hwndChild, HWND hwndParent)
  330. {
  331. RECT rChild, rParent, rWorkArea;
  332. int wChild, hChild, wParent, hParent;
  333. int xNew, yNew;
  334. BOOL bResult;
  335. /* Get the Height and Width of the child window */
  336. GetWindowRect (hwndChild, &rChild);
  337. wChild = rChild.right - rChild.left;
  338. hChild = rChild.bottom - rChild.top;
  339. /* Get the Height and Width of the parent window */
  340. GetWindowRect (hwndParent, &rParent);
  341. wParent = rParent.right - rParent.left;
  342. hParent = rParent.bottom - rParent.top;
  343. /* Get the limits of the 'workarea' */
  344. bResult = SystemParametersInfo(
  345. SPI_GETWORKAREA, /* system parameter to query or set */
  346. sizeof(RECT),
  347. &rWorkArea,
  348. 0);
  349. if (!bResult) {
  350. rWorkArea.left = rWorkArea.top = 0;
  351. rWorkArea.right = GetSystemMetrics(SM_CXSCREEN);
  352. rWorkArea.bottom = GetSystemMetrics(SM_CYSCREEN);
  353. }
  354. /* Calculate new X position, then adjust for workarea */
  355. xNew = rParent.left + ((wParent - wChild) /2);
  356. if (xNew < rWorkArea.left) {
  357. xNew = rWorkArea.left;
  358. } else if ((xNew+wChild) > rWorkArea.right) {
  359. xNew = rWorkArea.right - wChild;
  360. }
  361. /* Calculate new Y position, then adjust for workarea */
  362. yNew = rParent.top + ((hParent - hChild) /2);
  363. if (yNew < rWorkArea.top) {
  364. yNew = rWorkArea.top;
  365. } else if ((yNew+hChild) > rWorkArea.bottom) {
  366. yNew = rWorkArea.bottom - hChild;
  367. }
  368. /* Set it, and return */
  369. return SetWindowPos (hwndChild, NULL, xNew, yNew, 0, 0, SWP_NOSIZE |
  370. SWP_NOZORDER);
  371. }
  372. /*----------------
  373. * BuildPngList
  374. *----------------
  375. */
  376. BOOL BuildPngList (PTSTR pstrPathName, TCHAR **ppFileList, int *pFileCount,
  377. int *pFileIndex)
  378. {
  379. static TCHAR szImgPathName [MAX_PATH];
  380. static TCHAR szImgFileName [MAX_PATH];
  381. static TCHAR szImgFindName [MAX_PATH];
  382. WIN32_FIND_DATA finddata;
  383. HANDLE hFind;
  384. static TCHAR szTmp [MAX_PATH];
  385. BOOL bOk;
  386. int i, ii;
  387. int j, jj;
  388. /* free previous file-list */
  389. if (*ppFileList != NULL)
  390. {
  391. free (*ppFileList);
  392. *ppFileList = NULL;
  393. }
  394. /* extract foldername, filename and search-name */
  395. strcpy (szImgPathName, pstrPathName);
  396. strcpy (szImgFileName, strrchr (pstrPathName, '\\') + 1);
  397. strcpy (szImgFindName, szImgPathName);
  398. *(strrchr (szImgFindName, '\\') + 1) = '\0';
  399. strcat (szImgFindName, "*.png");
  400. /* first cycle: count number of files in directory for memory allocation */
  401. *pFileCount = 0;
  402. hFind = FindFirstFile(szImgFindName, &finddata);
  403. bOk = (hFind != (HANDLE) -1);
  404. while (bOk)
  405. {
  406. *pFileCount += 1;
  407. bOk = FindNextFile(hFind, &finddata);
  408. }
  409. FindClose(hFind);
  410. /* allocation memory for file-list */
  411. *ppFileList = (TCHAR *) malloc (*pFileCount * MAX_PATH);
  412. /* second cycle: read directory and store filenames in file-list */
  413. hFind = FindFirstFile(szImgFindName, &finddata);
  414. bOk = (hFind != (HANDLE) -1);
  415. i = 0;
  416. ii = 0;
  417. while (bOk)
  418. {
  419. strcpy (*ppFileList + ii, szImgPathName);
  420. strcpy (strrchr(*ppFileList + ii, '\\') + 1, finddata.cFileName);
  421. if (strcmp(pstrPathName, *ppFileList + ii) == 0)
  422. *pFileIndex = i;
  423. ii += MAX_PATH;
  424. i++;
  425. bOk = FindNextFile(hFind, &finddata);
  426. }
  427. FindClose(hFind);
  428. /* finally we must sort the file-list */
  429. for (i = 0; i < *pFileCount - 1; i++)
  430. {
  431. ii = i * MAX_PATH;
  432. for (j = i+1; j < *pFileCount; j++)
  433. {
  434. jj = j * MAX_PATH;
  435. if (strcmp (*ppFileList + ii, *ppFileList + jj) > 0)
  436. {
  437. strcpy (szTmp, *ppFileList + jj);
  438. strcpy (*ppFileList + jj, *ppFileList + ii);
  439. strcpy (*ppFileList + ii, szTmp);
  440. /* check if this was the current image that we moved */
  441. if (*pFileIndex == i)
  442. *pFileIndex = j;
  443. else
  444. if (*pFileIndex == j)
  445. *pFileIndex = i;
  446. }
  447. }
  448. }
  449. return TRUE;
  450. }
  451. /*----------------
  452. * SearchPngList
  453. *----------------
  454. */
  455. BOOL SearchPngList (
  456. TCHAR *pFileList, int FileCount, int *pFileIndex,
  457. PTSTR pstrPrevName, PTSTR pstrNextName)
  458. {
  459. if (FileCount > 0)
  460. {
  461. /* get previous entry */
  462. if (pstrPrevName != NULL)
  463. {
  464. if (*pFileIndex > 0)
  465. *pFileIndex -= 1;
  466. else
  467. *pFileIndex = FileCount - 1;
  468. strcpy (pstrPrevName, pFileList + (*pFileIndex * MAX_PATH));
  469. }
  470. /* get next entry */
  471. if (pstrNextName != NULL)
  472. {
  473. if (*pFileIndex < FileCount - 1)
  474. *pFileIndex += 1;
  475. else
  476. *pFileIndex = 0;
  477. strcpy (pstrNextName, pFileList + (*pFileIndex * MAX_PATH));
  478. }
  479. return TRUE;
  480. }
  481. else
  482. {
  483. return FALSE;
  484. }
  485. }
  486. /*-----------------
  487. * LoadImageFile
  488. *-----------------
  489. */
  490. BOOL LoadImageFile (HWND hwnd, PTSTR pstrPathName,
  491. png_byte **ppbImage, int *pxImgSize, int *pyImgSize,
  492. int *piChannels, png_color *pBkgColor)
  493. {
  494. static TCHAR szTmp [MAX_PATH];
  495. /* if there's an existing PNG, free the memory */
  496. if (*ppbImage)
  497. {
  498. free (*ppbImage);
  499. *ppbImage = NULL;
  500. }
  501. /* Load the entire PNG into memory */
  502. SetCursor (LoadCursor (NULL, IDC_WAIT));
  503. ShowCursor (TRUE);
  504. PngLoadImage (pstrPathName, ppbImage, pxImgSize, pyImgSize, piChannels,
  505. pBkgColor);
  506. ShowCursor (FALSE);
  507. SetCursor (LoadCursor (NULL, IDC_ARROW));
  508. if (*ppbImage != NULL)
  509. {
  510. sprintf (szTmp, "VisualPng - %s", strrchr(pstrPathName, '\\') + 1);
  511. SetWindowText (hwnd, szTmp);
  512. }
  513. else
  514. {
  515. MessageBox (hwnd, TEXT ("Error in loading the PNG image"),
  516. szProgName, MB_ICONEXCLAMATION | MB_OK);
  517. return FALSE;
  518. }
  519. return TRUE;
  520. }
  521. /*----------------
  522. * DisplayImage
  523. *----------------
  524. */
  525. BOOL DisplayImage (HWND hwnd, BYTE **ppDib,
  526. BYTE **ppDiData, int cxWinSize, int cyWinSize,
  527. BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels,
  528. BOOL bStretched)
  529. {
  530. BYTE *pDib = *ppDib;
  531. BYTE *pDiData = *ppDiData;
  532. /* BITMAPFILEHEADER *pbmfh; */
  533. BITMAPINFOHEADER *pbmih;
  534. WORD wDIRowBytes;
  535. png_color bkgBlack = {0, 0, 0};
  536. png_color bkgGray = {127, 127, 127};
  537. png_color bkgWhite = {255, 255, 255};
  538. /* allocate memory for the Device Independant bitmap */
  539. wDIRowBytes = (WORD) ((3 * cxWinSize + 3L) >> 2) << 2;
  540. if (pDib)
  541. {
  542. free (pDib);
  543. pDib = NULL;
  544. }
  545. if (!(pDib = (BYTE *) malloc (sizeof(BITMAPINFOHEADER) +
  546. wDIRowBytes * cyWinSize)))
  547. {
  548. MessageBox (hwnd, TEXT ("Error in displaying the PNG image"),
  549. szProgName, MB_ICONEXCLAMATION | MB_OK);
  550. *ppDib = pDib = NULL;
  551. return FALSE;
  552. }
  553. *ppDib = pDib;
  554. memset (pDib, 0, sizeof(BITMAPINFOHEADER));
  555. /* initialize the dib-structure */
  556. pbmih = (BITMAPINFOHEADER *) pDib;
  557. pbmih->biSize = sizeof(BITMAPINFOHEADER);
  558. pbmih->biWidth = cxWinSize;
  559. pbmih->biHeight = -((long) cyWinSize);
  560. pbmih->biPlanes = 1;
  561. pbmih->biBitCount = 24;
  562. pbmih->biCompression = 0;
  563. pDiData = pDib + sizeof(BITMAPINFOHEADER);
  564. *ppDiData = pDiData;
  565. /* first fill bitmap with gray and image border */
  566. InitBitmap (pDiData, cxWinSize, cyWinSize);
  567. /* then fill bitmap with image */
  568. if (pbImage)
  569. {
  570. FillBitmap (
  571. pDiData, cxWinSize, cyWinSize,
  572. pbImage, cxImgSize, cyImgSize, cImgChannels,
  573. bStretched);
  574. }
  575. return TRUE;
  576. }
  577. /*--------------
  578. * InitBitmap
  579. *--------------
  580. */
  581. BOOL InitBitmap (BYTE *pDiData, int cxWinSize, int cyWinSize)
  582. {
  583. BYTE *dst;
  584. int x, y, col;
  585. /* initialize the background with gray */
  586. dst = pDiData;
  587. for (y = 0; y < cyWinSize; y++)
  588. {
  589. col = 0;
  590. for (x = 0; x < cxWinSize; x++)
  591. {
  592. /* fill with GRAY */
  593. *dst++ = 127;
  594. *dst++ = 127;
  595. *dst++ = 127;
  596. col += 3;
  597. }
  598. /* rows start on 4 byte boundaries */
  599. while ((col % 4) != 0)
  600. {
  601. dst++;
  602. col++;
  603. }
  604. }
  605. return TRUE;
  606. }
  607. /*--------------
  608. * FillBitmap
  609. *--------------
  610. */
  611. BOOL FillBitmap (
  612. BYTE *pDiData, int cxWinSize, int cyWinSize,
  613. BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels,
  614. BOOL bStretched)
  615. {
  616. BYTE *pStretchedImage;
  617. BYTE *pImg;
  618. BYTE *src, *dst;
  619. BYTE r, g, b, a;
  620. const int cDIChannels = 3;
  621. WORD wImgRowBytes;
  622. WORD wDIRowBytes;
  623. int cxNewSize, cyNewSize;
  624. int cxImgPos, cyImgPos;
  625. int xImg, yImg;
  626. int xWin, yWin;
  627. int xOld, yOld;
  628. int xNew, yNew;
  629. if (bStretched)
  630. {
  631. cxNewSize = cxWinSize - 2 * MARGIN;
  632. cyNewSize = cyWinSize - 2 * MARGIN;
  633. /* stretch the image to it's window determined size */
  634. /* the following two are mathematically the same, but the first
  635. * has side-effects because of rounding
  636. */
  637. /* if ((cyNewSize / cxNewSize) > (cyImgSize / cxImgSize)) */
  638. if ((cyNewSize * cxImgSize) > (cyImgSize * cxNewSize))
  639. {
  640. cyNewSize = cxNewSize * cyImgSize / cxImgSize;
  641. cxImgPos = MARGIN;
  642. cyImgPos = (cyWinSize - cyNewSize) / 2;
  643. }
  644. else
  645. {
  646. cxNewSize = cyNewSize * cxImgSize / cyImgSize;
  647. cyImgPos = MARGIN;
  648. cxImgPos = (cxWinSize - cxNewSize) / 2;
  649. }
  650. pStretchedImage = malloc (cImgChannels * cxNewSize * cyNewSize);
  651. pImg = pStretchedImage;
  652. for (yNew = 0; yNew < cyNewSize; yNew++)
  653. {
  654. yOld = yNew * cyImgSize / cyNewSize;
  655. for (xNew = 0; xNew < cxNewSize; xNew++)
  656. {
  657. xOld = xNew * cxImgSize / cxNewSize;
  658. r = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 0);
  659. g = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 1);
  660. b = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 2);
  661. *pImg++ = r;
  662. *pImg++ = g;
  663. *pImg++ = b;
  664. if (cImgChannels == 4)
  665. {
  666. a = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld)
  667. + 3);
  668. *pImg++ = a;
  669. }
  670. }
  671. }
  672. /* calculate row-bytes */
  673. wImgRowBytes = cImgChannels * cxNewSize;
  674. wDIRowBytes = (WORD) ((cDIChannels * cxWinSize + 3L) >> 2) << 2;
  675. /* copy image to screen */
  676. for (yImg = 0, yWin = cyImgPos; yImg < cyNewSize; yImg++, yWin++)
  677. {
  678. if (yWin >= cyWinSize - cyImgPos)
  679. break;
  680. src = pStretchedImage + yImg * wImgRowBytes;
  681. dst = pDiData + yWin * wDIRowBytes + cxImgPos * cDIChannels;
  682. for (xImg = 0, xWin = cxImgPos; xImg < cxNewSize; xImg++, xWin++)
  683. {
  684. if (xWin >= cxWinSize - cxImgPos)
  685. break;
  686. r = *src++;
  687. g = *src++;
  688. b = *src++;
  689. *dst++ = b; /* note the reverse order */
  690. *dst++ = g;
  691. *dst++ = r;
  692. if (cImgChannels == 4)
  693. {
  694. a = *src++;
  695. }
  696. }
  697. }
  698. /* free memory */
  699. if (pStretchedImage != NULL)
  700. {
  701. free (pStretchedImage);
  702. pStretchedImage = NULL;
  703. }
  704. }
  705. /* process the image not-stretched */
  706. else
  707. {
  708. /* calculate the central position */
  709. cxImgPos = (cxWinSize - cxImgSize) / 2;
  710. cyImgPos = (cyWinSize - cyImgSize) / 2;
  711. /* check for image larger than window */
  712. if (cxImgPos < MARGIN)
  713. cxImgPos = MARGIN;
  714. if (cyImgPos < MARGIN)
  715. cyImgPos = MARGIN;
  716. /* calculate both row-bytes */
  717. wImgRowBytes = cImgChannels * cxImgSize;
  718. wDIRowBytes = (WORD) ((cDIChannels * cxWinSize + 3L) >> 2) << 2;
  719. /* copy image to screen */
  720. for (yImg = 0, yWin = cyImgPos; yImg < cyImgSize; yImg++, yWin++)
  721. {
  722. if (yWin >= cyWinSize - MARGIN)
  723. break;
  724. src = pbImage + yImg * wImgRowBytes;
  725. dst = pDiData + yWin * wDIRowBytes + cxImgPos * cDIChannels;
  726. for (xImg = 0, xWin = cxImgPos; xImg < cxImgSize; xImg++, xWin++)
  727. {
  728. if (xWin >= cxWinSize - MARGIN)
  729. break;
  730. r = *src++;
  731. g = *src++;
  732. b = *src++;
  733. *dst++ = b; /* note the reverse order */
  734. *dst++ = g;
  735. *dst++ = r;
  736. if (cImgChannels == 4)
  737. {
  738. a = *src++;
  739. }
  740. }
  741. }
  742. }
  743. return TRUE;
  744. }
  745. /*-----------------
  746. * end of source
  747. *-----------------
  748. */