all repos — mgba @ 9de8f084ba55460b02d300c1dd8b8e6c56f691d5

mGBA Game Boy Advance Emulator

src/third-party/libpng/contrib/visupng/VisualPng.c (view raw)

  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
 42LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
 43BOOL    CALLBACK AboutDlgProc (HWND, UINT, WPARAM, LPARAM) ;
 44
 45BOOL CenterAbout (HWND hwndChild, HWND hwndParent);
 46
 47BOOL BuildPngList (PTSTR pstrPathName, TCHAR **ppFileList, int *pFileCount,
 48        int *pFileIndex);
 49
 50BOOL SearchPngList (TCHAR *pFileList, int FileCount, int *pFileIndex,
 51        PTSTR pstrPrevName, PTSTR pstrNextName);
 52
 53BOOL LoadImageFile(HWND hwnd, PTSTR pstrPathName,
 54        png_byte **ppbImage, int *pxImgSize, int *pyImgSize, int *piChannels,
 55        png_color *pBkgColor);
 56
 57BOOL 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
 62BOOL InitBitmap (
 63        BYTE *pDiData, int cxWinSize, int cyWinSize);
 64
 65BOOL 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
 72static char *szProgName = PROGNAME;
 73static char *szAppName = LONGNAME;
 74static char *szIconName = PROGNAME;
 75static char szCmdFileName [MAX_PATH];
 76
 77/* MAIN routine */
 78
 79int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
 80                    PSTR szCmdLine, int iCmdShow)
 81{
 82    HACCEL   hAccel;
 83    HWND     hwnd;
 84    MSG      msg;
 85    WNDCLASS wndclass;
 86    int ixBorders, iyBorders;
 87
 88    wndclass.style         = CS_HREDRAW | CS_VREDRAW;
 89    wndclass.lpfnWndProc   = WndProc;
 90    wndclass.cbClsExtra    = 0;
 91    wndclass.cbWndExtra    = 0;
 92    wndclass.hInstance     = hInstance;
 93    wndclass.hIcon         = LoadIcon (hInstance, szIconName) ;
 94    wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);
 95    wndclass.hbrBackground = NULL; /* (HBRUSH) GetStockObject (GRAY_BRUSH); */
 96    wndclass.lpszMenuName  = szProgName;
 97    wndclass.lpszClassName = szProgName;
 98
 99    if (!RegisterClass (&wndclass))
100    {
101        MessageBox (NULL, TEXT ("Error: this program requires Windows NT!"),
102            szProgName, MB_ICONERROR);
103        return 0;
104    }
105
106    /* if filename given on commandline, store it */
107    if ((szCmdLine != NULL) && (*szCmdLine != '\0'))
108        if (szCmdLine[0] == '"')
109            strncpy (szCmdFileName, szCmdLine + 1, strlen(szCmdLine) - 2);
110        else
111            strcpy (szCmdFileName, szCmdLine);
112    else
113        strcpy (szCmdFileName, "");
114
115    /* calculate size of window-borders */
116    ixBorders = 2 * (GetSystemMetrics (SM_CXBORDER) +
117                     GetSystemMetrics (SM_CXDLGFRAME));
118    iyBorders = 2 * (GetSystemMetrics (SM_CYBORDER) +
119                     GetSystemMetrics (SM_CYDLGFRAME)) +
120                     GetSystemMetrics (SM_CYCAPTION) +
121                     GetSystemMetrics (SM_CYMENUSIZE) +
122                     1; /* WvS: don't ask me why?  */
123
124    hwnd = CreateWindow (szProgName, szAppName,
125        WS_OVERLAPPEDWINDOW,
126        CW_USEDEFAULT, CW_USEDEFAULT,
127        512 + 2 * MARGIN + ixBorders, 384 + 2 * MARGIN + iyBorders,
128/*      CW_USEDEFAULT, CW_USEDEFAULT, */
129        NULL, NULL, hInstance, NULL);
130
131    ShowWindow (hwnd, iCmdShow);
132    UpdateWindow (hwnd);
133
134    hAccel = LoadAccelerators (hInstance, szProgName);
135
136    while (GetMessage (&msg, NULL, 0, 0))
137    {
138        if (!TranslateAccelerator (hwnd, hAccel, &msg))
139        {
140            TranslateMessage (&msg);
141            DispatchMessage (&msg);
142        }
143    }
144    return msg.wParam;
145}
146
147LRESULT 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
431BOOL 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 */
459BOOL 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 */
513BOOL 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
618BOOL 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
661BOOL 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 */
705BOOL DisplayImage (HWND hwnd, BYTE **ppDib,
706        BYTE **ppDiData, int cxWinSize, int cyWinSize,
707        BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels,
708        BOOL bStretched)
709{
710    BYTE                       *pDib = *ppDib;
711    BYTE                       *pDiData = *ppDiData;
712    /* BITMAPFILEHEADER        *pbmfh; */
713    BITMAPINFOHEADER           *pbmih;
714    WORD                        wDIRowBytes;
715    png_color                   bkgBlack = {0, 0, 0};
716    png_color                   bkgGray  = {127, 127, 127};
717    png_color                   bkgWhite = {255, 255, 255};
718
719    /* allocate memory for the Device Independant bitmap */
720
721    wDIRowBytes = (WORD) ((3 * cxWinSize + 3L) >> 2) << 2;
722
723    if (pDib)
724    {
725        free (pDib);
726        pDib = NULL;
727    }
728
729    if (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 */
777BOOL 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 */
811BOOL 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 */