VisualPng.c
上传用户:sesekoo
上传日期:2020-07-18
资源大小:21543k
文件大小:26k
源码类别:

界面编程

开发平台:

Visual C++

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