heretic2-sdk/Toolkit/Programming/Tools/qMView/Dibapi.cpp
1998-11-24 00:00:00 +00:00

482 lines
14 KiB
C++

// dibapi.cpp
//
// Source file for Device-Independent Bitmap (DIB) API. Provides
// the following functions:
//
// PaintDIB() - Painting routine for a DIB
// CreateDIBPalette() - Creates a palette from a DIB
// FindDIBBits() - Returns a pointer to the DIB bits
// DIBWidth() - Gets the width of the DIB
// DIBHeight() - Gets the height of the DIB
// PaletteSize() - Gets the size required to store the DIB's palette
// DIBNumColors() - Calculates the number of colors
// in the DIB's color table
// CopyHandle() - Makes a copy of the given global memory block
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1997 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include "dibapi.h"
#include <io.h>
#include <errno.h>
/*************************************************************************
*
* PaintDIB()
*
* Parameters:
*
* HDC hDC - DC to do output to
*
* LPRECT lpDCRect - rectangle on DC to do output to
*
* HDIB hDIB - handle to global memory with a DIB spec
* in it followed by the DIB bits
*
* LPRECT lpDIBRect - rectangle of DIB to output into lpDCRect
*
* CPalette* pPal - pointer to CPalette containing DIB's palette
*
* Return Value:
*
* BOOL - TRUE if DIB was drawn, FALSE otherwise
*
* Description:
* Painting routine for a DIB. Calls StretchDIBits() or
* SetDIBitsToDevice() to paint the DIB. The DIB is
* output to the specified DC, at the coordinates given
* in lpDCRect. The area of the DIB to be output is
* given by lpDIBRect.
*
************************************************************************/
BOOL WINAPI PaintDIB(HDC hDC,
LPRECT lpDCRect,
HDIB hDIB,
LPRECT lpDIBRect,
CPalette* pPal)
{
LPSTR lpDIBHdr; // Pointer to BITMAPINFOHEADER
LPSTR lpDIBBits; // Pointer to DIB bits
BOOL bSuccess=FALSE; // Success/fail flag
HPALETTE hPal=NULL; // Our DIB's palette
HPALETTE hOldPal=NULL; // Previous palette
/* Check for valid DIB handle */
if (hDIB == NULL)
return FALSE;
/* Lock down the DIB, and get a pointer to the beginning of the bit
* buffer
*/
lpDIBHdr = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
lpDIBBits = ::FindDIBBits(lpDIBHdr);
// Get the DIB's palette, then select it into DC
if (pPal != NULL)
{
hPal = (HPALETTE) pPal->m_hObject;
// Select as background since we have
// already realized in forground if needed
hOldPal = ::SelectPalette(hDC, hPal, TRUE);
}
/* Make sure to use the stretching mode best for color pictures */
::SetStretchBltMode(hDC, COLORONCOLOR);
/* Determine whether to call StretchDIBits() or SetDIBitsToDevice() */
if ((RECTWIDTH(lpDCRect) == RECTWIDTH(lpDIBRect)) &&
(RECTHEIGHT(lpDCRect) == RECTHEIGHT(lpDIBRect)))
bSuccess = ::SetDIBitsToDevice(hDC, // hDC
lpDCRect->left, // DestX
lpDCRect->top, // DestY
RECTWIDTH(lpDCRect), // nDestWidth
RECTHEIGHT(lpDCRect), // nDestHeight
lpDIBRect->left, // SrcX
(int)DIBHeight(lpDIBHdr) -
lpDIBRect->top -
RECTHEIGHT(lpDIBRect), // SrcY
0, // nStartScan
(WORD)DIBHeight(lpDIBHdr), // nNumScans
lpDIBBits, // lpBits
(LPBITMAPINFO)lpDIBHdr, // lpBitsInfo
DIB_RGB_COLORS); // wUsage
else
bSuccess = ::StretchDIBits(hDC, // hDC
lpDCRect->left, // DestX
lpDCRect->top, // DestY
RECTWIDTH(lpDCRect), // nDestWidth
RECTHEIGHT(lpDCRect), // nDestHeight
lpDIBRect->left, // SrcX
lpDIBRect->top, // SrcY
RECTWIDTH(lpDIBRect), // wSrcWidth
RECTHEIGHT(lpDIBRect), // wSrcHeight
lpDIBBits, // lpBits
(LPBITMAPINFO)lpDIBHdr, // lpBitsInfo
DIB_RGB_COLORS, // wUsage
SRCCOPY); // dwROP
::GlobalUnlock((HGLOBAL) hDIB);
/* Reselect old palette */
if (hOldPal != NULL)
{
::SelectPalette(hDC, hOldPal, TRUE);
}
return bSuccess;
}
/*************************************************************************
*
* 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).
*
************************************************************************/
BOOL WINAPI CreateDIBPalette(HDIB hDIB, CPalette* pPal)
{
LPLOGPALETTE lpPal; // pointer to a logical palette
HANDLE hLogPal; // handle to a logical palette
HPALETTE hPal = NULL; // handle to a palette
int i; // loop index
WORD wNumColors; // 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 (old)
BOOL bWinStyleDIB; // flag which signifies whether this is a Win3.0 DIB
BOOL bResult = FALSE;
/* if handle to DIB is invalid, return FALSE */
if (hDIB == NULL)
return FALSE;
lpbi = (LPSTR) ::GlobalLock((HGLOBAL) hDIB);
/* get pointer to BITMAPINFO (Win 3.0) */
lpbmi = (LPBITMAPINFO)lpbi;
/* get pointer to BITMAPCOREINFO (old 1.x) */
lpbmc = (LPBITMAPCOREINFO)lpbi;
/* get the number of colors in the DIB */
wNumColors = ::DIBNumColors(lpbi);
if (wNumColors != 0)
{
/* 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 == 0)
{
::GlobalUnlock((HGLOBAL) hDIB);
return FALSE;
}
lpPal = (LPLOGPALETTE) ::GlobalLock((HGLOBAL) hLogPal);
/* set version and number of palette entries */
lpPal->palVersion = PALVERSION;
lpPal->palNumEntries = (WORD)wNumColors;
/* is this a Win 3.0 DIB? */
bWinStyleDIB = IS_WIN30_DIB(lpbi);
for (i = 0; i < (int)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 */
bResult = pPal->CreatePalette(lpPal);
::GlobalUnlock((HGLOBAL) hLogPal);
::GlobalFree((HGLOBAL) hLogPal);
}
::GlobalUnlock((HGLOBAL) hDIB);
return bResult;
}
/*************************************************************************
*
* FindDIBBits()
*
* Parameter:
*
* LPSTR lpbi - 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.
*
************************************************************************/
LPSTR WINAPI FindDIBBits(LPSTR lpbi)
{
return (lpbi + *(LPDWORD)lpbi + ::PaletteSize(lpbi));
}
/*************************************************************************
*
* DIBWidth()
*
* Parameter:
*
* LPSTR lpbi - 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 other-style DIB.
*
************************************************************************/
DWORD WINAPI DIBWidth(LPSTR lpDIB)
{
LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB
LPBITMAPCOREHEADER lpbmc; // pointer to an other-style DIB
/* point to the header (whether Win 3.0 and old) */
lpbmi = (LPBITMAPINFOHEADER)lpDIB;
lpbmc = (LPBITMAPCOREHEADER)lpDIB;
/* return the DIB width if it is a Win 3.0 DIB */
if (IS_WIN30_DIB(lpDIB))
return lpbmi->biWidth;
else /* it is an other-style DIB, so return its width */
return (DWORD)lpbmc->bcWidth;
}
/*************************************************************************
*
* DIBHeight()
*
* Parameter:
*
* LPSTR lpbi - 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 other-style DIB.
*
************************************************************************/
DWORD WINAPI DIBHeight(LPSTR lpDIB)
{
LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB
LPBITMAPCOREHEADER lpbmc; // pointer to an other-style DIB
/* point to the header (whether old or Win 3.0 */
lpbmi = (LPBITMAPINFOHEADER)lpDIB;
lpbmc = (LPBITMAPCOREHEADER)lpDIB;
/* return the DIB height if it is a Win 3.0 DIB */
if (IS_WIN30_DIB(lpDIB))
return lpbmi->biHeight;
else /* it is an other-style DIB, so return its height */
return (DWORD)lpbmc->bcHeight;
}
/*************************************************************************
*
* PaletteSize()
*
* Parameter:
*
* LPSTR lpbi - 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 other-
* style DIB).
*
************************************************************************/
WORD WINAPI PaletteSize(LPSTR lpbi)
{
/* calculate the size required by the palette */
if (IS_WIN30_DIB (lpbi))
return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBQUAD));
else
return (WORD)(::DIBNumColors(lpbi) * sizeof(RGBTRIPLE));
}
/*************************************************************************
*
* DIBNumColors()
*
* Parameter:
*
* LPSTR lpbi - 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 other-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.
*
************************************************************************/
WORD WINAPI DIBNumColors(LPSTR lpbi)
{
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(lpbi))
{
DWORD dwClrUsed;
dwClrUsed = ((LPBITMAPINFOHEADER)lpbi)->biClrUsed;
if (dwClrUsed != 0)
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(lpbi))
wBitCount = ((LPBITMAPINFOHEADER)lpbi)->biBitCount;
else
wBitCount = ((LPBITMAPCOREHEADER)lpbi)->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;
}
}
//////////////////////////////////////////////////////////////////////////
//// Clipboard support
//---------------------------------------------------------------------
//
// Function: CopyHandle (from SDK DibView sample clipbrd.c)
//
// Purpose: Makes a copy of the given global memory block. Returns
// a handle to the new memory block (NULL on error).
//
// Routine stolen verbatim out of ShowDIB.
//
// Parms: h == Handle to global memory to duplicate.
//
// Returns: Handle to new global memory block.
//
//---------------------------------------------------------------------
HGLOBAL WINAPI CopyHandle (HGLOBAL h)
{
if (h == NULL)
return NULL;
DWORD dwLen = ::GlobalSize((HGLOBAL) h);
HGLOBAL hCopy = ::GlobalAlloc(GHND, dwLen);
if (hCopy != NULL)
{
void* lpCopy = ::GlobalLock((HGLOBAL) hCopy);
void* lp = ::GlobalLock((HGLOBAL) h);
memcpy(lpCopy, lp, dwLen);
::GlobalUnlock(hCopy);
::GlobalUnlock(h);
}
return hCopy;
}