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