/ windows / pvbitmap.cpp
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  }