1 /*------------------------------------
2 * VisualPng.C -- Shows a PNG image
3 *------------------------------------
5 * Copyright 2000,2017 Willem van Schaik.
7 * This code is released under the libpng license.
8 * For conditions of distribution and use, see the disclaimer
16 #define PROGNAME "VisualPng"
17 #define LONGNAME "Win32 Viewer for PNG-files"
18 #define VERSION "1.0 of 2000 June 07"
24 /* standard includes */
32 /* application includes */
40 /* function prototypes */
42 LRESULT CALLBACK
WndProc (HWND
, UINT
, WPARAM
, LPARAM
);
43 BOOL CALLBACK
AboutDlgProc (HWND
, UINT
, WPARAM
, LPARAM
) ;
45 BOOL
CenterAbout (HWND hwndChild
, HWND hwndParent
);
47 BOOL
BuildPngList (PTSTR pstrPathName
, TCHAR
**ppFileList
, int *pFileCount
,
50 BOOL
SearchPngList (TCHAR
*pFileList
, int FileCount
, int *pFileIndex
,
51 PTSTR pstrPrevName
, PTSTR pstrNextName
);
53 BOOL
LoadImageFile(HWND hwnd
, PTSTR pstrPathName
,
54 png_byte
**ppbImage
, int *pxImgSize
, int *pyImgSize
, int *piChannels
,
55 png_color
*pBkgColor
);
57 BOOL
DisplayImage (HWND hwnd
, BYTE
**ppDib
,
58 BYTE
**ppDiData
, int cxWinSize
, int cyWinSize
,
59 BYTE
*pbImage
, int cxImgSize
, int cyImgSize
, int cImgChannels
,
63 BYTE
*pDiData
, int cxWinSize
, int cyWinSize
);
66 BYTE
*pDiData
, int cxWinSize
, int cyWinSize
,
67 BYTE
*pbImage
, int cxImgSize
, int cyImgSize
, int cImgChannels
,
70 /* a few global variables */
72 static char *szProgName
= PROGNAME
;
73 static char *szAppName
= LONGNAME
;
74 static char *szIconName
= PROGNAME
;
75 static char szCmdFileName
[MAX_PATH
];
79 int WINAPI
WinMain (HINSTANCE hInstance
, HINSTANCE hPrevInstance
,
80 PSTR szCmdLine
, int iCmdShow
)
86 int ixBorders
, iyBorders
;
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
;
99 if (!RegisterClass (&wndclass
))
101 MessageBox (NULL
, TEXT ("Error: this program requires Windows NT!"),
102 szProgName
, MB_ICONERROR
);
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);
111 strcpy (szCmdFileName
, szCmdLine
);
113 strcpy (szCmdFileName
, "");
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? */
124 hwnd
= CreateWindow (szProgName
, szAppName
,
126 CW_USEDEFAULT
, CW_USEDEFAULT
,
127 512 + 2 * MARGIN
+ ixBorders
, 384 + 2 * MARGIN
+ iyBorders
,
128 /* CW_USEDEFAULT, CW_USEDEFAULT, */
129 NULL
, NULL
, hInstance
, NULL
);
131 ShowWindow (hwnd
, iCmdShow
);
134 hAccel
= LoadAccelerators (hInstance
, szProgName
);
136 while (GetMessage (&msg
, NULL
, 0, 0))
138 if (!TranslateAccelerator (hwnd
, hAccel
, &msg
))
140 TranslateMessage (&msg
);
141 DispatchMessage (&msg
);
147 LRESULT CALLBACK
WndProc (HWND hwnd
, UINT message
, WPARAM wParam
,
150 static HINSTANCE hInstance
;
152 static PAINTSTRUCT ps
;
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};
163 static BOOL bStretched
= TRUE
;
165 static BYTE
*pDib
= NULL
;
166 static BYTE
*pDiData
= NULL
;
168 static TCHAR szImgPathName
[MAX_PATH
];
169 static TCHAR szTitleName
[MAX_PATH
];
171 static TCHAR
*pPngFileList
= NULL
;
172 static int iPngFileCount
;
173 static int iPngFileIndex
;
180 hInstance
= ((LPCREATESTRUCT
) lParam
)->hInstance
;
181 PngFileInitialize (hwnd
);
183 strcpy (szImgPathName
, "");
185 /* in case we process file given on command-line */
187 if (szCmdFileName
[0] != '\0')
189 strcpy (szImgPathName
, szCmdFileName
);
191 /* read the other png-files in the directory for later */
192 /* next/previous commands */
194 BuildPngList (szImgPathName
, &pPngFileList
, &iPngFileCount
,
197 /* load the image from file */
199 if (!LoadImageFile (hwnd
, szImgPathName
,
200 &pbImage
, &cxImgSize
, &cyImgSize
, &cImgChannels
, &bkgColor
))
203 /* invalidate the client area for later update */
205 InvalidateRect (hwnd
, NULL
, TRUE
);
207 /* display the PNG into the DIBitmap */
209 DisplayImage (hwnd
, &pDib
, &pDiData
, cxWinSize
, cyWinSize
,
210 pbImage
, cxImgSize
, cyImgSize
, cImgChannels
, bStretched
);
216 cxWinSize
= LOWORD (lParam
);
217 cyWinSize
= HIWORD (lParam
);
219 /* invalidate the client area for later update */
221 InvalidateRect (hwnd
, NULL
, TRUE
);
223 /* display the PNG into the DIBitmap */
225 DisplayImage (hwnd
, &pDib
, &pDiData
, cxWinSize
, cyWinSize
,
226 pbImage
, cxImgSize
, cyImgSize
, cImgChannels
, bStretched
);
230 case WM_INITMENUPOPUP
:
231 hMenu
= GetMenu (hwnd
);
234 EnableMenuItem (hMenu
, IDM_FILE_SAVE
, MF_ENABLED
);
236 EnableMenuItem (hMenu
, IDM_FILE_SAVE
, MF_GRAYED
);
241 hMenu
= GetMenu (hwnd
);
243 switch (LOWORD (wParam
))
247 /* show the File Open dialog box */
249 if (!PngFileOpenDlg (hwnd
, szImgPathName
, szTitleName
))
252 /* read the other png-files in the directory for later */
253 /* next/previous commands */
255 BuildPngList (szImgPathName
, &pPngFileList
, &iPngFileCount
,
258 /* load the image from file */
260 if (!LoadImageFile (hwnd
, szImgPathName
,
261 &pbImage
, &cxImgSize
, &cyImgSize
, &cImgChannels
, &bkgColor
))
264 /* invalidate the client area for later update */
266 InvalidateRect (hwnd
, NULL
, TRUE
);
268 /* display the PNG into the DIBitmap */
270 DisplayImage (hwnd
, &pDib
, &pDiData
, cxWinSize
, cyWinSize
,
271 pbImage
, cxImgSize
, cyImgSize
, cImgChannels
, bStretched
);
277 /* show the File Save dialog box */
279 if (!PngFileSaveDlg (hwnd
, szImgPathName
, szTitleName
))
282 /* save the PNG to a disk file */
284 SetCursor (LoadCursor (NULL
, IDC_WAIT
));
287 bOk
= PngSaveImage (szImgPathName
, pDiData
, cxWinSize
, cyWinSize
,
291 SetCursor (LoadCursor (NULL
, IDC_ARROW
));
294 MessageBox (hwnd
, TEXT ("Error in saving the PNG image"),
295 szProgName
, MB_ICONEXCLAMATION
| MB_OK
);
300 /* read next entry in the directory */
302 if (SearchPngList (pPngFileList
, iPngFileCount
, &iPngFileIndex
,
303 NULL
, szImgPathName
))
305 if (strcmp (szImgPathName
, "") == 0)
308 /* load the image from file */
310 if (!LoadImageFile (hwnd
, szImgPathName
, &pbImage
,
311 &cxImgSize
, &cyImgSize
, &cImgChannels
, &bkgColor
))
314 /* invalidate the client area for later update */
316 InvalidateRect (hwnd
, NULL
, TRUE
);
318 /* display the PNG into the DIBitmap */
320 DisplayImage (hwnd
, &pDib
, &pDiData
, cxWinSize
, cyWinSize
,
321 pbImage
, cxImgSize
, cyImgSize
, cImgChannels
, bStretched
);
326 case IDM_FILE_PREVIOUS
:
328 /* read previous entry in the directory */
330 if (SearchPngList (pPngFileList
, iPngFileCount
, &iPngFileIndex
,
331 szImgPathName
, NULL
))
334 if (strcmp (szImgPathName
, "") == 0)
337 /* load the image from file */
339 if (!LoadImageFile (hwnd
, szImgPathName
, &pbImage
, &cxImgSize
,
340 &cyImgSize
, &cImgChannels
, &bkgColor
))
343 /* invalidate the client area for later update */
345 InvalidateRect (hwnd
, NULL
, TRUE
);
347 /* display the PNG into the DIBitmap */
349 DisplayImage (hwnd
, &pDib
, &pDiData
, cxWinSize
, cyWinSize
,
350 pbImage
, cxImgSize
, cyImgSize
, cImgChannels
, bStretched
);
357 /* more cleanup needed... */
359 /* free image buffer */
369 if (pPngFileList
!= NULL
)
381 case IDM_OPTIONS_STRETCH
:
382 bStretched
= !bStretched
;
384 CheckMenuItem (hMenu
, IDM_OPTIONS_STRETCH
, MF_CHECKED
);
386 CheckMenuItem (hMenu
, IDM_OPTIONS_STRETCH
, MF_UNCHECKED
);
388 /* invalidate the client area for later update */
390 InvalidateRect (hwnd
, NULL
, TRUE
);
392 /* display the PNG into the DIBitmap */
394 DisplayImage (hwnd
, &pDib
, &pDiData
, cxWinSize
, cyWinSize
,
395 pbImage
, cxImgSize
, cyImgSize
, cImgChannels
, bStretched
);
400 DialogBox (hInstance
, TEXT ("AboutBox"), hwnd
, AboutDlgProc
) ;
408 hdc
= BeginPaint (hwnd
, &ps
);
411 SetDIBitsToDevice (hdc
, 0, 0, cxWinSize
, cyWinSize
, 0, 0,
412 0, cyWinSize
, pDiData
, (BITMAPINFO
*) pDib
, DIB_RGB_COLORS
);
414 EndPaint (hwnd
, &ps
);
428 return DefWindowProc (hwnd
, message
, wParam
, lParam
);
431 BOOL CALLBACK
AboutDlgProc (HWND hDlg
, UINT message
,
432 WPARAM wParam
, LPARAM lParam
)
437 ShowWindow (hDlg
, SW_HIDE
);
438 CenterAbout (hDlg
, GetWindow (hDlg
, GW_OWNER
));
439 ShowWindow (hDlg
, SW_SHOW
);
443 switch (LOWORD (wParam
))
447 EndDialog (hDlg
, 0) ;
459 BOOL
CenterAbout (HWND hwndChild
, HWND hwndParent
)
461 RECT rChild
, rParent
, rWorkArea
;
462 int wChild
, hChild
, wParent
, hParent
;
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
;
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
;
476 /* Get the limits of the 'workarea' */
477 bResult
= SystemParametersInfo(
478 SPI_GETWORKAREA
, /* system parameter to query or set */
483 rWorkArea
.left
= rWorkArea
.top
= 0;
484 rWorkArea
.right
= GetSystemMetrics(SM_CXSCREEN
);
485 rWorkArea
.bottom
= GetSystemMetrics(SM_CYSCREEN
);
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
;
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
;
504 /* Set it, and return */
505 return SetWindowPos (hwndChild
, NULL
, xNew
, yNew
, 0, 0, SWP_NOSIZE
|
513 BOOL
BuildPngList (PTSTR pstrPathName
, TCHAR
**ppFileList
, int *pFileCount
,
516 static TCHAR szImgPathName
[MAX_PATH
];
517 static TCHAR szImgFileName
[MAX_PATH
];
518 static TCHAR szImgFindName
[MAX_PATH
];
520 WIN32_FIND_DATA finddata
;
523 static TCHAR szTmp
[MAX_PATH
];
528 /* free previous file-list */
530 if (*ppFileList
!= NULL
)
536 /* extract foldername, filename and search-name */
538 strcpy (szImgPathName
, pstrPathName
);
539 strcpy (szImgFileName
, strrchr (pstrPathName
, '\\') + 1);
541 strcpy (szImgFindName
, szImgPathName
);
542 *(strrchr (szImgFindName
, '\\') + 1) = '\0';
543 strcat (szImgFindName
, "*.png");
545 /* first cycle: count number of files in directory for memory allocation */
549 hFind
= FindFirstFile(szImgFindName
, &finddata
);
550 bOk
= (hFind
!= (HANDLE
) -1);
555 bOk
= FindNextFile(hFind
, &finddata
);
559 /* allocation memory for file-list */
561 *ppFileList
= (TCHAR
*) malloc (*pFileCount
* MAX_PATH
);
563 /* second cycle: read directory and store filenames in file-list */
565 hFind
= FindFirstFile(szImgFindName
, &finddata
);
566 bOk
= (hFind
!= (HANDLE
) -1);
572 strcpy (*ppFileList
+ ii
, szImgPathName
);
573 strcpy (strrchr(*ppFileList
+ ii
, '\\') + 1, finddata
.cFileName
);
575 if (strcmp(pstrPathName
, *ppFileList
+ ii
) == 0)
581 bOk
= FindNextFile(hFind
, &finddata
);
585 /* finally we must sort the file-list */
587 for (i
= 0; i
< *pFileCount
- 1; i
++)
590 for (j
= i
+1; j
< *pFileCount
; j
++)
593 if (strcmp (*ppFileList
+ ii
, *ppFileList
+ jj
) > 0)
595 strcpy (szTmp
, *ppFileList
+ jj
);
596 strcpy (*ppFileList
+ jj
, *ppFileList
+ ii
);
597 strcpy (*ppFileList
+ ii
, szTmp
);
599 /* check if this was the current image that we moved */
601 if (*pFileIndex
== i
)
604 if (*pFileIndex
== j
)
619 TCHAR
*pFileList
, int FileCount
, int *pFileIndex
,
620 PTSTR pstrPrevName
, PTSTR pstrNextName
)
624 /* get previous entry */
626 if (pstrPrevName
!= NULL
)
631 *pFileIndex
= FileCount
- 1;
633 strcpy (pstrPrevName
, pFileList
+ (*pFileIndex
* MAX_PATH
));
638 if (pstrNextName
!= NULL
)
640 if (*pFileIndex
< FileCount
- 1)
645 strcpy (pstrNextName
, pFileList
+ (*pFileIndex
* MAX_PATH
));
661 BOOL
LoadImageFile (HWND hwnd
, PTSTR pstrPathName
,
662 png_byte
**ppbImage
, int *pxImgSize
, int *pyImgSize
,
663 int *piChannels
, png_color
*pBkgColor
)
665 static TCHAR szTmp
[MAX_PATH
];
667 /* if there's an existing PNG, free the memory */
675 /* Load the entire PNG into memory */
677 SetCursor (LoadCursor (NULL
, IDC_WAIT
));
680 PngLoadImage (pstrPathName
, ppbImage
, pxImgSize
, pyImgSize
, piChannels
,
684 SetCursor (LoadCursor (NULL
, IDC_ARROW
));
686 if (*ppbImage
!= NULL
)
688 sprintf (szTmp
, "VisualPng - %s", strrchr(pstrPathName
, '\\') + 1);
689 SetWindowText (hwnd
, szTmp
);
693 MessageBox (hwnd
, TEXT ("Error in loading the PNG image"),
694 szProgName
, MB_ICONEXCLAMATION
| MB_OK
);
705 BOOL
DisplayImage (HWND hwnd
, BYTE
**ppDib
,
706 BYTE
**ppDiData
, int cxWinSize
, int cyWinSize
,
707 BYTE
*pbImage
, int cxImgSize
, int cyImgSize
, int cImgChannels
,
711 BYTE
*pDiData
= *ppDiData
;
712 /* BITMAPFILEHEADER *pbmfh; */
713 BITMAPINFOHEADER
*pbmih
;
715 png_color bkgBlack
= {0, 0, 0};
716 png_color bkgGray
= {127, 127, 127};
717 png_color bkgWhite
= {255, 255, 255};
719 /* allocate memory for the Device Independent bitmap */
721 wDIRowBytes
= (WORD
) ((3 * cxWinSize
+ 3L) >> 2) << 2;
729 if (cyWinSize
> ((size_t)(-1))/wDIRowBytes
) {
731 MessageBox (hwnd
, TEXT ("Visual PNG: image is too big");
733 if (!(pDib
= (BYTE
*) malloc (sizeof(BITMAPINFOHEADER
) +
734 wDIRowBytes
* cyWinSize
)))
736 MessageBox (hwnd
, TEXT ("Error in displaying the PNG image"),
737 szProgName
, MB_ICONEXCLAMATION
| MB_OK
);
738 *ppDib
= pDib
= NULL
;
742 memset (pDib
, 0, sizeof(BITMAPINFOHEADER
));
744 /* initialize the dib-structure */
746 pbmih
= (BITMAPINFOHEADER
*) pDib
;
747 pbmih
->biSize
= sizeof(BITMAPINFOHEADER
);
748 pbmih
->biWidth
= cxWinSize
;
749 pbmih
->biHeight
= -((long) cyWinSize
);
751 pbmih
->biBitCount
= 24;
752 pbmih
->biCompression
= 0;
753 pDiData
= pDib
+ sizeof(BITMAPINFOHEADER
);
756 /* first fill bitmap with gray and image border */
758 InitBitmap (pDiData
, cxWinSize
, cyWinSize
);
760 /* then fill bitmap with image */
765 pDiData
, cxWinSize
, cyWinSize
,
766 pbImage
, cxImgSize
, cyImgSize
, cImgChannels
,
777 BOOL
InitBitmap (BYTE
*pDiData
, int cxWinSize
, int cyWinSize
)
782 /* initialize the background with gray */
785 for (y
= 0; y
< cyWinSize
; y
++)
788 for (x
= 0; x
< cxWinSize
; x
++)
796 /* rows start on 4 byte boundaries */
797 while ((col
% 4) != 0)
812 BYTE
*pDiData
, int cxWinSize
, int cyWinSize
,
813 BYTE
*pbImage
, int cxImgSize
, int cyImgSize
, int cImgChannels
,
816 BYTE
*pStretchedImage
;
820 const int cDIChannels
= 3;
823 int cxNewSize
, cyNewSize
;
824 int cxImgPos
, cyImgPos
;
832 cxNewSize
= cxWinSize
- 2 * MARGIN
;
833 cyNewSize
= cyWinSize
- 2 * MARGIN
;
835 /* stretch the image to it's window determined size */
837 /* the following two are mathematically the same, but the first
838 * has side-effects because of rounding
840 /* if ((cyNewSize / cxNewSize) > (cyImgSize / cxImgSize)) */
841 if ((cyNewSize
* cxImgSize
) > (cyImgSize
* cxNewSize
))
843 cyNewSize
= cxNewSize
* cyImgSize
/ cxImgSize
;
845 cyImgPos
= (cyWinSize
- cyNewSize
) / 2;
849 cxNewSize
= cyNewSize
* cxImgSize
/ cyImgSize
;
851 cxImgPos
= (cxWinSize
- cxNewSize
) / 2;
854 if (cyNewSize
> ((size_t)(-1))/(cImgChannels
* cxNewSize
)) {
856 MessageBox (hwnd
, TEXT ("Visual PNG: stretched image is too big");
858 pStretchedImage
= malloc (cImgChannels
* cxNewSize
* cyNewSize
);
859 pImg
= pStretchedImage
;
861 for (yNew
= 0; yNew
< cyNewSize
; yNew
++)
863 yOld
= yNew
* cyImgSize
/ cyNewSize
;
864 for (xNew
= 0; xNew
< cxNewSize
; xNew
++)
866 xOld
= xNew
* cxImgSize
/ cxNewSize
;
868 r
= *(pbImage
+ cImgChannels
* ((yOld
* cxImgSize
) + xOld
) + 0);
869 g
= *(pbImage
+ cImgChannels
* ((yOld
* cxImgSize
) + xOld
) + 1);
870 b
= *(pbImage
+ cImgChannels
* ((yOld
* cxImgSize
) + xOld
) + 2);
874 if (cImgChannels
== 4)
876 a
= *(pbImage
+ cImgChannels
* ((yOld
* cxImgSize
) + xOld
)
883 /* calculate row-bytes */
885 wImgRowBytes
= cImgChannels
* cxNewSize
;
886 wDIRowBytes
= (WORD
) ((cDIChannels
* cxWinSize
+ 3L) >> 2) << 2;
888 /* copy image to screen */
890 for (yImg
= 0, yWin
= cyImgPos
; yImg
< cyNewSize
; yImg
++, yWin
++)
892 if (yWin
>= cyWinSize
- cyImgPos
)
894 src
= pStretchedImage
+ yImg
* wImgRowBytes
;
895 dst
= pDiData
+ yWin
* wDIRowBytes
+ cxImgPos
* cDIChannels
;
897 for (xImg
= 0, xWin
= cxImgPos
; xImg
< cxNewSize
; xImg
++, xWin
++)
899 if (xWin
>= cxWinSize
- cxImgPos
)
904 *dst
++ = b
; /* note the reverse order */
907 if (cImgChannels
== 4)
916 if (pStretchedImage
!= NULL
)
918 free (pStretchedImage
);
919 pStretchedImage
= NULL
;
924 /* process the image not-stretched */
928 /* calculate the central position */
930 cxImgPos
= (cxWinSize
- cxImgSize
) / 2;
931 cyImgPos
= (cyWinSize
- cyImgSize
) / 2;
933 /* check for image larger than window */
935 if (cxImgPos
< MARGIN
)
937 if (cyImgPos
< MARGIN
)
940 /* calculate both row-bytes */
942 wImgRowBytes
= cImgChannels
* cxImgSize
;
943 wDIRowBytes
= (WORD
) ((cDIChannels
* cxWinSize
+ 3L) >> 2) << 2;
945 /* copy image to screen */
947 for (yImg
= 0, yWin
= cyImgPos
; yImg
< cyImgSize
; yImg
++, yWin
++)
949 if (yWin
>= cyWinSize
- MARGIN
)
951 src
= pbImage
+ yImg
* wImgRowBytes
;
952 dst
= pDiData
+ yWin
* wDIRowBytes
+ cxImgPos
* cDIChannels
;
954 for (xImg
= 0, xWin
= cxImgPos
; xImg
< cxImgSize
; xImg
++, xWin
++)
956 if (xWin
>= cxWinSize
- MARGIN
)
961 *dst
++ = b
; /* note the reverse order */
964 if (cImgChannels
== 4)