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 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 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 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 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 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 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 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 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 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 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