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