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