pvbitmap.cpp
1 /******************************************************************************* 2 * pvbitmap.cpp 3 * 4 * Provides an API for bitmap manipulation. 5 * 6 * This file is derived from Microsoft sample source and is used by permission. 7 * 8 * --------------------------------------------------------------------------- 9 * Persistence of Vision Ray Tracer ('POV-Ray') version 3.7. 10 * Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd. 11 * 12 * POV-Ray is free software: you can redistribute it and/or modify 13 * it under the terms of the GNU Affero General Public License as 14 * published by the Free Software Foundation, either version 3 of the 15 * License, or (at your option) any later version. 16 * 17 * POV-Ray is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU Affero General Public License for more details. 21 * 22 * You should have received a copy of the GNU Affero General Public License 23 * along with this program. If not, see <http://www.gnu.org/licenses/>. 24 * --------------------------------------------------------------------------- 25 * POV-Ray is based on the popular DKB raytracer version 2.12. 26 * DKBTrace was originally written by David K. Buck. 27 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins. 28 * --------------------------------------------------------------------------- 29 * $File: //depot/public/povray/3.x/windows/pvbitmap.cpp $ 30 * $Revision: #1 $ 31 * $Change: 6069 $ 32 * $DateTime: 2013/11/06 11:59:40 $ 33 * $Author: chrisc $ 34 *******************************************************************************/ 35 36 #define POVWIN_FILE 37 #define _WIN32_IE COMMONCTRL_VERSION 38 39 #include <windows.h> 40 #include <string.h> 41 #include "pvengine.h" 42 #include "pvbitmap.h" 43 #include "pvdisplay.h" 44 45 // this must be the last file included 46 #include "syspovdebug.h" 47 48 #define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B') 49 50 /********************************************************************* 51 * 52 * Local Function Prototypes 53 * 54 *********************************************************************/ 55 56 namespace povwin 57 { 58 59 HANDLE ReadDIBFile(int); 60 bool MyRead(int, LPSTR, DWORD); 61 bool SaveDIBFile(void); 62 bool WriteDIB(LPSTR, HANDLE); 63 DWORD PASCAL MyWrite(int, VOID *, DWORD); 64 65 extern int render_bitmap_depth ; 66 extern HPALETTE hPalBitmap ; 67 68 /************************************************************************* 69 * 70 * CreateDIB() 71 * 72 * Parameters: 73 * 74 * DWORD dwWidth - Width for new bitmap, in pixels 75 * DWORD dwHeight - Height for new bitmap 76 * WORD wBitCount - Bit Count for new DIB (1, 4, 8, or 24) 77 * 78 * Return Value: 79 * 80 * HDIB - Handle to new DIB 81 * 82 * Description: 83 * 84 * This function allocates memory for and initializes a new DIB by 85 * filling in the BITMAPINFOHEADER, allocating memory for the color 86 * table, and allocating memory for the bitmap bits. As with all 87 * HDIBs, the header, colortable and bits are all in one contiguous 88 * memory block. This function is similar to the CreateBitmap() 89 * Windows API. 90 * 91 * The colortable and bitmap bits are left uninitialized (zeroed) in the 92 * returned HDIB. 93 * 94 * 95 * History: Date Author Reason 96 * 3/20/92 Mark Bader Created 97 * 98 ************************************************************************/ 99 100 HDIB CreateDIB(DWORD dwWidth, DWORD dwHeight, WORD wBitCount) 101 { 102 BITMAPINFOHEADER bi; // bitmap header 103 LPBITMAPINFOHEADER lpbi; // pointer to BITMAPINFOHEADER 104 DWORD dwLen; // size of memory block 105 HDIB hDIB; 106 DWORD dwBytesPerLine; // Number of bytes per scanline 107 108 109 // Make sure bits per pixel is valid 110 if (wBitCount <= 1) 111 wBitCount = 1; 112 else if (wBitCount <= 4) 113 wBitCount = 4; 114 else if (wBitCount <= 8) 115 wBitCount = 8; 116 else if (wBitCount <= 24) 117 wBitCount = 24; 118 else 119 wBitCount = 4; // set default value to 4 if parameter is bogus 120 121 // initialize BITMAPINFOHEADER 122 bi.biSize = sizeof(BITMAPINFOHEADER); 123 bi.biWidth = dwWidth; // fill in width from parameter 124 bi.biHeight = dwHeight; // fill in height from parameter 125 bi.biPlanes = 1; // must be 1 126 bi.biBitCount = wBitCount; // from parameter 127 bi.biCompression = BI_RGB; 128 bi.biSizeImage = 0; // 0's here mean "default" 129 bi.biXPelsPerMeter = 0; 130 bi.biYPelsPerMeter = 0; 131 bi.biClrUsed = 0; 132 bi.biClrImportant = 0; 133 134 // calculate size of memory block required to store the DIB. This 135 // block should be big enough to hold the BITMAPINFOHEADER, the color 136 // table, and the bits 137 138 dwBytesPerLine = WIDTHBYTES(wBitCount * dwWidth); 139 dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + (dwBytesPerLine * dwHeight); 140 141 // alloc memory block to store our bitmap 142 hDIB = GlobalAlloc(GHND, dwLen); 143 144 // major bummer if we couldn't get memory block 145 if (!hDIB) 146 { 147 return NULL; 148 } 149 150 // lock memory and get pointer to it 151 lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 152 153 // use our bitmap info structure to fill in first part of 154 // our DIB with the BITMAPINFOHEADER 155 *lpbi = bi; 156 157 // Since we don't know what the colortable and bits should contain, 158 // just leave these blank. Unlock the DIB and return the HDIB. 159 160 GlobalUnlock(hDIB); 161 162 /* return handle to the DIB */ 163 return hDIB; 164 } 165 166 167 168 /************************************************************************* 169 * 170 * FindDIBBits() 171 * 172 * Parameter: 173 * 174 * LPSTR lpDIB - pointer to packed-DIB memory block 175 * 176 * Return Value: 177 * 178 * LPSTR - pointer to the DIB bits 179 * 180 * Description: 181 * 182 * This function calculates the address of the DIB's bits and returns a 183 * pointer to the DIB bits. 184 * 185 * History: Date Author Reason 186 * 6/01/91 Garrett McAuliffe Created 187 * 9/15/91 Patrick Schreiber Added header and comments 188 * 189 ************************************************************************/ 190 191 192 LPSTR FindDIBBits(LPSTR lpDIB) 193 { 194 return (lpDIB + *(LPDWORD)lpDIB + PaletteSize(lpDIB)); 195 } 196 197 198 /************************************************************************* 199 * 200 * DIBWidth() 201 * 202 * Parameter: 203 * 204 * LPSTR lpDIB - pointer to packed-DIB memory block 205 * 206 * Return Value: 207 * 208 * DWORD - width of the DIB 209 * 210 * Description: 211 * 212 * This function gets the width of the DIB from the BITMAPINFOHEADER 213 * width field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER 214 * width field if it is an OS/2-style DIB. 215 * 216 * History: Date Author Reason 217 * 6/01/91 Garrett McAuliffe Created 218 * 9/15/91 Patrick Schreiber Added header and comments 219 * 220 ************************************************************************/ 221 222 223 DWORD DIBWidth(LPSTR lpDIB) 224 { 225 LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB 226 LPBITMAPCOREHEADER lpbmc; // pointer to an OS/2-style DIB 227 228 /* point to the header (whether Win 3.0 and OS/2) */ 229 230 lpbmi = (LPBITMAPINFOHEADER)lpDIB; 231 lpbmc = (LPBITMAPCOREHEADER)lpDIB; 232 233 /* return the DIB width if it is a Win 3.0 DIB */ 234 if (lpbmi->biSize == sizeof(BITMAPINFOHEADER)) 235 return lpbmi->biWidth; 236 else /* it is an OS/2 DIB, so return its width */ 237 return (DWORD)lpbmc->bcWidth; 238 } 239 240 241 /************************************************************************* 242 * 243 * DIBHeight() 244 * 245 * Parameter: 246 * 247 * LPSTR lpDIB - pointer to packed-DIB memory block 248 * 249 * Return Value: 250 * 251 * DWORD - height of the DIB 252 * 253 * Description: 254 * 255 * This function gets the height of the DIB from the BITMAPINFOHEADER 256 * height field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER 257 * height field if it is an OS/2-style DIB. 258 * 259 * History: Date Author Reason 260 * 6/01/91 Garrett McAuliffe Created 261 * 9/15/91 Patrick Schreiber Added header and comments 262 * 263 ************************************************************************/ 264 265 266 DWORD DIBHeight(LPSTR lpDIB) 267 { 268 LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB 269 LPBITMAPCOREHEADER lpbmc; // pointer to an OS/2-style DIB 270 271 /* point to the header (whether OS/2 or Win 3.0 */ 272 273 lpbmi = (LPBITMAPINFOHEADER)lpDIB; 274 lpbmc = (LPBITMAPCOREHEADER)lpDIB; 275 276 /* return the DIB height if it is a Win 3.0 DIB */ 277 if (lpbmi->biSize == sizeof(BITMAPINFOHEADER)) 278 return lpbmi->biHeight; 279 else /* it is an OS/2 DIB, so return its height */ 280 return (DWORD)lpbmc->bcHeight; 281 } 282 283 284 /************************************************************************* 285 * 286 * PaletteSize() 287 * 288 * Parameter: 289 * 290 * LPSTR lpDIB - pointer to packed-DIB memory block 291 * 292 * Return Value: 293 * 294 * WORD - size of the color palette of the DIB 295 * 296 * Description: 297 * 298 * This function gets the size required to store the DIB's palette by 299 * multiplying the number of colors by the size of an RGBQUAD (for a 300 * Windows 3.0-style DIB) or by the size of an RGBTRIPLE (for an OS/2- 301 * style DIB). 302 * 303 * History: Date Author Reason 304 * 6/01/91 Garrett McAuliffe Created 305 * 9/15/91 Patrick Schreiber Added header and comments 306 * 307 ************************************************************************/ 308 309 310 WORD PaletteSize(LPSTR lpDIB) 311 { 312 /* calculate the size required by the palette */ 313 if (IS_WIN30_DIB (lpDIB)) 314 return (DIBNumColors(lpDIB) * sizeof(RGBQUAD)); 315 else 316 return (DIBNumColors(lpDIB) * sizeof(RGBTRIPLE)); 317 } 318 319 320 /************************************************************************* 321 * 322 * DIBNumColors() 323 * 324 * Parameter: 325 * 326 * LPSTR lpDIB - pointer to packed-DIB memory block 327 * 328 * Return Value: 329 * 330 * WORD - number of colors in the color table 331 * 332 * Description: 333 * 334 * This function calculates the number of colors in the DIB's color table 335 * by finding the bits per pixel for the DIB (whether Win3.0 or OS/2-style 336 * DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256, 337 * if 24, no colors in color table. 338 * 339 * History: Date Author Reason 340 * 6/01/91 Garrett McAuliffe Created 341 * 9/15/91 Patrick Schreiber Added header and comments 342 * 343 ************************************************************************/ 344 345 346 WORD DIBNumColors(LPSTR lpDIB) 347 { 348 WORD wBitCount; // DIB bit count 349 350 /* If this is a Windows-style DIB, the number of colors in the 351 * color table can be less than the number of bits per pixel 352 * allows for (i.e. lpbi->biClrUsed can be set to some value). 353 * If this is the case, return the appropriate value. 354 */ 355 356 if (IS_WIN30_DIB(lpDIB)) 357 { 358 DWORD dwClrUsed; 359 360 dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed; 361 if (dwClrUsed) 362 return (WORD)dwClrUsed; 363 } 364 365 /* Calculate the number of colors in the color table based on 366 * the number of bits per pixel for the DIB. 367 */ 368 if (IS_WIN30_DIB(lpDIB)) 369 wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount; 370 else 371 wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount; 372 373 /* return number of colors based on bits per pixel */ 374 switch (wBitCount) 375 { 376 case 1: 377 return 2; 378 379 case 4: 380 return 16; 381 382 case 8: 383 return 256; 384 385 default: 386 return 0; 387 } 388 } 389 390 391 /************************************************************************* 392 * 393 * CreateDIBPalette() 394 * 395 * Parameter: 396 * 397 * HDIB hDIB - specifies the DIB 398 * 399 * Return Value: 400 * 401 * HPALETTE - specifies the palette 402 * 403 * Description: 404 * 405 * This function creates a palette from a DIB by allocating memory for the 406 * logical palette, reading and storing the colors from the DIB's color table 407 * into the logical palette, creating a palette from this logical palette, 408 * and then returning the palette's handle. This allows the DIB to be 409 * displayed using the best possible colors (important for DIBs with 256 or 410 * more colors). 411 * 412 * History: Date Author Reason 413 * 6/01/91 Garrett McAuliffe Created 414 * 9/15/91 Patrick Schreiber Added header and comments 415 * 416 ************************************************************************/ 417 418 419 HPALETTE CreateDIBPalette(HDIB hDIB) 420 { 421 LPLOGPALETTE lpPal; // pointer to a logical palette 422 HANDLE hLogPal; // handle to a logical palette 423 HPALETTE hPal = NULL; // handle to a palette 424 int i, wNumColors; // loop index, number of colors in color table 425 LPSTR lpbi; // pointer to packed-DIB 426 LPBITMAPINFO lpbmi; // pointer to BITMAPINFO structure (Win3.0) 427 LPBITMAPCOREINFO lpbmc; // pointer to BITMAPCOREINFO structure (OS/2) 428 bool bWinStyleDIB; // flag which signifies whether this is a Win3.0 DIB 429 430 /* if handle to DIB is invalid, return NULL */ 431 432 if (!hDIB) 433 return NULL; 434 435 /* lock DIB memory block and get a pointer to it */ 436 lpbi = (LPSTR)GlobalLock(hDIB); 437 438 /* get pointer to BITMAPINFO (Win 3.0) */ 439 lpbmi = (LPBITMAPINFO)lpbi; 440 441 /* get pointer to BITMAPCOREINFO (OS/2 1.x) */ 442 lpbmc = (LPBITMAPCOREINFO)lpbi; 443 444 /* get the number of colors in the DIB */ 445 wNumColors = DIBNumColors(lpbi); 446 447 /* is this a Win 3.0 DIB? */ 448 bWinStyleDIB = IS_WIN30_DIB(lpbi); 449 if (wNumColors) 450 { 451 /* allocate memory block for logical palette */ 452 hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * 453 wNumColors); 454 455 /* if not enough memory, clean up and return NULL */ 456 if (!hLogPal) 457 { 458 GlobalUnlock(hDIB); 459 return NULL; 460 } 461 462 /* lock memory block and get pointer to it */ 463 lpPal = (LPLOGPALETTE)GlobalLock(hLogPal); 464 465 /* set version and number of palette entries */ 466 lpPal->palVersion = PALVERSION; 467 lpPal->palNumEntries = wNumColors; 468 469 /* store RGB triples (if Win 3.0 DIB) or RGB quads (if OS/2 DIB) 470 * into palette 471 */ 472 for (i = 0; i < wNumColors; i++) 473 { 474 if (bWinStyleDIB) 475 { 476 lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed; 477 lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen; 478 lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue; 479 lpPal->palPalEntry[i].peFlags = 0; 480 } 481 else 482 { 483 lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed; 484 lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen; 485 lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue; 486 lpPal->palPalEntry[i].peFlags = 0; 487 } 488 } 489 490 /* create the palette and get handle to it */ 491 hPal = CreatePalette(lpPal); 492 493 /* if error getting handle to palette, clean up and return NULL */ 494 if (!hPal) 495 { 496 GlobalUnlock(hLogPal); 497 GlobalFree(hLogPal); 498 return NULL; 499 } 500 } 501 502 /* clean up */ 503 GlobalUnlock(hLogPal); 504 GlobalFree(hLogPal); 505 GlobalUnlock(hDIB); 506 507 /* return handle to DIB's palette */ 508 return hPal; 509 } 510 511 /************************************************************************* 512 * 513 * DIBToBitmap() 514 * 515 * Parameters: 516 * 517 * HDIB hDIB - specifies the DIB to convert 518 * 519 * HPALETTE hPal - specifies the palette to use with the bitmap 520 * 521 * Return Value: 522 * 523 * HBITMAP - identifies the device-dependent bitmap 524 * 525 * Description: 526 * 527 * This function creates a bitmap from a DIB using the specified palette. 528 * If no palette is specified, default is used. 529 * 530 * NOTE: 531 * 532 * The bitmap returned from this funciton is always a bitmap compatible 533 * with the screen (e.g. same bits/pixel and color planes) rather than 534 * a bitmap with the same attributes as the DIB. This behavior is by 535 * design, and occurs because this function calls CreateDIBitmap to 536 * do its work, and CreateDIBitmap always creates a bitmap compatible 537 * with the hDC parameter passed in (because it in turn calls 538 * CreateCompatibleBitmap). 539 * 540 * So for instance, if your DIB is a monochrome DIB and you call this 541 * function, you will not get back a monochrome HBITMAP -- you will 542 * get an HBITMAP compatible with the screen DC, but with only 2 543 * colors used in the bitmap. 544 * 545 * If your application requires a monochrome HBITMAP returned for a 546 * monochrome DIB, use the function SetDIBits(). 547 * 548 * Also, the DIBpassed in to the function is not destroyed on exit. This 549 * must be done later, once it is no longer needed. 550 * 551 * History: Date Author Reason 552 * 6/01/91 Garrett McAuliffe Created 553 * 9/15/91 Patrick Schreiber Added header and comments 554 * 3/27/92 Mark Bader Added comments about resulting 555 * bitmap format 556 * 557 ************************************************************************/ 558 559 560 HBITMAP DIBToBitmap(HDIB hDIB, HPALETTE hPal) 561 { 562 LPSTR lpDIBHdr, lpDIBBits; // pointer to DIB header, pointer to DIB bits 563 HBITMAP hBitmap; // handle to device-dependent bitmap 564 HDC hDC; // handle to DC 565 HPALETTE hOldPal = NULL; // handle to a palette 566 567 /* if invalid handle, return NULL */ 568 569 if (!hDIB) 570 return NULL; 571 572 /* lock memory block and get a pointer to it */ 573 lpDIBHdr = (LPSTR)GlobalLock(hDIB); 574 575 /* get a pointer to the DIB bits */ 576 lpDIBBits = FindDIBBits(lpDIBHdr); 577 578 /* get a DC */ 579 hDC = GetDC(NULL); 580 if (!hDC) 581 { 582 /* clean up and return NULL */ 583 GlobalUnlock(hDIB); 584 return NULL; 585 } 586 587 /* select and realize palette */ 588 if (hPal) 589 hOldPal = SelectPalette(hDC, hPal, FALSE); 590 RealizePalette(hDC); 591 592 /* create bitmap from DIB info. and bits */ 593 hBitmap = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)lpDIBHdr, CBM_INIT, 594 lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS); 595 596 /* restore previous palette */ 597 if (hOldPal) 598 SelectPalette(hDC, hOldPal, FALSE); 599 600 /* clean up */ 601 ReleaseDC(NULL, hDC); 602 GlobalUnlock(hDIB); 603 604 /* return handle to the bitmap */ 605 return hBitmap; 606 } 607 608 HBITMAP lpDIBToBitmap(void *lpDIBHdr, HPALETTE hPal) 609 { 610 LPSTR lpDIBBits; // pointer to DIB header, pointer to DIB bits 611 HBITMAP hBitmap; // handle to device-dependent bitmap 612 HDC hDC; // handle to DC 613 HPALETTE hOldPal = NULL; // handle to a palette 614 615 if (!lpDIBHdr) 616 return NULL; 617 618 /* get a pointer to the DIB bits */ 619 lpDIBBits = FindDIBBits((LPSTR)lpDIBHdr) ; 620 621 /* get a DC */ 622 hDC = GetDC(NULL); 623 if (!hDC) 624 return NULL; 625 626 /* select and realize palette */ 627 if (hPal) 628 hOldPal = SelectPalette(hDC, hPal, FALSE); 629 RealizePalette(hDC); 630 631 /* create bitmap from DIB info. and bits */ 632 hBitmap = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)lpDIBHdr, CBM_INIT, 633 lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS); 634 635 /* restore previous palette */ 636 if (hOldPal) 637 SelectPalette(hDC, hOldPal, FALSE); 638 639 /* clean up */ 640 ReleaseDC(NULL, hDC); 641 642 /* return handle to the bitmap */ 643 return hBitmap; 644 } 645 646 HBITMAP lpDIBToBitmapAndPalette(void *lpDIBHdr) 647 { 648 LPSTR lpDIBBits; // pointer to DIB header, pointer to DIB bits 649 HBITMAP hBitmap; // handle to device-dependent bitmap 650 HDC hDC; // handle to DC 651 HPALETTE hOldPal; // handle to a palette 652 653 if (!lpDIBHdr) 654 return NULL; 655 656 /* get a pointer to the DIB bits */ 657 lpDIBBits = FindDIBBits((LPSTR)lpDIBHdr) ; 658 659 /* get a DC */ 660 hDC = GetDC(NULL); 661 if (!hDC) 662 return NULL; 663 664 hPalBitmap = pov_frontend::WinLegacyDisplay::CreatePalette (((BITMAPINFO *) lpDIBHdr)->bmiColors, ((BITMAPINFO *) lpDIBHdr)->bmiHeader.biClrImportant, render_bitmap_depth != 24) ; 665 if (hPalBitmap) 666 { 667 hOldPal = SelectPalette(hDC, hPalBitmap, FALSE); 668 SelectPalette(hDC, hPalBitmap, FALSE); 669 RealizePalette(hDC); 670 } 671 672 /* create bitmap from DIB info. and bits */ 673 hBitmap = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)lpDIBHdr, CBM_INIT, 674 lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS); 675 /* restore previous palette */ 676 if (hPalBitmap) 677 if (hOldPal) 678 SelectPalette(hDC, hOldPal, FALSE); 679 680 /* clean up */ 681 ReleaseDC(NULL, hDC); 682 683 /* return handle to the bitmap */ 684 return hBitmap; 685 } 686 687 /************************************************************************* 688 * 689 * BitmapToDIB() 690 * 691 * Parameters: 692 * 693 * HBITMAP hBitmap - specifies the bitmap to convert 694 * 695 * HPALETTE hPal - specifies the palette to use with the bitmap 696 * 697 * Return Value: 698 * 699 * HDIB - identifies the device-dependent bitmap 700 * 701 * Description: 702 * 703 * This function creates a DIB from a bitmap using the specified palette. 704 * 705 * History: Date Author Reason 706 * 6/01/91 Garrett McAuliffe Created 707 * 9/15/91 Patrick Schreiber Added header and comments 708 * 12/10/91 Patrick Schreiber Added bits per pixel validation 709 * and check GetObject return value 710 * 711 ************************************************************************/ 712 713 714 HDIB BitmapToDIB(HBITMAP hBitmap, HPALETTE hPal) 715 { 716 BITMAP bm; // bitmap structure 717 BITMAPINFOHEADER bi; // bitmap header 718 BITMAPINFOHEADER *lpbi; // pointer to BITMAPINFOHEADER 719 DWORD dwLen; // size of memory block 720 HANDLE hDIB, h; // handle to DIB, temp handle 721 HDC hDC; // handle to DC 722 WORD biBits; // bits per pixel 723 724 /* check if bitmap handle is valid */ 725 726 if (!hBitmap) 727 return NULL; 728 729 /* fill in BITMAP structure, return NULL if it didn't work */ 730 if (!GetObject(hBitmap, sizeof(bm), (LPSTR)&bm)) 731 return NULL; 732 733 /* if no palette is specified, use default palette */ 734 if (hPal == NULL) 735 hPal = (HPALETTE)GetStockObject(DEFAULT_PALETTE); 736 737 /* calculate bits per pixel */ 738 biBits = bm.bmPlanes * bm.bmBitsPixel; 739 740 /* make sure bits per pixel is valid */ 741 if (biBits <= 1) 742 biBits = 1; 743 else if (biBits <= 4) 744 biBits = 4; 745 else if (biBits <= 8) 746 biBits = 8; 747 else /* if greater than 8-bit, force to 24-bit */ 748 biBits = 24; 749 750 /* initialize BITMAPINFOHEADER */ 751 bi.biSize = sizeof(BITMAPINFOHEADER); 752 bi.biWidth = bm.bmWidth; 753 bi.biHeight = bm.bmHeight; 754 bi.biPlanes = 1; 755 bi.biBitCount = biBits; 756 bi.biCompression = BI_RGB; 757 bi.biSizeImage = 0; 758 bi.biXPelsPerMeter = 0; 759 bi.biYPelsPerMeter = 0; 760 bi.biClrUsed = 0; 761 bi.biClrImportant = 0; 762 763 /* calculate size of memory block required to store BITMAPINFO */ 764 dwLen = bi.biSize + PaletteSize((LPSTR)&bi); 765 766 /* get a DC */ 767 hDC = GetDC(NULL); 768 769 /* select and realize our palette */ 770 hPal = SelectPalette(hDC, hPal, FALSE); 771 RealizePalette(hDC); 772 773 /* alloc memory block to store our bitmap */ 774 hDIB = GlobalAlloc(GHND, dwLen); 775 776 /* if we couldn't get memory block */ 777 if (!hDIB) 778 { 779 /* clean up and return NULL */ 780 SelectPalette(hDC, hPal, TRUE); 781 RealizePalette(hDC); 782 ReleaseDC(NULL, hDC); 783 return NULL; 784 } 785 786 /* lock memory and get pointer to it */ 787 lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 788 789 /* use our bitmap info. to fill BITMAPINFOHEADER */ 790 *lpbi = bi; 791 792 /* call GetDIBits with a NULL lpBits param, so it will calculate the 793 * biSizeImage field for us 794 */ 795 GetDIBits(hDC, hBitmap, 0, (WORD)bi.biHeight, NULL, (LPBITMAPINFO)lpbi, 796 DIB_RGB_COLORS); 797 798 /* get the info. returned by GetDIBits and unlock memory block */ 799 bi = *lpbi; 800 GlobalUnlock(hDIB); 801 802 /* if the driver did not fill in the biSizeImage field, make one up */ 803 if (bi.biSizeImage == 0) 804 bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight; 805 806 /* realloc the buffer big enough to hold all the bits */ 807 dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + bi.biSizeImage; 808 if ((h = GlobalReAlloc(hDIB, dwLen, 0)) != NULL) 809 hDIB = h; 810 else 811 { 812 /* clean up and return NULL */ 813 GlobalFree(hDIB); 814 SelectPalette(hDC, hPal, TRUE); 815 RealizePalette(hDC); 816 ReleaseDC(NULL, hDC); 817 return NULL; 818 } 819 820 /* lock memory block and get pointer to it */ 821 lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 822 823 /* call GetDIBits with a NON-NULL lpBits param, and actualy get the 824 * bits this time 825 */ 826 if (GetDIBits(hDC, hBitmap, 0, (WORD)bi.biHeight, (LPSTR)lpbi + (WORD)lpbi 827 ->biSize + PaletteSize((LPSTR)lpbi), (LPBITMAPINFO)lpbi, 828 DIB_RGB_COLORS) == 0) 829 { 830 /* clean up and return NULL */ 831 GlobalUnlock(hDIB); 832 SelectPalette(hDC, hPal, TRUE); 833 RealizePalette(hDC); 834 ReleaseDC(NULL, hDC); 835 return NULL; 836 } 837 bi = *lpbi; 838 839 /* clean up */ 840 GlobalUnlock(hDIB); 841 SelectPalette(hDC, hPal, TRUE); 842 RealizePalette(hDC); 843 ReleaseDC(NULL, hDC); 844 845 /* return handle to the DIB */ 846 return hDIB; 847 } 848 849 850 /************************************************************************* 851 * 852 * PalEntriesOnDevice() 853 * 854 * Parameter: 855 * 856 * HDC hDC - device context 857 * 858 * Return Value: 859 * 860 * int - number of palette entries on device 861 * 862 * Description: 863 * 864 * This function gets the number of palette entries on the specified device 865 * 866 * History: Date Author Reason 867 * 6/01/91 Garrett McAuliffe Created 868 * 9/15/91 Patrick Schreiber Added header and comments 869 * 870 ************************************************************************/ 871 872 873 int PalEntriesOnDevice(HDC hDC) 874 { 875 int nColors; // number of colors 876 877 /* Find out the number of palette entries on this 878 * device. 879 */ 880 881 nColors = GetDeviceCaps(hDC, SIZEPALETTE); 882 883 /* For non-palette devices, we'll use the # of system 884 * colors for our palette size. 885 */ 886 if (!nColors) 887 nColors = GetDeviceCaps(hDC, NUMCOLORS); 888 return nColors; 889 } 890 891 892 /************************************************************************* 893 * 894 * GetSystemPalette() 895 * 896 * Parameters: 897 * 898 * None 899 * 900 * Return Value: 901 * 902 * HPALETTE - handle to a copy of the current system palette 903 * 904 * Description: 905 * 906 * This function returns a handle to a palette which represents the system 907 * palette. The system RGB values are copied into our logical palette using 908 * the GetSystemPaletteEntries function. 909 * 910 * History: 911 * 912 * Date Author Reason 913 * 6/01/91 Garrett McAuliffe Created 914 * 9/15/91 Patrick Schreiber Added header and comments 915 * 12/20/91 Mark Bader Added GetSystemPaletteEntries call 916 * 917 ************************************************************************/ 918 919 920 HPALETTE GetSystemPalette(void) 921 { 922 HDC hDC; // handle to a DC 923 static HPALETTE hPal = NULL; // handle to a palette 924 HANDLE hLogPal; // handle to a logical palette 925 LPLOGPALETTE lpLogPal; // pointer to a logical palette 926 int nColors; // number of colors 927 928 /* Find out how many palette entries we want. */ 929 930 hDC = GetDC(NULL); 931 if (!hDC) 932 return NULL; 933 nColors = PalEntriesOnDevice(hDC); // Number of palette entries 934 935 /* Allocate room for the palette and lock it. */ 936 hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + nColors * sizeof( 937 PALETTEENTRY)); 938 939 /* if we didn't get a logical palette, return NULL */ 940 if (!hLogPal) 941 return NULL; 942 943 /* get a pointer to the logical palette */ 944 lpLogPal = (LPLOGPALETTE)GlobalLock(hLogPal); 945 946 /* set some important fields */ 947 lpLogPal->palVersion = PALVERSION; 948 lpLogPal->palNumEntries = nColors; 949 950 /* Copy the current system palette into our logical palette */ 951 952 GetSystemPaletteEntries(hDC, 0, nColors, 953 (LPPALETTEENTRY)(lpLogPal->palPalEntry)); 954 955 /* Go ahead and create the palette. Once it's created, 956 * we no longer need the LOGPALETTE, so free it. 957 */ 958 959 hPal = CreatePalette(lpLogPal); 960 961 /* clean up */ 962 GlobalUnlock(hLogPal); 963 GlobalFree(hLogPal); 964 ReleaseDC(NULL, hDC); 965 966 return hPal; 967 } 968 969 970 /************************************************************************* 971 * 972 * AllocRoomForDIB() 973 * 974 * Parameters: 975 * 976 * BITMAPINFOHEADER - bitmap info header stucture 977 * 978 * HBITMAP - handle to the bitmap 979 * 980 * Return Value: 981 * 982 * HDIB - handle to memory block 983 * 984 * Description: 985 * 986 * This routine takes a BITMAPINOHEADER, and returns a handle to global 987 * memory which can contain a DIB with that header. It also initializes 988 * the header portion of the global memory. GetDIBits() is used to determine 989 * the amount of room for the DIB's bits. The total amount of memory 990 * needed = sizeof(BITMAPINFOHEADER) + size of color table + size of bits. 991 * 992 * History: Date Author Reason 993 * 6/01/91 Garrett McAuliffe Created 994 * 12/11/91 Patrick Schreiber Added header and some comments 995 * 996 ************************************************************************/ 997 998 HANDLE AllocRoomForDIB(BITMAPINFOHEADER bi, HBITMAP hBitmap) 999 { 1000 DWORD dwLen; 1001 HANDLE hDIB; 1002 HDC hDC; 1003 LPBITMAPINFOHEADER lpbi; 1004 HANDLE hTemp; 1005 1006 /* Figure out the size needed to hold the BITMAPINFO structure 1007 * (which includes the BITMAPINFOHEADER and the color table). 1008 */ 1009 1010 dwLen = bi.biSize + PaletteSize((LPSTR) &bi); 1011 hDIB = GlobalAlloc(GHND,dwLen); 1012 1013 /* Check that DIB handle is valid */ 1014 if (!hDIB) 1015 return NULL; 1016 1017 /* Set up the BITMAPINFOHEADER in the newly allocated global memory, 1018 * then call GetDIBits() with lpBits = NULL to have it fill in the 1019 * biSizeImage field for us. 1020 */ 1021 lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 1022 *lpbi = bi; 1023 1024 hDC = GetDC(NULL); 1025 GetDIBits(hDC, hBitmap, 0, (WORD) bi.biHeight, 1026 NULL, (LPBITMAPINFO) lpbi, DIB_RGB_COLORS); 1027 ReleaseDC(NULL, hDC); 1028 1029 /* If the driver did not fill in the biSizeImage field, 1030 * fill it in -- NOTE: this is a bug in the driver! 1031 */ 1032 if (lpbi->biSizeImage == 0) 1033 lpbi->biSizeImage = WIDTHBYTES((DWORD)lpbi->biWidth * lpbi->biBitCount) * 1034 lpbi->biHeight; 1035 1036 /* Get the size of the memory block we need */ 1037 dwLen = lpbi->biSize + PaletteSize((LPSTR) &bi) + lpbi->biSizeImage; 1038 1039 /* Unlock the memory block */ 1040 GlobalUnlock(hDIB); 1041 1042 /* ReAlloc the buffer big enough to hold all the bits */ 1043 if ((hTemp = GlobalReAlloc(hDIB,dwLen,0)) != NULL) 1044 return hTemp; 1045 else 1046 { 1047 /* Else free memory block and return failure */ 1048 GlobalFree(hDIB); 1049 return NULL; 1050 } 1051 } 1052 1053 1054 /************************************************************************* 1055 * 1056 * ChangeDIBFormat() 1057 * 1058 * Parameter: 1059 * 1060 * HDIB - handle to packed-DIB in memory 1061 * 1062 * WORD - desired bits per pixel 1063 * 1064 * DWORD - desired compression format 1065 * 1066 * Return Value: 1067 * 1068 * HDIB - handle to the new DIB if successful, else NULL 1069 * 1070 * Description: 1071 * 1072 * This function will convert the bits per pixel and/or the compression 1073 * format of the specified DIB. Note: If the conversion was unsuccessful, 1074 * we return NULL. The original DIB is left alone. Don't use code like the 1075 * following: 1076 * 1077 * hMyDIB = ChangeDIBFormat(hMyDIB, 8, BI_RLE4); 1078 * 1079 * The conversion will fail, but hMyDIB will now be NULL and the original 1080 * DIB will now hang around in memory. We could have returned the old 1081 * DIB, but we wanted to allow the programmer to check whether this 1082 * conversion succeeded or failed. 1083 * 1084 * History: 1085 * 1086 * Date Author Reason 1087 * 6/01/91 Garrett McAuliffe Created 1088 * 12/10/91 Patrick Schreiber Modified from converting RGB to RLE8 1089 * to converting RGB/RLE to RGB/RLE. 1090 * Added wBitCount and dwCompression 1091 * parameters. Also added header and 1092 * comments. 1093 * 1094 ************************************************************************/ 1095 1096 HDIB ChangeDIBFormat(HDIB hDIB, WORD wBitCount, DWORD dwCompression) 1097 { 1098 HDC hDC; // Handle to DC 1099 HBITMAP hBitmap; // Handle to bitmap 1100 BITMAP Bitmap; // BITMAP data structure 1101 BITMAPINFOHEADER bi; // Bitmap info header 1102 LPBITMAPINFOHEADER lpbi; // Pointer to bitmap info 1103 HDIB hNewDIB; // Handle to new DIB 1104 HPALETTE hPal, hOldPal; // Handle to palette, prev pal 1105 WORD DIBBPP, NewBPP; // DIB bits per pixel, new bpp 1106 DWORD NewComp; // New compression 1107 1108 /* Check for a valid DIB handle */ 1109 if (!hDIB) 1110 return NULL; 1111 1112 /* Get the old DIB's bits per pixel and compression format */ 1113 lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 1114 DIBBPP = ((LPBITMAPINFOHEADER)lpbi)->biBitCount; 1115 GlobalUnlock(hDIB); 1116 1117 /* Validate wBitCount and dwCompression 1118 * They must match correctly (i.e., BI_RLE4 and 4 BPP or 1119 * BI_RLE8 and 8BPP, etc.) or we return failure */ 1120 if (wBitCount == 0) 1121 { 1122 NewBPP = DIBBPP; 1123 if ((dwCompression == BI_RLE4 && NewBPP == 4) || 1124 (dwCompression == BI_RLE8 && NewBPP == 8) || 1125 (dwCompression == BI_RGB)) 1126 NewComp = dwCompression; 1127 else 1128 return NULL; 1129 } 1130 else if (wBitCount == 1 && dwCompression == BI_RGB) 1131 { 1132 NewBPP = wBitCount; 1133 NewComp = BI_RGB; 1134 } 1135 else if (wBitCount == 4) 1136 { 1137 NewBPP = wBitCount; 1138 if (dwCompression == BI_RGB || dwCompression == BI_RLE4) 1139 NewComp = dwCompression; 1140 else 1141 return NULL; 1142 } 1143 else if (wBitCount == 8) 1144 { 1145 NewBPP = wBitCount; 1146 if (dwCompression == BI_RGB || dwCompression == BI_RLE8) 1147 NewComp = dwCompression; 1148 else 1149 return NULL; 1150 } 1151 else if (wBitCount == 24 && dwCompression == BI_RGB) 1152 { 1153 NewBPP = wBitCount; 1154 NewComp = BI_RGB; 1155 } 1156 else 1157 return NULL; 1158 1159 /* Save the old DIB's palette */ 1160 hPal = CreateDIBPalette(hDIB); 1161 if (!hPal) 1162 return NULL; 1163 1164 /* Convert old DIB to a bitmap */ 1165 hBitmap = DIBToBitmap(hDIB, hPal); 1166 if (!hBitmap) 1167 { 1168 DeleteObject(hPal); 1169 return NULL; 1170 } 1171 1172 /* Get info about the bitmap */ 1173 GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap); 1174 1175 /* Fill in the BITMAPINFOHEADER appropriately */ 1176 bi.biSize = sizeof(BITMAPINFOHEADER); 1177 bi.biWidth = Bitmap.bmWidth; 1178 bi.biHeight = Bitmap.bmHeight; 1179 bi.biPlanes = 1; 1180 bi.biBitCount = NewBPP; 1181 bi.biCompression = NewComp; 1182 bi.biSizeImage = 0; 1183 bi.biXPelsPerMeter = 0; 1184 bi.biYPelsPerMeter = 0; 1185 bi.biClrUsed = 0; 1186 bi.biClrImportant = 0; 1187 1188 /* Go allocate room for the new DIB */ 1189 hNewDIB = AllocRoomForDIB(bi, hBitmap); 1190 if (!hNewDIB) 1191 return NULL; 1192 1193 /* Get a pointer to the new DIB */ 1194 lpbi = (LPBITMAPINFOHEADER)GlobalLock(hNewDIB); 1195 1196 /* Get a DC and select/realize our palette in it */ 1197 hDC = GetDC(NULL); 1198 hOldPal = SelectPalette(hDC, hPal, FALSE); 1199 RealizePalette(hDC); 1200 1201 /* Call GetDIBits and get the new DIB bits */ 1202 if (!GetDIBits(hDC, hBitmap, 0, (WORD) lpbi->biHeight, 1203 (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi), 1204 (LPBITMAPINFO)lpbi, DIB_RGB_COLORS)) 1205 { 1206 GlobalUnlock(hNewDIB); 1207 GlobalFree(hNewDIB); 1208 hNewDIB = NULL; 1209 } 1210 1211 /* Clean up and return */ 1212 SelectPalette(hDC, hOldPal, TRUE); 1213 RealizePalette(hDC); 1214 ReleaseDC(NULL, hDC); 1215 1216 if (hNewDIB) 1217 /* Unlock the new DIB's memory block */ 1218 GlobalUnlock(hNewDIB); 1219 1220 DeleteObject(hBitmap); 1221 DeleteObject(hPal); 1222 1223 return hNewDIB; 1224 } 1225 1226 1227 /************************************************************************* 1228 * 1229 * ChangeBitmapFormat() 1230 * 1231 * Parameter: 1232 * 1233 * HBITMAP - handle to a bitmap 1234 * 1235 * WORD - desired bits per pixel 1236 * 1237 * DWORD - desired compression format 1238 * 1239 * HPALETTE - handle to palette 1240 * 1241 * Return Value: 1242 * 1243 * HDIB - handle to the new DIB if successful, else NULL 1244 * 1245 * Description: 1246 * 1247 * This function will convert a bitmap to the specified bits per pixel 1248 * and compression format. The bitmap and it's palette will remain 1249 * after calling this function. 1250 * 1251 * History: 1252 * 1253 * Date Author Reason 1254 * 6/01/91 Garrett McAuliffe Created 1255 * 12/10/91 Patrick Schreiber Modified from converting RGB to RLE8 1256 * to converting RGB/RLE to RGB/RLE. 1257 * Added wBitCount and dwCompression 1258 * parameters. Also added header and 1259 * comments. 1260 * 12/11/91 Patrick Schreiber Destroy old DIB if conversion was 1261 * successful. 1262 * 12/16/91 Patrick Schreiber Modified from converting DIB to new 1263 * DIB to bitmap to new DIB. Added palette 1264 * parameter. 1265 * 1266 ************************************************************************/ 1267 1268 HDIB ChangeBitmapFormat(HBITMAP hBitmap, 1269 WORD wBitCount, 1270 DWORD dwCompression, 1271 HPALETTE hPal) 1272 { 1273 HDC hDC; // Screen DC 1274 HDIB hNewDIB; // Handle to new DIB 1275 BITMAP Bitmap; // BITMAP data structure 1276 BITMAPINFOHEADER bi; // Bitmap info. header 1277 LPBITMAPINFOHEADER lpbi; // Pointer to bitmap header 1278 HPALETTE hOldPal=NULL; // Handle to palette 1279 WORD NewBPP; // New bits per pixel 1280 DWORD NewComp; // New compression format 1281 1282 /* Check for a valid bitmap handle */ 1283 if (!hBitmap) 1284 return NULL; 1285 1286 /* Validate wBitCount and dwCompression 1287 * They must match correctly (i.e., BI_RLE4 and 4 BPP or 1288 * BI_RLE8 and 8BPP, etc.) or we return failure 1289 */ 1290 if (wBitCount == 0) 1291 { 1292 NewComp = dwCompression; 1293 if (NewComp == BI_RLE4) 1294 NewBPP = 4; 1295 else if (NewComp == BI_RLE8) 1296 NewBPP = 8; 1297 else /* Not enough info */ 1298 return NULL; 1299 } 1300 else if (wBitCount == 1 && dwCompression == BI_RGB) 1301 { 1302 NewBPP = wBitCount; 1303 NewComp = BI_RGB; 1304 } 1305 else if (wBitCount == 4) 1306 { 1307 NewBPP = wBitCount; 1308 if (dwCompression == BI_RGB || dwCompression == BI_RLE4) 1309 NewComp = dwCompression; 1310 else 1311 return NULL; 1312 } 1313 else if (wBitCount == 8) 1314 { 1315 NewBPP = wBitCount; 1316 if (dwCompression == BI_RGB || dwCompression == BI_RLE8) 1317 NewComp = dwCompression; 1318 else 1319 return NULL; 1320 } 1321 else if (wBitCount == 24 && dwCompression == BI_RGB) 1322 { 1323 NewBPP = wBitCount; 1324 NewComp = BI_RGB; 1325 } 1326 else 1327 return NULL; 1328 1329 /* Get info about the bitmap */ 1330 GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap); 1331 1332 /* Fill in the BITMAPINFOHEADER appropriately */ 1333 bi.biSize = sizeof(BITMAPINFOHEADER); 1334 bi.biWidth = Bitmap.bmWidth; 1335 bi.biHeight = Bitmap.bmHeight; 1336 bi.biPlanes = 1; 1337 bi.biBitCount = NewBPP; 1338 bi.biCompression = NewComp; 1339 bi.biSizeImage = 0; 1340 bi.biXPelsPerMeter = 0; 1341 bi.biYPelsPerMeter = 0; 1342 bi.biClrUsed = 0; 1343 bi.biClrImportant = 0; 1344 1345 /* Go allocate room for the new DIB */ 1346 hNewDIB = AllocRoomForDIB(bi, hBitmap); 1347 if (!hNewDIB) 1348 return NULL; 1349 1350 /* Get a pointer to the new DIB */ 1351 lpbi = (LPBITMAPINFOHEADER)GlobalLock(hNewDIB); 1352 1353 /* If we have a palette, get a DC and select/realize it */ 1354 if (hPal) 1355 { 1356 hDC = GetDC(NULL); 1357 hOldPal = SelectPalette(hDC, hPal, FALSE); 1358 RealizePalette(hDC); 1359 } 1360 1361 /* Call GetDIBits and get the new DIB bits */ 1362 if (!GetDIBits(hDC, hBitmap, 0, (WORD) lpbi->biHeight, 1363 (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi), 1364 (LPBITMAPINFO)lpbi, DIB_RGB_COLORS)) 1365 { 1366 GlobalUnlock(hNewDIB); 1367 GlobalFree(hNewDIB); 1368 hNewDIB = NULL; 1369 } 1370 1371 /* Clean up and return */ 1372 if (hOldPal) 1373 { 1374 SelectPalette(hDC, hOldPal, TRUE); 1375 RealizePalette(hDC); 1376 ReleaseDC(NULL, hDC); 1377 } 1378 1379 if (hNewDIB) 1380 { 1381 /* Unlock the new DIB's memory block */ 1382 GlobalUnlock(hNewDIB); 1383 } 1384 1385 return hNewDIB; 1386 } 1387 1388 /************************************************************************* 1389 * 1390 * LoadDIB() 1391 * 1392 * Loads the specified DIB from a file, allocates memory for it, 1393 * and reads the disk file into the memory. 1394 * 1395 * 1396 * Parameters: 1397 * 1398 * LPSTR lpFileName - specifies the file to load a DIB from 1399 * 1400 * Returns: A handle to a DIB, or NULL if unsuccessful. 1401 * 1402 * NOTE: The DIB API were not written to handle OS/2 DIBs; This 1403 * function will reject any file that is not a Windows DIB. 1404 * 1405 * History: Date Author Reason 1406 * 9/15/91 Mark Bader Based on DIBVIEW 1407 * 1408 *************************************************************************/ 1409 1410 HDIB LoadDIB(LPSTR lpFileName) 1411 { 1412 HDIB hDIB; 1413 int hFile; 1414 OFSTRUCT ofs; 1415 1416 /* 1417 * Set the cursor to a hourglass, in case the loading operation 1418 * takes more than a sec, the user will know what's going on. 1419 */ 1420 1421 SetCursor(LoadCursor(NULL, IDC_WAIT)); 1422 if ((hFile = OpenFile(lpFileName, &ofs, OF_READ)) != -1) 1423 { 1424 hDIB = ReadDIBFile(hFile); 1425 _lclose(hFile); 1426 SetCursor(LoadCursor(NULL, IDC_ARROW)); 1427 return hDIB; 1428 } 1429 else 1430 { 1431 SetCursor(LoadCursor(NULL, IDC_ARROW)); 1432 return NULL; 1433 } 1434 } 1435 1436 /************************************************************************* 1437 * 1438 * SaveDIB() 1439 * 1440 * Saves the specified DIB into the specified file name on disk. No 1441 * error checking is done, so if the file already exists, it will be 1442 * written over. 1443 * 1444 * Parameters: 1445 * 1446 * HDIB hDib - Handle to the dib to save 1447 * 1448 * LPSTR lpFileName - pointer to full pathname to save DIB under 1449 * 1450 * Return value: 0 if successful, or one of: 1451 * ERR_INVALIDHANDLE 1452 * ERR_OPEN 1453 * ERR_LOCK 1454 * 1455 * History: 1456 * 1457 * NOTE: The DIB API were not written to handle OS/2 DIBs, so this 1458 * function will not save a file if it is not a Windows DIB. 1459 * 1460 * History: Date Author Reason 1461 * 9/15/91 Mark Bader Taken from DIBVIEW (which was taken 1462 * from SHOWDIB) 1463 * 1/30/92 Mark Bader Fixed problem of writing too many 1464 * bytes to the file 1465 * 6/24/92 Mark Bader Added check for OS/2 DIB 1466 * 1467 *************************************************************************/ 1468 1469 1470 WORD SaveDIB(HDIB hDib, LPSTR lpFileName) 1471 { 1472 BITMAPFILEHEADER bmfHdr; // Header for Bitmap file 1473 LPBITMAPINFOHEADER lpBI; // Pointer to DIB info structure 1474 int fh; // file handle for opened file 1475 OFSTRUCT of; // OpenFile structure 1476 DWORD dwDIBSize; 1477 DWORD dwError; // Error return from MyWrite 1478 1479 if (!hDib) 1480 return ERR_INVALIDHANDLE; 1481 fh = OpenFile(lpFileName, &of, OF_CREATE | OF_READWRITE); 1482 if (fh == -1) 1483 return ERR_OPEN; 1484 1485 /* 1486 * Get a pointer to the DIB memory, the first of which contains 1487 * a BITMAPINFO structure 1488 */ 1489 lpBI = (LPBITMAPINFOHEADER)GlobalLock(hDib); 1490 if (!lpBI) 1491 return ERR_LOCK; 1492 1493 // Check to see if we're dealing with an OS/2 DIB. If so, don't 1494 // save it because our functions aren't written to deal with these 1495 // DIBs. 1496 1497 if (lpBI->biSize != sizeof(BITMAPINFOHEADER)) 1498 { 1499 GlobalUnlock(hDib); 1500 return ERR_NOT_DIB; 1501 } 1502 1503 /* 1504 * Fill in the fields of the file header 1505 */ 1506 1507 /* Fill in file type (first 2 bytes must be "BM" for a bitmap) */ 1508 bmfHdr.bfType = DIB_HEADER_MARKER; // "BM" 1509 1510 // Calculating the size of the DIB is a bit tricky (if we want to 1511 // do it right). The easiest way to do this is to call GlobalSize() 1512 // on our global handle, but since the size of our global memory may have 1513 // been padded a few bytes, we may end up writing out a few too 1514 // many bytes to the file (which may cause problems with some apps, 1515 // like HC 3.0). 1516 // 1517 // So, instead let's calculate the size manually. 1518 // 1519 // To do this, find size of header plus size of color table. Since the 1520 // first DWORD in both BITMAPINFOHEADER and BITMAPCOREHEADER conains 1521 // the size of the structure, let's use this. 1522 1523 dwDIBSize = *(LPDWORD)lpBI + PaletteSize((LPSTR)lpBI); // Partial Calculation 1524 1525 // Now calculate the size of the image 1526 1527 if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4)) { 1528 1529 // It's an RLE bitmap, we can't calculate size, so trust the 1530 // biSizeImage field 1531 1532 dwDIBSize += lpBI->biSizeImage; 1533 } 1534 else { 1535 DWORD dwBmBitsSize; // Size of Bitmap Bits only 1536 1537 // It's not RLE, so size is Width (DWORD aligned) * Height 1538 1539 dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight; 1540 1541 dwDIBSize += dwBmBitsSize; 1542 1543 // Now, since we have calculated the correct size, why don't we 1544 // fill in the biSizeImage field (this will fix any .BMP files which 1545 // have this field incorrect). 1546 1547 lpBI->biSizeImage = dwBmBitsSize; 1548 } 1549 1550 1551 // Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER) 1552 1553 bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER); 1554 bmfHdr.bfReserved1 = 0; 1555 bmfHdr.bfReserved2 = 0; 1556 1557 /* 1558 * Now, calculate the offset the actual bitmap bits will be in 1559 * the file -- It's the Bitmap file header plus the DIB header, 1560 * plus the size of the color table. 1561 */ 1562 bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize + 1563 PaletteSize((LPSTR)lpBI); 1564 1565 /* Write the file header */ 1566 _lwrite(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER)); 1567 1568 /* 1569 * Write the DIB header and the bits -- use local version of 1570 * MyWrite, so we can write more than 32767 bytes of data 1571 */ 1572 dwError = MyWrite(fh, (LPSTR)lpBI, dwDIBSize); 1573 GlobalUnlock(hDib); 1574 _lclose(fh); 1575 1576 if (dwError == 0) 1577 return ERR_OPEN; // oops, something happened in the write 1578 else 1579 return 0; // Success code 1580 } 1581 1582 1583 /************************************************************************* 1584 * 1585 * DestroyDIB () 1586 * 1587 * Purpose: Frees memory associated with a DIB 1588 * 1589 * Returns: Nothing 1590 * 1591 * History: Date Author Reason 1592 * 9/15/91 Mark Bader Created 1593 * 1594 *************************************************************************/ 1595 1596 1597 WORD DestroyDIB(HDIB hDib) 1598 { 1599 GlobalFree(hDib); 1600 return 0; 1601 } 1602 1603 1604 //************************************************************************ 1605 // 1606 // Auxiliary Functions which the above procedures use 1607 // 1608 //************************************************************************ 1609 1610 1611 /************************************************************************* 1612 * 1613 * Function: ReadDIBFile (int) 1614 * 1615 * Purpose: Reads in the specified DIB file into a global chunk of 1616 * memory. 1617 * 1618 * Returns: A handle to a dib (hDIB) if successful. 1619 * NULL if an error occurs. 1620 * 1621 * Comments: BITMAPFILEHEADER is stripped off of the DIB. Everything 1622 * from the end of the BITMAPFILEHEADER structure on is 1623 * returned in the global memory handle. 1624 * 1625 * 1626 * NOTE: The DIB API were not written to handle OS/2 DIBs, so this 1627 * function will reject any file that is not a Windows DIB. 1628 * 1629 * History: Date Author Reason 1630 * 9/15/91 Mark Bader Based on DIBVIEW 1631 * 6/25/92 Mark Bader Added check for OS/2 DIB 1632 * 7/21/92 Mark Bader Added code to deal with bfOffBits 1633 * field in BITMAPFILEHEADER 1634 * 9/11/92 Mark Bader Fixed Realloc Code to free original mem 1635 * 1636 *************************************************************************/ 1637 1638 HANDLE ReadDIBFile(int hFile) 1639 { 1640 BITMAPFILEHEADER bmfHeader; 1641 UINT nNumColors; // Number of colors in table 1642 HANDLE hDIB; 1643 HANDLE hDIBtmp; // Used for GlobalRealloc() //MPB 1644 LPBITMAPINFOHEADER lpbi; 1645 DWORD offBits; 1646 1647 /* 1648 * get length of DIB in bytes for use when reading 1649 */ 1650 1651 // Allocate memory for header & color table. We'll enlarge this 1652 // memory as needed. 1653 1654 hDIB = GlobalAlloc(GMEM_MOVEABLE, 1655 (DWORD)(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD))); 1656 1657 if (!hDIB) return NULL; 1658 1659 lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 1660 if (!lpbi) 1661 { 1662 GlobalFree(hDIB); 1663 return NULL; 1664 } 1665 1666 // read the BITMAPFILEHEADER from our file 1667 1668 if (sizeof (BITMAPFILEHEADER) != _lread (hFile, (LPSTR)&bmfHeader, sizeof (BITMAPFILEHEADER))) 1669 goto ErrExit; 1670 1671 if (bmfHeader.bfType != 0x4d42) /* 'BM' */ 1672 goto ErrExit; 1673 1674 // read the BITMAPINFOHEADER 1675 1676 if (sizeof(BITMAPINFOHEADER) != _lread (hFile, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER))) 1677 goto ErrExit; 1678 1679 // Check to see that it's a Windows DIB -- an OS/2 DIB would cause 1680 // strange problems with the rest of the DIB API since the fields 1681 // in the header are different and the color table entries are 1682 // smaller. 1683 // 1684 // If it's not a Windows DIB (e.g. if biSize is wrong), return NULL. 1685 1686 if (lpbi->biSize == sizeof(BITMAPCOREHEADER)) 1687 goto ErrExit; 1688 1689 // Now determine the size of the color table and read it. Since the 1690 // bitmap bits are offset in the file by bfOffBits, we need to do some 1691 // special processing here to make sure the bits directly follow 1692 // the color table (because that's the format we are susposed to pass 1693 // back) 1694 1695 if (!(nNumColors = (UINT)lpbi->biClrUsed)) 1696 { 1697 // no color table for 24-bit, default size otherwise 1698 if (lpbi->biBitCount != 24) 1699 nNumColors = 1 << lpbi->biBitCount; /* standard size table */ 1700 } 1701 1702 // fill in some default values if they are zero 1703 if (lpbi->biClrUsed == 0) 1704 lpbi->biClrUsed = nNumColors; 1705 1706 if (lpbi->biSizeImage == 0) 1707 { 1708 lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3) 1709 * lpbi->biHeight; 1710 } 1711 1712 // get a proper-sized buffer for header, color table and bits 1713 GlobalUnlock(hDIB); 1714 hDIBtmp = GlobalReAlloc(hDIB, lpbi->biSize + 1715 nNumColors * sizeof(RGBQUAD) + 1716 lpbi->biSizeImage, 0); 1717 1718 if (!hDIBtmp) // can't resize buffer for loading 1719 goto ErrExitNoUnlock; //MPB 1720 else 1721 hDIB = hDIBtmp; 1722 1723 lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 1724 1725 // read the color table 1726 _lread (hFile, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBQUAD)); 1727 1728 // offset to the bits from start of DIB header 1729 offBits = lpbi->biSize + nNumColors * sizeof(RGBQUAD); 1730 1731 // If the bfOffBits field is non-zero, then the bits might *not* be 1732 // directly following the color table in the file. Use the value in 1733 // bfOffBits to seek the bits. 1734 1735 if (bmfHeader.bfOffBits != 0L) 1736 _llseek(hFile, bmfHeader.bfOffBits, SEEK_SET); 1737 1738 if (MyRead(hFile, (LPSTR)lpbi + offBits, lpbi->biSizeImage)) 1739 goto OKExit; 1740 1741 1742 ErrExit: 1743 GlobalUnlock(hDIB); 1744 ErrExitNoUnlock: 1745 GlobalFree(hDIB); 1746 return NULL; 1747 1748 OKExit: 1749 GlobalUnlock(hDIB); 1750 return hDIB; 1751 } 1752 1753 /************************************************************************* 1754 1755 Function: MyRead (int, LPSTR, DWORD) 1756 1757 Purpose: Routine to read files greater than 64K in size. 1758 1759 Returns: TRUE if successful. 1760 FALSE if an error occurs. 1761 1762 1763 History: Date Author Reason 1764 9/15/91 Mark Bader Based on DIBVIEW 1765 1766 *************************************************************************/ 1767 1768 1769 bool MyRead(int hFile, LPSTR lpBuffer, DWORD dwSize) 1770 { 1771 char *lpInBuf = (char *)lpBuffer; 1772 int nBytes; 1773 1774 /* 1775 * Read in the data in 32767 byte chunks (or a smaller amount if it's 1776 * the last chunk of data read) 1777 */ 1778 1779 while (dwSize) 1780 { 1781 nBytes = (int)(dwSize > (DWORD)32767 ? 32767 : LOWORD (dwSize)); 1782 if (_lread(hFile, (LPSTR)lpInBuf, nBytes) != (WORD)nBytes) 1783 return FALSE; 1784 dwSize -= nBytes; 1785 lpInBuf += nBytes; 1786 } 1787 return TRUE; 1788 } 1789 1790 1791 /**************************************************************************** 1792 1793 FUNCTION : MyWrite(int fh, VOID *pv, DWORD ul) 1794 1795 PURPOSE : Writes data in steps of 32k till all the data is written. 1796 Normal _lwrite uses a WORD as 3rd parameter, so it is 1797 limited to 32767 bytes, but this procedure is not. 1798 1799 RETURNS : 0 - If write did not proceed correctly. 1800 number of bytes written otherwise. 1801 1802 History: Date Author Reason 1803 9/15/91 Mark Bader Based on DIBVIEW 1804 1805 ****************************************************************************/ 1806 1807 1808 DWORD PASCAL MyWrite(int iFileHandle, VOID *lpBuffer, DWORD dwBytes) 1809 { 1810 DWORD dwBytesTmp = dwBytes; // Save # of bytes for return value 1811 BYTE *hpBuffer = (BYTE *)lpBuffer; // make a huge pointer to the data 1812 1813 /* 1814 * Write out the data in 32767 byte chunks. 1815 */ 1816 1817 while (dwBytes > 32767) 1818 { 1819 if (_lwrite(iFileHandle, (LPSTR)hpBuffer, (WORD)32767) != 32767) 1820 return 0; 1821 dwBytes -= 32767; 1822 hpBuffer += 32767; 1823 } 1824 1825 /* Write out the last chunk (which is < 32767 bytes) */ 1826 if (_lwrite(iFileHandle, (LPSTR)hpBuffer, (WORD)dwBytes) != (WORD)dwBytes) 1827 return 0; 1828 return dwBytesTmp; 1829 } 1830 1831 }