CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

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