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