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