DIBUTIL.CPP (39079B)
1 // 2 // Copyright 2020 Electronic Arts Inc. 3 // 4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 5 // software: you can redistribute it and/or modify it under the terms of 6 // the GNU General Public License as published by the Free Software Foundation, 7 // either version 3 of the License, or (at your option) any later version. 8 9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 10 // in the hope that it will be useful, but with permitted additional restrictions 11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 // distributed with this program. You should have received a copy of the 13 // GNU General Public License along with permitted additional restrictions 14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection 15 16 //********************************************************************** 17 // 18 // dibutil.c 19 // 20 // Source file for Device-Independent Bitmap (DIB) API. Provides 21 // the following functions: 22 // 23 // CreateDIB() - Creates new DIB 24 // FindDIBBits() - Sets pointer to the DIB bits 25 // DIBWidth() - Gets the width of the DIB 26 // DIBHeight() - Gets the height of the DIB 27 // PaletteSize() - Calculates the buffer size required by a palette 28 // DIBNumColors() - Calculates number of colors in the DIB's color table 29 // CreateDIBPalette() - Creates a palette from a DIB 30 // DIBToBitmap() - Creates a bitmap from a DIB 31 // BitmapToDIB() - Creates a DIB from a bitmap 32 // PalEntriesOnDevice()- Gets the number of palette entries of a device 33 // GetSystemPalette() - Returns a handle to the current system palette 34 // AllocRoomForDIB() - Allocates memory for a DIB 35 // ChangeDIBFormat() - Changes a DIB's BPP and/or compression format 36 // ChangeBitmapFormat()- Changes a bitmap to a DIB with specified BPP and 37 // compression format 38 // 39 // Development Team: Mark Bader 40 // Patrick Schreiber 41 // Garrett McAuliffe 42 // Eric Flo 43 // Tony Claflin 44 // 45 // Written by Microsoft Product Support Services, Developer Support. 46 // COPYRIGHT: 47 // 48 // (C) Copyright Microsoft Corp. 1993. All rights reserved. 49 // 50 // You have a royalty-free right to use, modify, reproduce and 51 // distribute the Sample Files (and/or any modified version) in 52 // any way you find useful, provided that you agree that 53 // Microsoft has no warranty obligations or liability for any 54 // Sample Application Files which are modified. 55 // 56 //********************************************************************** 57 #if (0) // ST - 5/8/2019 58 /* header files */ 59 #include <windows.h> 60 #include <assert.h> 61 #include "dibapi.h" 62 #include "dibutil.h" 63 #include <stdio.h> 64 65 66 /************************************************************************* 67 * 68 * CreateDIB() 69 * 70 * Parameters: 71 * 72 * DWORD dwWidth - Width for new bitmap, in pixels 73 * DWORD dwHeight - Height for new bitmap 74 * WORD wBitCount - Bit Count for new DIB (1, 4, 8, or 24) 75 * 76 * Return Value: 77 * 78 * HDIB - Handle to new DIB 79 * 80 * Description: 81 * 82 * This function allocates memory for and initializes a new DIB by 83 * filling in the BITMAPINFOHEADER, allocating memory for the color 84 * table, and allocating memory for the bitmap bits. As with all 85 * HDIBs, the header, colortable and bits are all in one contiguous 86 * memory block. This function is similar to the CreateBitmap() 87 * Windows API. 88 * 89 * The colortable and bitmap bits are left uninitialized (zeroed) in the 90 * returned HDIB. 91 * 92 * 93 * History: Date Author Reason 94 * 3/20/92 Mark Bader Created 95 * 96 ************************************************************************/ 97 98 HDIB FAR CreateDIB(DWORD dwWidth, DWORD dwHeight, WORD wBitCount) 99 { 100 BITMAPINFOHEADER bi; // bitmap header 101 LPBITMAPINFOHEADER lpbi; // pointer to BITMAPINFOHEADER 102 DWORD dwLen; // size of memory block 103 HDIB hDIB; 104 DWORD dwBytesPerLine; // Number of bytes per scanline 105 106 107 // Make sure bits per pixel is valid 108 if (wBitCount <= 1) 109 wBitCount = 1; 110 else if (wBitCount <= 4) 111 wBitCount = 4; 112 else if (wBitCount <= 8) 113 wBitCount = 8; 114 else if (wBitCount <= 24) 115 wBitCount = 24; 116 else 117 wBitCount = 4; // set default value to 4 if parameter is bogus 118 119 // initialize BITMAPINFOHEADER 120 bi.biSize = sizeof(BITMAPINFOHEADER); 121 bi.biWidth = dwWidth; // fill in width from parameter 122 bi.biHeight = dwHeight; // fill in height from parameter 123 bi.biPlanes = 1; // must be 1 124 bi.biBitCount = wBitCount; // from parameter 125 bi.biCompression = BI_RGB; 126 bi.biSizeImage = 0; // 0's here mean "default" 127 bi.biXPelsPerMeter = 0; 128 bi.biYPelsPerMeter = 0; 129 bi.biClrUsed = 0; 130 bi.biClrImportant = 0; 131 132 // calculate size of memory block required to store the DIB. This 133 // block should be big enough to hold the BITMAPINFOHEADER, the color 134 // table, and the bits 135 136 dwBytesPerLine = WIDTHBYTES(wBitCount * dwWidth); 137 dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + (dwBytesPerLine * dwHeight); 138 139 // alloc memory block to store our bitmap 140 hDIB = GlobalAlloc(GHND, dwLen); 141 142 // major bummer if we couldn't get memory block 143 if (!hDIB) 144 { 145 return NULL; 146 } 147 148 // lock memory and get pointer to it 149 lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 150 151 // use our bitmap info structure to fill in first part of 152 // our DIB with the BITMAPINFOHEADER 153 *lpbi = bi; 154 155 // Since we don't know what the colortable and bits should contain, 156 // just leave these blank. Unlock the DIB and return the HDIB. 157 158 GlobalUnlock(hDIB); 159 160 /* return handle to the DIB */ 161 return hDIB; 162 } 163 164 165 166 /************************************************************************* 167 * 168 * FindDIBBits() 169 * 170 * Parameter: 171 * 172 * LPSTR lpDIB - pointer to packed-DIB memory block 173 * 174 * Return Value: 175 * 176 * LPSTR - pointer to the DIB bits 177 * 178 * Description: 179 * 180 * This function calculates the address of the DIB's bits and returns a 181 * pointer to the DIB bits. 182 * 183 * History: Date Author Reason 184 * 6/01/91 Garrett McAuliffe Created 185 * 9/15/91 Patrick Schreiber Added header and comments 186 * 187 ************************************************************************/ 188 189 190 LPSTR FAR FindDIBBits(LPCSTR lpDIB) 191 { 192 return (LPSTR)(lpDIB + *(LPDWORD)lpDIB + PaletteSize(lpDIB)); 193 } 194 195 196 /************************************************************************* 197 * 198 * DIBWidth() 199 * 200 * Parameter: 201 * 202 * LPSTR lpDIB - pointer to packed-DIB memory block 203 * 204 * Return Value: 205 * 206 * DWORD - width of the DIB 207 * 208 * Description: 209 * 210 * This function gets the width of the DIB from the BITMAPINFOHEADER 211 * width field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER 212 * width field if it is an OS/2-style DIB. 213 * 214 * History: Date Author Reason 215 * 6/01/91 Garrett McAuliffe Created 216 * 9/15/91 Patrick Schreiber Added header and comments 217 * 218 ************************************************************************/ 219 220 221 DWORD FAR DIBWidth(LPCSTR lpDIB) 222 { 223 LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB 224 LPBITMAPCOREHEADER lpbmc; // pointer to an OS/2-style DIB 225 226 /* point to the header (whether Win 3.0 and OS/2) */ 227 228 lpbmi = (LPBITMAPINFOHEADER)lpDIB; 229 lpbmc = (LPBITMAPCOREHEADER)lpDIB; 230 231 /* return the DIB width if it is a Win 3.0 DIB */ 232 if (lpbmi->biSize == sizeof(BITMAPINFOHEADER)) 233 return lpbmi->biWidth; 234 else /* it is an OS/2 DIB, so return its width */ 235 return (DWORD)lpbmc->bcWidth; 236 } 237 238 239 /************************************************************************* 240 * 241 * DIBHeight() 242 * 243 * Parameter: 244 * 245 * LPSTR lpDIB - pointer to packed-DIB memory block 246 * 247 * Return Value: 248 * 249 * DWORD - height of the DIB 250 * 251 * Description: 252 * 253 * This function gets the height of the DIB from the BITMAPINFOHEADER 254 * height field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER 255 * height field if it is an OS/2-style DIB. 256 * 257 * History: Date Author Reason 258 * 6/01/91 Garrett McAuliffe Created 259 * 9/15/91 Patrick Schreiber Added header and comments 260 * 261 ************************************************************************/ 262 263 264 DWORD FAR DIBHeight(LPCSTR lpDIB) 265 { 266 LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB 267 LPBITMAPCOREHEADER lpbmc; // pointer to an OS/2-style DIB 268 269 /* point to the header (whether OS/2 or Win 3.0 */ 270 271 lpbmi = (LPBITMAPINFOHEADER)lpDIB; 272 lpbmc = (LPBITMAPCOREHEADER)lpDIB; 273 274 /* return the DIB height if it is a Win 3.0 DIB */ 275 if (lpbmi->biSize == sizeof(BITMAPINFOHEADER)) 276 return lpbmi->biHeight; 277 else /* it is an OS/2 DIB, so return its height */ 278 return (DWORD)lpbmc->bcHeight; 279 } 280 281 282 /************************************************************************* 283 * 284 * PaletteSize() 285 * 286 * Parameter: 287 * 288 * LPSTR lpDIB - pointer to packed-DIB memory block 289 * 290 * Return Value: 291 * 292 * WORD - size of the color palette of the DIB 293 * 294 * Description: 295 * 296 * This function gets the size required to store the DIB's palette by 297 * multiplying the number of colors by the size of an RGBQUAD (for a 298 * Windows 3.0-style DIB) or by the size of an RGBTRIPLE (for an OS/2- 299 * style DIB). 300 * 301 * History: Date Author Reason 302 * 6/01/91 Garrett McAuliffe Created 303 * 9/15/91 Patrick Schreiber Added header and comments 304 * 305 ************************************************************************/ 306 307 308 WORD FAR PaletteSize(LPCSTR lpDIB) 309 { 310 /* calculate the size required by the palette */ 311 if (IS_WIN30_DIB (lpDIB)) 312 return (WORD FAR)(DIBNumColors(lpDIB) * sizeof(RGBQUAD)); 313 else 314 return (WORD FAR)(DIBNumColors(lpDIB) * sizeof(RGBTRIPLE)); 315 } 316 317 318 /************************************************************************* 319 * 320 * DIBNumColors() 321 * 322 * Parameter: 323 * 324 * LPSTR lpDIB - pointer to packed-DIB memory block 325 * 326 * Return Value: 327 * 328 * WORD - number of colors in the color table 329 * 330 * Description: 331 * 332 * This function calculates the number of colors in the DIB's color table 333 * by finding the bits per pixel for the DIB (whether Win3.0 or OS/2-style 334 * DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256, 335 * if 24, no colors in color table. 336 * 337 * History: Date Author Reason 338 * 6/01/91 Garrett McAuliffe Created 339 * 9/15/91 Patrick Schreiber Added header and comments 340 * 341 ************************************************************************/ 342 343 344 WORD FAR DIBNumColors(LPCSTR lpDIB) 345 { 346 WORD wBitCount; // DIB bit count 347 348 /* If this is a Windows-style DIB, the number of colors in the 349 * color table can be less than the number of bits per pixel 350 * allows for (i.e. lpbi->biClrUsed can be set to some value). 351 * If this is the case, return the appropriate value. 352 */ 353 354 if (IS_WIN30_DIB(lpDIB)) 355 { 356 DWORD dwClrUsed; 357 358 dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed; 359 if (dwClrUsed) 360 return (WORD)dwClrUsed; 361 } 362 363 /* Calculate the number of colors in the color table based on 364 * the number of bits per pixel for the DIB. 365 */ 366 if (IS_WIN30_DIB(lpDIB)) 367 wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount; 368 else 369 wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount; 370 371 /* return number of colors based on bits per pixel */ 372 switch (wBitCount) 373 { 374 case 1: 375 return 2; 376 377 case 4: 378 return 16; 379 380 case 8: 381 return 256; 382 383 default: 384 return 0; 385 } 386 } 387 388 389 /************************************************************************* 390 * 391 * CreateDIBPalette() 392 * 393 * Parameter: 394 * 395 * HDIB hDIB - specifies the DIB 396 * 397 * Return Value: 398 * 399 * HPALETTE - specifies the palette 400 * 401 * Description: 402 * 403 * This function creates a palette from a DIB by allocating memory for the 404 * logical palette, reading and storing the colors from the DIB's color table 405 * into the logical palette, creating a palette from this logical palette, 406 * and then returning the palette's handle. This allows the DIB to be 407 * displayed using the best possible colors (important for DIBs with 256 or 408 * more colors). 409 * 410 * History: Date Author Reason 411 * 6/01/91 Garrett McAuliffe Created 412 * 9/15/91 Patrick Schreiber Added header and comments 413 * 414 ************************************************************************/ 415 416 417 HPALETTE FAR CreateDIBPalette(HDIB hDIB) 418 { 419 LPLOGPALETTE lpPal; // pointer to a logical palette 420 HANDLE hLogPal; // handle to a logical palette 421 HPALETTE hPal = NULL; // handle to a palette 422 int i, wNumColors; // loop index, number of colors in color table 423 LPSTR lpbi; // pointer to packed-DIB 424 LPBITMAPINFO lpbmi; // pointer to BITMAPINFO structure (Win3.0) 425 LPBITMAPCOREINFO lpbmc; // pointer to BITMAPCOREINFO structure (OS/2) 426 BOOL bWinStyleDIB; // flag which signifies whether this is a Win3.0 DIB 427 428 /* if handle to DIB is invalid, return NULL */ 429 430 if (!hDIB) 431 return NULL; 432 433 /* lock DIB memory block and get a pointer to it */ 434 lpbi = (LPSTR)GlobalLock(hDIB); 435 436 /* get pointer to BITMAPINFO (Win 3.0) */ 437 lpbmi = (LPBITMAPINFO)lpbi; 438 439 /* get pointer to BITMAPCOREINFO (OS/2 1.x) */ 440 lpbmc = (LPBITMAPCOREINFO)lpbi; 441 442 /* get the number of colors in the DIB */ 443 wNumColors = DIBNumColors(lpbi); 444 445 /* is this a Win 3.0 DIB? */ 446 bWinStyleDIB = IS_WIN30_DIB(lpbi); 447 if (wNumColors) 448 { 449 /* allocate memory block for logical palette */ 450 hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * 451 wNumColors); 452 453 /* if not enough memory, clean up and return NULL */ 454 if (!hLogPal) 455 { 456 GlobalUnlock(hDIB); 457 return NULL; 458 } 459 460 /* lock memory block and get pointer to it */ 461 lpPal = (LPLOGPALETTE)GlobalLock(hLogPal); 462 463 /* set version and number of palette entries */ 464 lpPal->palVersion = PALVERSION; 465 lpPal->palNumEntries = (WORD)wNumColors; 466 467 /* store RGB triples (if Win 3.0 DIB) or RGB quads (if OS/2 DIB) 468 * into palette 469 */ 470 for (i = 0; i < wNumColors; i++) 471 { 472 if (bWinStyleDIB) 473 { 474 lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed; 475 lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen; 476 lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue; 477 lpPal->palPalEntry[i].peFlags = 0; 478 } 479 else 480 { 481 lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed; 482 lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen; 483 lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue; 484 lpPal->palPalEntry[i].peFlags = 0; 485 } 486 } 487 488 /* create the palette and get handle to it */ 489 hPal = CreatePalette(lpPal); 490 491 /* if error getting handle to palette, clean up and return NULL */ 492 if (!hPal) 493 { 494 GlobalUnlock(hLogPal); 495 GlobalFree(hLogPal); 496 return NULL; 497 } 498 } 499 500 /* clean up */ 501 GlobalUnlock(hLogPal); 502 GlobalFree(hLogPal); 503 GlobalUnlock(hDIB); 504 505 /* return handle to DIB's palette */ 506 return hPal; 507 } 508 509 510 /************************************************************************* 511 * 512 * DIBToBitmap() 513 * 514 * Parameters: 515 * 516 * HDIB hDIB - specifies the DIB to convert 517 * 518 * HPALETTE hPal - specifies the palette to use with the bitmap 519 * 520 * Return Value: 521 * 522 * HBITMAP - identifies the device-dependent bitmap 523 * 524 * Description: 525 * 526 * This function creates a bitmap from a DIB using the specified palette. 527 * If no palette is specified, default is used. 528 * 529 * NOTE: 530 * 531 * The bitmap returned from this funciton is always a bitmap compatible 532 * with the screen (e.g. same bits/pixel and color planes) rather than 533 * a bitmap with the same attributes as the DIB. This behavior is by 534 * design, and occurs because this function calls CreateDIBitmap to 535 * do its work, and CreateDIBitmap always creates a bitmap compatible 536 * with the hDC parameter passed in (because it in turn calls 537 * CreateCompatibleBitmap). 538 * 539 * So for instance, if your DIB is a monochrome DIB and you call this 540 * function, you will not get back a monochrome HBITMAP -- you will 541 * get an HBITMAP compatible with the screen DC, but with only 2 542 * colors used in the bitmap. 543 * 544 * If your application requires a monochrome HBITMAP returned for a 545 * monochrome DIB, use the function SetDIBits(). 546 * 547 * Also, the DIBpassed in to the function is not destroyed on exit. This 548 * must be done later, once it is no longer needed. 549 * 550 * History: Date Author Reason 551 * 6/01/91 Garrett McAuliffe Created 552 * 9/15/91 Patrick Schreiber Added header and comments 553 * 3/27/92 Mark Bader Added comments about resulting 554 * bitmap format 555 * 556 ************************************************************************/ 557 558 559 HBITMAP FAR DIBToBitmap(HDIB hDIB, HPALETTE hPal) 560 { 561 LPSTR lpDIBHdr, lpDIBBits; // pointer to DIB header, pointer to DIB bits 562 HBITMAP hBitmap; // handle to device-dependent bitmap 563 HDC hDC; // handle to DC 564 HPALETTE hOldPal = NULL; // handle to a palette 565 566 /* if invalid handle, return NULL */ 567 568 if (!hDIB) 569 return NULL; 570 571 /* lock memory block and get a pointer to it */ 572 lpDIBHdr = (LPSTR)GlobalLock(hDIB); 573 574 /* get a pointer to the DIB bits */ 575 lpDIBBits = FindDIBBits(lpDIBHdr); 576 577 /* get a DC */ 578 hDC = GetDC(NULL); 579 if (!hDC) 580 { 581 /* clean up and return NULL */ 582 GlobalUnlock(hDIB); 583 return NULL; 584 } 585 586 /* select and realize palette */ 587 if (hPal) 588 hOldPal = SelectPalette(hDC, hPal, FALSE); 589 RealizePalette(hDC); 590 591 /* create bitmap from DIB info. and bits */ 592 hBitmap = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)lpDIBHdr, CBM_INIT, 593 lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS); 594 595 /* restore previous palette */ 596 if (hOldPal) 597 SelectPalette(hDC, hOldPal, FALSE); 598 599 /* clean up */ 600 ReleaseDC(NULL, hDC); 601 GlobalUnlock(hDIB); 602 603 /* return handle to the bitmap */ 604 return hBitmap; 605 } 606 607 608 /************************************************************************* 609 * 610 * BitmapToDIB() 611 * 612 * Parameters: 613 * 614 * HBITMAP hBitmap - specifies the bitmap to convert 615 * 616 * HPALETTE hPal - specifies the palette to use with the bitmap 617 * 618 * Return Value: 619 * 620 * HDIB - identifies the device-dependent bitmap 621 * 622 * Description: 623 * 624 * This function creates a DIB from a bitmap using the specified palette. 625 * 626 * History: Date Author Reason 627 * 6/01/91 Garrett McAuliffe Created 628 * 9/15/91 Patrick Schreiber Added header and comments 629 * 12/10/91 Patrick Schreiber Added bits per pixel validation 630 * and check GetObject return value 631 * 632 ************************************************************************/ 633 634 635 HDIB FAR BitmapToDIB(HBITMAP hBitmap, HPALETTE hPal) 636 { 637 BITMAP bm; // bitmap structure 638 BITMAPINFOHEADER bi; // bitmap header 639 BITMAPINFOHEADER FAR *lpbi; // pointer to BITMAPINFOHEADER 640 DWORD dwLen; // size of memory block 641 HANDLE hDIB, h; // handle to DIB, temp handle 642 HDC hDC; // handle to DC 643 WORD biBits; // bits per pixel 644 645 /* check if bitmap handle is valid */ 646 647 if (!hBitmap) 648 return NULL; 649 650 /* fill in BITMAP structure, return NULL if it didn't work */ 651 if (!GetObject(hBitmap, sizeof(bm), (LPSTR)&bm)) 652 return NULL; 653 654 /* if no palette is specified, use default palette */ 655 if (hPal == NULL) 656 hPal = GetStockObject(DEFAULT_PALETTE); 657 658 /* calculate bits per pixel */ 659 biBits = (WORD)( bm.bmPlanes * bm.bmBitsPixel ); 660 661 /* make sure bits per pixel is valid */ 662 if (biBits <= 1) 663 biBits = 1; 664 else if (biBits <= 4) 665 biBits = 4; 666 else if (biBits <= 8) 667 biBits = 8; 668 else /* if greater than 8-bit, force to 24-bit */ 669 biBits = 24; 670 671 /* initialize BITMAPINFOHEADER */ 672 bi.biSize = sizeof(BITMAPINFOHEADER); 673 bi.biWidth = bm.bmWidth; 674 bi.biHeight = bm.bmHeight; 675 bi.biPlanes = 1; 676 bi.biBitCount = biBits; 677 bi.biCompression = BI_RGB; 678 bi.biSizeImage = 0; 679 bi.biXPelsPerMeter = 0; 680 bi.biYPelsPerMeter = 0; 681 bi.biClrUsed = 0; 682 bi.biClrImportant = 0; 683 684 /* calculate size of memory block required to store BITMAPINFO */ 685 dwLen = bi.biSize + PaletteSize((LPSTR)&bi); 686 687 /* get a DC */ 688 hDC = GetDC(NULL); 689 690 /* select and realize our palette */ 691 hPal = SelectPalette(hDC, hPal, FALSE); 692 RealizePalette(hDC); 693 694 /* alloc memory block to store our bitmap */ 695 hDIB = GlobalAlloc(GHND, dwLen); 696 697 /* if we couldn't get memory block */ 698 if (!hDIB) 699 { 700 /* clean up and return NULL */ 701 SelectPalette(hDC, hPal, TRUE); 702 RealizePalette(hDC); 703 ReleaseDC(NULL, hDC); 704 return NULL; 705 } 706 707 /* lock memory and get pointer to it */ 708 lpbi = (BITMAPINFOHEADER FAR *)GlobalLock(hDIB); 709 710 /* use our bitmap info. to fill BITMAPINFOHEADER */ 711 *lpbi = bi; 712 713 /* call GetDIBits with a NULL lpBits param, so it will calculate the 714 * biSizeImage field for us 715 */ 716 GetDIBits(hDC, hBitmap, 0, (WORD)bi.biHeight, NULL, (LPBITMAPINFO)lpbi, 717 DIB_RGB_COLORS); 718 719 /* get the info. returned by GetDIBits and unlock memory block */ 720 bi = *lpbi; 721 GlobalUnlock(hDIB); 722 723 /* if the driver did not fill in the biSizeImage field, make one up */ 724 if (bi.biSizeImage == 0) 725 bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight; 726 727 /* realloc the buffer big enough to hold all the bits */ 728 dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + bi.biSizeImage; 729 h = GlobalReAlloc(hDIB, dwLen, 0); 730 if (h) 731 hDIB = h; 732 else 733 { 734 /* clean up and return NULL */ 735 GlobalFree(hDIB); 736 hDIB = NULL; 737 SelectPalette(hDC, hPal, TRUE); 738 RealizePalette(hDC); 739 ReleaseDC(NULL, hDC); 740 return NULL; 741 } 742 743 /* lock memory block and get pointer to it */ 744 lpbi = (BITMAPINFOHEADER FAR *)GlobalLock(hDIB); 745 746 /* call GetDIBits with a NON-NULL lpBits param, and actualy get the 747 * bits this time 748 */ 749 if (GetDIBits(hDC, hBitmap, 0, (WORD)bi.biHeight, (LPSTR)lpbi + (WORD)lpbi 750 ->biSize + PaletteSize((LPSTR)lpbi), (LPBITMAPINFO)lpbi, 751 DIB_RGB_COLORS) == 0) 752 { 753 /* clean up and return NULL */ 754 GlobalUnlock(hDIB); 755 hDIB = NULL; 756 SelectPalette(hDC, hPal, TRUE); 757 RealizePalette(hDC); 758 ReleaseDC(NULL, hDC); 759 return NULL; 760 } 761 bi = *lpbi; 762 763 /* clean up */ 764 GlobalUnlock(hDIB); 765 SelectPalette(hDC, hPal, TRUE); 766 RealizePalette(hDC); 767 ReleaseDC(NULL, hDC); 768 769 /* return handle to the DIB */ 770 return hDIB; 771 } 772 773 774 /************************************************************************* 775 * 776 * PalEntriesOnDevice() 777 * 778 * Parameter: 779 * 780 * HDC hDC - device context 781 * 782 * Return Value: 783 * 784 * int - number of palette entries on device 785 * 786 * Description: 787 * 788 * This function gets the number of palette entries on the specified device 789 * 790 * History: Date Author Reason 791 * 6/01/91 Garrett McAuliffe Created 792 * 9/15/91 Patrick Schreiber Added header and comments 793 * 794 ************************************************************************/ 795 796 797 int FAR PalEntriesOnDevice(HDC hDC) 798 { 799 int nColors; // number of colors 800 801 /* Find out the number of palette entries on this 802 * device. 803 */ 804 805 nColors = GetDeviceCaps(hDC, SIZEPALETTE); 806 807 /* For non-palette devices, we'll use the # of system 808 * colors for our palette size. 809 */ 810 if (!nColors) 811 nColors = GetDeviceCaps(hDC, NUMCOLORS); 812 assert(nColors); 813 return nColors; 814 } 815 816 817 /************************************************************************* 818 * 819 * GetSystemPalette() 820 * 821 * Parameters: 822 * 823 * None 824 * 825 * Return Value: 826 * 827 * HPALETTE - handle to a copy of the current system palette 828 * 829 * Description: 830 * 831 * This function returns a handle to a palette which represents the system 832 * palette. The system RGB values are copied into our logical palette using 833 * the GetSystemPaletteEntries function. 834 * 835 * History: 836 * 837 * Date Author Reason 838 * 6/01/91 Garrett McAuliffe Created 839 * 9/15/91 Patrick Schreiber Added header and comments 840 * 12/20/91 Mark Bader Added GetSystemPaletteEntries call 841 * 842 ************************************************************************/ 843 844 845 HPALETTE FAR GetSystemPalette(void) 846 { 847 HDC hDC; // handle to a DC 848 static HPALETTE hPal = NULL; // handle to a palette 849 HANDLE hLogPal; // handle to a logical palette 850 LPLOGPALETTE lpLogPal; // pointer to a logical palette 851 int nColors; // number of colors 852 853 /* Find out how many palette entries we want. */ 854 855 hDC = GetDC(NULL); 856 if (!hDC) 857 return NULL; 858 nColors = PalEntriesOnDevice(hDC); // Number of palette entries 859 860 /* Allocate room for the palette and lock it. */ 861 hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + nColors * sizeof( 862 PALETTEENTRY)); 863 864 /* if we didn't get a logical palette, return NULL */ 865 if (!hLogPal) 866 return NULL; 867 868 /* get a pointer to the logical palette */ 869 lpLogPal = (LPLOGPALETTE)GlobalLock(hLogPal); 870 871 /* set some important fields */ 872 lpLogPal->palVersion = (WORD)PALVERSION; 873 lpLogPal->palNumEntries = (WORD)nColors; 874 875 /* Copy the current system palette into our logical palette */ 876 877 GetSystemPaletteEntries(hDC, 0, nColors, 878 (LPPALETTEENTRY)(lpLogPal->palPalEntry)); 879 880 /* Go ahead and create the palette. Once it's created, 881 * we no longer need the LOGPALETTE, so free it. 882 */ 883 884 hPal = CreatePalette(lpLogPal); 885 886 /* clean up */ 887 GlobalUnlock(hLogPal); 888 GlobalFree(hLogPal); 889 ReleaseDC(NULL, hDC); 890 891 return hPal; 892 } 893 894 895 /************************************************************************* 896 * 897 * AllocRoomForDIB() 898 * 899 * Parameters: 900 * 901 * BITMAPINFOHEADER - bitmap info header stucture 902 * 903 * HBITMAP - handle to the bitmap 904 * 905 * Return Value: 906 * 907 * HDIB - handle to memory block 908 * 909 * Description: 910 * 911 * This routine takes a BITMAPINOHEADER, and returns a handle to global 912 * memory which can contain a DIB with that header. It also initializes 913 * the header portion of the global memory. GetDIBits() is used to determine 914 * the amount of room for the DIB's bits. The total amount of memory 915 * needed = sizeof(BITMAPINFOHEADER) + size of color table + size of bits. 916 * 917 * History: Date Author Reason 918 * 6/01/91 Garrett McAuliffe Created 919 * 12/11/91 Patrick Schreiber Added header and some comments 920 * 921 ************************************************************************/ 922 923 HANDLE AllocRoomForDIB(BITMAPINFOHEADER bi, HBITMAP hBitmap) 924 { 925 DWORD dwLen; 926 HANDLE hDIB; 927 HDC hDC; 928 LPBITMAPINFOHEADER lpbi; 929 HANDLE hTemp; 930 931 /* Figure out the size needed to hold the BITMAPINFO structure 932 * (which includes the BITMAPINFOHEADER and the color table). 933 */ 934 935 dwLen = bi.biSize + PaletteSize((LPSTR) &bi); 936 hDIB = GlobalAlloc(GHND,dwLen); 937 938 /* Check that DIB handle is valid */ 939 if (!hDIB) 940 return NULL; 941 942 /* Set up the BITMAPINFOHEADER in the newly allocated global memory, 943 * then call GetDIBits() with lpBits = NULL to have it fill in the 944 * biSizeImage field for us. 945 */ 946 lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 947 *lpbi = bi; 948 949 hDC = GetDC(NULL); 950 GetDIBits(hDC, hBitmap, 0, (WORD) bi.biHeight, 951 NULL, (LPBITMAPINFO) lpbi, DIB_RGB_COLORS); 952 ReleaseDC(NULL, hDC); 953 954 /* If the driver did not fill in the biSizeImage field, 955 * fill it in -- NOTE: this is a bug in the driver! 956 */ 957 if (lpbi->biSizeImage == 0) 958 lpbi->biSizeImage = WIDTHBYTES((DWORD)lpbi->biWidth * lpbi->biBitCount) * 959 lpbi->biHeight; 960 961 /* Get the size of the memory block we need */ 962 dwLen = lpbi->biSize + PaletteSize((LPSTR) &bi) + lpbi->biSizeImage; 963 964 /* Unlock the memory block */ 965 GlobalUnlock(hDIB); 966 967 /* ReAlloc the buffer big enough to hold all the bits */ 968 hTemp = GlobalReAlloc(hDIB,dwLen,0); 969 if (hTemp) 970 return hTemp; 971 else 972 { 973 /* Else free memory block and return failure */ 974 GlobalFree(hDIB); 975 return NULL; 976 } 977 } 978 979 980 /************************************************************************* 981 * 982 * ChangeDIBFormat() 983 * 984 * Parameter: 985 * 986 * HDIB - handle to packed-DIB in memory 987 * 988 * WORD - desired bits per pixel 989 * 990 * DWORD - desired compression format 991 * 992 * Return Value: 993 * 994 * HDIB - handle to the new DIB if successful, else NULL 995 * 996 * Description: 997 * 998 * This function will convert the bits per pixel and/or the compression 999 * format of the specified DIB. Note: If the conversion was unsuccessful, 1000 * we return NULL. The original DIB is left alone. Don't use code like the 1001 * following: 1002 * 1003 * hMyDIB = ChangeDIBFormat(hMyDIB, 8, BI_RLE4); 1004 * 1005 * The conversion will fail, but hMyDIB will now be NULL and the original 1006 * DIB will now hang around in memory. We could have returned the old 1007 * DIB, but we wanted to allow the programmer to check whether this 1008 * conversion succeeded or failed. 1009 * 1010 * History: 1011 * 1012 * Date Author Reason 1013 * 6/01/91 Garrett McAuliffe Created 1014 * 12/10/91 Patrick Schreiber Modified from converting RGB to RLE8 1015 * to converting RGB/RLE to RGB/RLE. 1016 * Added wBitCount and dwCompression 1017 * parameters. Also added header and 1018 * comments. 1019 * 1020 ************************************************************************/ 1021 1022 HDIB FAR ChangeDIBFormat(HDIB hDIB, WORD wBitCount, DWORD dwCompression) 1023 { 1024 HDC hDC; // Handle to DC 1025 HBITMAP hBitmap; // Handle to bitmap 1026 BITMAP Bitmap; // BITMAP data structure 1027 BITMAPINFOHEADER bi; // Bitmap info header 1028 LPBITMAPINFOHEADER lpbi; // Pointer to bitmap info 1029 HDIB hNewDIB = NULL; // Handle to new DIB 1030 HPALETTE hPal, hOldPal; // Handle to palette, prev pal 1031 WORD DIBBPP, NewBPP; // DIB bits per pixel, new bpp 1032 DWORD DIBComp, NewComp;// DIB compression, new compression 1033 1034 /* Check for a valid DIB handle */ 1035 if (!hDIB) 1036 return NULL; 1037 1038 /* Get the old DIB's bits per pixel and compression format */ 1039 lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 1040 DIBBPP = ((LPBITMAPINFOHEADER)lpbi)->biBitCount; 1041 DIBComp = ((LPBITMAPINFOHEADER)lpbi)->biCompression; 1042 GlobalUnlock(hDIB); 1043 1044 /* Validate wBitCount and dwCompression 1045 * They must match correctly (i.e., BI_RLE4 and 4 BPP or 1046 * BI_RLE8 and 8BPP, etc.) or we return failure */ 1047 if (wBitCount == 0) 1048 { 1049 NewBPP = DIBBPP; 1050 if ((dwCompression == BI_RLE4 && NewBPP == 4) || 1051 (dwCompression == BI_RLE8 && NewBPP == 8) || 1052 (dwCompression == BI_RGB)) 1053 NewComp = dwCompression; 1054 else 1055 return NULL; 1056 } 1057 else if (wBitCount == 1 && dwCompression == BI_RGB) 1058 { 1059 NewBPP = wBitCount; 1060 NewComp = BI_RGB; 1061 } 1062 else if (wBitCount == 4) 1063 { 1064 NewBPP = wBitCount; 1065 if (dwCompression == BI_RGB || dwCompression == BI_RLE4) 1066 NewComp = dwCompression; 1067 else 1068 return NULL; 1069 } 1070 else if (wBitCount == 8) 1071 { 1072 NewBPP = wBitCount; 1073 if (dwCompression == BI_RGB || dwCompression == BI_RLE8) 1074 NewComp = dwCompression; 1075 else 1076 return NULL; 1077 } 1078 else if (wBitCount == 24 && dwCompression == BI_RGB) 1079 { 1080 NewBPP = wBitCount; 1081 NewComp = BI_RGB; 1082 } 1083 else 1084 return NULL; 1085 1086 /* Save the old DIB's palette */ 1087 hPal = CreateDIBPalette(hDIB); 1088 if (!hPal) 1089 return NULL; 1090 1091 /* Convert old DIB to a bitmap */ 1092 hBitmap = DIBToBitmap(hDIB, hPal); 1093 if (!hBitmap) 1094 { 1095 DeleteObject(hPal); 1096 return NULL; 1097 } 1098 1099 /* Get info about the bitmap */ 1100 GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap); 1101 1102 /* Fill in the BITMAPINFOHEADER appropriately */ 1103 bi.biSize = sizeof(BITMAPINFOHEADER); 1104 bi.biWidth = Bitmap.bmWidth; 1105 bi.biHeight = Bitmap.bmHeight; 1106 bi.biPlanes = 1; 1107 bi.biBitCount = NewBPP; 1108 bi.biCompression = NewComp; 1109 bi.biSizeImage = 0; 1110 bi.biXPelsPerMeter = 0; 1111 bi.biYPelsPerMeter = 0; 1112 bi.biClrUsed = 0; 1113 bi.biClrImportant = 0; 1114 1115 /* Go allocate room for the new DIB */ 1116 hNewDIB = AllocRoomForDIB(bi, hBitmap); 1117 if (!hNewDIB) 1118 return NULL; 1119 1120 /* Get a pointer to the new DIB */ 1121 lpbi = (LPBITMAPINFOHEADER)GlobalLock(hNewDIB); 1122 1123 /* Get a DC and select/realize our palette in it */ 1124 hDC = GetDC(NULL); 1125 hOldPal = SelectPalette(hDC, hPal, FALSE); 1126 RealizePalette(hDC); 1127 1128 /* Call GetDIBits and get the new DIB bits */ 1129 if (!GetDIBits(hDC, hBitmap, 0, (WORD) lpbi->biHeight, 1130 (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi), 1131 (LPBITMAPINFO)lpbi, DIB_RGB_COLORS)) 1132 { 1133 GlobalUnlock(hNewDIB); 1134 GlobalFree(hNewDIB); 1135 hNewDIB = NULL; 1136 } 1137 1138 /* Clean up and return */ 1139 SelectPalette(hDC, hOldPal, TRUE); 1140 RealizePalette(hDC); 1141 ReleaseDC(NULL, hDC); 1142 1143 if (hNewDIB) 1144 /* Unlock the new DIB's memory block */ 1145 GlobalUnlock(hNewDIB); 1146 1147 DeleteObject(hBitmap); 1148 DeleteObject(hPal); 1149 1150 return hNewDIB; 1151 } 1152 1153 1154 /************************************************************************* 1155 * 1156 * ChangeBitmapFormat() 1157 * 1158 * Parameter: 1159 * 1160 * HBITMAP - handle to a bitmap 1161 * 1162 * WORD - desired bits per pixel 1163 * 1164 * DWORD - desired compression format 1165 * 1166 * HPALETTE - handle to palette 1167 * 1168 * Return Value: 1169 * 1170 * HDIB - handle to the new DIB if successful, else NULL 1171 * 1172 * Description: 1173 * 1174 * This function will convert a bitmap to the specified bits per pixel 1175 * and compression format. The bitmap and it's palette will remain 1176 * after calling this function. 1177 * 1178 * History: 1179 * 1180 * Date Author Reason 1181 * 6/01/91 Garrett McAuliffe Created 1182 * 12/10/91 Patrick Schreiber Modified from converting RGB to RLE8 1183 * to converting RGB/RLE to RGB/RLE. 1184 * Added wBitCount and dwCompression 1185 * parameters. Also added header and 1186 * comments. 1187 * 12/11/91 Patrick Schreiber Destroy old DIB if conversion was 1188 * successful. 1189 * 12/16/91 Patrick Schreiber Modified from converting DIB to new 1190 * DIB to bitmap to new DIB. Added palette 1191 * parameter. 1192 * 1193 ************************************************************************/ 1194 1195 HDIB FAR ChangeBitmapFormat(HBITMAP hBitmap, 1196 WORD wBitCount, 1197 DWORD dwCompression, 1198 HPALETTE hPal) 1199 { 1200 HDC hDC; // Screen DC 1201 HDIB hNewDIB=NULL; // Handle to new DIB 1202 BITMAP Bitmap; // BITMAP data structure 1203 BITMAPINFOHEADER bi; // Bitmap info. header 1204 LPBITMAPINFOHEADER lpbi; // Pointer to bitmap header 1205 HPALETTE hOldPal=NULL; // Handle to palette 1206 WORD NewBPP; // New bits per pixel 1207 DWORD NewComp; // New compression format 1208 1209 /* Check for a valid bitmap handle */ 1210 if (!hBitmap) 1211 return NULL; 1212 1213 /* Validate wBitCount and dwCompression 1214 * They must match correctly (i.e., BI_RLE4 and 4 BPP or 1215 * BI_RLE8 and 8BPP, etc.) or we return failure 1216 */ 1217 if (wBitCount == 0) 1218 { 1219 NewComp = dwCompression; 1220 if (NewComp == BI_RLE4) 1221 NewBPP = 4; 1222 else if (NewComp == BI_RLE8) 1223 NewBPP = 8; 1224 else /* Not enough info */ 1225 return NULL; 1226 } 1227 else if (wBitCount == 1 && dwCompression == BI_RGB) 1228 { 1229 NewBPP = wBitCount; 1230 NewComp = BI_RGB; 1231 } 1232 else if (wBitCount == 4) 1233 { 1234 NewBPP = wBitCount; 1235 if (dwCompression == BI_RGB || dwCompression == BI_RLE4) 1236 NewComp = dwCompression; 1237 else 1238 return NULL; 1239 } 1240 else if (wBitCount == 8) 1241 { 1242 NewBPP = wBitCount; 1243 if (dwCompression == BI_RGB || dwCompression == BI_RLE8) 1244 NewComp = dwCompression; 1245 else 1246 return NULL; 1247 } 1248 else if (wBitCount == 24 && dwCompression == BI_RGB) 1249 { 1250 NewBPP = wBitCount; 1251 NewComp = BI_RGB; 1252 } 1253 else 1254 return NULL; 1255 1256 /* Get info about the bitmap */ 1257 GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap); 1258 1259 /* Fill in the BITMAPINFOHEADER appropriately */ 1260 bi.biSize = sizeof(BITMAPINFOHEADER); 1261 bi.biWidth = Bitmap.bmWidth; 1262 bi.biHeight = Bitmap.bmHeight; 1263 bi.biPlanes = 1; 1264 bi.biBitCount = NewBPP; 1265 bi.biCompression = NewComp; 1266 bi.biSizeImage = 0; 1267 bi.biXPelsPerMeter = 0; 1268 bi.biYPelsPerMeter = 0; 1269 bi.biClrUsed = 0; 1270 bi.biClrImportant = 0; 1271 1272 /* Go allocate room for the new DIB */ 1273 hNewDIB = AllocRoomForDIB(bi, hBitmap); 1274 if (!hNewDIB) 1275 return NULL; 1276 1277 /* Get a pointer to the new DIB */ 1278 lpbi = (LPBITMAPINFOHEADER)GlobalLock(hNewDIB); 1279 1280 /* If we have a palette, get a DC and select/realize it */ 1281 if (hPal) 1282 { 1283 hDC = GetDC(NULL); 1284 hOldPal = SelectPalette(hDC, hPal, FALSE); 1285 RealizePalette(hDC); 1286 } 1287 1288 /* Call GetDIBits and get the new DIB bits */ 1289 if (!GetDIBits(hDC, hBitmap, 0, (WORD) lpbi->biHeight, 1290 (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi), 1291 (LPBITMAPINFO)lpbi, DIB_RGB_COLORS)) 1292 { 1293 GlobalUnlock(hNewDIB); 1294 GlobalFree(hNewDIB); 1295 hNewDIB = NULL; 1296 } 1297 1298 /* Clean up and return */ 1299 if (hOldPal) 1300 { 1301 SelectPalette(hDC, hOldPal, TRUE); 1302 RealizePalette(hDC); 1303 ReleaseDC(NULL, hDC); 1304 } 1305 1306 if (hNewDIB) 1307 { 1308 /* Unlock the new DIB's memory block */ 1309 GlobalUnlock(hNewDIB); 1310 } 1311 1312 return hNewDIB; 1313 } 1314 #endif