(root)/
libpng-1.6.40/
contrib/
visupng/
VisualPng.c
       1  /*------------------------------------
       2   *  VisualPng.C -- Shows a PNG image
       3   *------------------------------------
       4   *
       5   * Copyright 2000,2017 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 command line, 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 Independent 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 (cyWinSize > ((size_t)(-1))/wDIRowBytes) {
     730      {
     731          MessageBox (hwnd, TEXT ("Visual PNG: image is too big");
     732      }
     733      if (!(pDib = (BYTE *) malloc (sizeof(BITMAPINFOHEADER) +
     734          wDIRowBytes * cyWinSize)))
     735      {
     736          MessageBox (hwnd, TEXT ("Error in displaying the PNG image"),
     737              szProgName, MB_ICONEXCLAMATION | MB_OK);
     738          *ppDib = pDib = NULL;
     739          return FALSE;
     740      }
     741      *ppDib = pDib;
     742      memset (pDib, 0, sizeof(BITMAPINFOHEADER));
     743  
     744      /* initialize the dib-structure */
     745  
     746      pbmih = (BITMAPINFOHEADER *) pDib;
     747      pbmih->biSize = sizeof(BITMAPINFOHEADER);
     748      pbmih->biWidth = cxWinSize;
     749      pbmih->biHeight = -((long) cyWinSize);
     750      pbmih->biPlanes = 1;
     751      pbmih->biBitCount = 24;
     752      pbmih->biCompression = 0;
     753      pDiData = pDib + sizeof(BITMAPINFOHEADER);
     754      *ppDiData = pDiData;
     755  
     756      /* first fill bitmap with gray and image border */
     757  
     758      InitBitmap (pDiData, cxWinSize, cyWinSize);
     759  
     760      /* then fill bitmap with image */
     761  
     762      if (pbImage)
     763      {
     764          FillBitmap (
     765              pDiData, cxWinSize, cyWinSize,
     766              pbImage, cxImgSize, cyImgSize, cImgChannels,
     767              bStretched);
     768      }
     769  
     770      return TRUE;
     771  }
     772  
     773  /*--------------
     774   *  InitBitmap
     775   *--------------
     776   */
     777  BOOL InitBitmap (BYTE *pDiData, int cxWinSize, int cyWinSize)
     778  {
     779      BYTE *dst;
     780      int x, y, col;
     781  
     782      /* initialize the background with gray */
     783  
     784      dst = pDiData;
     785      for (y = 0; y < cyWinSize; y++)
     786      {
     787          col = 0;
     788          for (x = 0; x < cxWinSize; x++)
     789          {
     790              /* fill with GRAY */
     791              *dst++ = 127;
     792              *dst++ = 127;
     793              *dst++ = 127;
     794              col += 3;
     795          }
     796          /* rows start on 4 byte boundaries */
     797          while ((col % 4) != 0)
     798          {
     799              dst++;
     800              col++;
     801          }
     802      }
     803  
     804      return TRUE;
     805  }
     806  
     807  /*--------------
     808   *  FillBitmap
     809   *--------------
     810   */
     811  BOOL FillBitmap (
     812          BYTE *pDiData, int cxWinSize, int cyWinSize,
     813          BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels,
     814          BOOL bStretched)
     815  {
     816      BYTE *pStretchedImage;
     817      BYTE *pImg;
     818      BYTE *src, *dst;
     819      BYTE r, g, b, a;
     820      const int cDIChannels = 3;
     821      WORD wImgRowBytes;
     822      WORD wDIRowBytes;
     823      int cxNewSize, cyNewSize;
     824      int cxImgPos, cyImgPos;
     825      int xImg, yImg;
     826      int xWin, yWin;
     827      int xOld, yOld;
     828      int xNew, yNew;
     829  
     830      if (bStretched)
     831      {
     832          cxNewSize = cxWinSize - 2 * MARGIN;
     833          cyNewSize = cyWinSize - 2 * MARGIN;
     834  
     835          /* stretch the image to it's window determined size */
     836  
     837          /* the following two are mathematically the same, but the first
     838           * has side-effects because of rounding
     839           */
     840  /*      if ((cyNewSize / cxNewSize) > (cyImgSize / cxImgSize)) */
     841          if ((cyNewSize * cxImgSize) > (cyImgSize * cxNewSize))
     842          {
     843              cyNewSize = cxNewSize * cyImgSize / cxImgSize;
     844              cxImgPos = MARGIN;
     845              cyImgPos = (cyWinSize - cyNewSize) / 2;
     846          }
     847          else
     848          {
     849              cxNewSize = cyNewSize * cxImgSize / cyImgSize;
     850              cyImgPos = MARGIN;
     851              cxImgPos = (cxWinSize - cxNewSize) / 2;
     852          }
     853  
     854          if (cyNewSize > ((size_t)(-1))/(cImgChannels * cxNewSize)) {
     855          {
     856              MessageBox (hwnd, TEXT ("Visual PNG: stretched image is too big");
     857          }
     858          pStretchedImage = malloc (cImgChannels * cxNewSize * cyNewSize);
     859          pImg = pStretchedImage;
     860  
     861          for (yNew = 0; yNew < cyNewSize; yNew++)
     862          {
     863              yOld = yNew * cyImgSize / cyNewSize;
     864              for (xNew = 0; xNew < cxNewSize; xNew++)
     865              {
     866                  xOld = xNew * cxImgSize / cxNewSize;
     867  
     868                  r = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 0);
     869                  g = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 1);
     870                  b = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 2);
     871                  *pImg++ = r;
     872                  *pImg++ = g;
     873                  *pImg++ = b;
     874                  if (cImgChannels == 4)
     875                  {
     876                      a = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld)
     877                          + 3);
     878                      *pImg++ = a;
     879                  }
     880              }
     881          }
     882  
     883          /* calculate row-bytes */
     884  
     885          wImgRowBytes = cImgChannels * cxNewSize;
     886          wDIRowBytes = (WORD) ((cDIChannels * cxWinSize + 3L) >> 2) << 2;
     887  
     888          /* copy image to screen */
     889  
     890          for (yImg = 0, yWin = cyImgPos; yImg < cyNewSize; yImg++, yWin++)
     891          {
     892              if (yWin >= cyWinSize - cyImgPos)
     893                  break;
     894              src = pStretchedImage + yImg * wImgRowBytes;
     895              dst = pDiData + yWin * wDIRowBytes + cxImgPos * cDIChannels;
     896  
     897              for (xImg = 0, xWin = cxImgPos; xImg < cxNewSize; xImg++, xWin++)
     898              {
     899                  if (xWin >= cxWinSize - cxImgPos)
     900                      break;
     901                  r = *src++;
     902                  g = *src++;
     903                  b = *src++;
     904                  *dst++ = b; /* note the reverse order  */
     905                  *dst++ = g;
     906                  *dst++ = r;
     907                  if (cImgChannels == 4)
     908                  {
     909                      a = *src++;
     910                  }
     911              }
     912          }
     913  
     914          /* free memory */
     915  
     916          if (pStretchedImage != NULL)
     917          {
     918              free (pStretchedImage);
     919              pStretchedImage = NULL;
     920          }
     921  
     922      }
     923  
     924      /* process the image not-stretched */
     925  
     926      else
     927      {
     928          /* calculate the central position */
     929  
     930          cxImgPos = (cxWinSize - cxImgSize) / 2;
     931          cyImgPos = (cyWinSize - cyImgSize) / 2;
     932  
     933          /* check for image larger than window */
     934  
     935          if (cxImgPos < MARGIN)
     936              cxImgPos = MARGIN;
     937          if (cyImgPos < MARGIN)
     938              cyImgPos = MARGIN;
     939  
     940          /* calculate both row-bytes */
     941  
     942          wImgRowBytes = cImgChannels * cxImgSize;
     943          wDIRowBytes = (WORD) ((cDIChannels * cxWinSize + 3L) >> 2) << 2;
     944  
     945          /* copy image to screen */
     946  
     947          for (yImg = 0, yWin = cyImgPos; yImg < cyImgSize; yImg++, yWin++)
     948          {
     949              if (yWin >= cyWinSize - MARGIN)
     950                  break;
     951              src = pbImage + yImg * wImgRowBytes;
     952              dst = pDiData + yWin * wDIRowBytes + cxImgPos * cDIChannels;
     953  
     954              for (xImg = 0, xWin = cxImgPos; xImg < cxImgSize; xImg++, xWin++)
     955              {
     956                  if (xWin >= cxWinSize - MARGIN)
     957                      break;
     958                  r = *src++;
     959                  g = *src++;
     960                  b = *src++;
     961                  *dst++ = b; /* note the reverse order  */
     962                  *dst++ = g;
     963                  *dst++ = r;
     964                  if (cImgChannels == 4)
     965                  {
     966                      a = *src++;
     967                  }
     968              }
     969          }
     970      }
     971  
     972      return TRUE;
     973  }
     974  
     975  /*-----------------
     976   *  end of source
     977   *-----------------
     978   */