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 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 42 LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); 43 BOOL CALLBACK AboutDlgProc (HWND, UINT, WPARAM, LPARAM) ; 44 45 BOOL CenterAbout (HWND hwndChild, HWND hwndParent); 46 47 BOOL BuildPngList (PTSTR pstrPathName, TCHAR **ppFileList, int *pFileCount, 48 int *pFileIndex); 49 50 BOOL SearchPngList (TCHAR *pFileList, int FileCount, int *pFileIndex, 51 PTSTR pstrPrevName, PTSTR pstrNextName); 52 53 BOOL LoadImageFile(HWND hwnd, PTSTR pstrPathName, 54 png_byte **ppbImage, int *pxImgSize, int *pyImgSize, int *piChannels, 55 png_color *pBkgColor); 56 57 BOOL 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 62 BOOL InitBitmap ( 63 BYTE *pDiData, int cxWinSize, int cyWinSize); 64 65 BOOL 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 72 static char *szProgName = PROGNAME; 73 static char *szAppName = LONGNAME; 74 static char *szIconName = PROGNAME; 75 static char szCmdFileName [MAX_PATH]; 76 77 /* MAIN routine */ 78 79 int 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 147 LRESULT 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 431 BOOL 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 */ 459 BOOL 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 */ 513 BOOL 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 618 BOOL 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 661 BOOL 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 */ 705 BOOL 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 (!(pDib = (BYTE *) malloc (sizeof(BITMAPINFOHEADER) + 730 wDIRowBytes * cyWinSize))) 731 { 732 MessageBox (hwnd, TEXT ("Error in displaying the PNG image"), 733 szProgName, MB_ICONEXCLAMATION | MB_OK); 734 *ppDib = pDib = NULL; 735 return FALSE; 736 } 737 *ppDib = pDib; 738 memset (pDib, 0, sizeof(BITMAPINFOHEADER)); 739 740 /* initialize the dib-structure */ 741 742 pbmih = (BITMAPINFOHEADER *) pDib; 743 pbmih->biSize = sizeof(BITMAPINFOHEADER); 744 pbmih->biWidth = cxWinSize; 745 pbmih->biHeight = -((long) cyWinSize); 746 pbmih->biPlanes = 1; 747 pbmih->biBitCount = 24; 748 pbmih->biCompression = 0; 749 pDiData = pDib + sizeof(BITMAPINFOHEADER); 750 *ppDiData = pDiData; 751 752 /* first fill bitmap with gray and image border */ 753 754 InitBitmap (pDiData, cxWinSize, cyWinSize); 755 756 /* then fill bitmap with image */ 757 758 if (pbImage) 759 { 760 FillBitmap ( 761 pDiData, cxWinSize, cyWinSize, 762 pbImage, cxImgSize, cyImgSize, cImgChannels, 763 bStretched); 764 } 765 766 return TRUE; 767 } 768 769 /*-------------- 770 * InitBitmap 771 *-------------- 772 */ 773 BOOL InitBitmap (BYTE *pDiData, int cxWinSize, int cyWinSize) 774 { 775 BYTE *dst; 776 int x, y, col; 777 778 /* initialize the background with gray */ 779 780 dst = pDiData; 781 for (y = 0; y < cyWinSize; y++) 782 { 783 col = 0; 784 for (x = 0; x < cxWinSize; x++) 785 { 786 /* fill with GRAY */ 787 *dst++ = 127; 788 *dst++ = 127; 789 *dst++ = 127; 790 col += 3; 791 } 792 /* rows start on 4 byte boundaries */ 793 while ((col % 4) != 0) 794 { 795 dst++; 796 col++; 797 } 798 } 799 800 return TRUE; 801 } 802 803 /*-------------- 804 * FillBitmap 805 *-------------- 806 */ 807 BOOL FillBitmap ( 808 BYTE *pDiData, int cxWinSize, int cyWinSize, 809 BYTE *pbImage, int cxImgSize, int cyImgSize, int cImgChannels, 810 BOOL bStretched) 811 { 812 BYTE *pStretchedImage; 813 BYTE *pImg; 814 BYTE *src, *dst; 815 BYTE r, g, b, a; 816 const int cDIChannels = 3; 817 WORD wImgRowBytes; 818 WORD wDIRowBytes; 819 int cxNewSize, cyNewSize; 820 int cxImgPos, cyImgPos; 821 int xImg, yImg; 822 int xWin, yWin; 823 int xOld, yOld; 824 int xNew, yNew; 825 826 if (bStretched) 827 { 828 cxNewSize = cxWinSize - 2 * MARGIN; 829 cyNewSize = cyWinSize - 2 * MARGIN; 830 831 /* stretch the image to it's window determined size */ 832 833 /* the following two are mathematically the same, but the first 834 * has side-effects because of rounding 835 */ 836 /* if ((cyNewSize / cxNewSize) > (cyImgSize / cxImgSize)) */ 837 if ((cyNewSize * cxImgSize) > (cyImgSize * cxNewSize)) 838 { 839 cyNewSize = cxNewSize * cyImgSize / cxImgSize; 840 cxImgPos = MARGIN; 841 cyImgPos = (cyWinSize - cyNewSize) / 2; 842 } 843 else 844 { 845 cxNewSize = cyNewSize * cxImgSize / cyImgSize; 846 cyImgPos = MARGIN; 847 cxImgPos = (cxWinSize - cxNewSize) / 2; 848 } 849 850 pStretchedImage = malloc (cImgChannels * cxNewSize * cyNewSize); 851 pImg = pStretchedImage; 852 853 for (yNew = 0; yNew < cyNewSize; yNew++) 854 { 855 yOld = yNew * cyImgSize / cyNewSize; 856 for (xNew = 0; xNew < cxNewSize; xNew++) 857 { 858 xOld = xNew * cxImgSize / cxNewSize; 859 860 r = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 0); 861 g = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 1); 862 b = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) + 2); 863 *pImg++ = r; 864 *pImg++ = g; 865 *pImg++ = b; 866 if (cImgChannels == 4) 867 { 868 a = *(pbImage + cImgChannels * ((yOld * cxImgSize) + xOld) 869 + 3); 870 *pImg++ = a; 871 } 872 } 873 } 874 875 /* calculate row-bytes */ 876 877 wImgRowBytes = cImgChannels * cxNewSize; 878 wDIRowBytes = (WORD) ((cDIChannels * cxWinSize + 3L) >> 2) << 2; 879 880 /* copy image to screen */ 881 882 for (yImg = 0, yWin = cyImgPos; yImg < cyNewSize; yImg++, yWin++) 883 { 884 if (yWin >= cyWinSize - cyImgPos) 885 break; 886 src = pStretchedImage + yImg * wImgRowBytes; 887 dst = pDiData + yWin * wDIRowBytes + cxImgPos * cDIChannels; 888 889 for (xImg = 0, xWin = cxImgPos; xImg < cxNewSize; xImg++, xWin++) 890 { 891 if (xWin >= cxWinSize - cxImgPos) 892 break; 893 r = *src++; 894 g = *src++; 895 b = *src++; 896 *dst++ = b; /* note the reverse order */ 897 *dst++ = g; 898 *dst++ = r; 899 if (cImgChannels == 4) 900 { 901 a = *src++; 902 } 903 } 904 } 905 906 /* free memory */ 907 908 if (pStretchedImage != NULL) 909 { 910 free (pStretchedImage); 911 pStretchedImage = NULL; 912 } 913 914 } 915 916 /* process the image not-stretched */ 917 918 else 919 { 920 /* calculate the central position */ 921 922 cxImgPos = (cxWinSize - cxImgSize) / 2; 923 cyImgPos = (cyWinSize - cyImgSize) / 2; 924 925 /* check for image larger than window */ 926 927 if (cxImgPos < MARGIN) 928 cxImgPos = MARGIN; 929 if (cyImgPos < MARGIN) 930 cyImgPos = MARGIN; 931 932 /* calculate both row-bytes */ 933 934 wImgRowBytes = cImgChannels * cxImgSize; 935 wDIRowBytes = (WORD) ((cDIChannels * cxWinSize + 3L) >> 2) << 2; 936 937 /* copy image to screen */ 938 939 for (yImg = 0, yWin = cyImgPos; yImg < cyImgSize; yImg++, yWin++) 940 { 941 if (yWin >= cyWinSize - MARGIN) 942 break; 943 src = pbImage + yImg * wImgRowBytes; 944 dst = pDiData + yWin * wDIRowBytes + cxImgPos * cDIChannels; 945 946 for (xImg = 0, xWin = cxImgPos; xImg < cxImgSize; xImg++, xWin++) 947 { 948 if (xWin >= cxWinSize - MARGIN) 949 break; 950 r = *src++; 951 g = *src++; 952 b = *src++; 953 *dst++ = b; /* note the reverse order */ 954 *dst++ = g; 955 *dst++ = r; 956 if (cImgChannels == 4) 957 { 958 a = *src++; 959 } 960 } 961 } 962 } 963 964 return TRUE; 965 } 966 967 /*----------------- 968 * end of source 969 *----------------- 970 */ 971