| /*------------------------------------ | |
| * 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> | |
| #include <zlib.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 mathematically 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 | |
| *----------------- | |
| */ |