1831 lines
52 KiB
C++
1831 lines
52 KiB
C++
/*******************************************************************************
|
|
* pvbitmap.cpp
|
|
*
|
|
* Provides an API for bitmap manipulation.
|
|
*
|
|
* This file is derived from Microsoft sample source and is used by permission.
|
|
*
|
|
* ---------------------------------------------------------------------------
|
|
* Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
|
|
* Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.
|
|
*
|
|
* POV-Ray is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* POV-Ray is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
* ---------------------------------------------------------------------------
|
|
* POV-Ray is based on the popular DKB raytracer version 2.12.
|
|
* DKBTrace was originally written by David K. Buck.
|
|
* DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
|
|
* ---------------------------------------------------------------------------
|
|
* $File: //depot/public/povray/3.x/windows/pvbitmap.cpp $
|
|
* $Revision: #1 $
|
|
* $Change: 6069 $
|
|
* $DateTime: 2013/11/06 11:59:40 $
|
|
* $Author: chrisc $
|
|
*******************************************************************************/
|
|
|
|
#define POVWIN_FILE
|
|
#define _WIN32_IE COMMONCTRL_VERSION
|
|
|
|
#include <windows.h>
|
|
#include <string.h>
|
|
#include "pvengine.h"
|
|
#include "pvbitmap.h"
|
|
#include "pvdisplay.h"
|
|
|
|
// this must be the last file included
|
|
#include "syspovdebug.h"
|
|
|
|
#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')
|
|
|
|
/*********************************************************************
|
|
*
|
|
* Local Function Prototypes
|
|
*
|
|
*********************************************************************/
|
|
|
|
namespace povwin
|
|
{
|
|
|
|
HANDLE ReadDIBFile(int);
|
|
bool MyRead(int, LPSTR, DWORD);
|
|
bool SaveDIBFile(void);
|
|
bool WriteDIB(LPSTR, HANDLE);
|
|
DWORD PASCAL MyWrite(int, VOID *, DWORD);
|
|
|
|
extern int render_bitmap_depth ;
|
|
extern HPALETTE hPalBitmap ;
|
|
|
|
/*************************************************************************
|
|
*
|
|
* CreateDIB()
|
|
*
|
|
* Parameters:
|
|
*
|
|
* DWORD dwWidth - Width for new bitmap, in pixels
|
|
* DWORD dwHeight - Height for new bitmap
|
|
* WORD wBitCount - Bit Count for new DIB (1, 4, 8, or 24)
|
|
*
|
|
* Return Value:
|
|
*
|
|
* HDIB - Handle to new DIB
|
|
*
|
|
* Description:
|
|
*
|
|
* This function allocates memory for and initializes a new DIB by
|
|
* filling in the BITMAPINFOHEADER, allocating memory for the color
|
|
* table, and allocating memory for the bitmap bits. As with all
|
|
* HDIBs, the header, colortable and bits are all in one contiguous
|
|
* memory block. This function is similar to the CreateBitmap()
|
|
* Windows API.
|
|
*
|
|
* The colortable and bitmap bits are left uninitialized (zeroed) in the
|
|
* returned HDIB.
|
|
*
|
|
*
|
|
* History: Date Author Reason
|
|
* 3/20/92 Mark Bader Created
|
|
*
|
|
************************************************************************/
|
|
|
|
HDIB CreateDIB(DWORD dwWidth, DWORD dwHeight, WORD wBitCount)
|
|
{
|
|
BITMAPINFOHEADER bi; // bitmap header
|
|
LPBITMAPINFOHEADER lpbi; // pointer to BITMAPINFOHEADER
|
|
DWORD dwLen; // size of memory block
|
|
HDIB hDIB;
|
|
DWORD dwBytesPerLine; // Number of bytes per scanline
|
|
|
|
|
|
// Make sure bits per pixel is valid
|
|
if (wBitCount <= 1)
|
|
wBitCount = 1;
|
|
else if (wBitCount <= 4)
|
|
wBitCount = 4;
|
|
else if (wBitCount <= 8)
|
|
wBitCount = 8;
|
|
else if (wBitCount <= 24)
|
|
wBitCount = 24;
|
|
else
|
|
wBitCount = 4; // set default value to 4 if parameter is bogus
|
|
|
|
// initialize BITMAPINFOHEADER
|
|
bi.biSize = sizeof(BITMAPINFOHEADER);
|
|
bi.biWidth = dwWidth; // fill in width from parameter
|
|
bi.biHeight = dwHeight; // fill in height from parameter
|
|
bi.biPlanes = 1; // must be 1
|
|
bi.biBitCount = wBitCount; // from parameter
|
|
bi.biCompression = BI_RGB;
|
|
bi.biSizeImage = 0; // 0's here mean "default"
|
|
bi.biXPelsPerMeter = 0;
|
|
bi.biYPelsPerMeter = 0;
|
|
bi.biClrUsed = 0;
|
|
bi.biClrImportant = 0;
|
|
|
|
// calculate size of memory block required to store the DIB. This
|
|
// block should be big enough to hold the BITMAPINFOHEADER, the color
|
|
// table, and the bits
|
|
|
|
dwBytesPerLine = WIDTHBYTES(wBitCount * dwWidth);
|
|
dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + (dwBytesPerLine * dwHeight);
|
|
|
|
// alloc memory block to store our bitmap
|
|
hDIB = GlobalAlloc(GHND, dwLen);
|
|
|
|
// major bummer if we couldn't get memory block
|
|
if (!hDIB)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// lock memory and get pointer to it
|
|
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
|
|
|
|
// use our bitmap info structure to fill in first part of
|
|
// our DIB with the BITMAPINFOHEADER
|
|
*lpbi = bi;
|
|
|
|
// Since we don't know what the colortable and bits should contain,
|
|
// just leave these blank. Unlock the DIB and return the HDIB.
|
|
|
|
GlobalUnlock(hDIB);
|
|
|
|
/* return handle to the DIB */
|
|
return hDIB;
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* FindDIBBits()
|
|
*
|
|
* Parameter:
|
|
*
|
|
* LPSTR lpDIB - pointer to packed-DIB memory block
|
|
*
|
|
* Return Value:
|
|
*
|
|
* LPSTR - pointer to the DIB bits
|
|
*
|
|
* Description:
|
|
*
|
|
* This function calculates the address of the DIB's bits and returns a
|
|
* pointer to the DIB bits.
|
|
*
|
|
* History: Date Author Reason
|
|
* 6/01/91 Garrett McAuliffe Created
|
|
* 9/15/91 Patrick Schreiber Added header and comments
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
LPSTR FindDIBBits(LPSTR lpDIB)
|
|
{
|
|
return (lpDIB + *(LPDWORD)lpDIB + PaletteSize(lpDIB));
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* DIBWidth()
|
|
*
|
|
* Parameter:
|
|
*
|
|
* LPSTR lpDIB - pointer to packed-DIB memory block
|
|
*
|
|
* Return Value:
|
|
*
|
|
* DWORD - width of the DIB
|
|
*
|
|
* Description:
|
|
*
|
|
* This function gets the width of the DIB from the BITMAPINFOHEADER
|
|
* width field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER
|
|
* width field if it is an OS/2-style DIB.
|
|
*
|
|
* History: Date Author Reason
|
|
* 6/01/91 Garrett McAuliffe Created
|
|
* 9/15/91 Patrick Schreiber Added header and comments
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
DWORD DIBWidth(LPSTR lpDIB)
|
|
{
|
|
LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB
|
|
LPBITMAPCOREHEADER lpbmc; // pointer to an OS/2-style DIB
|
|
|
|
/* point to the header (whether Win 3.0 and OS/2) */
|
|
|
|
lpbmi = (LPBITMAPINFOHEADER)lpDIB;
|
|
lpbmc = (LPBITMAPCOREHEADER)lpDIB;
|
|
|
|
/* return the DIB width if it is a Win 3.0 DIB */
|
|
if (lpbmi->biSize == sizeof(BITMAPINFOHEADER))
|
|
return lpbmi->biWidth;
|
|
else /* it is an OS/2 DIB, so return its width */
|
|
return (DWORD)lpbmc->bcWidth;
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* DIBHeight()
|
|
*
|
|
* Parameter:
|
|
*
|
|
* LPSTR lpDIB - pointer to packed-DIB memory block
|
|
*
|
|
* Return Value:
|
|
*
|
|
* DWORD - height of the DIB
|
|
*
|
|
* Description:
|
|
*
|
|
* This function gets the height of the DIB from the BITMAPINFOHEADER
|
|
* height field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER
|
|
* height field if it is an OS/2-style DIB.
|
|
*
|
|
* History: Date Author Reason
|
|
* 6/01/91 Garrett McAuliffe Created
|
|
* 9/15/91 Patrick Schreiber Added header and comments
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
DWORD DIBHeight(LPSTR lpDIB)
|
|
{
|
|
LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB
|
|
LPBITMAPCOREHEADER lpbmc; // pointer to an OS/2-style DIB
|
|
|
|
/* point to the header (whether OS/2 or Win 3.0 */
|
|
|
|
lpbmi = (LPBITMAPINFOHEADER)lpDIB;
|
|
lpbmc = (LPBITMAPCOREHEADER)lpDIB;
|
|
|
|
/* return the DIB height if it is a Win 3.0 DIB */
|
|
if (lpbmi->biSize == sizeof(BITMAPINFOHEADER))
|
|
return lpbmi->biHeight;
|
|
else /* it is an OS/2 DIB, so return its height */
|
|
return (DWORD)lpbmc->bcHeight;
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* PaletteSize()
|
|
*
|
|
* Parameter:
|
|
*
|
|
* LPSTR lpDIB - pointer to packed-DIB memory block
|
|
*
|
|
* Return Value:
|
|
*
|
|
* WORD - size of the color palette of the DIB
|
|
*
|
|
* Description:
|
|
*
|
|
* This function gets the size required to store the DIB's palette by
|
|
* multiplying the number of colors by the size of an RGBQUAD (for a
|
|
* Windows 3.0-style DIB) or by the size of an RGBTRIPLE (for an OS/2-
|
|
* style DIB).
|
|
*
|
|
* History: Date Author Reason
|
|
* 6/01/91 Garrett McAuliffe Created
|
|
* 9/15/91 Patrick Schreiber Added header and comments
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
WORD PaletteSize(LPSTR lpDIB)
|
|
{
|
|
/* calculate the size required by the palette */
|
|
if (IS_WIN30_DIB (lpDIB))
|
|
return (DIBNumColors(lpDIB) * sizeof(RGBQUAD));
|
|
else
|
|
return (DIBNumColors(lpDIB) * sizeof(RGBTRIPLE));
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* DIBNumColors()
|
|
*
|
|
* Parameter:
|
|
*
|
|
* LPSTR lpDIB - pointer to packed-DIB memory block
|
|
*
|
|
* Return Value:
|
|
*
|
|
* WORD - number of colors in the color table
|
|
*
|
|
* Description:
|
|
*
|
|
* This function calculates the number of colors in the DIB's color table
|
|
* by finding the bits per pixel for the DIB (whether Win3.0 or OS/2-style
|
|
* DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256,
|
|
* if 24, no colors in color table.
|
|
*
|
|
* History: Date Author Reason
|
|
* 6/01/91 Garrett McAuliffe Created
|
|
* 9/15/91 Patrick Schreiber Added header and comments
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
WORD DIBNumColors(LPSTR lpDIB)
|
|
{
|
|
WORD wBitCount; // DIB bit count
|
|
|
|
/* If this is a Windows-style DIB, the number of colors in the
|
|
* color table can be less than the number of bits per pixel
|
|
* allows for (i.e. lpbi->biClrUsed can be set to some value).
|
|
* If this is the case, return the appropriate value.
|
|
*/
|
|
|
|
if (IS_WIN30_DIB(lpDIB))
|
|
{
|
|
DWORD dwClrUsed;
|
|
|
|
dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed;
|
|
if (dwClrUsed)
|
|
return (WORD)dwClrUsed;
|
|
}
|
|
|
|
/* Calculate the number of colors in the color table based on
|
|
* the number of bits per pixel for the DIB.
|
|
*/
|
|
if (IS_WIN30_DIB(lpDIB))
|
|
wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount;
|
|
else
|
|
wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount;
|
|
|
|
/* return number of colors based on bits per pixel */
|
|
switch (wBitCount)
|
|
{
|
|
case 1:
|
|
return 2;
|
|
|
|
case 4:
|
|
return 16;
|
|
|
|
case 8:
|
|
return 256;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* CreateDIBPalette()
|
|
*
|
|
* Parameter:
|
|
*
|
|
* HDIB hDIB - specifies the DIB
|
|
*
|
|
* Return Value:
|
|
*
|
|
* HPALETTE - specifies the palette
|
|
*
|
|
* Description:
|
|
*
|
|
* This function creates a palette from a DIB by allocating memory for the
|
|
* logical palette, reading and storing the colors from the DIB's color table
|
|
* into the logical palette, creating a palette from this logical palette,
|
|
* and then returning the palette's handle. This allows the DIB to be
|
|
* displayed using the best possible colors (important for DIBs with 256 or
|
|
* more colors).
|
|
*
|
|
* History: Date Author Reason
|
|
* 6/01/91 Garrett McAuliffe Created
|
|
* 9/15/91 Patrick Schreiber Added header and comments
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
HPALETTE CreateDIBPalette(HDIB hDIB)
|
|
{
|
|
LPLOGPALETTE lpPal; // pointer to a logical palette
|
|
HANDLE hLogPal; // handle to a logical palette
|
|
HPALETTE hPal = NULL; // handle to a palette
|
|
int i, wNumColors; // loop index, number of colors in color table
|
|
LPSTR lpbi; // pointer to packed-DIB
|
|
LPBITMAPINFO lpbmi; // pointer to BITMAPINFO structure (Win3.0)
|
|
LPBITMAPCOREINFO lpbmc; // pointer to BITMAPCOREINFO structure (OS/2)
|
|
bool bWinStyleDIB; // flag which signifies whether this is a Win3.0 DIB
|
|
|
|
/* if handle to DIB is invalid, return NULL */
|
|
|
|
if (!hDIB)
|
|
return NULL;
|
|
|
|
/* lock DIB memory block and get a pointer to it */
|
|
lpbi = (LPSTR)GlobalLock(hDIB);
|
|
|
|
/* get pointer to BITMAPINFO (Win 3.0) */
|
|
lpbmi = (LPBITMAPINFO)lpbi;
|
|
|
|
/* get pointer to BITMAPCOREINFO (OS/2 1.x) */
|
|
lpbmc = (LPBITMAPCOREINFO)lpbi;
|
|
|
|
/* get the number of colors in the DIB */
|
|
wNumColors = DIBNumColors(lpbi);
|
|
|
|
/* is this a Win 3.0 DIB? */
|
|
bWinStyleDIB = IS_WIN30_DIB(lpbi);
|
|
if (wNumColors)
|
|
{
|
|
/* allocate memory block for logical palette */
|
|
hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) *
|
|
wNumColors);
|
|
|
|
/* if not enough memory, clean up and return NULL */
|
|
if (!hLogPal)
|
|
{
|
|
GlobalUnlock(hDIB);
|
|
return NULL;
|
|
}
|
|
|
|
/* lock memory block and get pointer to it */
|
|
lpPal = (LPLOGPALETTE)GlobalLock(hLogPal);
|
|
|
|
/* set version and number of palette entries */
|
|
lpPal->palVersion = PALVERSION;
|
|
lpPal->palNumEntries = wNumColors;
|
|
|
|
/* store RGB triples (if Win 3.0 DIB) or RGB quads (if OS/2 DIB)
|
|
* into palette
|
|
*/
|
|
for (i = 0; i < wNumColors; i++)
|
|
{
|
|
if (bWinStyleDIB)
|
|
{
|
|
lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed;
|
|
lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen;
|
|
lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue;
|
|
lpPal->palPalEntry[i].peFlags = 0;
|
|
}
|
|
else
|
|
{
|
|
lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed;
|
|
lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen;
|
|
lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue;
|
|
lpPal->palPalEntry[i].peFlags = 0;
|
|
}
|
|
}
|
|
|
|
/* create the palette and get handle to it */
|
|
hPal = CreatePalette(lpPal);
|
|
|
|
/* if error getting handle to palette, clean up and return NULL */
|
|
if (!hPal)
|
|
{
|
|
GlobalUnlock(hLogPal);
|
|
GlobalFree(hLogPal);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* clean up */
|
|
GlobalUnlock(hLogPal);
|
|
GlobalFree(hLogPal);
|
|
GlobalUnlock(hDIB);
|
|
|
|
/* return handle to DIB's palette */
|
|
return hPal;
|
|
}
|
|
|
|
/*************************************************************************
|
|
*
|
|
* DIBToBitmap()
|
|
*
|
|
* Parameters:
|
|
*
|
|
* HDIB hDIB - specifies the DIB to convert
|
|
*
|
|
* HPALETTE hPal - specifies the palette to use with the bitmap
|
|
*
|
|
* Return Value:
|
|
*
|
|
* HBITMAP - identifies the device-dependent bitmap
|
|
*
|
|
* Description:
|
|
*
|
|
* This function creates a bitmap from a DIB using the specified palette.
|
|
* If no palette is specified, default is used.
|
|
*
|
|
* NOTE:
|
|
*
|
|
* The bitmap returned from this funciton is always a bitmap compatible
|
|
* with the screen (e.g. same bits/pixel and color planes) rather than
|
|
* a bitmap with the same attributes as the DIB. This behavior is by
|
|
* design, and occurs because this function calls CreateDIBitmap to
|
|
* do its work, and CreateDIBitmap always creates a bitmap compatible
|
|
* with the hDC parameter passed in (because it in turn calls
|
|
* CreateCompatibleBitmap).
|
|
*
|
|
* So for instance, if your DIB is a monochrome DIB and you call this
|
|
* function, you will not get back a monochrome HBITMAP -- you will
|
|
* get an HBITMAP compatible with the screen DC, but with only 2
|
|
* colors used in the bitmap.
|
|
*
|
|
* If your application requires a monochrome HBITMAP returned for a
|
|
* monochrome DIB, use the function SetDIBits().
|
|
*
|
|
* Also, the DIBpassed in to the function is not destroyed on exit. This
|
|
* must be done later, once it is no longer needed.
|
|
*
|
|
* History: Date Author Reason
|
|
* 6/01/91 Garrett McAuliffe Created
|
|
* 9/15/91 Patrick Schreiber Added header and comments
|
|
* 3/27/92 Mark Bader Added comments about resulting
|
|
* bitmap format
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
HBITMAP DIBToBitmap(HDIB hDIB, HPALETTE hPal)
|
|
{
|
|
LPSTR lpDIBHdr, lpDIBBits; // pointer to DIB header, pointer to DIB bits
|
|
HBITMAP hBitmap; // handle to device-dependent bitmap
|
|
HDC hDC; // handle to DC
|
|
HPALETTE hOldPal = NULL; // handle to a palette
|
|
|
|
/* if invalid handle, return NULL */
|
|
|
|
if (!hDIB)
|
|
return NULL;
|
|
|
|
/* lock memory block and get a pointer to it */
|
|
lpDIBHdr = (LPSTR)GlobalLock(hDIB);
|
|
|
|
/* get a pointer to the DIB bits */
|
|
lpDIBBits = FindDIBBits(lpDIBHdr);
|
|
|
|
/* get a DC */
|
|
hDC = GetDC(NULL);
|
|
if (!hDC)
|
|
{
|
|
/* clean up and return NULL */
|
|
GlobalUnlock(hDIB);
|
|
return NULL;
|
|
}
|
|
|
|
/* select and realize palette */
|
|
if (hPal)
|
|
hOldPal = SelectPalette(hDC, hPal, FALSE);
|
|
RealizePalette(hDC);
|
|
|
|
/* create bitmap from DIB info. and bits */
|
|
hBitmap = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)lpDIBHdr, CBM_INIT,
|
|
lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS);
|
|
|
|
/* restore previous palette */
|
|
if (hOldPal)
|
|
SelectPalette(hDC, hOldPal, FALSE);
|
|
|
|
/* clean up */
|
|
ReleaseDC(NULL, hDC);
|
|
GlobalUnlock(hDIB);
|
|
|
|
/* return handle to the bitmap */
|
|
return hBitmap;
|
|
}
|
|
|
|
HBITMAP lpDIBToBitmap(void *lpDIBHdr, HPALETTE hPal)
|
|
{
|
|
LPSTR lpDIBBits; // pointer to DIB header, pointer to DIB bits
|
|
HBITMAP hBitmap; // handle to device-dependent bitmap
|
|
HDC hDC; // handle to DC
|
|
HPALETTE hOldPal = NULL; // handle to a palette
|
|
|
|
if (!lpDIBHdr)
|
|
return NULL;
|
|
|
|
/* get a pointer to the DIB bits */
|
|
lpDIBBits = FindDIBBits((LPSTR)lpDIBHdr) ;
|
|
|
|
/* get a DC */
|
|
hDC = GetDC(NULL);
|
|
if (!hDC)
|
|
return NULL;
|
|
|
|
/* select and realize palette */
|
|
if (hPal)
|
|
hOldPal = SelectPalette(hDC, hPal, FALSE);
|
|
RealizePalette(hDC);
|
|
|
|
/* create bitmap from DIB info. and bits */
|
|
hBitmap = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)lpDIBHdr, CBM_INIT,
|
|
lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS);
|
|
|
|
/* restore previous palette */
|
|
if (hOldPal)
|
|
SelectPalette(hDC, hOldPal, FALSE);
|
|
|
|
/* clean up */
|
|
ReleaseDC(NULL, hDC);
|
|
|
|
/* return handle to the bitmap */
|
|
return hBitmap;
|
|
}
|
|
|
|
HBITMAP lpDIBToBitmapAndPalette(void *lpDIBHdr)
|
|
{
|
|
LPSTR lpDIBBits; // pointer to DIB header, pointer to DIB bits
|
|
HBITMAP hBitmap; // handle to device-dependent bitmap
|
|
HDC hDC; // handle to DC
|
|
HPALETTE hOldPal; // handle to a palette
|
|
|
|
if (!lpDIBHdr)
|
|
return NULL;
|
|
|
|
/* get a pointer to the DIB bits */
|
|
lpDIBBits = FindDIBBits((LPSTR)lpDIBHdr) ;
|
|
|
|
/* get a DC */
|
|
hDC = GetDC(NULL);
|
|
if (!hDC)
|
|
return NULL;
|
|
|
|
hPalBitmap = pov_frontend::WinLegacyDisplay::CreatePalette (((BITMAPINFO *) lpDIBHdr)->bmiColors, ((BITMAPINFO *) lpDIBHdr)->bmiHeader.biClrImportant, render_bitmap_depth != 24) ;
|
|
if (hPalBitmap)
|
|
{
|
|
hOldPal = SelectPalette(hDC, hPalBitmap, FALSE);
|
|
SelectPalette(hDC, hPalBitmap, FALSE);
|
|
RealizePalette(hDC);
|
|
}
|
|
|
|
/* create bitmap from DIB info. and bits */
|
|
hBitmap = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)lpDIBHdr, CBM_INIT,
|
|
lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS);
|
|
/* restore previous palette */
|
|
if (hPalBitmap)
|
|
if (hOldPal)
|
|
SelectPalette(hDC, hOldPal, FALSE);
|
|
|
|
/* clean up */
|
|
ReleaseDC(NULL, hDC);
|
|
|
|
/* return handle to the bitmap */
|
|
return hBitmap;
|
|
}
|
|
|
|
/*************************************************************************
|
|
*
|
|
* BitmapToDIB()
|
|
*
|
|
* Parameters:
|
|
*
|
|
* HBITMAP hBitmap - specifies the bitmap to convert
|
|
*
|
|
* HPALETTE hPal - specifies the palette to use with the bitmap
|
|
*
|
|
* Return Value:
|
|
*
|
|
* HDIB - identifies the device-dependent bitmap
|
|
*
|
|
* Description:
|
|
*
|
|
* This function creates a DIB from a bitmap using the specified palette.
|
|
*
|
|
* History: Date Author Reason
|
|
* 6/01/91 Garrett McAuliffe Created
|
|
* 9/15/91 Patrick Schreiber Added header and comments
|
|
* 12/10/91 Patrick Schreiber Added bits per pixel validation
|
|
* and check GetObject return value
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
HDIB BitmapToDIB(HBITMAP hBitmap, HPALETTE hPal)
|
|
{
|
|
BITMAP bm; // bitmap structure
|
|
BITMAPINFOHEADER bi; // bitmap header
|
|
BITMAPINFOHEADER *lpbi; // pointer to BITMAPINFOHEADER
|
|
DWORD dwLen; // size of memory block
|
|
HANDLE hDIB, h; // handle to DIB, temp handle
|
|
HDC hDC; // handle to DC
|
|
WORD biBits; // bits per pixel
|
|
|
|
/* check if bitmap handle is valid */
|
|
|
|
if (!hBitmap)
|
|
return NULL;
|
|
|
|
/* fill in BITMAP structure, return NULL if it didn't work */
|
|
if (!GetObject(hBitmap, sizeof(bm), (LPSTR)&bm))
|
|
return NULL;
|
|
|
|
/* if no palette is specified, use default palette */
|
|
if (hPal == NULL)
|
|
hPal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
|
|
|
|
/* calculate bits per pixel */
|
|
biBits = bm.bmPlanes * bm.bmBitsPixel;
|
|
|
|
/* make sure bits per pixel is valid */
|
|
if (biBits <= 1)
|
|
biBits = 1;
|
|
else if (biBits <= 4)
|
|
biBits = 4;
|
|
else if (biBits <= 8)
|
|
biBits = 8;
|
|
else /* if greater than 8-bit, force to 24-bit */
|
|
biBits = 24;
|
|
|
|
/* initialize BITMAPINFOHEADER */
|
|
bi.biSize = sizeof(BITMAPINFOHEADER);
|
|
bi.biWidth = bm.bmWidth;
|
|
bi.biHeight = bm.bmHeight;
|
|
bi.biPlanes = 1;
|
|
bi.biBitCount = biBits;
|
|
bi.biCompression = BI_RGB;
|
|
bi.biSizeImage = 0;
|
|
bi.biXPelsPerMeter = 0;
|
|
bi.biYPelsPerMeter = 0;
|
|
bi.biClrUsed = 0;
|
|
bi.biClrImportant = 0;
|
|
|
|
/* calculate size of memory block required to store BITMAPINFO */
|
|
dwLen = bi.biSize + PaletteSize((LPSTR)&bi);
|
|
|
|
/* get a DC */
|
|
hDC = GetDC(NULL);
|
|
|
|
/* select and realize our palette */
|
|
hPal = SelectPalette(hDC, hPal, FALSE);
|
|
RealizePalette(hDC);
|
|
|
|
/* alloc memory block to store our bitmap */
|
|
hDIB = GlobalAlloc(GHND, dwLen);
|
|
|
|
/* if we couldn't get memory block */
|
|
if (!hDIB)
|
|
{
|
|
/* clean up and return NULL */
|
|
SelectPalette(hDC, hPal, TRUE);
|
|
RealizePalette(hDC);
|
|
ReleaseDC(NULL, hDC);
|
|
return NULL;
|
|
}
|
|
|
|
/* lock memory and get pointer to it */
|
|
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
|
|
|
|
/* use our bitmap info. to fill BITMAPINFOHEADER */
|
|
*lpbi = bi;
|
|
|
|
/* call GetDIBits with a NULL lpBits param, so it will calculate the
|
|
* biSizeImage field for us
|
|
*/
|
|
GetDIBits(hDC, hBitmap, 0, (WORD)bi.biHeight, NULL, (LPBITMAPINFO)lpbi,
|
|
DIB_RGB_COLORS);
|
|
|
|
/* get the info. returned by GetDIBits and unlock memory block */
|
|
bi = *lpbi;
|
|
GlobalUnlock(hDIB);
|
|
|
|
/* if the driver did not fill in the biSizeImage field, make one up */
|
|
if (bi.biSizeImage == 0)
|
|
bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight;
|
|
|
|
/* realloc the buffer big enough to hold all the bits */
|
|
dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + bi.biSizeImage;
|
|
if ((h = GlobalReAlloc(hDIB, dwLen, 0)) != NULL)
|
|
hDIB = h;
|
|
else
|
|
{
|
|
/* clean up and return NULL */
|
|
GlobalFree(hDIB);
|
|
SelectPalette(hDC, hPal, TRUE);
|
|
RealizePalette(hDC);
|
|
ReleaseDC(NULL, hDC);
|
|
return NULL;
|
|
}
|
|
|
|
/* lock memory block and get pointer to it */
|
|
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
|
|
|
|
/* call GetDIBits with a NON-NULL lpBits param, and actualy get the
|
|
* bits this time
|
|
*/
|
|
if (GetDIBits(hDC, hBitmap, 0, (WORD)bi.biHeight, (LPSTR)lpbi + (WORD)lpbi
|
|
->biSize + PaletteSize((LPSTR)lpbi), (LPBITMAPINFO)lpbi,
|
|
DIB_RGB_COLORS) == 0)
|
|
{
|
|
/* clean up and return NULL */
|
|
GlobalUnlock(hDIB);
|
|
SelectPalette(hDC, hPal, TRUE);
|
|
RealizePalette(hDC);
|
|
ReleaseDC(NULL, hDC);
|
|
return NULL;
|
|
}
|
|
bi = *lpbi;
|
|
|
|
/* clean up */
|
|
GlobalUnlock(hDIB);
|
|
SelectPalette(hDC, hPal, TRUE);
|
|
RealizePalette(hDC);
|
|
ReleaseDC(NULL, hDC);
|
|
|
|
/* return handle to the DIB */
|
|
return hDIB;
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* PalEntriesOnDevice()
|
|
*
|
|
* Parameter:
|
|
*
|
|
* HDC hDC - device context
|
|
*
|
|
* Return Value:
|
|
*
|
|
* int - number of palette entries on device
|
|
*
|
|
* Description:
|
|
*
|
|
* This function gets the number of palette entries on the specified device
|
|
*
|
|
* History: Date Author Reason
|
|
* 6/01/91 Garrett McAuliffe Created
|
|
* 9/15/91 Patrick Schreiber Added header and comments
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
int PalEntriesOnDevice(HDC hDC)
|
|
{
|
|
int nColors; // number of colors
|
|
|
|
/* Find out the number of palette entries on this
|
|
* device.
|
|
*/
|
|
|
|
nColors = GetDeviceCaps(hDC, SIZEPALETTE);
|
|
|
|
/* For non-palette devices, we'll use the # of system
|
|
* colors for our palette size.
|
|
*/
|
|
if (!nColors)
|
|
nColors = GetDeviceCaps(hDC, NUMCOLORS);
|
|
return nColors;
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* GetSystemPalette()
|
|
*
|
|
* Parameters:
|
|
*
|
|
* None
|
|
*
|
|
* Return Value:
|
|
*
|
|
* HPALETTE - handle to a copy of the current system palette
|
|
*
|
|
* Description:
|
|
*
|
|
* This function returns a handle to a palette which represents the system
|
|
* palette. The system RGB values are copied into our logical palette using
|
|
* the GetSystemPaletteEntries function.
|
|
*
|
|
* History:
|
|
*
|
|
* Date Author Reason
|
|
* 6/01/91 Garrett McAuliffe Created
|
|
* 9/15/91 Patrick Schreiber Added header and comments
|
|
* 12/20/91 Mark Bader Added GetSystemPaletteEntries call
|
|
*
|
|
************************************************************************/
|
|
|
|
|
|
HPALETTE GetSystemPalette(void)
|
|
{
|
|
HDC hDC; // handle to a DC
|
|
static HPALETTE hPal = NULL; // handle to a palette
|
|
HANDLE hLogPal; // handle to a logical palette
|
|
LPLOGPALETTE lpLogPal; // pointer to a logical palette
|
|
int nColors; // number of colors
|
|
|
|
/* Find out how many palette entries we want. */
|
|
|
|
hDC = GetDC(NULL);
|
|
if (!hDC)
|
|
return NULL;
|
|
nColors = PalEntriesOnDevice(hDC); // Number of palette entries
|
|
|
|
/* Allocate room for the palette and lock it. */
|
|
hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + nColors * sizeof(
|
|
PALETTEENTRY));
|
|
|
|
/* if we didn't get a logical palette, return NULL */
|
|
if (!hLogPal)
|
|
return NULL;
|
|
|
|
/* get a pointer to the logical palette */
|
|
lpLogPal = (LPLOGPALETTE)GlobalLock(hLogPal);
|
|
|
|
/* set some important fields */
|
|
lpLogPal->palVersion = PALVERSION;
|
|
lpLogPal->palNumEntries = nColors;
|
|
|
|
/* Copy the current system palette into our logical palette */
|
|
|
|
GetSystemPaletteEntries(hDC, 0, nColors,
|
|
(LPPALETTEENTRY)(lpLogPal->palPalEntry));
|
|
|
|
/* Go ahead and create the palette. Once it's created,
|
|
* we no longer need the LOGPALETTE, so free it.
|
|
*/
|
|
|
|
hPal = CreatePalette(lpLogPal);
|
|
|
|
/* clean up */
|
|
GlobalUnlock(hLogPal);
|
|
GlobalFree(hLogPal);
|
|
ReleaseDC(NULL, hDC);
|
|
|
|
return hPal;
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* AllocRoomForDIB()
|
|
*
|
|
* Parameters:
|
|
*
|
|
* BITMAPINFOHEADER - bitmap info header stucture
|
|
*
|
|
* HBITMAP - handle to the bitmap
|
|
*
|
|
* Return Value:
|
|
*
|
|
* HDIB - handle to memory block
|
|
*
|
|
* Description:
|
|
*
|
|
* This routine takes a BITMAPINOHEADER, and returns a handle to global
|
|
* memory which can contain a DIB with that header. It also initializes
|
|
* the header portion of the global memory. GetDIBits() is used to determine
|
|
* the amount of room for the DIB's bits. The total amount of memory
|
|
* needed = sizeof(BITMAPINFOHEADER) + size of color table + size of bits.
|
|
*
|
|
* History: Date Author Reason
|
|
* 6/01/91 Garrett McAuliffe Created
|
|
* 12/11/91 Patrick Schreiber Added header and some comments
|
|
*
|
|
************************************************************************/
|
|
|
|
HANDLE AllocRoomForDIB(BITMAPINFOHEADER bi, HBITMAP hBitmap)
|
|
{
|
|
DWORD dwLen;
|
|
HANDLE hDIB;
|
|
HDC hDC;
|
|
LPBITMAPINFOHEADER lpbi;
|
|
HANDLE hTemp;
|
|
|
|
/* Figure out the size needed to hold the BITMAPINFO structure
|
|
* (which includes the BITMAPINFOHEADER and the color table).
|
|
*/
|
|
|
|
dwLen = bi.biSize + PaletteSize((LPSTR) &bi);
|
|
hDIB = GlobalAlloc(GHND,dwLen);
|
|
|
|
/* Check that DIB handle is valid */
|
|
if (!hDIB)
|
|
return NULL;
|
|
|
|
/* Set up the BITMAPINFOHEADER in the newly allocated global memory,
|
|
* then call GetDIBits() with lpBits = NULL to have it fill in the
|
|
* biSizeImage field for us.
|
|
*/
|
|
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
|
|
*lpbi = bi;
|
|
|
|
hDC = GetDC(NULL);
|
|
GetDIBits(hDC, hBitmap, 0, (WORD) bi.biHeight,
|
|
NULL, (LPBITMAPINFO) lpbi, DIB_RGB_COLORS);
|
|
ReleaseDC(NULL, hDC);
|
|
|
|
/* If the driver did not fill in the biSizeImage field,
|
|
* fill it in -- NOTE: this is a bug in the driver!
|
|
*/
|
|
if (lpbi->biSizeImage == 0)
|
|
lpbi->biSizeImage = WIDTHBYTES((DWORD)lpbi->biWidth * lpbi->biBitCount) *
|
|
lpbi->biHeight;
|
|
|
|
/* Get the size of the memory block we need */
|
|
dwLen = lpbi->biSize + PaletteSize((LPSTR) &bi) + lpbi->biSizeImage;
|
|
|
|
/* Unlock the memory block */
|
|
GlobalUnlock(hDIB);
|
|
|
|
/* ReAlloc the buffer big enough to hold all the bits */
|
|
if ((hTemp = GlobalReAlloc(hDIB,dwLen,0)) != NULL)
|
|
return hTemp;
|
|
else
|
|
{
|
|
/* Else free memory block and return failure */
|
|
GlobalFree(hDIB);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* ChangeDIBFormat()
|
|
*
|
|
* Parameter:
|
|
*
|
|
* HDIB - handle to packed-DIB in memory
|
|
*
|
|
* WORD - desired bits per pixel
|
|
*
|
|
* DWORD - desired compression format
|
|
*
|
|
* Return Value:
|
|
*
|
|
* HDIB - handle to the new DIB if successful, else NULL
|
|
*
|
|
* Description:
|
|
*
|
|
* This function will convert the bits per pixel and/or the compression
|
|
* format of the specified DIB. Note: If the conversion was unsuccessful,
|
|
* we return NULL. The original DIB is left alone. Don't use code like the
|
|
* following:
|
|
*
|
|
* hMyDIB = ChangeDIBFormat(hMyDIB, 8, BI_RLE4);
|
|
*
|
|
* The conversion will fail, but hMyDIB will now be NULL and the original
|
|
* DIB will now hang around in memory. We could have returned the old
|
|
* DIB, but we wanted to allow the programmer to check whether this
|
|
* conversion succeeded or failed.
|
|
*
|
|
* History:
|
|
*
|
|
* Date Author Reason
|
|
* 6/01/91 Garrett McAuliffe Created
|
|
* 12/10/91 Patrick Schreiber Modified from converting RGB to RLE8
|
|
* to converting RGB/RLE to RGB/RLE.
|
|
* Added wBitCount and dwCompression
|
|
* parameters. Also added header and
|
|
* comments.
|
|
*
|
|
************************************************************************/
|
|
|
|
HDIB ChangeDIBFormat(HDIB hDIB, WORD wBitCount, DWORD dwCompression)
|
|
{
|
|
HDC hDC; // Handle to DC
|
|
HBITMAP hBitmap; // Handle to bitmap
|
|
BITMAP Bitmap; // BITMAP data structure
|
|
BITMAPINFOHEADER bi; // Bitmap info header
|
|
LPBITMAPINFOHEADER lpbi; // Pointer to bitmap info
|
|
HDIB hNewDIB; // Handle to new DIB
|
|
HPALETTE hPal, hOldPal; // Handle to palette, prev pal
|
|
WORD DIBBPP, NewBPP; // DIB bits per pixel, new bpp
|
|
DWORD NewComp; // New compression
|
|
|
|
/* Check for a valid DIB handle */
|
|
if (!hDIB)
|
|
return NULL;
|
|
|
|
/* Get the old DIB's bits per pixel and compression format */
|
|
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
|
|
DIBBPP = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;
|
|
GlobalUnlock(hDIB);
|
|
|
|
/* Validate wBitCount and dwCompression
|
|
* They must match correctly (i.e., BI_RLE4 and 4 BPP or
|
|
* BI_RLE8 and 8BPP, etc.) or we return failure */
|
|
if (wBitCount == 0)
|
|
{
|
|
NewBPP = DIBBPP;
|
|
if ((dwCompression == BI_RLE4 && NewBPP == 4) ||
|
|
(dwCompression == BI_RLE8 && NewBPP == 8) ||
|
|
(dwCompression == BI_RGB))
|
|
NewComp = dwCompression;
|
|
else
|
|
return NULL;
|
|
}
|
|
else if (wBitCount == 1 && dwCompression == BI_RGB)
|
|
{
|
|
NewBPP = wBitCount;
|
|
NewComp = BI_RGB;
|
|
}
|
|
else if (wBitCount == 4)
|
|
{
|
|
NewBPP = wBitCount;
|
|
if (dwCompression == BI_RGB || dwCompression == BI_RLE4)
|
|
NewComp = dwCompression;
|
|
else
|
|
return NULL;
|
|
}
|
|
else if (wBitCount == 8)
|
|
{
|
|
NewBPP = wBitCount;
|
|
if (dwCompression == BI_RGB || dwCompression == BI_RLE8)
|
|
NewComp = dwCompression;
|
|
else
|
|
return NULL;
|
|
}
|
|
else if (wBitCount == 24 && dwCompression == BI_RGB)
|
|
{
|
|
NewBPP = wBitCount;
|
|
NewComp = BI_RGB;
|
|
}
|
|
else
|
|
return NULL;
|
|
|
|
/* Save the old DIB's palette */
|
|
hPal = CreateDIBPalette(hDIB);
|
|
if (!hPal)
|
|
return NULL;
|
|
|
|
/* Convert old DIB to a bitmap */
|
|
hBitmap = DIBToBitmap(hDIB, hPal);
|
|
if (!hBitmap)
|
|
{
|
|
DeleteObject(hPal);
|
|
return NULL;
|
|
}
|
|
|
|
/* Get info about the bitmap */
|
|
GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);
|
|
|
|
/* Fill in the BITMAPINFOHEADER appropriately */
|
|
bi.biSize = sizeof(BITMAPINFOHEADER);
|
|
bi.biWidth = Bitmap.bmWidth;
|
|
bi.biHeight = Bitmap.bmHeight;
|
|
bi.biPlanes = 1;
|
|
bi.biBitCount = NewBPP;
|
|
bi.biCompression = NewComp;
|
|
bi.biSizeImage = 0;
|
|
bi.biXPelsPerMeter = 0;
|
|
bi.biYPelsPerMeter = 0;
|
|
bi.biClrUsed = 0;
|
|
bi.biClrImportant = 0;
|
|
|
|
/* Go allocate room for the new DIB */
|
|
hNewDIB = AllocRoomForDIB(bi, hBitmap);
|
|
if (!hNewDIB)
|
|
return NULL;
|
|
|
|
/* Get a pointer to the new DIB */
|
|
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hNewDIB);
|
|
|
|
/* Get a DC and select/realize our palette in it */
|
|
hDC = GetDC(NULL);
|
|
hOldPal = SelectPalette(hDC, hPal, FALSE);
|
|
RealizePalette(hDC);
|
|
|
|
/* Call GetDIBits and get the new DIB bits */
|
|
if (!GetDIBits(hDC, hBitmap, 0, (WORD) lpbi->biHeight,
|
|
(LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi),
|
|
(LPBITMAPINFO)lpbi, DIB_RGB_COLORS))
|
|
{
|
|
GlobalUnlock(hNewDIB);
|
|
GlobalFree(hNewDIB);
|
|
hNewDIB = NULL;
|
|
}
|
|
|
|
/* Clean up and return */
|
|
SelectPalette(hDC, hOldPal, TRUE);
|
|
RealizePalette(hDC);
|
|
ReleaseDC(NULL, hDC);
|
|
|
|
if (hNewDIB)
|
|
/* Unlock the new DIB's memory block */
|
|
GlobalUnlock(hNewDIB);
|
|
|
|
DeleteObject(hBitmap);
|
|
DeleteObject(hPal);
|
|
|
|
return hNewDIB;
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* ChangeBitmapFormat()
|
|
*
|
|
* Parameter:
|
|
*
|
|
* HBITMAP - handle to a bitmap
|
|
*
|
|
* WORD - desired bits per pixel
|
|
*
|
|
* DWORD - desired compression format
|
|
*
|
|
* HPALETTE - handle to palette
|
|
*
|
|
* Return Value:
|
|
*
|
|
* HDIB - handle to the new DIB if successful, else NULL
|
|
*
|
|
* Description:
|
|
*
|
|
* This function will convert a bitmap to the specified bits per pixel
|
|
* and compression format. The bitmap and it's palette will remain
|
|
* after calling this function.
|
|
*
|
|
* History:
|
|
*
|
|
* Date Author Reason
|
|
* 6/01/91 Garrett McAuliffe Created
|
|
* 12/10/91 Patrick Schreiber Modified from converting RGB to RLE8
|
|
* to converting RGB/RLE to RGB/RLE.
|
|
* Added wBitCount and dwCompression
|
|
* parameters. Also added header and
|
|
* comments.
|
|
* 12/11/91 Patrick Schreiber Destroy old DIB if conversion was
|
|
* successful.
|
|
* 12/16/91 Patrick Schreiber Modified from converting DIB to new
|
|
* DIB to bitmap to new DIB. Added palette
|
|
* parameter.
|
|
*
|
|
************************************************************************/
|
|
|
|
HDIB ChangeBitmapFormat(HBITMAP hBitmap,
|
|
WORD wBitCount,
|
|
DWORD dwCompression,
|
|
HPALETTE hPal)
|
|
{
|
|
HDC hDC; // Screen DC
|
|
HDIB hNewDIB; // Handle to new DIB
|
|
BITMAP Bitmap; // BITMAP data structure
|
|
BITMAPINFOHEADER bi; // Bitmap info. header
|
|
LPBITMAPINFOHEADER lpbi; // Pointer to bitmap header
|
|
HPALETTE hOldPal=NULL; // Handle to palette
|
|
WORD NewBPP; // New bits per pixel
|
|
DWORD NewComp; // New compression format
|
|
|
|
/* Check for a valid bitmap handle */
|
|
if (!hBitmap)
|
|
return NULL;
|
|
|
|
/* Validate wBitCount and dwCompression
|
|
* They must match correctly (i.e., BI_RLE4 and 4 BPP or
|
|
* BI_RLE8 and 8BPP, etc.) or we return failure
|
|
*/
|
|
if (wBitCount == 0)
|
|
{
|
|
NewComp = dwCompression;
|
|
if (NewComp == BI_RLE4)
|
|
NewBPP = 4;
|
|
else if (NewComp == BI_RLE8)
|
|
NewBPP = 8;
|
|
else /* Not enough info */
|
|
return NULL;
|
|
}
|
|
else if (wBitCount == 1 && dwCompression == BI_RGB)
|
|
{
|
|
NewBPP = wBitCount;
|
|
NewComp = BI_RGB;
|
|
}
|
|
else if (wBitCount == 4)
|
|
{
|
|
NewBPP = wBitCount;
|
|
if (dwCompression == BI_RGB || dwCompression == BI_RLE4)
|
|
NewComp = dwCompression;
|
|
else
|
|
return NULL;
|
|
}
|
|
else if (wBitCount == 8)
|
|
{
|
|
NewBPP = wBitCount;
|
|
if (dwCompression == BI_RGB || dwCompression == BI_RLE8)
|
|
NewComp = dwCompression;
|
|
else
|
|
return NULL;
|
|
}
|
|
else if (wBitCount == 24 && dwCompression == BI_RGB)
|
|
{
|
|
NewBPP = wBitCount;
|
|
NewComp = BI_RGB;
|
|
}
|
|
else
|
|
return NULL;
|
|
|
|
/* Get info about the bitmap */
|
|
GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap);
|
|
|
|
/* Fill in the BITMAPINFOHEADER appropriately */
|
|
bi.biSize = sizeof(BITMAPINFOHEADER);
|
|
bi.biWidth = Bitmap.bmWidth;
|
|
bi.biHeight = Bitmap.bmHeight;
|
|
bi.biPlanes = 1;
|
|
bi.biBitCount = NewBPP;
|
|
bi.biCompression = NewComp;
|
|
bi.biSizeImage = 0;
|
|
bi.biXPelsPerMeter = 0;
|
|
bi.biYPelsPerMeter = 0;
|
|
bi.biClrUsed = 0;
|
|
bi.biClrImportant = 0;
|
|
|
|
/* Go allocate room for the new DIB */
|
|
hNewDIB = AllocRoomForDIB(bi, hBitmap);
|
|
if (!hNewDIB)
|
|
return NULL;
|
|
|
|
/* Get a pointer to the new DIB */
|
|
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hNewDIB);
|
|
|
|
/* If we have a palette, get a DC and select/realize it */
|
|
if (hPal)
|
|
{
|
|
hDC = GetDC(NULL);
|
|
hOldPal = SelectPalette(hDC, hPal, FALSE);
|
|
RealizePalette(hDC);
|
|
}
|
|
|
|
/* Call GetDIBits and get the new DIB bits */
|
|
if (!GetDIBits(hDC, hBitmap, 0, (WORD) lpbi->biHeight,
|
|
(LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi),
|
|
(LPBITMAPINFO)lpbi, DIB_RGB_COLORS))
|
|
{
|
|
GlobalUnlock(hNewDIB);
|
|
GlobalFree(hNewDIB);
|
|
hNewDIB = NULL;
|
|
}
|
|
|
|
/* Clean up and return */
|
|
if (hOldPal)
|
|
{
|
|
SelectPalette(hDC, hOldPal, TRUE);
|
|
RealizePalette(hDC);
|
|
ReleaseDC(NULL, hDC);
|
|
}
|
|
|
|
if (hNewDIB)
|
|
{
|
|
/* Unlock the new DIB's memory block */
|
|
GlobalUnlock(hNewDIB);
|
|
}
|
|
|
|
return hNewDIB;
|
|
}
|
|
|
|
/*************************************************************************
|
|
*
|
|
* LoadDIB()
|
|
*
|
|
* Loads the specified DIB from a file, allocates memory for it,
|
|
* and reads the disk file into the memory.
|
|
*
|
|
*
|
|
* Parameters:
|
|
*
|
|
* LPSTR lpFileName - specifies the file to load a DIB from
|
|
*
|
|
* Returns: A handle to a DIB, or NULL if unsuccessful.
|
|
*
|
|
* NOTE: The DIB API were not written to handle OS/2 DIBs; This
|
|
* function will reject any file that is not a Windows DIB.
|
|
*
|
|
* History: Date Author Reason
|
|
* 9/15/91 Mark Bader Based on DIBVIEW
|
|
*
|
|
*************************************************************************/
|
|
|
|
HDIB LoadDIB(LPSTR lpFileName)
|
|
{
|
|
HDIB hDIB;
|
|
int hFile;
|
|
OFSTRUCT ofs;
|
|
|
|
/*
|
|
* Set the cursor to a hourglass, in case the loading operation
|
|
* takes more than a sec, the user will know what's going on.
|
|
*/
|
|
|
|
SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
if ((hFile = OpenFile(lpFileName, &ofs, OF_READ)) != -1)
|
|
{
|
|
hDIB = ReadDIBFile(hFile);
|
|
_lclose(hFile);
|
|
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
|
return hDIB;
|
|
}
|
|
else
|
|
{
|
|
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/*************************************************************************
|
|
*
|
|
* SaveDIB()
|
|
*
|
|
* Saves the specified DIB into the specified file name on disk. No
|
|
* error checking is done, so if the file already exists, it will be
|
|
* written over.
|
|
*
|
|
* Parameters:
|
|
*
|
|
* HDIB hDib - Handle to the dib to save
|
|
*
|
|
* LPSTR lpFileName - pointer to full pathname to save DIB under
|
|
*
|
|
* Return value: 0 if successful, or one of:
|
|
* ERR_INVALIDHANDLE
|
|
* ERR_OPEN
|
|
* ERR_LOCK
|
|
*
|
|
* History:
|
|
*
|
|
* NOTE: The DIB API were not written to handle OS/2 DIBs, so this
|
|
* function will not save a file if it is not a Windows DIB.
|
|
*
|
|
* History: Date Author Reason
|
|
* 9/15/91 Mark Bader Taken from DIBVIEW (which was taken
|
|
* from SHOWDIB)
|
|
* 1/30/92 Mark Bader Fixed problem of writing too many
|
|
* bytes to the file
|
|
* 6/24/92 Mark Bader Added check for OS/2 DIB
|
|
*
|
|
*************************************************************************/
|
|
|
|
|
|
WORD SaveDIB(HDIB hDib, LPSTR lpFileName)
|
|
{
|
|
BITMAPFILEHEADER bmfHdr; // Header for Bitmap file
|
|
LPBITMAPINFOHEADER lpBI; // Pointer to DIB info structure
|
|
int fh; // file handle for opened file
|
|
OFSTRUCT of; // OpenFile structure
|
|
DWORD dwDIBSize;
|
|
DWORD dwError; // Error return from MyWrite
|
|
|
|
if (!hDib)
|
|
return ERR_INVALIDHANDLE;
|
|
fh = OpenFile(lpFileName, &of, OF_CREATE | OF_READWRITE);
|
|
if (fh == -1)
|
|
return ERR_OPEN;
|
|
|
|
/*
|
|
* Get a pointer to the DIB memory, the first of which contains
|
|
* a BITMAPINFO structure
|
|
*/
|
|
lpBI = (LPBITMAPINFOHEADER)GlobalLock(hDib);
|
|
if (!lpBI)
|
|
return ERR_LOCK;
|
|
|
|
// Check to see if we're dealing with an OS/2 DIB. If so, don't
|
|
// save it because our functions aren't written to deal with these
|
|
// DIBs.
|
|
|
|
if (lpBI->biSize != sizeof(BITMAPINFOHEADER))
|
|
{
|
|
GlobalUnlock(hDib);
|
|
return ERR_NOT_DIB;
|
|
}
|
|
|
|
/*
|
|
* Fill in the fields of the file header
|
|
*/
|
|
|
|
/* Fill in file type (first 2 bytes must be "BM" for a bitmap) */
|
|
bmfHdr.bfType = DIB_HEADER_MARKER; // "BM"
|
|
|
|
// Calculating the size of the DIB is a bit tricky (if we want to
|
|
// do it right). The easiest way to do this is to call GlobalSize()
|
|
// on our global handle, but since the size of our global memory may have
|
|
// been padded a few bytes, we may end up writing out a few too
|
|
// many bytes to the file (which may cause problems with some apps,
|
|
// like HC 3.0).
|
|
//
|
|
// So, instead let's calculate the size manually.
|
|
//
|
|
// To do this, find size of header plus size of color table. Since the
|
|
// first DWORD in both BITMAPINFOHEADER and BITMAPCOREHEADER conains
|
|
// the size of the structure, let's use this.
|
|
|
|
dwDIBSize = *(LPDWORD)lpBI + PaletteSize((LPSTR)lpBI); // Partial Calculation
|
|
|
|
// Now calculate the size of the image
|
|
|
|
if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4)) {
|
|
|
|
// It's an RLE bitmap, we can't calculate size, so trust the
|
|
// biSizeImage field
|
|
|
|
dwDIBSize += lpBI->biSizeImage;
|
|
}
|
|
else {
|
|
DWORD dwBmBitsSize; // Size of Bitmap Bits only
|
|
|
|
// It's not RLE, so size is Width (DWORD aligned) * Height
|
|
|
|
dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight;
|
|
|
|
dwDIBSize += dwBmBitsSize;
|
|
|
|
// Now, since we have calculated the correct size, why don't we
|
|
// fill in the biSizeImage field (this will fix any .BMP files which
|
|
// have this field incorrect).
|
|
|
|
lpBI->biSizeImage = dwBmBitsSize;
|
|
}
|
|
|
|
|
|
// Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER)
|
|
|
|
bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
|
|
bmfHdr.bfReserved1 = 0;
|
|
bmfHdr.bfReserved2 = 0;
|
|
|
|
/*
|
|
* Now, calculate the offset the actual bitmap bits will be in
|
|
* the file -- It's the Bitmap file header plus the DIB header,
|
|
* plus the size of the color table.
|
|
*/
|
|
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize +
|
|
PaletteSize((LPSTR)lpBI);
|
|
|
|
/* Write the file header */
|
|
_lwrite(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
|
|
|
|
/*
|
|
* Write the DIB header and the bits -- use local version of
|
|
* MyWrite, so we can write more than 32767 bytes of data
|
|
*/
|
|
dwError = MyWrite(fh, (LPSTR)lpBI, dwDIBSize);
|
|
GlobalUnlock(hDib);
|
|
_lclose(fh);
|
|
|
|
if (dwError == 0)
|
|
return ERR_OPEN; // oops, something happened in the write
|
|
else
|
|
return 0; // Success code
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* DestroyDIB ()
|
|
*
|
|
* Purpose: Frees memory associated with a DIB
|
|
*
|
|
* Returns: Nothing
|
|
*
|
|
* History: Date Author Reason
|
|
* 9/15/91 Mark Bader Created
|
|
*
|
|
*************************************************************************/
|
|
|
|
|
|
WORD DestroyDIB(HDIB hDib)
|
|
{
|
|
GlobalFree(hDib);
|
|
return 0;
|
|
}
|
|
|
|
|
|
//************************************************************************
|
|
//
|
|
// Auxiliary Functions which the above procedures use
|
|
//
|
|
//************************************************************************
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* Function: ReadDIBFile (int)
|
|
*
|
|
* Purpose: Reads in the specified DIB file into a global chunk of
|
|
* memory.
|
|
*
|
|
* Returns: A handle to a dib (hDIB) if successful.
|
|
* NULL if an error occurs.
|
|
*
|
|
* Comments: BITMAPFILEHEADER is stripped off of the DIB. Everything
|
|
* from the end of the BITMAPFILEHEADER structure on is
|
|
* returned in the global memory handle.
|
|
*
|
|
*
|
|
* NOTE: The DIB API were not written to handle OS/2 DIBs, so this
|
|
* function will reject any file that is not a Windows DIB.
|
|
*
|
|
* History: Date Author Reason
|
|
* 9/15/91 Mark Bader Based on DIBVIEW
|
|
* 6/25/92 Mark Bader Added check for OS/2 DIB
|
|
* 7/21/92 Mark Bader Added code to deal with bfOffBits
|
|
* field in BITMAPFILEHEADER
|
|
* 9/11/92 Mark Bader Fixed Realloc Code to free original mem
|
|
*
|
|
*************************************************************************/
|
|
|
|
HANDLE ReadDIBFile(int hFile)
|
|
{
|
|
BITMAPFILEHEADER bmfHeader;
|
|
UINT nNumColors; // Number of colors in table
|
|
HANDLE hDIB;
|
|
HANDLE hDIBtmp; // Used for GlobalRealloc() //MPB
|
|
LPBITMAPINFOHEADER lpbi;
|
|
DWORD offBits;
|
|
|
|
/*
|
|
* get length of DIB in bytes for use when reading
|
|
*/
|
|
|
|
// Allocate memory for header & color table. We'll enlarge this
|
|
// memory as needed.
|
|
|
|
hDIB = GlobalAlloc(GMEM_MOVEABLE,
|
|
(DWORD)(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)));
|
|
|
|
if (!hDIB) return NULL;
|
|
|
|
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
|
|
if (!lpbi)
|
|
{
|
|
GlobalFree(hDIB);
|
|
return NULL;
|
|
}
|
|
|
|
// read the BITMAPFILEHEADER from our file
|
|
|
|
if (sizeof (BITMAPFILEHEADER) != _lread (hFile, (LPSTR)&bmfHeader, sizeof (BITMAPFILEHEADER)))
|
|
goto ErrExit;
|
|
|
|
if (bmfHeader.bfType != 0x4d42) /* 'BM' */
|
|
goto ErrExit;
|
|
|
|
// read the BITMAPINFOHEADER
|
|
|
|
if (sizeof(BITMAPINFOHEADER) != _lread (hFile, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)))
|
|
goto ErrExit;
|
|
|
|
// Check to see that it's a Windows DIB -- an OS/2 DIB would cause
|
|
// strange problems with the rest of the DIB API since the fields
|
|
// in the header are different and the color table entries are
|
|
// smaller.
|
|
//
|
|
// If it's not a Windows DIB (e.g. if biSize is wrong), return NULL.
|
|
|
|
if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
|
|
goto ErrExit;
|
|
|
|
// Now determine the size of the color table and read it. Since the
|
|
// bitmap bits are offset in the file by bfOffBits, we need to do some
|
|
// special processing here to make sure the bits directly follow
|
|
// the color table (because that's the format we are susposed to pass
|
|
// back)
|
|
|
|
if (!(nNumColors = (UINT)lpbi->biClrUsed))
|
|
{
|
|
// no color table for 24-bit, default size otherwise
|
|
if (lpbi->biBitCount != 24)
|
|
nNumColors = 1 << lpbi->biBitCount; /* standard size table */
|
|
}
|
|
|
|
// fill in some default values if they are zero
|
|
if (lpbi->biClrUsed == 0)
|
|
lpbi->biClrUsed = nNumColors;
|
|
|
|
if (lpbi->biSizeImage == 0)
|
|
{
|
|
lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3)
|
|
* lpbi->biHeight;
|
|
}
|
|
|
|
// get a proper-sized buffer for header, color table and bits
|
|
GlobalUnlock(hDIB);
|
|
hDIBtmp = GlobalReAlloc(hDIB, lpbi->biSize +
|
|
nNumColors * sizeof(RGBQUAD) +
|
|
lpbi->biSizeImage, 0);
|
|
|
|
if (!hDIBtmp) // can't resize buffer for loading
|
|
goto ErrExitNoUnlock; //MPB
|
|
else
|
|
hDIB = hDIBtmp;
|
|
|
|
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
|
|
|
|
// read the color table
|
|
_lread (hFile, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBQUAD));
|
|
|
|
// offset to the bits from start of DIB header
|
|
offBits = lpbi->biSize + nNumColors * sizeof(RGBQUAD);
|
|
|
|
// If the bfOffBits field is non-zero, then the bits might *not* be
|
|
// directly following the color table in the file. Use the value in
|
|
// bfOffBits to seek the bits.
|
|
|
|
if (bmfHeader.bfOffBits != 0L)
|
|
_llseek(hFile, bmfHeader.bfOffBits, SEEK_SET);
|
|
|
|
if (MyRead(hFile, (LPSTR)lpbi + offBits, lpbi->biSizeImage))
|
|
goto OKExit;
|
|
|
|
|
|
ErrExit:
|
|
GlobalUnlock(hDIB);
|
|
ErrExitNoUnlock:
|
|
GlobalFree(hDIB);
|
|
return NULL;
|
|
|
|
OKExit:
|
|
GlobalUnlock(hDIB);
|
|
return hDIB;
|
|
}
|
|
|
|
/*************************************************************************
|
|
|
|
Function: MyRead (int, LPSTR, DWORD)
|
|
|
|
Purpose: Routine to read files greater than 64K in size.
|
|
|
|
Returns: TRUE if successful.
|
|
FALSE if an error occurs.
|
|
|
|
|
|
History: Date Author Reason
|
|
9/15/91 Mark Bader Based on DIBVIEW
|
|
|
|
*************************************************************************/
|
|
|
|
|
|
bool MyRead(int hFile, LPSTR lpBuffer, DWORD dwSize)
|
|
{
|
|
char *lpInBuf = (char *)lpBuffer;
|
|
int nBytes;
|
|
|
|
/*
|
|
* Read in the data in 32767 byte chunks (or a smaller amount if it's
|
|
* the last chunk of data read)
|
|
*/
|
|
|
|
while (dwSize)
|
|
{
|
|
nBytes = (int)(dwSize > (DWORD)32767 ? 32767 : LOWORD (dwSize));
|
|
if (_lread(hFile, (LPSTR)lpInBuf, nBytes) != (WORD)nBytes)
|
|
return FALSE;
|
|
dwSize -= nBytes;
|
|
lpInBuf += nBytes;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
FUNCTION : MyWrite(int fh, VOID *pv, DWORD ul)
|
|
|
|
PURPOSE : Writes data in steps of 32k till all the data is written.
|
|
Normal _lwrite uses a WORD as 3rd parameter, so it is
|
|
limited to 32767 bytes, but this procedure is not.
|
|
|
|
RETURNS : 0 - If write did not proceed correctly.
|
|
number of bytes written otherwise.
|
|
|
|
History: Date Author Reason
|
|
9/15/91 Mark Bader Based on DIBVIEW
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
DWORD PASCAL MyWrite(int iFileHandle, VOID *lpBuffer, DWORD dwBytes)
|
|
{
|
|
DWORD dwBytesTmp = dwBytes; // Save # of bytes for return value
|
|
BYTE *hpBuffer = (BYTE *)lpBuffer; // make a huge pointer to the data
|
|
|
|
/*
|
|
* Write out the data in 32767 byte chunks.
|
|
*/
|
|
|
|
while (dwBytes > 32767)
|
|
{
|
|
if (_lwrite(iFileHandle, (LPSTR)hpBuffer, (WORD)32767) != 32767)
|
|
return 0;
|
|
dwBytes -= 32767;
|
|
hpBuffer += 32767;
|
|
}
|
|
|
|
/* Write out the last chunk (which is < 32767 bytes) */
|
|
if (_lwrite(iFileHandle, (LPSTR)hpBuffer, (WORD)dwBytes) != (WORD)dwBytes)
|
|
return 0;
|
|
return dwBytesTmp;
|
|
}
|
|
|
|
}
|