mirror of
				https://git.code.sf.net/p/libpng/code.git
				synced 2025-07-10 18:04:09 +02:00 
			
		
		
		
	Some are user facing. Some are in actual code. Most are in source comments. Also, please double check the changes in contrib/tools/pngfix.c
		
			
				
	
	
		
			979 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			979 lines
		
	
	
		
			26 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*------------------------------------
 | 
						|
 *  VisualPng.C -- Shows a PNG image
 | 
						|
 *------------------------------------
 | 
						|
 *
 | 
						|
 * Copyright 2000,2017 Willem van Schaik.
 | 
						|
 *
 | 
						|
 * This code is released under the libpng license.
 | 
						|
 * For conditions of distribution and use, see the disclaimer
 | 
						|
 * and license in png.h
 | 
						|
 */
 | 
						|
 | 
						|
/* switches */
 | 
						|
 | 
						|
/* defines */
 | 
						|
 | 
						|
#define PROGNAME  "VisualPng"
 | 
						|
#define LONGNAME  "Win32 Viewer for PNG-files"
 | 
						|
#define VERSION   "1.0 of 2000 June 07"
 | 
						|
 | 
						|
/* constants */
 | 
						|
 | 
						|
#define MARGIN 8
 | 
						|
 | 
						|
/* standard includes */
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#include <windows.h>
 | 
						|
#include <zlib.h>
 | 
						|
 | 
						|
/* application includes */
 | 
						|
 | 
						|
#include "png.h"
 | 
						|
#include "pngfile.h"
 | 
						|
#include "resource.h"
 | 
						|
 | 
						|
/* macros */
 | 
						|
 | 
						|
/* function prototypes */
 | 
						|
 | 
						|
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
 | 
						|
BOOL    CALLBACK AboutDlgProc (HWND, UINT, WPARAM, LPARAM) ;
 | 
						|
 | 
						|
BOOL CenterAbout (HWND hwndChild, HWND hwndParent);
 | 
						|
 | 
						|
BOOL BuildPngList (PTSTR pstrPathName, TCHAR **ppFileList, int *pFileCount,
 | 
						|
        int *pFileIndex);
 | 
						|
 | 
						|
BOOL SearchPngList (TCHAR *pFileList, int FileCount, int *pFileIndex,
 | 
						|
        PTSTR pstrPrevName, PTSTR pstrNextName);
 | 
						|
 | 
						|
BOOL LoadImageFile(HWND hwnd, PTSTR pstrPathName,
 | 
						|
        png_byte **ppbImage, int *pxImgSize, int *pyImgSize, int *piChannels,
 | 
						|
        png_color *pBkgColor);
 | 
						|
 | 
						|
BOOL DisplayImage (HWND hwnd, BYTE **ppDib,
 | 
						|
        BYTE **ppDiData, int cxWinSize, int cyWinSize,
 | 
						|
        BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels,
 | 
						|
        BOOL bStretched);
 | 
						|
 | 
						|
BOOL InitBitmap (
 | 
						|
        BYTE *pDiData, int cxWinSize, int cyWinSize);
 | 
						|
 | 
						|
BOOL FillBitmap (
 | 
						|
        BYTE *pDiData, int cxWinSize, int cyWinSize,
 | 
						|
        BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels,
 | 
						|
        BOOL bStretched);
 | 
						|
 | 
						|
/* a few global variables */
 | 
						|
 | 
						|
static char *szProgName = PROGNAME;
 | 
						|
static char *szAppName = LONGNAME;
 | 
						|
static char *szIconName = PROGNAME;
 | 
						|
static char szCmdFileName [MAX_PATH];
 | 
						|
 | 
						|
/* MAIN routine */
 | 
						|
 | 
						|
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
 | 
						|
                    PSTR szCmdLine, int iCmdShow)
 | 
						|
{
 | 
						|
    HACCEL   hAccel;
 | 
						|
    HWND     hwnd;
 | 
						|
    MSG      msg;
 | 
						|
    WNDCLASS wndclass;
 | 
						|
    int ixBorders, iyBorders;
 | 
						|
 | 
						|
    wndclass.style         = CS_HREDRAW | CS_VREDRAW;
 | 
						|
    wndclass.lpfnWndProc   = WndProc;
 | 
						|
    wndclass.cbClsExtra    = 0;
 | 
						|
    wndclass.cbWndExtra    = 0;
 | 
						|
    wndclass.hInstance     = hInstance;
 | 
						|
    wndclass.hIcon         = LoadIcon (hInstance, szIconName) ;
 | 
						|
    wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);
 | 
						|
    wndclass.hbrBackground = NULL; /* (HBRUSH) GetStockObject (GRAY_BRUSH); */
 | 
						|
    wndclass.lpszMenuName  = szProgName;
 | 
						|
    wndclass.lpszClassName = szProgName;
 | 
						|
 | 
						|
    if (!RegisterClass (&wndclass))
 | 
						|
    {
 | 
						|
        MessageBox (NULL, TEXT ("Error: this program requires Windows NT!"),
 | 
						|
            szProgName, MB_ICONERROR);
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    /* if filename given on commandline, store it */
 | 
						|
    if ((szCmdLine != NULL) && (*szCmdLine != '\0'))
 | 
						|
        if (szCmdLine[0] == '"')
 | 
						|
            strncpy (szCmdFileName, szCmdLine + 1, strlen(szCmdLine) - 2);
 | 
						|
        else
 | 
						|
            strcpy (szCmdFileName, szCmdLine);
 | 
						|
    else
 | 
						|
        strcpy (szCmdFileName, "");
 | 
						|
 | 
						|
    /* calculate size of window-borders */
 | 
						|
    ixBorders = 2 * (GetSystemMetrics (SM_CXBORDER) +
 | 
						|
                     GetSystemMetrics (SM_CXDLGFRAME));
 | 
						|
    iyBorders = 2 * (GetSystemMetrics (SM_CYBORDER) +
 | 
						|
                     GetSystemMetrics (SM_CYDLGFRAME)) +
 | 
						|
                     GetSystemMetrics (SM_CYCAPTION) +
 | 
						|
                     GetSystemMetrics (SM_CYMENUSIZE) +
 | 
						|
                     1; /* WvS: don't ask me why?  */
 | 
						|
 | 
						|
    hwnd = CreateWindow (szProgName, szAppName,
 | 
						|
        WS_OVERLAPPEDWINDOW,
 | 
						|
        CW_USEDEFAULT, CW_USEDEFAULT,
 | 
						|
        512 + 2 * MARGIN + ixBorders, 384 + 2 * MARGIN + iyBorders,
 | 
						|
/*      CW_USEDEFAULT, CW_USEDEFAULT, */
 | 
						|
        NULL, NULL, hInstance, NULL);
 | 
						|
 | 
						|
    ShowWindow (hwnd, iCmdShow);
 | 
						|
    UpdateWindow (hwnd);
 | 
						|
 | 
						|
    hAccel = LoadAccelerators (hInstance, szProgName);
 | 
						|
 | 
						|
    while (GetMessage (&msg, NULL, 0, 0))
 | 
						|
    {
 | 
						|
        if (!TranslateAccelerator (hwnd, hAccel, &msg))
 | 
						|
        {
 | 
						|
            TranslateMessage (&msg);
 | 
						|
            DispatchMessage (&msg);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return msg.wParam;
 | 
						|
}
 | 
						|
 | 
						|
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam,
 | 
						|
        LPARAM lParam)
 | 
						|
{
 | 
						|
    static HINSTANCE          hInstance ;
 | 
						|
    static HDC                hdc;
 | 
						|
    static PAINTSTRUCT        ps;
 | 
						|
    static HMENU              hMenu;
 | 
						|
 | 
						|
    static BITMAPFILEHEADER  *pbmfh;
 | 
						|
    static BITMAPINFOHEADER  *pbmih;
 | 
						|
    static BYTE              *pbImage;
 | 
						|
    static int                cxWinSize, cyWinSize;
 | 
						|
    static int                cxImgSize, cyImgSize;
 | 
						|
    static int                cImgChannels;
 | 
						|
    static png_color          bkgColor = {127, 127, 127};
 | 
						|
 | 
						|
    static BOOL               bStretched = TRUE;
 | 
						|
 | 
						|
    static BYTE              *pDib = NULL;
 | 
						|
    static BYTE              *pDiData = NULL;
 | 
						|
 | 
						|
    static TCHAR              szImgPathName [MAX_PATH];
 | 
						|
    static TCHAR              szTitleName [MAX_PATH];
 | 
						|
 | 
						|
    static TCHAR             *pPngFileList = NULL;
 | 
						|
    static int                iPngFileCount;
 | 
						|
    static int                iPngFileIndex;
 | 
						|
 | 
						|
    BOOL                      bOk;
 | 
						|
 | 
						|
    switch (message)
 | 
						|
    {
 | 
						|
    case WM_CREATE:
 | 
						|
        hInstance = ((LPCREATESTRUCT) lParam)->hInstance ;
 | 
						|
        PngFileInitialize (hwnd);
 | 
						|
 | 
						|
        strcpy (szImgPathName, "");
 | 
						|
 | 
						|
        /* in case we process file given on command-line */
 | 
						|
 | 
						|
        if (szCmdFileName[0] != '\0')
 | 
						|
        {
 | 
						|
            strcpy (szImgPathName, szCmdFileName);
 | 
						|
 | 
						|
            /* read the other png-files in the directory for later */
 | 
						|
            /* next/previous commands */
 | 
						|
 | 
						|
            BuildPngList (szImgPathName, &pPngFileList, &iPngFileCount,
 | 
						|
                          &iPngFileIndex);
 | 
						|
 | 
						|
            /* load the image from file */
 | 
						|
 | 
						|
            if (!LoadImageFile (hwnd, szImgPathName,
 | 
						|
                &pbImage, &cxImgSize, &cyImgSize, &cImgChannels, &bkgColor))
 | 
						|
                return 0;
 | 
						|
 | 
						|
            /* invalidate the client area for later update */
 | 
						|
 | 
						|
            InvalidateRect (hwnd, NULL, TRUE);
 | 
						|
 | 
						|
            /* display the PNG into the DIBitmap */
 | 
						|
 | 
						|
            DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
 | 
						|
                pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
 | 
						|
        }
 | 
						|
 | 
						|
        return 0;
 | 
						|
 | 
						|
    case WM_SIZE:
 | 
						|
        cxWinSize = LOWORD (lParam);
 | 
						|
        cyWinSize = HIWORD (lParam);
 | 
						|
 | 
						|
        /* invalidate the client area for later update */
 | 
						|
 | 
						|
        InvalidateRect (hwnd, NULL, TRUE);
 | 
						|
 | 
						|
        /* display the PNG into the DIBitmap */
 | 
						|
 | 
						|
        DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
 | 
						|
            pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
 | 
						|
 | 
						|
        return 0;
 | 
						|
 | 
						|
    case WM_INITMENUPOPUP:
 | 
						|
        hMenu = GetMenu (hwnd);
 | 
						|
 | 
						|
        if (pbImage)
 | 
						|
            EnableMenuItem (hMenu, IDM_FILE_SAVE, MF_ENABLED);
 | 
						|
        else
 | 
						|
            EnableMenuItem (hMenu, IDM_FILE_SAVE, MF_GRAYED);
 | 
						|
 | 
						|
        return 0;
 | 
						|
 | 
						|
    case WM_COMMAND:
 | 
						|
        hMenu = GetMenu (hwnd);
 | 
						|
 | 
						|
        switch (LOWORD (wParam))
 | 
						|
        {
 | 
						|
        case IDM_FILE_OPEN:
 | 
						|
 | 
						|
            /* show the File Open dialog box */
 | 
						|
 | 
						|
            if (!PngFileOpenDlg (hwnd, szImgPathName, szTitleName))
 | 
						|
                return 0;
 | 
						|
 | 
						|
            /* read the other png-files in the directory for later */
 | 
						|
            /* next/previous commands */
 | 
						|
 | 
						|
            BuildPngList (szImgPathName, &pPngFileList, &iPngFileCount,
 | 
						|
                          &iPngFileIndex);
 | 
						|
 | 
						|
            /* load the image from file */
 | 
						|
 | 
						|
            if (!LoadImageFile (hwnd, szImgPathName,
 | 
						|
                &pbImage, &cxImgSize, &cyImgSize, &cImgChannels, &bkgColor))
 | 
						|
                return 0;
 | 
						|
 | 
						|
            /* invalidate the client area for later update */
 | 
						|
 | 
						|
            InvalidateRect (hwnd, NULL, TRUE);
 | 
						|
 | 
						|
            /* display the PNG into the DIBitmap */
 | 
						|
 | 
						|
            DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
 | 
						|
                pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
 | 
						|
 | 
						|
            return 0;
 | 
						|
 | 
						|
        case IDM_FILE_SAVE:
 | 
						|
 | 
						|
            /* show the File Save dialog box */
 | 
						|
 | 
						|
            if (!PngFileSaveDlg (hwnd, szImgPathName, szTitleName))
 | 
						|
                return 0;
 | 
						|
 | 
						|
            /* save the PNG to a disk file */
 | 
						|
 | 
						|
            SetCursor (LoadCursor (NULL, IDC_WAIT));
 | 
						|
            ShowCursor (TRUE);
 | 
						|
 | 
						|
            bOk = PngSaveImage (szImgPathName, pDiData, cxWinSize, cyWinSize,
 | 
						|
                  bkgColor);
 | 
						|
 | 
						|
            ShowCursor (FALSE);
 | 
						|
            SetCursor (LoadCursor (NULL, IDC_ARROW));
 | 
						|
 | 
						|
            if (!bOk)
 | 
						|
                MessageBox (hwnd, TEXT ("Error in saving the PNG image"),
 | 
						|
                szProgName, MB_ICONEXCLAMATION | MB_OK);
 | 
						|
            return 0;
 | 
						|
 | 
						|
        case IDM_FILE_NEXT:
 | 
						|
 | 
						|
            /* read next entry in the directory */
 | 
						|
 | 
						|
            if (SearchPngList (pPngFileList, iPngFileCount, &iPngFileIndex,
 | 
						|
                NULL, szImgPathName))
 | 
						|
            {
 | 
						|
                if (strcmp (szImgPathName, "") == 0)
 | 
						|
                    return 0;
 | 
						|
 | 
						|
                /* load the image from file */
 | 
						|
 | 
						|
                if (!LoadImageFile (hwnd, szImgPathName, &pbImage,
 | 
						|
                        &cxImgSize, &cyImgSize, &cImgChannels, &bkgColor))
 | 
						|
                    return 0;
 | 
						|
 | 
						|
                /* invalidate the client area for later update */
 | 
						|
 | 
						|
                InvalidateRect (hwnd, NULL, TRUE);
 | 
						|
 | 
						|
                /* display the PNG into the DIBitmap */
 | 
						|
 | 
						|
                DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
 | 
						|
                    pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
 | 
						|
            }
 | 
						|
 | 
						|
            return 0;
 | 
						|
 | 
						|
        case IDM_FILE_PREVIOUS:
 | 
						|
 | 
						|
            /* read previous entry in the directory */
 | 
						|
 | 
						|
            if (SearchPngList (pPngFileList, iPngFileCount, &iPngFileIndex,
 | 
						|
                szImgPathName, NULL))
 | 
						|
            {
 | 
						|
 | 
						|
                if (strcmp (szImgPathName, "") == 0)
 | 
						|
                    return 0;
 | 
						|
 | 
						|
                /* load the image from file */
 | 
						|
 | 
						|
                if (!LoadImageFile (hwnd, szImgPathName, &pbImage, &cxImgSize,
 | 
						|
                    &cyImgSize, &cImgChannels, &bkgColor))
 | 
						|
                    return 0;
 | 
						|
 | 
						|
                /* invalidate the client area for later update */
 | 
						|
 | 
						|
                InvalidateRect (hwnd, NULL, TRUE);
 | 
						|
 | 
						|
                /* display the PNG into the DIBitmap */
 | 
						|
 | 
						|
                DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
 | 
						|
                    pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
 | 
						|
            }
 | 
						|
 | 
						|
            return 0;
 | 
						|
 | 
						|
        case IDM_FILE_EXIT:
 | 
						|
 | 
						|
            /* more cleanup needed... */
 | 
						|
 | 
						|
            /* free image buffer */
 | 
						|
 | 
						|
            if (pDib != NULL)
 | 
						|
            {
 | 
						|
                free (pDib);
 | 
						|
                pDib = NULL;
 | 
						|
            }
 | 
						|
 | 
						|
            /* free file-list */
 | 
						|
 | 
						|
            if (pPngFileList != NULL)
 | 
						|
            {
 | 
						|
                free (pPngFileList);
 | 
						|
                pPngFileList = NULL;
 | 
						|
            }
 | 
						|
 | 
						|
            /* let's go ... */
 | 
						|
 | 
						|
            exit (0);
 | 
						|
 | 
						|
            return 0;
 | 
						|
 | 
						|
        case IDM_OPTIONS_STRETCH:
 | 
						|
            bStretched = !bStretched;
 | 
						|
            if (bStretched)
 | 
						|
                CheckMenuItem (hMenu, IDM_OPTIONS_STRETCH, MF_CHECKED);
 | 
						|
            else
 | 
						|
                CheckMenuItem (hMenu, IDM_OPTIONS_STRETCH, MF_UNCHECKED);
 | 
						|
 | 
						|
            /* invalidate the client area for later update */
 | 
						|
 | 
						|
            InvalidateRect (hwnd, NULL, TRUE);
 | 
						|
 | 
						|
            /* display the PNG into the DIBitmap */
 | 
						|
 | 
						|
            DisplayImage (hwnd, &pDib, &pDiData, cxWinSize, cyWinSize,
 | 
						|
                pbImage, cxImgSize, cyImgSize, cImgChannels, bStretched);
 | 
						|
 | 
						|
            return 0;
 | 
						|
 | 
						|
        case IDM_HELP_ABOUT:
 | 
						|
            DialogBox (hInstance, TEXT ("AboutBox"), hwnd, AboutDlgProc) ;
 | 
						|
            return 0;
 | 
						|
 | 
						|
        } /* end switch */
 | 
						|
 | 
						|
        break;
 | 
						|
 | 
						|
    case WM_PAINT:
 | 
						|
        hdc = BeginPaint (hwnd, &ps);
 | 
						|
 | 
						|
        if (pDib)
 | 
						|
            SetDIBitsToDevice (hdc, 0, 0, cxWinSize, cyWinSize, 0, 0,
 | 
						|
                0, cyWinSize, pDiData, (BITMAPINFO *) pDib, DIB_RGB_COLORS);
 | 
						|
 | 
						|
        EndPaint (hwnd, &ps);
 | 
						|
        return 0;
 | 
						|
 | 
						|
    case WM_DESTROY:
 | 
						|
        if (pbmfh)
 | 
						|
        {
 | 
						|
            free (pbmfh);
 | 
						|
            pbmfh = NULL;
 | 
						|
        }
 | 
						|
 | 
						|
        PostQuitMessage (0);
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    return DefWindowProc (hwnd, message, wParam, lParam);
 | 
						|
}
 | 
						|
 | 
						|
BOOL CALLBACK AboutDlgProc (HWND hDlg, UINT message,
 | 
						|
                            WPARAM wParam, LPARAM lParam)
 | 
						|
{
 | 
						|
     switch (message)
 | 
						|
     {
 | 
						|
     case WM_INITDIALOG :
 | 
						|
          ShowWindow (hDlg, SW_HIDE);
 | 
						|
          CenterAbout (hDlg, GetWindow (hDlg, GW_OWNER));
 | 
						|
          ShowWindow (hDlg, SW_SHOW);
 | 
						|
          return TRUE ;
 | 
						|
 | 
						|
     case WM_COMMAND :
 | 
						|
          switch (LOWORD (wParam))
 | 
						|
          {
 | 
						|
          case IDOK :
 | 
						|
          case IDCANCEL :
 | 
						|
               EndDialog (hDlg, 0) ;
 | 
						|
               return TRUE ;
 | 
						|
          }
 | 
						|
          break ;
 | 
						|
     }
 | 
						|
     return FALSE ;
 | 
						|
}
 | 
						|
 | 
						|
/*---------------
 | 
						|
 *  CenterAbout
 | 
						|
 *---------------
 | 
						|
 */
 | 
						|
BOOL CenterAbout (HWND hwndChild, HWND hwndParent)
 | 
						|
{
 | 
						|
   RECT    rChild, rParent, rWorkArea;
 | 
						|
   int     wChild, hChild, wParent, hParent;
 | 
						|
   int     xNew, yNew;
 | 
						|
   BOOL  bResult;
 | 
						|
 | 
						|
   /* Get the Height and Width of the child window */
 | 
						|
   GetWindowRect (hwndChild, &rChild);
 | 
						|
   wChild = rChild.right - rChild.left;
 | 
						|
   hChild = rChild.bottom - rChild.top;
 | 
						|
 | 
						|
   /* Get the Height and Width of the parent window */
 | 
						|
   GetWindowRect (hwndParent, &rParent);
 | 
						|
   wParent = rParent.right - rParent.left;
 | 
						|
   hParent = rParent.bottom - rParent.top;
 | 
						|
 | 
						|
   /* Get the limits of the 'workarea' */
 | 
						|
   bResult = SystemParametersInfo(
 | 
						|
      SPI_GETWORKAREA,  /* system parameter to query or set */
 | 
						|
      sizeof(RECT),
 | 
						|
      &rWorkArea,
 | 
						|
      0);
 | 
						|
   if (!bResult) {
 | 
						|
      rWorkArea.left = rWorkArea.top = 0;
 | 
						|
      rWorkArea.right = GetSystemMetrics(SM_CXSCREEN);
 | 
						|
      rWorkArea.bottom = GetSystemMetrics(SM_CYSCREEN);
 | 
						|
   }
 | 
						|
 | 
						|
   /* Calculate new X position, then adjust for workarea */
 | 
						|
   xNew = rParent.left + ((wParent - wChild) /2);
 | 
						|
   if (xNew < rWorkArea.left) {
 | 
						|
      xNew = rWorkArea.left;
 | 
						|
   } else if ((xNew+wChild) > rWorkArea.right) {
 | 
						|
      xNew = rWorkArea.right - wChild;
 | 
						|
   }
 | 
						|
 | 
						|
   /* Calculate new Y position, then adjust for workarea */
 | 
						|
   yNew = rParent.top  + ((hParent - hChild) /2);
 | 
						|
   if (yNew < rWorkArea.top) {
 | 
						|
      yNew = rWorkArea.top;
 | 
						|
   } else if ((yNew+hChild) > rWorkArea.bottom) {
 | 
						|
      yNew = rWorkArea.bottom - hChild;
 | 
						|
   }
 | 
						|
 | 
						|
   /* Set it, and return */
 | 
						|
   return SetWindowPos (hwndChild, NULL, xNew, yNew, 0, 0, SWP_NOSIZE |
 | 
						|
          SWP_NOZORDER);
 | 
						|
}
 | 
						|
 | 
						|
/*----------------
 | 
						|
 *  BuildPngList
 | 
						|
 *----------------
 | 
						|
 */
 | 
						|
BOOL BuildPngList (PTSTR pstrPathName, TCHAR **ppFileList, int *pFileCount,
 | 
						|
     int *pFileIndex)
 | 
						|
{
 | 
						|
    static TCHAR              szImgPathName [MAX_PATH];
 | 
						|
    static TCHAR              szImgFileName [MAX_PATH];
 | 
						|
    static TCHAR              szImgFindName [MAX_PATH];
 | 
						|
 | 
						|
    WIN32_FIND_DATA           finddata;
 | 
						|
    HANDLE                    hFind;
 | 
						|
 | 
						|
    static TCHAR              szTmp [MAX_PATH];
 | 
						|
    BOOL                      bOk;
 | 
						|
    int                       i, ii;
 | 
						|
    int                       j, jj;
 | 
						|
 | 
						|
    /* free previous file-list */
 | 
						|
 | 
						|
    if (*ppFileList != NULL)
 | 
						|
    {
 | 
						|
        free (*ppFileList);
 | 
						|
        *ppFileList = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    /* extract foldername, filename and search-name */
 | 
						|
 | 
						|
    strcpy (szImgPathName, pstrPathName);
 | 
						|
    strcpy (szImgFileName, strrchr (pstrPathName, '\\') + 1);
 | 
						|
 | 
						|
    strcpy (szImgFindName, szImgPathName);
 | 
						|
    *(strrchr (szImgFindName, '\\') + 1) = '\0';
 | 
						|
    strcat (szImgFindName, "*.png");
 | 
						|
 | 
						|
    /* first cycle: count number of files in directory for memory allocation */
 | 
						|
 | 
						|
    *pFileCount = 0;
 | 
						|
 | 
						|
    hFind = FindFirstFile(szImgFindName, &finddata);
 | 
						|
    bOk = (hFind != (HANDLE) -1);
 | 
						|
 | 
						|
    while (bOk)
 | 
						|
    {
 | 
						|
        *pFileCount += 1;
 | 
						|
        bOk = FindNextFile(hFind, &finddata);
 | 
						|
    }
 | 
						|
    FindClose(hFind);
 | 
						|
 | 
						|
    /* allocation memory for file-list */
 | 
						|
 | 
						|
    *ppFileList = (TCHAR *) malloc (*pFileCount * MAX_PATH);
 | 
						|
 | 
						|
    /* second cycle: read directory and store filenames in file-list */
 | 
						|
 | 
						|
    hFind = FindFirstFile(szImgFindName, &finddata);
 | 
						|
    bOk = (hFind != (HANDLE) -1);
 | 
						|
 | 
						|
    i = 0;
 | 
						|
    ii = 0;
 | 
						|
    while (bOk)
 | 
						|
    {
 | 
						|
        strcpy (*ppFileList + ii, szImgPathName);
 | 
						|
        strcpy (strrchr(*ppFileList + ii, '\\') + 1, finddata.cFileName);
 | 
						|
 | 
						|
        if (strcmp(pstrPathName, *ppFileList + ii) == 0)
 | 
						|
            *pFileIndex = i;
 | 
						|
 | 
						|
        ii += MAX_PATH;
 | 
						|
        i++;
 | 
						|
 | 
						|
        bOk = FindNextFile(hFind, &finddata);
 | 
						|
    }
 | 
						|
    FindClose(hFind);
 | 
						|
 | 
						|
    /* finally we must sort the file-list */
 | 
						|
 | 
						|
    for (i = 0; i < *pFileCount - 1; i++)
 | 
						|
    {
 | 
						|
        ii = i * MAX_PATH;
 | 
						|
        for (j = i+1; j < *pFileCount; j++)
 | 
						|
        {
 | 
						|
            jj = j * MAX_PATH;
 | 
						|
            if (strcmp (*ppFileList + ii, *ppFileList + jj) > 0)
 | 
						|
            {
 | 
						|
                strcpy (szTmp, *ppFileList + jj);
 | 
						|
                strcpy (*ppFileList + jj, *ppFileList + ii);
 | 
						|
                strcpy (*ppFileList + ii, szTmp);
 | 
						|
 | 
						|
                /* check if this was the current image that we moved */
 | 
						|
 | 
						|
                if (*pFileIndex == i)
 | 
						|
                    *pFileIndex = j;
 | 
						|
                else
 | 
						|
                    if (*pFileIndex == j)
 | 
						|
                        *pFileIndex = i;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/*----------------
 | 
						|
 *  SearchPngList
 | 
						|
 *----------------
 | 
						|
 */
 | 
						|
 | 
						|
BOOL SearchPngList (
 | 
						|
        TCHAR *pFileList, int FileCount, int *pFileIndex,
 | 
						|
        PTSTR pstrPrevName, PTSTR pstrNextName)
 | 
						|
{
 | 
						|
    if (FileCount > 0)
 | 
						|
    {
 | 
						|
        /* get previous entry */
 | 
						|
 | 
						|
        if (pstrPrevName != NULL)
 | 
						|
        {
 | 
						|
            if (*pFileIndex > 0)
 | 
						|
                *pFileIndex -= 1;
 | 
						|
            else
 | 
						|
                *pFileIndex = FileCount - 1;
 | 
						|
 | 
						|
            strcpy (pstrPrevName, pFileList + (*pFileIndex * MAX_PATH));
 | 
						|
        }
 | 
						|
 | 
						|
        /* get next entry */
 | 
						|
 | 
						|
        if (pstrNextName != NULL)
 | 
						|
        {
 | 
						|
            if (*pFileIndex < FileCount - 1)
 | 
						|
                *pFileIndex += 1;
 | 
						|
            else
 | 
						|
                *pFileIndex = 0;
 | 
						|
 | 
						|
            strcpy (pstrNextName, pFileList + (*pFileIndex * MAX_PATH));
 | 
						|
        }
 | 
						|
 | 
						|
        return TRUE;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        return FALSE;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/*-----------------
 | 
						|
 *  LoadImageFile
 | 
						|
 *-----------------
 | 
						|
 */
 | 
						|
 | 
						|
BOOL LoadImageFile (HWND hwnd, PTSTR pstrPathName,
 | 
						|
                png_byte **ppbImage, int *pxImgSize, int *pyImgSize,
 | 
						|
                int *piChannels, png_color *pBkgColor)
 | 
						|
{
 | 
						|
    static TCHAR szTmp [MAX_PATH];
 | 
						|
 | 
						|
    /* if there's an existing PNG, free the memory */
 | 
						|
 | 
						|
    if (*ppbImage)
 | 
						|
    {
 | 
						|
        free (*ppbImage);
 | 
						|
        *ppbImage = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    /* Load the entire PNG into memory */
 | 
						|
 | 
						|
    SetCursor (LoadCursor (NULL, IDC_WAIT));
 | 
						|
    ShowCursor (TRUE);
 | 
						|
 | 
						|
    PngLoadImage (pstrPathName, ppbImage, pxImgSize, pyImgSize, piChannels,
 | 
						|
                  pBkgColor);
 | 
						|
 | 
						|
    ShowCursor (FALSE);
 | 
						|
    SetCursor (LoadCursor (NULL, IDC_ARROW));
 | 
						|
 | 
						|
    if (*ppbImage != NULL)
 | 
						|
    {
 | 
						|
        sprintf (szTmp, "VisualPng - %s", strrchr(pstrPathName, '\\') + 1);
 | 
						|
        SetWindowText (hwnd, szTmp);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        MessageBox (hwnd, TEXT ("Error in loading the PNG image"),
 | 
						|
            szProgName, MB_ICONEXCLAMATION | MB_OK);
 | 
						|
        return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/*----------------
 | 
						|
 *  DisplayImage
 | 
						|
 *----------------
 | 
						|
 */
 | 
						|
BOOL DisplayImage (HWND hwnd, BYTE **ppDib,
 | 
						|
        BYTE **ppDiData, int cxWinSize, int cyWinSize,
 | 
						|
        BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels,
 | 
						|
        BOOL bStretched)
 | 
						|
{
 | 
						|
    BYTE                       *pDib = *ppDib;
 | 
						|
    BYTE                       *pDiData = *ppDiData;
 | 
						|
    /* BITMAPFILEHEADER        *pbmfh; */
 | 
						|
    BITMAPINFOHEADER           *pbmih;
 | 
						|
    WORD                        wDIRowBytes;
 | 
						|
    png_color                   bkgBlack = {0, 0, 0};
 | 
						|
    png_color                   bkgGray  = {127, 127, 127};
 | 
						|
    png_color                   bkgWhite = {255, 255, 255};
 | 
						|
 | 
						|
    /* allocate memory for the Device Independent bitmap */
 | 
						|
 | 
						|
    wDIRowBytes = (WORD) ((3 * cxWinSize + 3L) >> 2) << 2;
 | 
						|
 | 
						|
    if (pDib)
 | 
						|
    {
 | 
						|
        free (pDib);
 | 
						|
        pDib = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (cyWinSize > ((size_t)(-1))/wDIRowBytes) {
 | 
						|
    {
 | 
						|
        MessageBox (hwnd, TEXT ("Visual PNG: image is too big");
 | 
						|
    }
 | 
						|
    if (!(pDib = (BYTE *) malloc (sizeof(BITMAPINFOHEADER) +
 | 
						|
        wDIRowBytes * cyWinSize)))
 | 
						|
    {
 | 
						|
        MessageBox (hwnd, TEXT ("Error in displaying the PNG image"),
 | 
						|
            szProgName, MB_ICONEXCLAMATION | MB_OK);
 | 
						|
        *ppDib = pDib = NULL;
 | 
						|
        return FALSE;
 | 
						|
    }
 | 
						|
    *ppDib = pDib;
 | 
						|
    memset (pDib, 0, sizeof(BITMAPINFOHEADER));
 | 
						|
 | 
						|
    /* initialize the dib-structure */
 | 
						|
 | 
						|
    pbmih = (BITMAPINFOHEADER *) pDib;
 | 
						|
    pbmih->biSize = sizeof(BITMAPINFOHEADER);
 | 
						|
    pbmih->biWidth = cxWinSize;
 | 
						|
    pbmih->biHeight = -((long) cyWinSize);
 | 
						|
    pbmih->biPlanes = 1;
 | 
						|
    pbmih->biBitCount = 24;
 | 
						|
    pbmih->biCompression = 0;
 | 
						|
    pDiData = pDib + sizeof(BITMAPINFOHEADER);
 | 
						|
    *ppDiData = pDiData;
 | 
						|
 | 
						|
    /* first fill bitmap with gray and image border */
 | 
						|
 | 
						|
    InitBitmap (pDiData, cxWinSize, cyWinSize);
 | 
						|
 | 
						|
    /* then fill bitmap with image */
 | 
						|
 | 
						|
    if (pbImage)
 | 
						|
    {
 | 
						|
        FillBitmap (
 | 
						|
            pDiData, cxWinSize, cyWinSize,
 | 
						|
            pbImage, cxImgSize, cyImgSize, cImgChannels,
 | 
						|
            bStretched);
 | 
						|
    }
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/*--------------
 | 
						|
 *  InitBitmap
 | 
						|
 *--------------
 | 
						|
 */
 | 
						|
BOOL InitBitmap (BYTE *pDiData, int cxWinSize, int cyWinSize)
 | 
						|
{
 | 
						|
    BYTE *dst;
 | 
						|
    int x, y, col;
 | 
						|
 | 
						|
    /* initialize the background with gray */
 | 
						|
 | 
						|
    dst = pDiData;
 | 
						|
    for (y = 0; y < cyWinSize; y++)
 | 
						|
    {
 | 
						|
        col = 0;
 | 
						|
        for (x = 0; x < cxWinSize; x++)
 | 
						|
        {
 | 
						|
            /* fill with GRAY */
 | 
						|
            *dst++ = 127;
 | 
						|
            *dst++ = 127;
 | 
						|
            *dst++ = 127;
 | 
						|
            col += 3;
 | 
						|
        }
 | 
						|
        /* rows start on 4 byte boundaries */
 | 
						|
        while ((col % 4) != 0)
 | 
						|
        {
 | 
						|
            dst++;
 | 
						|
            col++;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/*--------------
 | 
						|
 *  FillBitmap
 | 
						|
 *--------------
 | 
						|
 */
 | 
						|
BOOL FillBitmap (
 | 
						|
        BYTE *pDiData, int cxWinSize, int cyWinSize,
 | 
						|
        BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels,
 | 
						|
        BOOL bStretched)
 | 
						|
{
 | 
						|
    BYTE *pStretchedImage;
 | 
						|
    BYTE *pImg;
 | 
						|
    BYTE *src, *dst;
 | 
						|
    BYTE r, g, b, a;
 | 
						|
    const int cDIChannels = 3;
 | 
						|
    WORD wImgRowBytes;
 | 
						|
    WORD wDIRowBytes;
 | 
						|
    int cxNewSize, cyNewSize;
 | 
						|
    int cxImgPos, cyImgPos;
 | 
						|
    int xImg, yImg;
 | 
						|
    int xWin, yWin;
 | 
						|
    int xOld, yOld;
 | 
						|
    int xNew, yNew;
 | 
						|
 | 
						|
    if (bStretched)
 | 
						|
    {
 | 
						|
        cxNewSize = cxWinSize - 2 * MARGIN;
 | 
						|
        cyNewSize = cyWinSize - 2 * MARGIN;
 | 
						|
 | 
						|
        /* stretch the image to it's window determined size */
 | 
						|
 | 
						|
        /* the following two are mathematically the same, but the first
 | 
						|
         * has side-effects because of rounding
 | 
						|
         */
 | 
						|
/*      if ((cyNewSize / cxNewSize) > (cyImgSize / cxImgSize)) */
 | 
						|
        if ((cyNewSize * cxImgSize) > (cyImgSize * cxNewSize))
 | 
						|
        {
 | 
						|
            cyNewSize = cxNewSize * cyImgSize / cxImgSize;
 | 
						|
            cxImgPos = MARGIN;
 | 
						|
            cyImgPos = (cyWinSize - cyNewSize) / 2;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            cxNewSize = cyNewSize * cxImgSize / cyImgSize;
 | 
						|
            cyImgPos = MARGIN;
 | 
						|
            cxImgPos = (cxWinSize - cxNewSize) / 2;
 | 
						|
        }
 | 
						|
 | 
						|
        if (cyNewSize > ((size_t)(-1))/(cImgChannels * cxNewSize)) {
 | 
						|
        {
 | 
						|
            MessageBox (hwnd, TEXT ("Visual PNG: stretched image is too big");
 | 
						|
        }
 | 
						|
        pStretchedImage = malloc (cImgChannels * cxNewSize * cyNewSize);
 | 
						|
        pImg = pStretchedImage;
 | 
						|
 | 
						|
        for (yNew = 0; yNew < cyNewSize; yNew++)
 | 
						|
        {
 | 
						|
            yOld = yNew * cyImgSize / cyNewSize;
 | 
						|
            for (xNew = 0; xNew < cxNewSize; xNew++)
 | 
						|
            {
 | 
						|
                xOld = xNew * cxImgSize / cxNewSize;
 | 
						|
 | 
						|
                r = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 0);
 | 
						|
                g = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 1);
 | 
						|
                b = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 2);
 | 
						|
                *pImg++ = r;
 | 
						|
                *pImg++ = g;
 | 
						|
                *pImg++ = b;
 | 
						|
                if (cImgChannels == 4)
 | 
						|
                {
 | 
						|
                    a = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld)
 | 
						|
                        + 3);
 | 
						|
                    *pImg++ = a;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        /* calculate row-bytes */
 | 
						|
 | 
						|
        wImgRowBytes = cImgChannels * cxNewSize;
 | 
						|
        wDIRowBytes = (WORD) ((cDIChannels * cxWinSize + 3L) >> 2) << 2;
 | 
						|
 | 
						|
        /* copy image to screen */
 | 
						|
 | 
						|
        for (yImg = 0, yWin = cyImgPos; yImg < cyNewSize; yImg++, yWin++)
 | 
						|
        {
 | 
						|
            if (yWin >= cyWinSize - cyImgPos)
 | 
						|
                break;
 | 
						|
            src = pStretchedImage + yImg * wImgRowBytes;
 | 
						|
            dst = pDiData + yWin * wDIRowBytes + cxImgPos * cDIChannels;
 | 
						|
 | 
						|
            for (xImg = 0, xWin = cxImgPos; xImg < cxNewSize; xImg++, xWin++)
 | 
						|
            {
 | 
						|
                if (xWin >= cxWinSize - cxImgPos)
 | 
						|
                    break;
 | 
						|
                r = *src++;
 | 
						|
                g = *src++;
 | 
						|
                b = *src++;
 | 
						|
                *dst++ = b; /* note the reverse order  */
 | 
						|
                *dst++ = g;
 | 
						|
                *dst++ = r;
 | 
						|
                if (cImgChannels == 4)
 | 
						|
                {
 | 
						|
                    a = *src++;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        /* free memory */
 | 
						|
 | 
						|
        if (pStretchedImage != NULL)
 | 
						|
        {
 | 
						|
            free (pStretchedImage);
 | 
						|
            pStretchedImage = NULL;
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    /* process the image not-stretched */
 | 
						|
 | 
						|
    else
 | 
						|
    {
 | 
						|
        /* calculate the central position */
 | 
						|
 | 
						|
        cxImgPos = (cxWinSize - cxImgSize) / 2;
 | 
						|
        cyImgPos = (cyWinSize - cyImgSize) / 2;
 | 
						|
 | 
						|
        /* check for image larger than window */
 | 
						|
 | 
						|
        if (cxImgPos < MARGIN)
 | 
						|
            cxImgPos = MARGIN;
 | 
						|
        if (cyImgPos < MARGIN)
 | 
						|
            cyImgPos = MARGIN;
 | 
						|
 | 
						|
        /* calculate both row-bytes */
 | 
						|
 | 
						|
        wImgRowBytes = cImgChannels * cxImgSize;
 | 
						|
        wDIRowBytes = (WORD) ((cDIChannels * cxWinSize + 3L) >> 2) << 2;
 | 
						|
 | 
						|
        /* copy image to screen */
 | 
						|
 | 
						|
        for (yImg = 0, yWin = cyImgPos; yImg < cyImgSize; yImg++, yWin++)
 | 
						|
        {
 | 
						|
            if (yWin >= cyWinSize - MARGIN)
 | 
						|
                break;
 | 
						|
            src = pbImage + yImg * wImgRowBytes;
 | 
						|
            dst = pDiData + yWin * wDIRowBytes + cxImgPos * cDIChannels;
 | 
						|
 | 
						|
            for (xImg = 0, xWin = cxImgPos; xImg < cxImgSize; xImg++, xWin++)
 | 
						|
            {
 | 
						|
                if (xWin >= cxWinSize - MARGIN)
 | 
						|
                    break;
 | 
						|
                r = *src++;
 | 
						|
                g = *src++;
 | 
						|
                b = *src++;
 | 
						|
                *dst++ = b; /* note the reverse order  */
 | 
						|
                *dst++ = g;
 | 
						|
                *dst++ = r;
 | 
						|
                if (cImgChannels == 4)
 | 
						|
                {
 | 
						|
                    a = *src++;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/*-----------------
 | 
						|
 *  end of source
 | 
						|
 *-----------------
 | 
						|
 */
 |