mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1381 lines
36 KiB
1381 lines
36 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: bitmap.c *
|
|
* *
|
|
* Client side stubs that move bitmaps over the C/S interface. *
|
|
* *
|
|
* Created: 14-May-1991 11:04:49 *
|
|
* Author: Eric Kutter [erick] *
|
|
* *
|
|
* Copyright (c) 1991 Microsoft Corporation *
|
|
\**************************************************************************/
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
ULONG cjBitmapBitsSize(CONST BITMAPINFO *pbmi)
|
|
{
|
|
// Check for PM-style DIB
|
|
|
|
if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
|
|
{
|
|
LPBITMAPCOREINFO pbmci;
|
|
pbmci = (LPBITMAPCOREINFO)pbmi;
|
|
return(CJSCAN(pbmci->bmciHeader.bcWidth,pbmci->bmciHeader.bcPlanes,
|
|
pbmci->bmciHeader.bcBitCount) *
|
|
pbmci->bmciHeader.bcHeight);
|
|
}
|
|
|
|
// not a core header
|
|
|
|
if ((pbmi->bmiHeader.biCompression == BI_RGB) ||
|
|
(pbmi->bmiHeader.biCompression == BI_BITFIELDS))
|
|
{
|
|
return(CJSCAN(pbmi->bmiHeader.biWidth,pbmi->bmiHeader.biPlanes,
|
|
pbmi->bmiHeader.biBitCount) *
|
|
ABS(pbmi->bmiHeader.biHeight));
|
|
}
|
|
else
|
|
{
|
|
return(pbmi->bmiHeader.biSizeImage);
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************************************\
|
|
* pbmiConvertInfo
|
|
*
|
|
* Does two things:
|
|
*
|
|
* 1. takes BITMAPINFO, Converts BITMAPCOREHEADER
|
|
* into BITMAPINFOHEADER and copies the the color table
|
|
*
|
|
* 2. also return the size of the size of INFO struct if bPackedDIB is FALSE
|
|
* otherwise pass back the size of INFO plus cjBits
|
|
*
|
|
* 10-1-95 -by- Lingyun Wang [lingyunw]
|
|
\**********************************************************************/
|
|
LPBITMAPINFO pbmiConvertInfo(CONST BITMAPINFO *pbmi, ULONG iUsage, ULONG *count, BOOL bPackedDIB)
|
|
{
|
|
LPBITMAPINFO pbmiNew;
|
|
ULONG cjRGB;
|
|
ULONG cColorsMax;
|
|
ULONG cColors;
|
|
UINT uiBitCount;
|
|
UINT uiPalUsed;
|
|
UINT uiCompression;
|
|
BOOL bCoreHeader = FALSE;
|
|
ULONG ulSize;
|
|
ULONG cjBits = 0;
|
|
PVOID pjBits, pjBitsNew;
|
|
|
|
if (pbmi == (LPBITMAPINFO) NULL)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
//
|
|
// Checking for different bitmap headers
|
|
//
|
|
ulSize = pbmi->bmiHeader.biSize;
|
|
|
|
if (ulSize == sizeof(BITMAPCOREHEADER))
|
|
{
|
|
cjRGB = sizeof(RGBQUAD);
|
|
uiBitCount = ((LPBITMAPCOREINFO)pbmi)->bmciHeader.bcBitCount;
|
|
uiPalUsed = 0;
|
|
uiCompression = (UINT) BI_RGB;
|
|
bCoreHeader = TRUE;
|
|
}
|
|
else if (ulSize >= sizeof(BITMAPINFOHEADER))
|
|
{
|
|
cjRGB = sizeof(RGBQUAD);
|
|
uiBitCount = pbmi->bmiHeader.biBitCount;
|
|
uiPalUsed = pbmi->bmiHeader.biClrUsed;
|
|
uiCompression = (UINT) pbmi->bmiHeader.biCompression;
|
|
}
|
|
else
|
|
{
|
|
WARNING("ConvertInfo failed - invalid header size\n");
|
|
return(0);
|
|
}
|
|
|
|
//
|
|
// figure out the size of the color table
|
|
//
|
|
if (uiCompression == BI_BITFIELDS)
|
|
{
|
|
// Handle 16 and 32 bit per pel bitmaps.
|
|
|
|
if (iUsage == DIB_PAL_COLORS)
|
|
{
|
|
iUsage = DIB_RGB_COLORS;
|
|
}
|
|
|
|
switch (uiBitCount)
|
|
{
|
|
case 16:
|
|
case 32:
|
|
break;
|
|
default:
|
|
WARNING("ConvertInfo failed for BI_BITFIELDS\n");
|
|
return(0);
|
|
}
|
|
|
|
uiPalUsed = cColorsMax = 3;
|
|
}
|
|
else if (uiCompression == BI_RGB)
|
|
{
|
|
switch (uiBitCount)
|
|
{
|
|
case 1:
|
|
cColorsMax = 2;
|
|
break;
|
|
case 4:
|
|
cColorsMax = 16;
|
|
break;
|
|
case 8:
|
|
cColorsMax = 256;
|
|
break;
|
|
default:
|
|
|
|
if (iUsage == DIB_PAL_COLORS)
|
|
{
|
|
iUsage = DIB_RGB_COLORS;
|
|
}
|
|
|
|
cColorsMax = 0;
|
|
|
|
switch (uiBitCount)
|
|
{
|
|
case 16:
|
|
case 24:
|
|
case 32:
|
|
break;
|
|
default:
|
|
WARNING("convertinfo failed invalid bitcount in bmi BI_RGB\n");
|
|
return(0);
|
|
}
|
|
}
|
|
}
|
|
else if (uiCompression == BI_RLE4)
|
|
{
|
|
if (uiBitCount != 4)
|
|
{
|
|
// WARNING("cjBitmapSize invalid bitcount BI_RLE4\n");
|
|
return(0);
|
|
}
|
|
|
|
cColorsMax = 16;
|
|
}
|
|
else if (uiCompression == BI_RLE8)
|
|
{
|
|
if (uiBitCount != 8)
|
|
{
|
|
// WARNING("cjBitmapSize invalid bitcount BI_RLE8\n");
|
|
return(0);
|
|
}
|
|
|
|
cColorsMax = 256;
|
|
}
|
|
else
|
|
{
|
|
WARNING("convertinfo failed invalid Compression in header\n");
|
|
return(0);
|
|
}
|
|
|
|
if (uiPalUsed != 0)
|
|
{
|
|
if (uiPalUsed <= cColorsMax)
|
|
cColors = uiPalUsed;
|
|
else
|
|
cColors = cColorsMax;
|
|
}
|
|
else
|
|
cColors = cColorsMax;
|
|
|
|
if (iUsage == DIB_PAL_COLORS)
|
|
cjRGB = sizeof(USHORT);
|
|
else if (iUsage == DIB_PAL_INDICES)
|
|
cjRGB = 0;
|
|
|
|
if (bPackedDIB)
|
|
cjBits = cjBitmapBitsSize(pbmi);
|
|
|
|
//
|
|
// if passed non COREHEADER, donot need to convert
|
|
//
|
|
if (!bCoreHeader)
|
|
{
|
|
pbmiNew = (LPBITMAPINFO)pbmi;
|
|
}
|
|
else
|
|
{
|
|
RGBTRIPLE *pTri;
|
|
RGBQUAD *pQuad;
|
|
|
|
//
|
|
// allocate new header to hold the info
|
|
//
|
|
ulSize = sizeof(BITMAPINFOHEADER);
|
|
|
|
pbmiNew = (PBITMAPINFO)LocalAlloc(LMEM_FIXED,ulSize +
|
|
cjRGB * cColors+cjBits);
|
|
|
|
if (pbmiNew == NULL)
|
|
return (0);
|
|
|
|
pbmiNew->bmiHeader.biSize = ulSize;
|
|
|
|
//
|
|
// copy COREHEADER info over
|
|
//
|
|
|
|
pbmiNew->bmiHeader.biWidth = ((BITMAPCOREHEADER *)pbmi)->bcWidth;
|
|
pbmiNew->bmiHeader.biHeight = ((BITMAPCOREHEADER *)pbmi)->bcHeight;
|
|
pbmiNew->bmiHeader.biPlanes = ((BITMAPCOREHEADER *)pbmi)->bcPlanes;
|
|
pbmiNew->bmiHeader.biBitCount = ((BITMAPCOREHEADER *)pbmi)->bcBitCount;
|
|
pbmiNew->bmiHeader.biCompression = 0;
|
|
pbmiNew->bmiHeader.biSizeImage = 0;
|
|
pbmiNew->bmiHeader.biXPelsPerMeter = 0;
|
|
pbmiNew->bmiHeader.biYPelsPerMeter = 0;
|
|
pbmiNew->bmiHeader.biClrUsed = 0;
|
|
pbmiNew->bmiHeader.biClrImportant = 0;
|
|
|
|
//
|
|
// copy the color table
|
|
//
|
|
|
|
pTri = (RGBTRIPLE *)((LPBYTE)pbmi + sizeof(BITMAPCOREHEADER));
|
|
pQuad = (RGBQUAD *)((LPBYTE)pbmiNew + sizeof(BITMAPINFOHEADER));
|
|
|
|
//
|
|
// copy RGBTRIPLE to RGBQUAD
|
|
//
|
|
if (iUsage != DIB_PAL_COLORS)
|
|
{
|
|
INT cj = cColors;
|
|
|
|
while (cj--)
|
|
{
|
|
pQuad->rgbRed = pTri->rgbtRed;
|
|
pQuad->rgbGreen = pTri->rgbtGreen;
|
|
pQuad->rgbBlue = pTri->rgbtBlue;
|
|
pQuad->rgbReserved = 0;
|
|
|
|
pQuad++;
|
|
pTri++;
|
|
}
|
|
|
|
if (bPackedDIB)
|
|
pjBits = (LPBYTE)pbmi + sizeof(BITMAPCOREHEADER) + cColors*sizeof(RGBTRIPLE);
|
|
}
|
|
else
|
|
// DIB_PAL_COLORS
|
|
{
|
|
RtlCopyMemory((LPBYTE)pQuad,(LPBYTE)pTri,cColors * cjRGB);
|
|
|
|
if (bPackedDIB)
|
|
pjBits = (LPBYTE)pbmi + sizeof(BITMAPCOREHEADER) + cColors * cjRGB;
|
|
}
|
|
|
|
//
|
|
// copy the packed bits
|
|
//
|
|
if (bPackedDIB)
|
|
{
|
|
pjBitsNew = (LPBYTE)pbmiNew + ulSize + cColors*cjRGB;
|
|
|
|
RtlCopyMemory((LPBYTE)pjBitsNew,
|
|
(LPBYTE)pjBits,
|
|
cjBits);
|
|
}
|
|
}
|
|
|
|
*count = ((ulSize + (cjRGB * cColors) + cjBits) + 3) & ~3;
|
|
|
|
return((LPBITMAPINFO) pbmiNew);
|
|
}
|
|
|
|
ULONG cjBitmapScanSize(
|
|
CONST BITMAPINFO *pbmi,
|
|
int nScans
|
|
)
|
|
{
|
|
// Check for PM-style DIB
|
|
|
|
if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
|
|
{
|
|
LPBITMAPCOREINFO pbmci;
|
|
pbmci = (LPBITMAPCOREINFO)pbmi;
|
|
|
|
return(CJSCAN(pbmci->bmciHeader.bcWidth,pbmci->bmciHeader.bcPlanes,
|
|
pbmci->bmciHeader.bcBitCount) * nScans);
|
|
}
|
|
|
|
// not a core header
|
|
|
|
if ((pbmi->bmiHeader.biCompression == BI_RGB) ||
|
|
(pbmi->bmiHeader.biCompression == BI_BITFIELDS))
|
|
{
|
|
return(CJSCAN(pbmi->bmiHeader.biWidth,pbmi->bmiHeader.biPlanes,
|
|
pbmi->bmiHeader.biBitCount) * nScans);
|
|
}
|
|
//
|
|
// rle: use image size, nScans is not used
|
|
//
|
|
//else if (nScans >= pbmi->bmiHeader.biHeight)
|
|
//{
|
|
else
|
|
{
|
|
return(pbmi->bmiHeader.biSizeImage);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* CopyCoreToInfoHeader
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID CopyCoreToInfoHeader(LPBITMAPINFOHEADER pbmih, LPBITMAPCOREHEADER pbmch)
|
|
{
|
|
pbmih->biSize = sizeof(BITMAPINFOHEADER);
|
|
pbmih->biWidth = pbmch->bcWidth;
|
|
pbmih->biHeight = pbmch->bcHeight;
|
|
pbmih->biPlanes = pbmch->bcPlanes;
|
|
pbmih->biBitCount = pbmch->bcBitCount;
|
|
pbmih->biCompression = BI_RGB;
|
|
pbmih->biSizeImage = 0;
|
|
pbmih->biXPelsPerMeter = 0;
|
|
pbmih->biYPelsPerMeter = 0;
|
|
pbmih->biClrUsed = 0;
|
|
pbmih->biClrImportant = 0;
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD SetDIBitsToDevice *
|
|
* *
|
|
* Can reduce it to 1 scan at a time. If compressed mode, this could *
|
|
* gete very difficult. There must be enough space for the header and *
|
|
* color table. This will be needed for every batch. *
|
|
* *
|
|
* BITMAPINFO *
|
|
* BITMAPINFOHEADER *
|
|
* RGBQUAD[cEntries] | RGBTRIPLE[cEntries] *
|
|
* *
|
|
* *
|
|
* 1. compute header size (including color table) *
|
|
* 2. compute size of required bits *
|
|
* 3. compute total size (header + bits + args) *
|
|
* 4. if (memory window is large enough for header + at least 1 scan *
|
|
* *
|
|
* History: *
|
|
* Tue 29-Oct-1991 -by- Patrick Haluptzok [patrickh] *
|
|
* Add shared memory action for large RLE's. *
|
|
* *
|
|
* Tue 19-Oct-1991 -by- Patrick Haluptzok [patrickh] *
|
|
* Add support for RLE's *
|
|
* *
|
|
* Thu 20-Jun-1991 01:41:45 -by- Charles Whitmer [chuckwh] *
|
|
* Added handle translation and metafiling. *
|
|
* *
|
|
* 14-May-1991 -by- Eric Kutter [erick] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
int SetDIBitsToDevice(
|
|
HDC hdc,
|
|
int xDest,
|
|
int yDest,
|
|
DWORD nWidth,
|
|
DWORD nHeight,
|
|
int xSrc,
|
|
int ySrc,
|
|
UINT nStartScan,
|
|
UINT nNumScans,
|
|
CONST VOID * pBits,
|
|
CONST BITMAPINFO *pbmi,
|
|
UINT iUsage) // DIB_PAL_COLORS || DIB_RGB_COLORS
|
|
{
|
|
LONG cScansCopied = 0; // total # of scans copied
|
|
LONG ySrcMax; // maximum ySrc possible
|
|
|
|
// hold info about the header
|
|
|
|
UINT uiWidth;
|
|
UINT uiHeight;
|
|
PULONG pulBits = NULL;
|
|
INT cjHeader = 0;
|
|
LPBITMAPINFO pbmiNew = NULL;
|
|
ULONG cjBits;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
// Let's validate the parameters so we don't gp-fault ourselves and
|
|
// to save checks later on.
|
|
|
|
if ((nNumScans == 0) ||
|
|
(pbmi == (LPBITMAPINFO) NULL) ||
|
|
(pBits == (LPVOID) NULL) ||
|
|
((iUsage != DIB_RGB_COLORS) &&
|
|
(iUsage != DIB_PAL_COLORS) &&
|
|
(iUsage != DIB_PAL_INDICES)))
|
|
{
|
|
WARNING("You failed a param validation in SetDIBitsToDevice\n");
|
|
return(0);
|
|
}
|
|
|
|
pbmiNew = pbmiConvertInfo(pbmi, iUsage, &cjHeader, FALSE);
|
|
|
|
if (pbmiNew == NULL)
|
|
return (0);
|
|
|
|
uiWidth = (UINT) pbmiNew->bmiHeader.biWidth;
|
|
uiHeight = (UINT) pbmiNew->bmiHeader.biHeight;
|
|
|
|
// Compute the minimum nNumScans to send across csr interface.
|
|
// It will also prevent faults as a result of overreading the source.
|
|
|
|
ySrcMax = max(ySrc, ySrc + (int) nHeight);
|
|
if (ySrcMax <= 0)
|
|
return(0);
|
|
ySrcMax = min(ySrcMax, (int) uiHeight);
|
|
nNumScans = min(nNumScans, (UINT) ySrcMax - nStartScan);
|
|
|
|
// NEWFRAME support for backward compatibility.
|
|
// Ship the transform to the server side if needed.
|
|
|
|
if (IS_ALTDC_TYPE(hdc))
|
|
{
|
|
PLDC pldc;
|
|
|
|
if (IS_METADC16_TYPE(hdc))
|
|
{
|
|
cScansCopied = MF_AnyDIBits(
|
|
hdc,
|
|
xDest,yDest,0,0,
|
|
xSrc,ySrc,(int) nWidth,(int) nHeight,
|
|
nStartScan,nNumScans,
|
|
pBits,pbmi,
|
|
iUsage,
|
|
SRCCOPY,
|
|
META_SETDIBTODEV
|
|
);
|
|
|
|
goto Exit;
|
|
|
|
}
|
|
|
|
DC_PLDC(hdc,pldc,0);
|
|
|
|
if (pldc->iType == LO_METADC)
|
|
{
|
|
if (!MF_AnyDIBits(
|
|
hdc,
|
|
xDest,yDest,0,0,
|
|
xSrc,ySrc,(int) nWidth,(int) nHeight,
|
|
nStartScan,nNumScans,
|
|
pBits,pbmi,
|
|
iUsage,
|
|
SRCCOPY,
|
|
EMR_SETDIBITSTODEVICE
|
|
))
|
|
{
|
|
cScansCopied = 0;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if (pldc->fl & LDC_CALL_STARTPAGE)
|
|
StartPage(hdc);
|
|
|
|
if (pldc->fl & LDC_SAP_CALLBACK)
|
|
vSAPCallback(pldc);
|
|
|
|
//BUGBUG - for printing, we may want to band like in the old days
|
|
// so we can call vSAPCallback every few bands.
|
|
|
|
if (pldc->fl & LDC_DOC_CANCELLED)
|
|
{
|
|
cScansCopied = 0;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// reset user's poll count so it counts this as output
|
|
// put it right next to BEGINMSG so that NtCurrentTeb() is optimized
|
|
|
|
RESETUSERPOLLCOUNT();
|
|
|
|
//
|
|
// Calculate bitmap bits size based on BITMAPINFO and nNumScans
|
|
//
|
|
|
|
cjBits = cjBitmapScanSize(pbmi,nNumScans);
|
|
|
|
// if the pBits are not dword aligned we need to allocate a buffer and copy them
|
|
|
|
if ((ULONG)pBits & (sizeof(DWORD) - 1))
|
|
{
|
|
|
|
pulBits = LocalAlloc(LMEM_FIXED,cjBits);
|
|
if (pulBits)
|
|
{
|
|
RtlCopyMemory(pulBits,pBits,cjBits);
|
|
pBits = pulBits;
|
|
}
|
|
}
|
|
|
|
cScansCopied = NtGdiSetDIBitsToDeviceInternal(
|
|
hdc,
|
|
xDest,
|
|
yDest,
|
|
nWidth,
|
|
nHeight,
|
|
xSrc,
|
|
ySrc,
|
|
nStartScan,
|
|
nNumScans,
|
|
(LPBYTE)pBits,
|
|
pbmiNew,
|
|
iUsage,
|
|
(UINT)cjBits,
|
|
(UINT)cjHeader,
|
|
TRUE);
|
|
|
|
if (pulBits)
|
|
LocalFree(pulBits);
|
|
|
|
Exit:
|
|
if (pbmiNew && (pbmiNew != pbmi))
|
|
{
|
|
LocalFree (pbmiNew);
|
|
}
|
|
return (cScansCopied);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* DWORD GetDIBits
|
|
*
|
|
* Can reduce it to 1 scan at a time. There must be enough space
|
|
* for the header and color table. This will be needed for every chunk
|
|
*
|
|
* History:
|
|
* Wed 04-Dec-1991 -by- Patrick Haluptzok [patrickh]
|
|
* bug fix, only check for valid DC if DIB_PAL_COLORS.
|
|
*
|
|
* Fri 22-Nov-1991 -by- Patrick Haluptzok [patrickh]
|
|
* bug fix, copy the header into memory window for NULL bits.
|
|
*
|
|
* Tue 20-Aug-1991 -by- Patrick Haluptzok [patrickh]
|
|
* bug fix, make iStart and cNum be in valid range.
|
|
*
|
|
* Thu 20-Jun-1991 01:44:41 -by- Charles Whitmer [chuckwh]
|
|
* Added handle translation.
|
|
*
|
|
* 14-May-1991 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int GetDIBits(
|
|
HDC hdc,
|
|
HBITMAP hbm,
|
|
UINT nStartScan,
|
|
UINT nNumScans,
|
|
LPVOID pBits,
|
|
LPBITMAPINFO pbmi,
|
|
UINT iUsage) // DIB_PAL_COLORS || DIB_RGB_COLORS
|
|
{
|
|
PULONG pulBits = pBits;
|
|
ULONG cjBits;
|
|
int iRet;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
FIXUP_HANDLE(hbm);
|
|
|
|
cjBits = cjBitmapScanSize(pbmi,nNumScans);
|
|
|
|
// if the pBits are not dword aligned we need to allocate a buffer and copy them
|
|
|
|
if ((ULONG)pBits & (sizeof(DWORD) - 1))
|
|
{
|
|
pulBits = LocalAlloc(LMEM_FIXED,cjBits);
|
|
|
|
if (pulBits == NULL)
|
|
return(0);
|
|
}
|
|
|
|
iRet = NtGdiGetDIBitsInternal(
|
|
hdc,
|
|
hbm,
|
|
nStartScan,
|
|
nNumScans,
|
|
(LPVOID)pulBits,
|
|
pbmi,
|
|
iUsage,
|
|
cjBits,
|
|
0);
|
|
|
|
if (pulBits != pBits)
|
|
{
|
|
RtlCopyMemory(pBits,pulBits,cjBits);
|
|
|
|
LocalFree(pulBits);
|
|
}
|
|
|
|
return(iRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* CreateDIBitmap
|
|
*
|
|
* History:
|
|
* Mon 25-Jan-1993 -by- Patrick Haluptzok [patrickh]
|
|
* Add CBM_CREATEDIB support.
|
|
*
|
|
* Thu 20-Jun-1991 02:14:59 -by- Charles Whitmer [chuckwh]
|
|
* Added local handle support.
|
|
*
|
|
* 23-May-1991 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HBITMAP CreateDIBitmap(
|
|
HDC hdc,
|
|
CONST BITMAPINFOHEADER *pbmih,
|
|
DWORD flInit,
|
|
CONST VOID *pjBits,
|
|
CONST BITMAPINFO *pbmi,
|
|
UINT iUsage)
|
|
{
|
|
|
|
LONG cjBMI = 0;
|
|
LONG cjBits = 0;
|
|
INT cx = 0;
|
|
INT cy = 0;
|
|
PULONG pulBits = NULL;
|
|
HBITMAP hRet = (HBITMAP)-1;
|
|
LPBITMAPINFO pbmiNew = NULL;
|
|
|
|
FIXUP_HANDLEZ(hdc);
|
|
|
|
if (iUsage & DIB_LOCALFLAGS)
|
|
{
|
|
hRet = 0;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// covert pbmi
|
|
//
|
|
pbmiNew = pbmiConvertInfo(pbmi,iUsage,&cjBMI,FALSE);
|
|
|
|
if (flInit & CBM_CREATEDIB)
|
|
{
|
|
// With CBM_CREATEDIB we ignore pbmih
|
|
|
|
pbmih = (LPBITMAPINFOHEADER) pbmi;
|
|
|
|
if (cjBMI == 0)
|
|
{
|
|
hRet = 0;
|
|
}
|
|
else if (flInit & CBM_INIT)
|
|
{
|
|
if (pjBits == NULL)
|
|
{
|
|
// doesn't make sence if they asked to initialize it but
|
|
// didn't pass the bits.
|
|
|
|
hRet = 0;
|
|
}
|
|
else
|
|
{
|
|
cjBits = cjBitmapBitsSize(pbmiNew);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pjBits = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// compute the size of the optional init bits and BITMAPINFO
|
|
|
|
if (flInit & CBM_INIT)
|
|
{
|
|
if (pjBits == NULL)
|
|
{
|
|
// doesn't make sence if they asked to initialize it but
|
|
// didn't pass the bits.
|
|
|
|
flInit &= ~CBM_INIT;
|
|
}
|
|
else
|
|
{
|
|
if (cjBMI == 0)
|
|
{
|
|
hRet = 0;
|
|
}
|
|
else
|
|
{
|
|
// compute the size of the bits
|
|
|
|
cjBits = cjBitmapBitsSize(pbmiNew);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// if they passed us a zero height or zero width
|
|
// bitmap then return a pointer to the stock bitmap
|
|
|
|
if (pbmih)
|
|
{
|
|
if (pbmih->biSize >= sizeof(BITMAPINFOHEADER))
|
|
{
|
|
cx = pbmih->biWidth;
|
|
cy = pbmih->biHeight;
|
|
}
|
|
else
|
|
{
|
|
cx = ((LPBITMAPCOREHEADER) pbmih)->bcWidth;
|
|
cy = ((LPBITMAPCOREHEADER) pbmih)->bcHeight;
|
|
}
|
|
|
|
if ((cx == 0) || (cy == 0))
|
|
{
|
|
hRet = GetStockObject(PRIV_STOCK_BITMAP);
|
|
}
|
|
}
|
|
|
|
// if hRet is still -1, then all is OK and we need to try to the bitmap
|
|
|
|
if (hRet == (HBITMAP)-1)
|
|
{
|
|
// if the pJBits are not dword aligned we need to allocate a buffer and copy them
|
|
|
|
if ((ULONG)pjBits & (sizeof(DWORD) - 1))
|
|
{
|
|
pulBits = LocalAlloc(LMEM_FIXED,cjBits);
|
|
if (pulBits)
|
|
{
|
|
RtlCopyMemory(pulBits,pjBits,cjBits);
|
|
pjBits = pulBits;
|
|
}
|
|
}
|
|
|
|
hRet = NtGdiCreateDIBitmapInternal(hdc,
|
|
cx,
|
|
cy,
|
|
flInit,
|
|
(LPBYTE) pjBits,
|
|
(LPBITMAPINFO) pbmiNew,
|
|
iUsage,
|
|
cjBMI,
|
|
cjBits,
|
|
0);
|
|
|
|
if (pulBits)
|
|
LocalFree(pulBits);
|
|
}
|
|
|
|
if (pbmiNew && (pbmiNew != pbmi))
|
|
LocalFree(pbmiNew);
|
|
}
|
|
return(hRet);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* Set/GetBitmapBits *
|
|
* *
|
|
* History: *
|
|
* 05-Jun-1991 -by- Eric Kutter [erick] *
|
|
* Wrote it. *
|
|
\**************************************************************************/
|
|
|
|
LONG WINAPI SetBitmapBits(
|
|
HBITMAP hbm,
|
|
DWORD c,
|
|
CONST VOID *pv)
|
|
{
|
|
LONG lRet;
|
|
|
|
FIXUP_HANDLE(hbm);
|
|
|
|
lRet = (LONG)NtGdiSetBitmapBits(hbm,c,(PBYTE)pv);
|
|
|
|
return(lRet);
|
|
}
|
|
|
|
LONG WINAPI GetBitmapBits(
|
|
HBITMAP hbm,
|
|
LONG c,
|
|
LPVOID pv)
|
|
{
|
|
LONG lRet;
|
|
|
|
FIXUP_HANDLE(hbm);
|
|
|
|
lRet = (LONG)NtGdiGetBitmapBits(hbm,c,(PBYTE)pv);
|
|
|
|
return(lRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GdiGetPaletteFromDC
|
|
*
|
|
* Returns the palette for the DC, 0 for error.
|
|
*
|
|
* History:
|
|
* 04-Oct-1991 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HANDLE GdiGetPaletteFromDC(HDC h)
|
|
{
|
|
return((HANDLE)GetDCObject(h,LO_PALETTE_TYPE));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GdiGetDCforBitmap
|
|
*
|
|
* Returns the DC a bitmap is selected into, 0 if none or if error occurs.
|
|
*
|
|
* History:
|
|
* 22-Sep-1991 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HDC GdiGetDCforBitmap(HBITMAP hbm)
|
|
{
|
|
FIXUP_HANDLE(hbm);
|
|
|
|
return (NtGdiGetDCforBitmap(hbm));
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* SetDIBits
|
|
*
|
|
* API to initialize bitmap with DIB
|
|
*
|
|
* History:
|
|
* Sun 22-Sep-1991 -by- Patrick Haluptzok [patrickh]
|
|
* Make it work even if it is selected into a DC, Win3.0 compatibility.
|
|
*
|
|
* 06-Jun-1991 -by- Patrick Haluptzok patrickh
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int WINAPI SetDIBits(
|
|
HDC hdc,
|
|
HBITMAP hbm,
|
|
UINT iStartScans,
|
|
UINT cNumScans,
|
|
CONST VOID *pInitBits,
|
|
CONST BITMAPINFO *pInitInfo,
|
|
UINT iUsage)
|
|
{
|
|
HDC hdcTemp;
|
|
HBITMAP hbmTemp;
|
|
int iReturn = 0;
|
|
BOOL bMakeDC = FALSE;
|
|
HPALETTE hpalTemp;
|
|
DWORD cWidth;
|
|
DWORD cHeight;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
FIXUP_HANDLE(hbm);
|
|
|
|
// if no bits or hbm is not a bitmap, fail
|
|
|
|
if ((pInitBits == (PVOID) NULL) ||
|
|
(GRE_TYPE(hbm) != SURF_TYPE))
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
// First we need a DC to select this bitmap into. If he is already in a
|
|
// DC we just use that DC temporarily to blt to (we still have to select
|
|
// it in and out because someone might do a SaveDC and select another
|
|
// bitmap in). If he hasn't been stuck in a DC anywhere we just create
|
|
// one temporarily.
|
|
|
|
hdcTemp = GdiGetDCforBitmap(hbm);
|
|
|
|
if (hdcTemp == (HDC) 0)
|
|
{
|
|
hdcTemp = CreateCompatibleDC(hdc);
|
|
bMakeDC = TRUE;
|
|
|
|
if (hdcTemp == (HDC) NULL)
|
|
{
|
|
WARNING("SetDIBits failed CreateCompatibleDC, is hdc valid?\n");
|
|
return(0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (SaveDC(hdcTemp) == 0)
|
|
return(0);
|
|
}
|
|
|
|
hbmTemp = SelectObject(hdcTemp, hbm);
|
|
|
|
if (hbmTemp == (HBITMAP) 0)
|
|
{
|
|
//WARNING("ERROR SetDIBits failed to Select, is bitmap valid?\n");
|
|
goto Error_SetDIBits;
|
|
}
|
|
|
|
if (hdc != (HDC) 0)
|
|
{
|
|
hpalTemp = SelectPalette(hdcTemp, GdiGetPaletteFromDC(hdc), 0);
|
|
}
|
|
|
|
if (pInitInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
|
|
{
|
|
cWidth = pInitInfo->bmiHeader.biWidth;
|
|
cHeight = ABS(pInitInfo->bmiHeader.biHeight);
|
|
}
|
|
else
|
|
{
|
|
cWidth = ((LPBITMAPCOREHEADER)pInitInfo)->bcWidth;
|
|
cHeight = ((LPBITMAPCOREHEADER)pInitInfo)->bcHeight;
|
|
}
|
|
|
|
iReturn = SetDIBitsToDevice(hdcTemp,
|
|
0,
|
|
0,
|
|
cWidth,
|
|
cHeight,
|
|
0, 0,
|
|
iStartScans,
|
|
cNumScans,
|
|
(VOID *) pInitBits,
|
|
pInitInfo,
|
|
iUsage);
|
|
|
|
if (hdc != (HDC) 0)
|
|
{
|
|
SelectPalette(hdcTemp, hpalTemp, 0);
|
|
}
|
|
|
|
SelectObject(hdcTemp, hbmTemp);
|
|
|
|
Error_SetDIBits:
|
|
|
|
if (bMakeDC)
|
|
{
|
|
DeleteDC(hdcTemp);
|
|
}
|
|
else
|
|
{
|
|
RestoreDC(hdcTemp, -1);
|
|
}
|
|
|
|
return(iReturn);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* StretchDIBits()
|
|
*
|
|
*
|
|
* Effects:
|
|
*
|
|
* Warnings:
|
|
*
|
|
* History:
|
|
* 22-Jul-1991 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
int WINAPI StretchDIBits(
|
|
HDC hdc,
|
|
int xDest,
|
|
int yDest,
|
|
int nDestWidth,
|
|
int nDestHeight,
|
|
int xSrc,
|
|
int ySrc,
|
|
int nSrcWidth,
|
|
int nSrcHeight,
|
|
CONST VOID *pj,
|
|
CONST BITMAPINFO *pbmi,
|
|
UINT iUsage,
|
|
DWORD lRop)
|
|
{
|
|
LONG cPoints = 0;
|
|
LONG cjHeader;
|
|
LONG cjBits;
|
|
ULONG ulResult = 0;
|
|
PULONG pulBits = NULL;
|
|
int iRet;
|
|
BITMAPINFO * pbmiNew = NULL;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
// NEWFRAME support for backward compatibility.
|
|
// Ship the transform to the server side if needed.
|
|
|
|
if (IS_ALTDC_TYPE(hdc))
|
|
{
|
|
PLDC pldc;
|
|
|
|
if (IS_METADC16_TYPE(hdc))
|
|
{
|
|
return(MF_AnyDIBits(
|
|
hdc,
|
|
xDest,
|
|
yDest,
|
|
nDestWidth,
|
|
nDestHeight,
|
|
xSrc,
|
|
ySrc,
|
|
nSrcWidth,
|
|
nSrcHeight,
|
|
0,
|
|
0,
|
|
(BYTE *) pj,
|
|
pbmi,
|
|
iUsage,
|
|
lRop,
|
|
META_STRETCHDIB
|
|
));
|
|
}
|
|
|
|
DC_PLDC(hdc,pldc,ulResult);
|
|
|
|
if (pldc->iType == LO_METADC)
|
|
{
|
|
if (!MF_AnyDIBits(hdc,
|
|
xDest,
|
|
yDest,
|
|
nDestWidth,
|
|
nDestHeight,
|
|
xSrc,
|
|
ySrc,
|
|
nSrcWidth,
|
|
nSrcHeight,
|
|
0,
|
|
0,
|
|
(BYTE *) pj,
|
|
pbmi,
|
|
iUsage,
|
|
lRop,
|
|
EMR_STRETCHDIBITS
|
|
))
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
|
|
if (pldc->fl & LDC_SAP_CALLBACK)
|
|
vSAPCallback(pldc);
|
|
|
|
if (pldc->fl & LDC_DOC_CANCELLED)
|
|
return(0);
|
|
|
|
if (pldc->fl & LDC_CALL_STARTPAGE)
|
|
StartPage(hdc);
|
|
}
|
|
|
|
// compute the size
|
|
|
|
if (pbmi != NULL)
|
|
{
|
|
pbmiNew = pbmiConvertInfo (pbmi, iUsage, &cjHeader,FALSE);
|
|
|
|
if (pbmiNew == NULL)
|
|
return (0);
|
|
|
|
cjBits = cjBitmapBitsSize(pbmiNew);
|
|
}
|
|
else
|
|
{
|
|
cjHeader = 0;
|
|
cjBits = 0;
|
|
}
|
|
|
|
// reset user's poll count so it counts this as output
|
|
// put it right next to BEGINMSG so that NtCurrentTeb() is optimized
|
|
|
|
RESETUSERPOLLCOUNT();
|
|
|
|
// if the pj are not dword aligned we need to allocate a buffer and copy them
|
|
|
|
if ((ULONG)pj & (sizeof(DWORD) - 1))
|
|
{
|
|
pulBits = LocalAlloc(LMEM_FIXED,cjBits);
|
|
if (pulBits)
|
|
{
|
|
RtlCopyMemory(pulBits,pj,cjBits);
|
|
pj = pulBits;
|
|
}
|
|
}
|
|
|
|
iRet = NtGdiStretchDIBitsInternal(
|
|
hdc,
|
|
xDest,
|
|
yDest,
|
|
nDestWidth,
|
|
nDestHeight,
|
|
xSrc,
|
|
ySrc,
|
|
nSrcWidth,
|
|
nSrcHeight,
|
|
(LPBYTE) pj,
|
|
(LPBITMAPINFO) pbmiNew,
|
|
iUsage,
|
|
lRop,
|
|
cjHeader,
|
|
cjBits);
|
|
|
|
|
|
if (pulBits)
|
|
LocalFree(pulBits);
|
|
|
|
if (pbmiNew && (pbmiNew != pbmi))
|
|
LocalFree(pbmiNew);
|
|
|
|
return(iRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* History:
|
|
* 28-May-1991 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HBITMAP CreateBitmap(
|
|
int nWidth,
|
|
int nHeight,
|
|
UINT nPlanes,
|
|
UINT nBitCount,
|
|
CONST VOID *lpBits)
|
|
{
|
|
LONG cj;
|
|
HBITMAP hbm = (HBITMAP)0;
|
|
INT ii;
|
|
|
|
// check if it is an empty bitmap
|
|
|
|
if ((nWidth == 0) || (nHeight == 0))
|
|
{
|
|
return(GetStockObject(PRIV_STOCK_BITMAP));
|
|
}
|
|
|
|
// Pass call to the server
|
|
|
|
if (lpBits == (VOID *) NULL)
|
|
cj = 0;
|
|
else
|
|
{
|
|
cj = (((nWidth*nPlanes*nBitCount + 15) >> 4) << 1) * nHeight;
|
|
|
|
if (cj < 0)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return((HBITMAP)0);
|
|
}
|
|
}
|
|
|
|
hbm = NtGdiCreateBitmap(nWidth,
|
|
nHeight,
|
|
nPlanes,
|
|
nBitCount,
|
|
(LPBYTE) lpBits);
|
|
|
|
return(hbm);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* HBITMAP CreateBitmapIndirect(CONST BITMAP * pbm)
|
|
*
|
|
* NOTE: if the bmWidthBytes is larger than it needs to be, GetBitmapBits
|
|
* will return different info than the set.
|
|
*
|
|
* History:
|
|
* Tue 18-Jan-1994 -by- Bodin Dresevic [BodinD]
|
|
* update: added bmWidthBytes support
|
|
* 28-May-1991 -by- Eric Kutter [erick]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HBITMAP CreateBitmapIndirect(CONST BITMAP * pbm)
|
|
{
|
|
HBITMAP hbm = (HBITMAP)0;
|
|
LPBYTE lpBits = (LPBYTE)NULL; // important to zero init
|
|
BOOL bAlloc = FALSE; // indicates that tmp bitmap was allocated
|
|
|
|
// compute minimal word aligned scan width in bytes given the number of
|
|
// pixels in x. The width refers to one plane only. Our multi - planar
|
|
// support is broken anyway. I believe that we should take an early
|
|
// exit if bmPlanes != 1. [bodind].
|
|
|
|
LONG cjWidthWordAligned = ((pbm->bmWidth * pbm->bmBitsPixel + 15) >> 4) << 1;
|
|
|
|
// Win 31 requires at least WORD alinged scans, have to reject inconsistent
|
|
// input, this is what win31 does
|
|
|
|
if
|
|
(
|
|
(pbm->bmWidthBytes & 1) ||
|
|
(pbm->bmWidthBytes == 0) ||
|
|
(pbm->bmWidthBytes < cjWidthWordAligned)
|
|
)
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return (HBITMAP)0;
|
|
}
|
|
|
|
// take an early exit if this is not the case we know how to handle:
|
|
|
|
if (pbm->bmPlanes != 1)
|
|
{
|
|
WARNING("gdi32: can not handle bmPlanes != 1\n");
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return (HBITMAP)0;
|
|
}
|
|
|
|
// if bmBits is nonzero and bmWidthBytes is bigger than the minimal required
|
|
// word aligned width we will first convert the bitmap to one that
|
|
// has the rows that are minimally word aligned:
|
|
|
|
if (pbm->bmBits)
|
|
{
|
|
if (pbm->bmWidthBytes > cjWidthWordAligned)
|
|
{
|
|
PBYTE pjSrc, pjDst, pjDstEnd;
|
|
ULONGLONG lrg;
|
|
|
|
lrg = UInt32x32To64(
|
|
(ULONG)cjWidthWordAligned,
|
|
(ULONG)pbm->bmHeight
|
|
);
|
|
|
|
if (lrg > ULONG_MAX ||
|
|
!(lpBits = (LPBYTE)LOCALALLOC((size_t) lrg)))
|
|
{
|
|
// the result does not fit in 32 bits, alloc memory will fail
|
|
// this is too big to digest
|
|
|
|
GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return (HBITMAP)0;
|
|
}
|
|
|
|
// flag that we have allocated memory so that we can free it later
|
|
|
|
bAlloc = TRUE;
|
|
|
|
// convert bitmap to minimally word aligned format
|
|
|
|
pjSrc = (LPBYTE)pbm->bmBits;
|
|
pjDst = lpBits;
|
|
pjDstEnd = lpBits + (size_t) lrg;
|
|
|
|
while (pjDst < pjDstEnd)
|
|
{
|
|
RtlCopyMemory(pjDst,pjSrc, cjWidthWordAligned);
|
|
pjDst += cjWidthWordAligned, pjSrc += pbm->bmWidthBytes;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// bits already in minimally aligned format, do nothing
|
|
|
|
ASSERTGDI(
|
|
pbm->bmWidthBytes == cjWidthWordAligned,
|
|
"pbm->bmWidthBytes != cjWidthWordAligned\n"
|
|
);
|
|
lpBits = (LPBYTE)pbm->bmBits;
|
|
}
|
|
}
|
|
|
|
hbm = CreateBitmap(
|
|
pbm->bmWidth,
|
|
pbm->bmHeight,
|
|
(UINT) pbm->bmPlanes,
|
|
(UINT) pbm->bmBitsPixel,
|
|
lpBits);
|
|
|
|
if (bAlloc)
|
|
LOCALFREE(lpBits);
|
|
|
|
return(hbm);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* CreateDIBSection
|
|
*
|
|
* Allocate a file mapping object for a DIB. Return the pointer to it
|
|
* and the handle of the bitmap.
|
|
*
|
|
* History:
|
|
*
|
|
* 25-Aug-1993 -by- Wendy Wu [wendywu]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HBITMAP
|
|
WINAPI
|
|
CreateDIBSection(
|
|
HDC hdc,
|
|
CONST BITMAPINFO *pbmi,
|
|
UINT iUsage,
|
|
VOID **ppvBits,
|
|
HANDLE hSectionApp,
|
|
DWORD dwOffset)
|
|
{
|
|
HBITMAP hbm = NULL;
|
|
PVOID pjBits = NULL;
|
|
BITMAPINFO * pbmiNew = NULL;
|
|
INT cjHdr;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
|
|
pbmiNew = pbmiConvertInfo(pbmi, iUsage, &cjHdr, FALSE);
|
|
|
|
//
|
|
// dwOffset has to be a multiple of 4 (sizeof(DWORD))
|
|
// if there is a section. If the section is NULL we do
|
|
// not care
|
|
//
|
|
|
|
if ( (hSectionApp == NULL) ||
|
|
((dwOffset & 3) == 0) )
|
|
{
|
|
hbm = NtGdiCreateDIBSection(
|
|
hdc,
|
|
hSectionApp,
|
|
dwOffset,
|
|
(LPBITMAPINFO) pbmiNew,
|
|
iUsage,
|
|
cjHdr,
|
|
0,
|
|
(PVOID *)&pjBits);
|
|
|
|
if ((hbm == NULL) || (pjBits == NULL))
|
|
{
|
|
hbm = 0;
|
|
pjBits = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Assign the appropriate value to the caller's pointer
|
|
//
|
|
|
|
if (ppvBits != NULL)
|
|
{
|
|
*ppvBits = pjBits;
|
|
}
|
|
|
|
if (pbmiNew && (pbmiNew != pbmi))
|
|
LocalFree(pbmiNew);
|
|
|
|
return(hbm);
|
|
|
|
}
|