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.
2871 lines
86 KiB
2871 lines
86 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-1999 Microsoft Corporation *
|
|
\**************************************************************************/
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#define EXTRAPIXEL 4
|
|
//
|
|
//The default band size is set to 4Mb
|
|
//
|
|
#define BAND_SIZE (4194304)
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* cjBitmapBitsSize - calculate the size of the bitmap bits for the
|
|
* given BITMAPINFO
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pbmi - pointer to BITMAPINFO
|
|
*
|
|
* Return Value:
|
|
*
|
|
* size of bitmap bits in butes
|
|
*
|
|
* History:
|
|
*
|
|
* 11-Jul-1996 -by- Mark Enstrom [marke]
|
|
*
|
|
\**************************************************************************/
|
|
|
|
|
|
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) ||
|
|
(pbmi->bmiHeader.biCompression == BI_CMYK))
|
|
{
|
|
return(CJSCAN(pbmi->bmiHeader.biWidth,pbmi->bmiHeader.biPlanes,
|
|
pbmi->bmiHeader.biBitCount) *
|
|
ABS(pbmi->bmiHeader.biHeight));
|
|
}
|
|
else
|
|
{
|
|
return(pbmi->bmiHeader.biSizeImage);
|
|
}
|
|
}
|
|
|
|
//
|
|
// IS_BMI_RLE
|
|
//
|
|
// Checks if the header pointed to by pv is a BITMAPINFO for a RLE4 or RLE8.
|
|
// Evaluates to TRUE if RLE, FALSE otherwise.
|
|
//
|
|
|
|
#define IS_BMI_RLE(pv) \
|
|
((pv) && \
|
|
(((BITMAPINFO *)(pv))->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) && \
|
|
((((BITMAPINFO *)(pv))->bmiHeader.biCompression == BI_RLE4) || \
|
|
(((BITMAPINFO *)(pv))->bmiHeader.biCompression == BI_RLE8) ))
|
|
|
|
//
|
|
// IS_BMI_JPEG
|
|
//
|
|
// Checks if the header pointed to by pv is a BITMAPINFO for a JPEG.
|
|
// Evaluates to TRUE if JPEG, FALSE otherwise.
|
|
//
|
|
|
|
#define IS_BMI_JPEG(pv) \
|
|
((pv) && \
|
|
(((BITMAPINFO *)(pv))->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) && \
|
|
(((BITMAPINFO *)(pv))->bmiHeader.biCompression == BI_JPEG))
|
|
|
|
//
|
|
// IS_BMI_PNG
|
|
//
|
|
// Checks if the header pointed to by pv is a BITMAPINFO for a PNG.
|
|
// Evaluates to TRUE if PNG, FALSE otherwise.
|
|
//
|
|
|
|
#define IS_BMI_PNG(pv) \
|
|
((pv) && \
|
|
(((BITMAPINFO *)(pv))->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) && \
|
|
(((BITMAPINFO *)(pv))->bmiHeader.biCompression == BI_PNG))
|
|
|
|
//
|
|
// IS_PASSTHROUGH_IMAGE
|
|
//
|
|
// Checks if the biCompression value is one of the passthrough formats that
|
|
// can be passed to devices (BI_JPEG or BI_PNG).
|
|
//
|
|
|
|
#define IS_PASSTHROUGH_IMAGE(biCompression) \
|
|
(((biCompression) == BI_JPEG) || ((biCompression) == BI_PNG))
|
|
|
|
//
|
|
// IS_BMI_PASSTHROUGH_IMAGE
|
|
//
|
|
// Checks if the header pointed to by pv is a BITMAPINFO for a JPEG or PNG.
|
|
// Evaluates to TRUE if JPEG or PNG, FALSE otherwise.
|
|
//
|
|
|
|
#define IS_BMI_PASSTHROUGH_IMAGE(pv) \
|
|
((pv) && \
|
|
(((BITMAPINFO *)(pv))->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) && \
|
|
IS_PASSTHROUGH_IMAGE(((BITMAPINFO *)(pv))->bmiHeader.biCompression))
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* cCalculateColorTableSize(
|
|
*
|
|
* Arguments:
|
|
*
|
|
*
|
|
*
|
|
* Return Value:
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
* 11-Jul-1996 -by- Mark Enstrom [marke]
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
cCalculateColorTableSize(
|
|
UINT uiBitCount,
|
|
UINT uiPalUsed,
|
|
UINT uiCompression,
|
|
UINT biSize,
|
|
ULONG *piUsage,
|
|
ULONG *pColors
|
|
)
|
|
{
|
|
BOOL bStatus = FALSE;
|
|
ULONG cColorsMax = 0;
|
|
|
|
if (uiCompression == BI_BITFIELDS)
|
|
{
|
|
//
|
|
// Handle 16 and 32 bit per pel bitmaps.
|
|
//
|
|
|
|
if (*piUsage == DIB_PAL_COLORS)
|
|
{
|
|
*piUsage = DIB_RGB_COLORS;
|
|
}
|
|
|
|
switch (uiBitCount)
|
|
{
|
|
case 16:
|
|
case 32:
|
|
break;
|
|
default:
|
|
WARNING("ConvertInfo failed for BI_BITFIELDS\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
if (biSize <= sizeof(BITMAPINFOHEADER))
|
|
{
|
|
uiPalUsed = cColorsMax = 3;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// masks are part of BITMAPV4 and greater
|
|
//
|
|
|
|
uiPalUsed = cColorsMax = 0;
|
|
}
|
|
}
|
|
else if (uiCompression == BI_RGB)
|
|
{
|
|
switch (uiBitCount)
|
|
{
|
|
case 1:
|
|
cColorsMax = 2;
|
|
break;
|
|
case 4:
|
|
cColorsMax = 16;
|
|
break;
|
|
case 8:
|
|
cColorsMax = 256;
|
|
break;
|
|
default:
|
|
|
|
if (*piUsage == DIB_PAL_COLORS)
|
|
{
|
|
*piUsage = 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(FALSE);
|
|
}
|
|
}
|
|
}
|
|
else if (uiCompression == BI_CMYK)
|
|
{
|
|
if (*piUsage == DIB_PAL_COLORS)
|
|
{
|
|
*piUsage = DIB_RGB_COLORS;
|
|
}
|
|
|
|
switch (uiBitCount)
|
|
{
|
|
case 1:
|
|
cColorsMax = 2;
|
|
break;
|
|
case 4:
|
|
cColorsMax = 16;
|
|
break;
|
|
case 8:
|
|
cColorsMax = 256;
|
|
break;
|
|
case 32:
|
|
cColorsMax = 0;
|
|
break;
|
|
default:
|
|
WARNING("convertinfo failed invalid bitcount in bmi BI_CMYK\n");
|
|
return(FALSE);
|
|
}
|
|
}
|
|
else if ((uiCompression == BI_RLE4) || (uiCompression == BI_CMYKRLE4))
|
|
{
|
|
if (uiBitCount != 4)
|
|
{
|
|
// WARNING("cCalculateColroTableSize invalid bitcount BI_RLE4\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
cColorsMax = 16;
|
|
}
|
|
else if ((uiCompression == BI_RLE8) || (uiCompression == BI_CMYKRLE8))
|
|
{
|
|
if (uiBitCount != 8)
|
|
{
|
|
// WARNING("cjBitmapSize invalid bitcount BI_RLE8\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
cColorsMax = 256;
|
|
}
|
|
else if ((uiCompression == BI_JPEG) || (uiCompression == BI_PNG))
|
|
{
|
|
cColorsMax = 0;
|
|
}
|
|
else
|
|
{
|
|
WARNING("convertinfo failed invalid Compression in header\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
if (uiPalUsed != 0)
|
|
{
|
|
if (uiPalUsed <= cColorsMax)
|
|
{
|
|
cColorsMax = uiPalUsed;
|
|
}
|
|
}
|
|
|
|
*pColors = cColorsMax;
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/**********************************************************************\
|
|
* 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
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pbmi - original bitmapinfo
|
|
* iUsage - iUsage from API
|
|
* *count - return size
|
|
* bCopyInfoHeader - force copy if input is BITMAPINFOHEADER
|
|
* and bPackedDIB is NOT set
|
|
* bPackedDIB - BITMAPINFO has bitmap data that must be
|
|
* copied also
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Converted PBITMAPINFO if successful, otherwise NULL
|
|
*
|
|
* 10-1-95 -by- Lingyun Wang [lingyunw]
|
|
\**********************************************************************/
|
|
|
|
LPBITMAPINFO
|
|
pbmiConvertInfo(
|
|
CONST BITMAPINFO *pbmi,
|
|
ULONG iUsage,
|
|
ULONG *count,
|
|
BOOL bPackedDIB
|
|
)
|
|
{
|
|
LPBITMAPINFO pbmiNew;
|
|
ULONG cjRGB;
|
|
ULONG cColors;
|
|
UINT uiBitCount;
|
|
UINT uiPalUsed;
|
|
UINT uiCompression;
|
|
BOOL bCoreHeader = FALSE;
|
|
ULONG ulSize;
|
|
ULONG cjBits = 0;
|
|
PVOID pjBits, pjBitsNew;
|
|
BOOL bStatus;
|
|
|
|
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)) &&
|
|
(ulSize <= ( 2 * sizeof(BITMAPV5HEADER))))
|
|
{
|
|
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
|
|
//
|
|
|
|
bStatus = cCalculateColorTableSize(
|
|
uiBitCount,
|
|
uiPalUsed,
|
|
uiCompression,
|
|
ulSize,
|
|
&iUsage,
|
|
&cColors
|
|
);
|
|
if (!bStatus)
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
if (iUsage == DIB_PAL_COLORS)
|
|
{
|
|
cjRGB = sizeof(USHORT);
|
|
}
|
|
else if (iUsage == DIB_PAL_INDICES)
|
|
{
|
|
cjRGB = 0;
|
|
}
|
|
|
|
if (bPackedDIB)
|
|
{
|
|
cjBits = cjBitmapBitsSize(pbmi);
|
|
}
|
|
|
|
//
|
|
// if passed COREHEADER then convert to BITMAPINFOHEADER
|
|
//
|
|
|
|
if (bCoreHeader)
|
|
{
|
|
RGBTRIPLE *pTri;
|
|
RGBQUAD *pQuad;
|
|
|
|
//
|
|
// allocate new header to hold the info
|
|
//
|
|
|
|
ulSize = sizeof(BITMAPINFOHEADER);
|
|
|
|
pbmiNew = (PBITMAPINFO)LOCALALLOC(ulSize +
|
|
cjRGB * cColors+cjBits);
|
|
|
|
if (pbmiNew == NULL)
|
|
return (0);
|
|
|
|
//
|
|
// copy COREHEADER info over
|
|
//
|
|
|
|
CopyCoreToInfoHeader(&pbmiNew->bmiHeader, (BITMAPCOREHEADER *)pbmi);
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pbmiNew = (LPBITMAPINFO)pbmi;
|
|
}
|
|
|
|
*count = ((ulSize + (cjRGB * cColors) + cjBits) + 3) & ~3;
|
|
|
|
return((LPBITMAPINFO) pbmiNew);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
* cjBitmapScanSize
|
|
*
|
|
* Arguments:
|
|
*
|
|
* pbmi
|
|
* nScans
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Image size based on number of scans
|
|
*
|
|
* History:
|
|
*
|
|
* 11-Jul-1996 -by- Mark Enstrom [marke]
|
|
*
|
|
\**************************************************************************/
|
|
|
|
|
|
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) ||
|
|
(pbmi->bmiHeader.biCompression == BI_CMYK))
|
|
{
|
|
return(CJSCAN(pbmi->bmiHeader.biWidth,pbmi->bmiHeader.biPlanes,
|
|
pbmi->bmiHeader.biBitCount) * nScans);
|
|
}
|
|
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;
|
|
|
|
// ICM related variables
|
|
|
|
PCACHED_COLORSPACE pBitmapColorSpace = NULL;
|
|
PCACHED_COLORTRANSFORM pCXform = NULL;
|
|
HANDLE hcmTempXform = NULL;
|
|
|
|
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);
|
|
|
|
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 (that's because we always guarantee display and printer
|
|
// drivers that bitmaps are dword aligned):
|
|
//
|
|
|
|
cScansCopied = 1;
|
|
|
|
if ((ULONG_PTR)pBits & (sizeof(DWORD) - 1))
|
|
{
|
|
pulBits = LOCALALLOC(cjBits);
|
|
if (pulBits)
|
|
{
|
|
//
|
|
// We used to simply access violate here if we had been given
|
|
// a corrupt DIB bitmap. This was bad because WinLogon is
|
|
// responsible for showing the original background bitmap, and
|
|
// if that bitmap is corrupt, and we access violate, we'll
|
|
// cause the system to blue-screen:
|
|
//
|
|
|
|
try
|
|
{
|
|
RtlCopyMemory(pulBits,pBits,cjBits);
|
|
pBits = pulBits;
|
|
}
|
|
except(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
WARNING("SetDIBitsToDevice: Corrupt bitmap\n");
|
|
cScansCopied = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cScansCopied)
|
|
{
|
|
PDC_ATTR pdcattr;
|
|
|
|
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
|
|
|
|
if (pdcattr)
|
|
{
|
|
//
|
|
// ICM translation of BITMAP bits or color table
|
|
//
|
|
// At this moment, ensured that pBits and pbmiNew is not NULL.
|
|
// (see above parameter validate check and NULL check !)
|
|
//
|
|
|
|
if (
|
|
IS_ICM_INSIDEDC(pdcattr->lIcmMode) &&
|
|
(iUsage != DIB_PAL_COLORS) &&
|
|
!IS_BMI_PASSTHROUGH_IMAGE(pbmiNew))
|
|
{
|
|
LPBITMAPINFO pbmiIcm = NULL;
|
|
PVOID pvBitsIcm = NULL;
|
|
ULONG cjHeaderNew = 0;
|
|
BOOL bIcmStatus;
|
|
VOID *pBitsBand = (VOID *)pBits;
|
|
ULONG CurrentBandSize;
|
|
ULONG SizeOfOneScanline;
|
|
ULONG nBands;
|
|
ULONG nScansInBand;
|
|
ULONG nScansInCurrentBand;
|
|
ULONG nScansInRemainderBand;
|
|
ULONG CumulativeScans=0;
|
|
ULONG i;
|
|
LONG PositiveBandDelta=0;
|
|
LONG NegativeBandDelta=0;
|
|
LONG TotalBandDelta=0;
|
|
LONG IcmSizeOfOneScanline;
|
|
INT iRet;
|
|
LONG HeaderHeightHack;
|
|
|
|
SizeOfOneScanline = cjBitmapScanSize(pbmi, 1);
|
|
|
|
//
|
|
//pbmiNew must be initialized before getting to this point.
|
|
//
|
|
|
|
ASSERTGDI(pbmiNew!=NULL, "SetDIBitsToDevice cannot proceed with pbmiNew==NULL\n");
|
|
|
|
nScansInBand = BAND_SIZE/SizeOfOneScanline;
|
|
|
|
//
|
|
// Set the number of bands provided there are enough scanlines
|
|
// and the hdc is a printer dc.
|
|
//
|
|
// Else set the nubmer of bands to 1 and the scanlines in the
|
|
// remainder band to all of them, so the entire bitmap is printed
|
|
// in one band (All the code below reduces to doing a single piece)
|
|
//
|
|
// If the bitmap is RLE compressed, we set it up to do one band
|
|
// only. When this is the case, Start and NegativeBandDelta will be
|
|
// computed as 0 and the SizeOfOneScanline parameter will be
|
|
// multiplied away to zero.
|
|
//
|
|
|
|
|
|
|
|
|
|
if ((nScansInBand>0)&&
|
|
(GetDeviceCaps(hdc, TECHNOLOGY)==DT_RASPRINTER)&&
|
|
(!IS_BMI_RLE(pbmiNew)))
|
|
{
|
|
//
|
|
// Compressed images cannot be converted in this way.
|
|
// This should never be hit and is included as a guard against
|
|
// someone inventing a new compression mode and not updating
|
|
// this conditional.
|
|
//
|
|
|
|
ASSERTGDI(SizeOfOneScanline*nNumScans==cjBits, "SetDIBitsToDevice, cannot band compressed image");
|
|
|
|
nBands = (nNumScans)/nScansInBand;
|
|
nScansInRemainderBand = nNumScans % nScansInBand;
|
|
}
|
|
else
|
|
{
|
|
nBands = 0;
|
|
nScansInRemainderBand = (nNumScans);
|
|
}
|
|
|
|
if (nScansInRemainderBand>0)
|
|
{
|
|
nBands++;
|
|
nScansInCurrentBand = nScansInRemainderBand;
|
|
}
|
|
else
|
|
{
|
|
nScansInCurrentBand = nScansInBand;
|
|
}
|
|
|
|
|
|
cScansCopied = 0;
|
|
|
|
HeaderHeightHack = pbmiNew->bmiHeader.biHeight;
|
|
|
|
for (i=0; i<nBands; i++)
|
|
{
|
|
|
|
CurrentBandSize = nScansInCurrentBand*SizeOfOneScanline;
|
|
IcmSizeOfOneScanline = SizeOfOneScanline;
|
|
|
|
//
|
|
// The Delta refers to the number of extra scanlines to pass
|
|
// to the internal blting routines in order to avoid halftone
|
|
// seams.
|
|
//
|
|
// PositiveBandDelta is the number of scanlines to
|
|
// add on to the end of the band. (relative to the start in
|
|
// memory)
|
|
//
|
|
// NegativeBandDelta is the number of scanlines to
|
|
// subtract from the begining of the band (ie move the start
|
|
// pointer back this many scanlines).
|
|
//
|
|
// Total BandDelta is simply the total number of extra scans
|
|
// added for this band (both at the start and end).
|
|
//
|
|
|
|
PositiveBandDelta = MIN(EXTRAPIXEL, CumulativeScans);
|
|
NegativeBandDelta = MIN(EXTRAPIXEL, nNumScans-(CumulativeScans+nScansInCurrentBand));
|
|
TotalBandDelta = NegativeBandDelta+PositiveBandDelta;
|
|
|
|
|
|
if (nBands!=1)
|
|
{
|
|
SaveDC(hdc);
|
|
|
|
|
|
//
|
|
// Intersect the clip rectangles.
|
|
// This clip rectangle is designed to restrict the output to
|
|
// just the displayed portion of the band.
|
|
// We may pass more scanlines on the top and bottom of the band
|
|
// to get halftoning to merge seamlessly.
|
|
//
|
|
|
|
iRet = IntersectClipRect(
|
|
hdc,
|
|
xDest,
|
|
nNumScans - (nStartScan+CumulativeScans+nScansInCurrentBand),
|
|
xDest+nWidth,
|
|
nNumScans - (nStartScan+CumulativeScans));
|
|
|
|
if (iRet==ERROR)
|
|
{
|
|
WARNING("SetDIBitsToDevice: error intersecting clip rect\n");
|
|
RestoreDC(hdc, -1);
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Empty clip rectangle
|
|
// If the clip regions don't intersect, we can quit without
|
|
// doing anything.
|
|
//
|
|
|
|
if (iRet==NULLREGION)
|
|
{
|
|
RestoreDC(hdc, -1);
|
|
|
|
//
|
|
// Nothing to do - fall through and do
|
|
// initialization for next iteration.
|
|
//
|
|
|
|
goto Continue_With_Init;
|
|
}
|
|
}
|
|
|
|
|
|
if (HeaderHeightHack >= 0)
|
|
{
|
|
//
|
|
//Bottom Up
|
|
//
|
|
|
|
pBitsBand = (char *)pBits + (CumulativeScans-PositiveBandDelta)*SizeOfOneScanline;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
//TopDown
|
|
//
|
|
|
|
pBitsBand = (char *)pBits + (nNumScans-nScansInCurrentBand-CumulativeScans-NegativeBandDelta)*SizeOfOneScanline;
|
|
}
|
|
|
|
cjHeaderNew=0;
|
|
pbmiIcm=NULL;
|
|
pvBitsIcm = NULL;
|
|
|
|
//
|
|
// Call ICM with an oversized band for later halftoning by
|
|
// NtGdiSetDIBitsInternal
|
|
//
|
|
|
|
bIcmStatus = IcmTranslateDIB(
|
|
hdc,
|
|
pdcattr,
|
|
CurrentBandSize+TotalBandDelta*SizeOfOneScanline,
|
|
(PVOID)pBitsBand,
|
|
&pvBitsIcm,
|
|
pbmiNew,
|
|
&pbmiIcm,
|
|
&cjHeaderNew,
|
|
nScansInCurrentBand+TotalBandDelta,
|
|
iUsage,
|
|
ICM_FORWARD,
|
|
&pBitmapColorSpace,
|
|
&pCXform);
|
|
|
|
if (bIcmStatus)
|
|
{
|
|
if (pvBitsIcm == NULL)
|
|
{
|
|
pvBitsIcm = pBitsBand;
|
|
}
|
|
if (pbmiIcm == NULL)
|
|
{
|
|
pbmiIcm = pbmiNew;
|
|
cjHeaderNew = cjHeader;
|
|
}
|
|
else
|
|
{
|
|
CurrentBandSize = cjBitmapScanSize(pbmiIcm, nScansInCurrentBand);
|
|
IcmSizeOfOneScanline = cjBitmapScanSize(pbmiIcm, 1);
|
|
if (!cjHeaderNew)
|
|
{
|
|
cjHeaderNew = cjHeader;
|
|
}
|
|
}
|
|
if (pCXform)
|
|
{
|
|
hcmTempXform = pCXform->ColorTransform;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pvBitsIcm = pBitsBand;
|
|
pbmiIcm = pbmiNew;
|
|
cjHeaderNew = cjHeader;
|
|
}
|
|
|
|
cScansCopied += NtGdiSetDIBitsToDeviceInternal(
|
|
hdc,
|
|
xDest,
|
|
yDest,
|
|
nWidth,
|
|
nHeight,
|
|
xSrc,
|
|
ySrc,
|
|
nStartScan+CumulativeScans-PositiveBandDelta,
|
|
nScansInCurrentBand+TotalBandDelta,
|
|
(LPBYTE)pvBitsIcm,
|
|
pbmiIcm,
|
|
iUsage,
|
|
(UINT)CurrentBandSize+TotalBandDelta*IcmSizeOfOneScanline,
|
|
(UINT)cjHeaderNew,
|
|
TRUE,
|
|
hcmTempXform);
|
|
|
|
cScansCopied -= TotalBandDelta;
|
|
|
|
if (pBitmapColorSpace)
|
|
{
|
|
if (pCXform)
|
|
{
|
|
IcmDeleteColorTransform(pCXform,FALSE);
|
|
}
|
|
IcmReleaseColorSpace(NULL,pBitmapColorSpace,FALSE);
|
|
}
|
|
|
|
|
|
if ((pvBitsIcm!=NULL)&&(pvBitsIcm!=pBitsBand))
|
|
{
|
|
LOCALFREE(pvBitsIcm);
|
|
pvBitsIcm = NULL;
|
|
}
|
|
if ((pbmiIcm!=NULL)&&(pbmiIcm!=pbmiNew))
|
|
{
|
|
LOCALFREE(pbmiIcm);
|
|
pbmiIcm = NULL;
|
|
}
|
|
|
|
hcmTempXform = NULL;
|
|
|
|
Continue_With_Init:
|
|
CumulativeScans += nScansInCurrentBand;
|
|
nScansInCurrentBand = nScansInBand;
|
|
if (nBands != 1)
|
|
{
|
|
RestoreDC(hdc, -1);
|
|
}
|
|
}
|
|
|
|
//
|
|
// We do our own NtGdiSetDIBitsToDeviceInternal
|
|
// So we need to fall through to cleanup at this point.
|
|
//
|
|
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Do the non-ICM version of the SetDIB
|
|
//
|
|
cScansCopied = NtGdiSetDIBitsToDeviceInternal(
|
|
hdc,
|
|
xDest,
|
|
yDest,
|
|
nWidth,
|
|
nHeight,
|
|
xSrc,
|
|
ySrc,
|
|
nStartScan,
|
|
nNumScans,
|
|
(LPBYTE)pBits,
|
|
pbmiNew,
|
|
iUsage,
|
|
(UINT)cjBits,
|
|
(UINT)cjHeader,
|
|
TRUE,
|
|
hcmTempXform);
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (pulBits)
|
|
{
|
|
//
|
|
// Free temporary buffer, this would be the buffer which allocated
|
|
// to align, Or to do ICM.
|
|
//
|
|
LOCALFREE (pulBits);
|
|
}
|
|
|
|
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 = 0;
|
|
PDC_ATTR pdcattr;
|
|
|
|
FIXUP_HANDLE(hdc);
|
|
FIXUP_HANDLE(hbm);
|
|
|
|
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
|
|
|
|
if (pdcattr)
|
|
{
|
|
BOOL bNeedICM = TRUE;
|
|
|
|
cjBits = cjBitmapScanSize(pbmi,nNumScans);
|
|
|
|
//
|
|
// If pbmi is a input buffer specifying image format
|
|
// (i.e., pBits != NULL), then fail for passthrough
|
|
// images (BI_JPEG and BI_PNG)
|
|
//
|
|
if (pBits && IS_BMI_PASSTHROUGH_IMAGE(pbmi))
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
|
|
if (pbmi->bmiHeader.biBitCount == 0)
|
|
{
|
|
//
|
|
// no color table required.
|
|
//
|
|
bNeedICM = FALSE;
|
|
}
|
|
|
|
//
|
|
// if the pBits are not dword aligned, we need to allocate
|
|
// a buffer and copy them
|
|
//
|
|
if ((ULONG_PTR)pBits & (sizeof(DWORD) - 1))
|
|
{
|
|
pulBits = LOCALALLOC(cjBits);
|
|
|
|
if (pulBits == NULL)
|
|
return(0);
|
|
}
|
|
|
|
iRet = NtGdiGetDIBitsInternal(
|
|
hdc,
|
|
hbm,
|
|
nStartScan,
|
|
nNumScans,
|
|
(LPVOID)pulBits,
|
|
pbmi,
|
|
iUsage,
|
|
cjBits,
|
|
0);
|
|
|
|
//
|
|
// translate DIB if needed
|
|
//
|
|
if (bNeedICM &&
|
|
(IS_ICM_HOST(pdcattr->lIcmMode)) && (iUsage != DIB_PAL_COLORS))
|
|
{
|
|
//
|
|
// UNDER_CONSTRUCTION: Failed on GetDIBits() from CMYK surface.
|
|
//
|
|
if (IS_CMYK_COLOR(pdcattr->lIcmMode))
|
|
{
|
|
WARNING("GetDIBits(): was called on CMYK bitmap\n");
|
|
iRet = 0;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Do backward transform.
|
|
//
|
|
if (!IcmTranslateDIB(hdc,
|
|
pdcattr,
|
|
cjBits,
|
|
pulBits,
|
|
NULL, // Indicates overwrite original...
|
|
pbmi,
|
|
NULL, // Indicates overwrite original...
|
|
NULL,
|
|
nNumScans,
|
|
iUsage,
|
|
ICM_BACKWARD,
|
|
NULL,NULL))
|
|
{
|
|
//
|
|
// ICM translation failed.
|
|
//
|
|
iRet = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pulBits != pBits)
|
|
{
|
|
if (iRet)
|
|
{
|
|
RtlCopyMemory(pBits,pulBits,cjBits);
|
|
}
|
|
|
|
LOCALFREE(pulBits);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
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;
|
|
PDC_ATTR pdcattr;
|
|
|
|
// ICM related variables.
|
|
|
|
PCACHED_COLORSPACE pBitmapColorSpace = NULL;
|
|
PCACHED_COLORTRANSFORM pCXform = NULL;
|
|
HANDLE hcmTempXform = NULL;
|
|
|
|
FIXUP_HANDLEZ(hdc);
|
|
|
|
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pjBits = NULL;
|
|
}
|
|
}
|
|
|
|
// CreateDIBitmap cannot handle passthrough image (BI_JPEG or BI_PNG)
|
|
// init data
|
|
|
|
if (IS_BMI_PASSTHROUGH_IMAGE(pbmiNew))
|
|
{
|
|
hRet = 0;
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
BOOL bStatus = TRUE;
|
|
|
|
// if the pJBits are not dword aligned we need to allocate a buffer and copy them
|
|
|
|
if ((ULONG_PTR)pjBits & (sizeof(DWORD) - 1))
|
|
{
|
|
pulBits = LOCALALLOC(cjBits);
|
|
if (pulBits)
|
|
{
|
|
RtlCopyMemory(pulBits,pjBits,cjBits);
|
|
pjBits = pulBits;
|
|
}
|
|
}
|
|
|
|
// ICM conversion
|
|
//
|
|
// Convert bitmap data only when ...
|
|
//
|
|
// - HDC is not NULL.
|
|
// - ICM is enanled.
|
|
// - ICM is not lazy mode.
|
|
// - Initialize data is not Palette Index.
|
|
// - Initialize data is provided.
|
|
|
|
if (pdcattr &&
|
|
IS_ICM_INSIDEDC(pdcattr->lIcmMode) &&
|
|
(IS_ICM_LAZY_CORRECTION(pdcattr->lIcmMode) == FALSE) &&
|
|
(iUsage != DIB_PAL_COLORS) &&
|
|
pjBits && pbmiNew)
|
|
{
|
|
PVOID pvBitsIcm = NULL;
|
|
PBITMAPINFO pbmiIcm = NULL;
|
|
ULONG cjBMINew = 0;
|
|
BOOL bIcmStatus;
|
|
|
|
bIcmStatus = IcmTranslateDIB(hdc,
|
|
pdcattr,
|
|
cjBits,
|
|
(PVOID)pjBits,
|
|
&pvBitsIcm,
|
|
pbmiNew,
|
|
&pbmiIcm,
|
|
&cjBMINew,
|
|
(DWORD)-1,
|
|
iUsage,
|
|
ICM_FORWARD,
|
|
&pBitmapColorSpace,
|
|
&pCXform);
|
|
|
|
//
|
|
// IcmTranslateDIB will create a duplicate dib
|
|
// pointed to by pulBits if needed.
|
|
//
|
|
|
|
if (bIcmStatus)
|
|
{
|
|
if (pvBitsIcm != NULL)
|
|
{
|
|
ICMMSG(("CreateDIBitmap(): Temp bits are allocated\n"));
|
|
|
|
if (pulBits)
|
|
{
|
|
LOCALFREE(pulBits);
|
|
}
|
|
|
|
pjBits = (PVOID)pulBits = pvBitsIcm;
|
|
}
|
|
|
|
if (pbmiIcm != NULL)
|
|
{
|
|
ICMMSG(("CreateDIBitmap(): Temp bmi are allocated\n"));
|
|
|
|
if (pbmiNew && (pbmiNew != pbmi))
|
|
{
|
|
LOCALFREE(pbmiNew);
|
|
}
|
|
|
|
pbmiNew = pbmiIcm;
|
|
|
|
//
|
|
// Calculate bitmap bits size based on BITMAPINFO and nNumScans
|
|
//
|
|
cjBits = cjBitmapBitsSize(pbmiNew);
|
|
|
|
//
|
|
// Update sizeof bitmap info (including color table)
|
|
//
|
|
if (cjBMINew)
|
|
{
|
|
cjBMI = cjBMINew;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get color transform handle need to pass kernel
|
|
//
|
|
if (pCXform)
|
|
{
|
|
hcmTempXform = pCXform->ColorTransform;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bStatus)
|
|
{
|
|
hRet = NtGdiCreateDIBitmapInternal(hdc,
|
|
cx,
|
|
cy,
|
|
flInit,
|
|
(LPBYTE) pjBits,
|
|
(LPBITMAPINFO) pbmiNew,
|
|
iUsage,
|
|
cjBMI,
|
|
cjBits,
|
|
0,
|
|
hcmTempXform);
|
|
|
|
#if TRACE_SURFACE_ALLOCS
|
|
{
|
|
PULONGLONG pUserAlloc;
|
|
|
|
PSHARED_GET_VALIDATE(pUserAlloc, hRet, SURF_TYPE);
|
|
|
|
if (pUserAlloc != NULL)
|
|
{
|
|
RtlWalkFrameChain((PVOID *)&pUserAlloc[1], (ULONG)*pUserAlloc, 0);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (pBitmapColorSpace)
|
|
{
|
|
if (pCXform)
|
|
{
|
|
IcmDeleteColorTransform(pCXform,FALSE);
|
|
}
|
|
|
|
IcmReleaseColorSpace(NULL,pBitmapColorSpace,FALSE);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
// if passthrough image (BI_JPEG or BI_JPEG), fail
|
|
|
|
if (IS_BMI_PASSTHROUGH_IMAGE(pInitInfo))
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
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 = ((LPBITMAPCOREHEADER)pInitInfo)->bcWidth;
|
|
cHeight = ((LPBITMAPCOREHEADER)pInitInfo)->bcHeight;
|
|
}
|
|
else
|
|
{
|
|
cWidth = pInitInfo->bmiHeader.biWidth;
|
|
cHeight = ABS(pInitInfo->bmiHeader.biHeight);
|
|
}
|
|
|
|
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 = 0;
|
|
BITMAPINFO * pbmiNew = NULL;
|
|
PDC_ATTR pdcattr;
|
|
|
|
BOOL bStatus = TRUE;
|
|
|
|
// ICM related variables.
|
|
|
|
PCACHED_COLORSPACE pBitmapColorSpace = NULL;
|
|
PCACHED_COLORTRANSFORM pCXform = NULL;
|
|
HANDLE hcmTempXform = 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)
|
|
{
|
|
//
|
|
// speeds up cases when partial sources bits are sent
|
|
//
|
|
|
|
int iStart = 0;
|
|
int iEnd = 0;
|
|
int cScans = 0;
|
|
|
|
if (pbmi && (pbmi->bmiHeader.biWidth == nSrcWidth) && (pbmi->bmiHeader.biHeight > nSrcHeight) &&
|
|
(pbmi->bmiHeader.biHeight > 0) &&
|
|
!(IS_BMI_RLE(pbmi) || IS_BMI_PASSTHROUGH_IMAGE(pbmi)))
|
|
{
|
|
iStart = ((ySrc - EXTRAPIXEL) > 0) ? (ySrc - EXTRAPIXEL) : 0;
|
|
|
|
iEnd = ((ySrc+nSrcHeight + EXTRAPIXEL) > pbmi->bmiHeader.biHeight)?
|
|
pbmi->bmiHeader.biHeight : (ySrc+nSrcHeight + EXTRAPIXEL);
|
|
|
|
cScans = iEnd - iStart;
|
|
|
|
}
|
|
|
|
if (!MF_AnyDIBits(hdc,
|
|
xDest,
|
|
yDest,
|
|
nDestWidth,
|
|
nDestHeight,
|
|
xSrc,
|
|
ySrc,
|
|
nSrcWidth,
|
|
nSrcHeight,
|
|
iStart,
|
|
cScans,
|
|
(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);
|
|
}
|
|
|
|
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_PTR)pj & (sizeof(DWORD) - 1))
|
|
{
|
|
pulBits = LOCALALLOC(cjBits);
|
|
if (pulBits)
|
|
{
|
|
RtlCopyMemory(pulBits,pj,cjBits);
|
|
pj = pulBits;
|
|
}
|
|
}
|
|
|
|
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
|
|
|
|
if (pdcattr)
|
|
{
|
|
// icm tranlation
|
|
//
|
|
// Convert bitmap data only when ...
|
|
//
|
|
// - ICM is enabled.
|
|
// - Bitmap is not Palette Index.
|
|
// - Bitmap header & data is provided.
|
|
// - Bitmap is not passthrough image (BI_JPEG or BI_PNG).
|
|
|
|
if (IS_ICM_INSIDEDC(pdcattr->lIcmMode) &&
|
|
(iUsage != DIB_PAL_COLORS) &&
|
|
pbmiNew && pj &&
|
|
!IS_BMI_PASSTHROUGH_IMAGE(pbmiNew))
|
|
{
|
|
|
|
LPBITMAPINFO pbmiIcm = NULL;
|
|
LPBITMAPINFO pbmiSave = NULL;
|
|
PVOID pvBitsIcm = NULL;
|
|
ULONG cjHeaderNew = 0;
|
|
ULONG cjBitsIcm;
|
|
BOOL bIcmStatus;
|
|
VOID *pBitsBand = (VOID *)pj;
|
|
LONG CurrentBandSize;
|
|
LONG SizeOfOneScanline;
|
|
LONG IcmSizeOfOneScanline;
|
|
LONG nBands;
|
|
LONG nScansInBand;
|
|
LONG nScansInCurrentBand;
|
|
LONG nScansInRemainderBand;
|
|
LONG CumulativeScans=0;
|
|
LONG i;
|
|
LONG PositiveBandDelta=0;
|
|
LONG NegativeBandDelta=0;
|
|
LONG TotalBandDelta=0;
|
|
HRGN hrgnBandClip = NULL;
|
|
RECT rectCurrentClip;
|
|
LONG HeaderHeightHack;
|
|
INT cScanCount=0;
|
|
float lMulDivStoreY1;
|
|
float lMulDivStoreY2;
|
|
|
|
|
|
SizeOfOneScanline = cjBitmapScanSize(pbmiNew, 1);
|
|
|
|
//
|
|
//pbmiNew must be initialized before getting to this point.
|
|
//
|
|
|
|
ASSERTGDI(pbmiNew!=NULL, "StretchDIBits cannot proceed with pbmiNew==NULL\n");
|
|
|
|
nScansInBand = BAND_SIZE/SizeOfOneScanline;
|
|
|
|
//
|
|
// Set the number of bands provided there are enough scanlines
|
|
// and the hdc is a printer dc.
|
|
//
|
|
// Else set the nubmer of bands to 1 and the scanlines in the
|
|
// remainder band to all of them, so the entire bitmap is printed
|
|
// in one band (All the code below reduces to doing a single piece)
|
|
//
|
|
// If the bitmap is RLE compressed, we set it up to do one band
|
|
// only. When this is the case, Start and NegativeBandDelta will be
|
|
// computed as 0 and the SizeOfOneScanline parameter will be
|
|
// multiplied away to zero.
|
|
//
|
|
|
|
if ((nScansInBand>0)&&
|
|
(GetDeviceCaps(hdc, TECHNOLOGY)==DT_RASPRINTER)&&
|
|
(!IS_BMI_RLE(pbmiNew)))
|
|
{
|
|
//
|
|
// Compressed images cannot be converted in this way.
|
|
// This should never be hit and is included as a guard against
|
|
// someone inventing a new compression mode and not updating
|
|
// this conditional.
|
|
//
|
|
|
|
//This assert needs a rethink - cjBits refers to the whole image
|
|
//which could be larger than the nSrcHeight portion.
|
|
//ASSERTGDI(SizeOfOneScanline*nSrcHeight==cjBits, "StretchDIBits, cannot band compressed image");
|
|
|
|
nBands = (nSrcHeight)/nScansInBand;
|
|
nScansInRemainderBand = nSrcHeight % nScansInBand;
|
|
}
|
|
else
|
|
{
|
|
nBands = 0;
|
|
nScansInRemainderBand = (nSrcHeight);
|
|
}
|
|
|
|
if (nScansInRemainderBand>0)
|
|
{
|
|
nBands++;
|
|
nScansInCurrentBand = nScansInRemainderBand;
|
|
}
|
|
else
|
|
{
|
|
nScansInCurrentBand = nScansInBand;
|
|
}
|
|
|
|
if (nBands != 1)
|
|
{
|
|
//
|
|
// We're going to have to modify the bmi for this image to
|
|
// coerce NtGdiStretchDIBitsInternal to do the banding.
|
|
// There is a codepath that gets to this point with pbmiNew
|
|
// set to pbmi (pointer copy) rather than local allocated space.
|
|
// if the memory passed in the pointer to pbmi is read only,
|
|
// we won't be able to hack the header, so we make a local copy
|
|
// for banding.
|
|
//
|
|
|
|
pbmiSave = pbmiNew; //store the old value
|
|
pbmiNew = (LPBITMAPINFO)LOCALALLOC(cjHeader);
|
|
if (pbmiNew)
|
|
{
|
|
|
|
RtlCopyMemory((LPBYTE)pbmiNew,
|
|
(LPBYTE)pbmiSave,
|
|
cjHeader);
|
|
|
|
HeaderHeightHack = pbmiNew->bmiHeader.biHeight;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// we need to bail out here. Goto the cleanup code.
|
|
//
|
|
|
|
WARNING("StretchDIBits: couldn't allocate memory for temporary BITMAPINFO\n");
|
|
|
|
pbmiNew = pbmiSave;
|
|
iRet = 0;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
for (i=0; i<nBands; i++)
|
|
{
|
|
//
|
|
// Initialize band specific size counters.
|
|
//
|
|
|
|
CurrentBandSize = nScansInCurrentBand*SizeOfOneScanline;
|
|
IcmSizeOfOneScanline = SizeOfOneScanline;
|
|
cjBitsIcm = cjBits;
|
|
|
|
//
|
|
// The Delta refers to the number of extra scanlines to pass
|
|
// to the internal blting routines in order to avoid halftone
|
|
// seams.
|
|
//
|
|
// PositiveBandDelta is usually the number of scanlines to
|
|
// add on to the end of the band. (relative to the start in
|
|
// memory)
|
|
//
|
|
// NegativeBandDelta is usually the number of scanlines to
|
|
// subtract from the begining of the band (ie move the start
|
|
// pointer back this many scanlines).
|
|
//
|
|
// Total BandDelta is simply the total number of extra scans
|
|
// added for this band (both at the start and end).
|
|
//
|
|
// We reverse the sense of positive and negative when rendering
|
|
// bottom up DIBs
|
|
//
|
|
|
|
NegativeBandDelta = MIN(EXTRAPIXEL, CumulativeScans);
|
|
PositiveBandDelta = MIN(EXTRAPIXEL, MAX(0, nSrcHeight-(CumulativeScans+nScansInCurrentBand)));
|
|
TotalBandDelta = NegativeBandDelta+PositiveBandDelta;
|
|
|
|
if (nBands != 1)
|
|
{
|
|
//
|
|
// We're going to be doing fancy banding stuff with the clip
|
|
// region so we'll want to restore it after the band is done.
|
|
//
|
|
|
|
SaveDC(hdc);
|
|
|
|
//
|
|
// Intersect the clip rectangles.
|
|
// This clip rectangle is designed to restrict the output to
|
|
// just the displayed portion of the band.
|
|
// We may pass more scanlines on the top and bottom of the band
|
|
// to get halftoning to merge seamlessly.
|
|
//
|
|
|
|
|
|
lMulDivStoreY1 = (float)nDestHeight*CumulativeScans;
|
|
lMulDivStoreY2 = (float)nDestHeight*(CumulativeScans+nScansInCurrentBand);
|
|
|
|
|
|
iRet = IntersectClipRect(
|
|
hdc,
|
|
xDest,
|
|
yDest+(LONG)(lMulDivStoreY1/nSrcHeight+0.5),
|
|
xDest+nDestWidth,
|
|
yDest+(LONG)(lMulDivStoreY2/nSrcHeight+0.5));
|
|
|
|
if (iRet==ERROR)
|
|
{
|
|
WARNING("StretchDIBits: error intersecting clip rect\n");
|
|
RestoreDC(hdc, -1);
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Empty clip rectangle
|
|
// If the clip regions don't intersect, we can quit without
|
|
// doing anything.
|
|
//
|
|
|
|
if (iRet==NULLREGION)
|
|
{
|
|
RestoreDC(hdc, -1);
|
|
|
|
//
|
|
// Nothing to do - fall through and do
|
|
// initialization for next iteration.
|
|
//
|
|
|
|
goto Continue_With_Init;
|
|
}
|
|
|
|
//
|
|
// Hack the BITMAPINFO header so that NtGdiStretchDIBitsInternal
|
|
// works correctly. Note that hacking it before the ICM call will
|
|
// carry through to the NtGdiStretchDIBitsInteral call.
|
|
//
|
|
// This code also updates the pointer to the bits, in a manner
|
|
// appropriate to the topdown/bottomup nature of the DIB.
|
|
//
|
|
|
|
if (HeaderHeightHack >= 0)
|
|
{
|
|
//
|
|
//Bottom Up
|
|
//
|
|
|
|
pBitsBand = (char *)pj + (ySrc+nSrcHeight-nScansInCurrentBand-CumulativeScans-PositiveBandDelta)*SizeOfOneScanline;
|
|
pbmiNew->bmiHeader.biHeight = nScansInCurrentBand+TotalBandDelta;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
//Top Down
|
|
//
|
|
|
|
pBitsBand = (char *)pj + (ySrc+CumulativeScans-NegativeBandDelta)*SizeOfOneScanline;
|
|
pbmiNew->bmiHeader.biHeight = -(nScansInCurrentBand+TotalBandDelta);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pBitsBand = (char *)pj;
|
|
}
|
|
|
|
//
|
|
// Initialize per band ICM variables
|
|
//
|
|
|
|
cjHeaderNew=0;
|
|
pbmiIcm = NULL;
|
|
pvBitsIcm = NULL;
|
|
|
|
//
|
|
// Call ICM with an oversized band for later halftoning by
|
|
// NtGdiStretchDIBitsInternal
|
|
//
|
|
|
|
bIcmStatus = IcmTranslateDIB(
|
|
hdc,
|
|
pdcattr,
|
|
(nBands==1)?cjBits:(CurrentBandSize+TotalBandDelta*SizeOfOneScanline),
|
|
(PVOID)pBitsBand,
|
|
&pvBitsIcm,
|
|
pbmiNew,
|
|
&pbmiIcm,
|
|
&cjHeaderNew,
|
|
(nBands==1)?((DWORD)-1):(nScansInCurrentBand+TotalBandDelta),
|
|
iUsage,
|
|
ICM_FORWARD,
|
|
&pBitmapColorSpace,
|
|
&pCXform);
|
|
|
|
if (bIcmStatus)
|
|
{
|
|
if (pvBitsIcm == NULL)
|
|
{
|
|
pvBitsIcm = pBitsBand;
|
|
}
|
|
if (pbmiIcm == NULL)
|
|
{
|
|
pbmiIcm = pbmiNew;
|
|
cjHeaderNew = cjHeader;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// new bits and header means a possibly different size bitmap
|
|
// and different size scanline.
|
|
//
|
|
// if nBands==1 then nScansInCurrentBand==nNumScans and
|
|
// TotalBandDelta==0
|
|
//
|
|
// Also note that nNumScans is the number of scans rendered,
|
|
// not the number of scans in the bitmap or converted in
|
|
// IcmTranslateDIB for nBands==1 case
|
|
//
|
|
|
|
if(nBands == 1) {
|
|
cjBitsIcm = cjBitmapBitsSize(pbmiIcm);
|
|
}
|
|
CurrentBandSize = cjBitmapScanSize(pbmiIcm, nScansInCurrentBand);
|
|
IcmSizeOfOneScanline = cjBitmapScanSize(pbmiIcm, 1);
|
|
if (!cjHeaderNew)
|
|
{
|
|
cjHeaderNew = cjHeader;
|
|
}
|
|
}
|
|
if (pCXform)
|
|
{
|
|
hcmTempXform = pCXform->ColorTransform;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pvBitsIcm = pBitsBand;
|
|
pbmiIcm = pbmiNew;
|
|
cjHeaderNew = cjHeader;
|
|
}
|
|
|
|
lMulDivStoreY1 = (float)nDestHeight*(CumulativeScans-NegativeBandDelta);
|
|
lMulDivStoreY2 = (float)nDestHeight*(nScansInCurrentBand+TotalBandDelta);
|
|
iRet = NtGdiStretchDIBitsInternal(
|
|
hdc,
|
|
xDest,
|
|
yDest+(LONG)(lMulDivStoreY1/nSrcHeight+0.5),
|
|
nDestWidth,
|
|
(LONG)(lMulDivStoreY2/nSrcHeight+0.5),
|
|
xSrc,
|
|
(nBands==1)?ySrc:0,
|
|
nSrcWidth,
|
|
nScansInCurrentBand+TotalBandDelta,
|
|
(LPBYTE) pvBitsIcm,
|
|
(LPBITMAPINFO) pbmiIcm,
|
|
iUsage,
|
|
lRop,
|
|
(UINT)cjHeaderNew,
|
|
(nBands==1)?cjBitsIcm:(UINT)CurrentBandSize+TotalBandDelta*IcmSizeOfOneScanline,
|
|
hcmTempXform);
|
|
|
|
|
|
if (nBands != 1)
|
|
{
|
|
//
|
|
// Unhack the header
|
|
//
|
|
|
|
pbmiNew->bmiHeader.biHeight = HeaderHeightHack;
|
|
}
|
|
|
|
if (iRet==GDI_ERROR)
|
|
{
|
|
WARNING("StretchDIBits: NtGdiStretchDIBitsInternal returned GDI_ERROR\n");
|
|
if (nBands!=1)
|
|
{
|
|
RestoreDC(hdc, -1);
|
|
}
|
|
goto Exit; //Some GDI error and we need to quit.
|
|
}
|
|
cScanCount+=iRet-TotalBandDelta;
|
|
|
|
//
|
|
//Throw away temp storage
|
|
//
|
|
|
|
if (pBitmapColorSpace)
|
|
{
|
|
if (pCXform)
|
|
{
|
|
IcmDeleteColorTransform(pCXform,FALSE);
|
|
pCXform = NULL;
|
|
}
|
|
IcmReleaseColorSpace(NULL,pBitmapColorSpace,FALSE);
|
|
pBitmapColorSpace = NULL;
|
|
}
|
|
if ((pvBitsIcm!=NULL)&&(pvBitsIcm!=pBitsBand))
|
|
{
|
|
LOCALFREE(pvBitsIcm);
|
|
pvBitsIcm = NULL;
|
|
}
|
|
if ((pbmiIcm!=NULL)&&(pbmiIcm!=pbmiNew))
|
|
{
|
|
LOCALFREE(pbmiIcm);
|
|
pbmiIcm = NULL;
|
|
}
|
|
hcmTempXform = NULL;
|
|
|
|
|
|
Continue_With_Init:
|
|
//
|
|
//Initialize variables for next loop.
|
|
//
|
|
|
|
CumulativeScans += nScansInCurrentBand;
|
|
nScansInCurrentBand = nScansInBand;
|
|
if (nBands != 1)
|
|
{
|
|
RestoreDC(hdc, -1);
|
|
}
|
|
}
|
|
|
|
if (nBands != 1)
|
|
{
|
|
ASSERTGDI(pbmiSave!=NULL, "StretchDIBits: pbmiSave==NULL\n");
|
|
ASSERTGDI(pbmiNew!=NULL, "StretchDIBits: pbmiNew==NULL\n");
|
|
LOCALFREE(pbmiNew);
|
|
pbmiNew = pbmiSave;
|
|
|
|
//
|
|
// pbmiNew will be cleaned up in the
|
|
// regular cleanup code below.
|
|
//
|
|
}
|
|
//
|
|
// We do our own NtGdiSetDIBitsToDeviceInternal
|
|
// So we need to fall through to cleanup at this point.
|
|
//
|
|
iRet=cScanCount;
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if (bStatus)
|
|
{
|
|
iRet = NtGdiStretchDIBitsInternal(hdc,
|
|
xDest,
|
|
yDest,
|
|
nDestWidth,
|
|
nDestHeight,
|
|
xSrc,
|
|
ySrc,
|
|
nSrcWidth,
|
|
nSrcHeight,
|
|
(LPBYTE) pj,
|
|
(LPBITMAPINFO) pbmiNew,
|
|
iUsage,
|
|
lRop,
|
|
cjHeader,
|
|
cjBits,
|
|
hcmTempXform);
|
|
}
|
|
|
|
Exit:
|
|
if (pulBits)
|
|
{
|
|
LOCALFREE(pulBits);
|
|
}
|
|
|
|
if (pbmiNew && (pbmiNew != pbmi))
|
|
{
|
|
LOCALFREE(pbmiNew);
|
|
}
|
|
|
|
return (iRet);
|
|
}
|
|
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* History:
|
|
* 27-Oct-2000 -by- Pravin Santiago [pravins]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HBITMAP SetBitmapAttributes(HBITMAP hbm, DWORD dwFlags)
|
|
{
|
|
FIXUP_HANDLE(hbm);
|
|
|
|
if ((dwFlags & ~SBA_STOCK) != 0)
|
|
return (HBITMAP)0;
|
|
|
|
return (HBITMAP)NtGdiSetBitmapAttributes(hbm,dwFlags);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* History:
|
|
* 27-Oct-2000 -by- Pravin Santiago [pravins]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HBITMAP ClearBitmapAttributes(HBITMAP hbm, DWORD dwFlags)
|
|
{
|
|
FIXUP_HANDLE(hbm);
|
|
|
|
if ((dwFlags & ~SBA_STOCK) != 0)
|
|
return (HBITMAP)0;
|
|
|
|
return (HBITMAP)NtGdiClearBitmapAttributes(hbm,dwFlags);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* History:
|
|
* 27-Oct-2000 -by- Pravin Santiago [pravins]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD GetBitmapAttributes(HBITMAP hbm)
|
|
{
|
|
DWORD dwRet = 0;
|
|
FIXUP_HANDLE(hbm);
|
|
|
|
if (IS_STOCKOBJ(hbm))
|
|
dwRet |= SBA_STOCK;
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* History:
|
|
* 27-Oct-2000 -by- Pravin Santiago [pravins]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HBRUSH SetBrushAttributes(HBRUSH hbr, DWORD dwFlags)
|
|
{
|
|
FIXUP_HANDLE(hbr);
|
|
|
|
if ((dwFlags & ~SBA_STOCK) != 0)
|
|
return (HBRUSH)0;
|
|
|
|
return (HBRUSH)NtGdiSetBrushAttributes(hbr,dwFlags);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* History:
|
|
* 27-Oct-2000 -by- Pravin Santiago [pravins]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
HBRUSH ClearBrushAttributes(HBRUSH hbr, DWORD dwFlags)
|
|
{
|
|
FIXUP_HANDLE(hbr);
|
|
|
|
if ((dwFlags & ~SBA_STOCK) != 0)
|
|
return (HBRUSH)0;
|
|
|
|
return (HBRUSH)NtGdiClearBrushAttributes(hbr,dwFlags);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
*
|
|
* History:
|
|
* 27-Oct-2000 -by- Pravin Santiago [pravins]
|
|
* Wrote it.
|
|
\**************************************************************************/
|
|
|
|
DWORD GetBrushAttributes(HBRUSH hbr)
|
|
{
|
|
DWORD dwRet = 0;
|
|
FIXUP_HANDLE(hbr);
|
|
|
|
if (IS_STOCKOBJ(hbr))
|
|
dwRet |= SBA_STOCK;
|
|
|
|
return dwRet;
|
|
}
|
|
|
|
/******************************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);
|
|
|
|
#if TRACE_SURFACE_ALLOCS
|
|
{
|
|
PULONG pUserAlloc;
|
|
|
|
PSHARED_GET_VALIDATE(pUserAlloc, hbm, SURF_TYPE);
|
|
|
|
if (pUserAlloc != NULL)
|
|
{
|
|
pUserAlloc[1] = RtlWalkFrameChain((PVOID *)&pUserAlloc[2], pUserAlloc[0], 0);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
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 TRACE_SURFACE_ALLOCS
|
|
{
|
|
PULONG pUserAlloc;
|
|
|
|
PSHARED_GET_VALIDATE(pUserAlloc, hbm, SURF_TYPE);
|
|
|
|
if (pUserAlloc != NULL)
|
|
{
|
|
pUserAlloc[1] = RtlWalkFrameChain((PVOID *)&pUserAlloc[2], pUserAlloc[0], 0);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
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);
|
|
|
|
//
|
|
// Does not support passthrough image (BI_JPEG or BI_PNG).
|
|
// Return NULL for error.
|
|
//
|
|
|
|
if (IS_BMI_PASSTHROUGH_IMAGE(pbmiNew))
|
|
{
|
|
GdiSetLastError(ERROR_INVALID_PARAMETER);
|
|
return hbm;
|
|
}
|
|
|
|
//
|
|
// 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) )
|
|
{
|
|
PCACHED_COLORSPACE pBitmapColorSpace = NULL;
|
|
BOOL bCreatedColorSpace = FALSE;
|
|
|
|
LOGCOLORSPACEW LogColorSpace;
|
|
PROFILE ColorProfile;
|
|
DWORD dwFlags = 0;
|
|
|
|
//
|
|
// Check they has thier own color space or not.
|
|
//
|
|
if (pbmiNew && IcmGetBitmapColorSpace(pbmiNew,&LogColorSpace,&ColorProfile,&dwFlags))
|
|
{
|
|
//
|
|
// Find ColorSpace from cache.
|
|
//
|
|
pBitmapColorSpace = IcmGetColorSpaceByColorSpace(
|
|
(HGDIOBJ)hdc,
|
|
&LogColorSpace,
|
|
&ColorProfile,
|
|
dwFlags);
|
|
|
|
if (pBitmapColorSpace == NULL)
|
|
{
|
|
//
|
|
// If we can not find the color space for this DIBSection from existing color space.
|
|
// create new one for this, but we mark it as DIBSECTION_COLORSPACE, then associated
|
|
// to this hdc (later hbm), so that we can make sure this color space get deleted
|
|
// when hbm is deleted.
|
|
//
|
|
dwFlags |= DIBSECTION_COLORSPACE;
|
|
|
|
//
|
|
// Mark we will create new colorspace for this bitmap.
|
|
//
|
|
bCreatedColorSpace = TRUE;
|
|
|
|
//
|
|
// Create new cache.
|
|
//
|
|
pBitmapColorSpace = IcmCreateColorSpaceByColorSpace(
|
|
(HGDIOBJ)hdc,
|
|
&LogColorSpace,
|
|
&ColorProfile,
|
|
dwFlags);
|
|
}
|
|
}
|
|
|
|
hbm = NtGdiCreateDIBSection(
|
|
hdc,
|
|
hSectionApp,
|
|
dwOffset,
|
|
(LPBITMAPINFO) pbmiNew,
|
|
iUsage,
|
|
cjHdr,
|
|
0,
|
|
(ULONG_PTR)pBitmapColorSpace,
|
|
(PVOID *)&pjBits);
|
|
|
|
if ((hbm == NULL) || (pjBits == NULL))
|
|
{
|
|
hbm = 0;
|
|
pjBits = NULL;
|
|
if (pBitmapColorSpace)
|
|
{
|
|
IcmReleaseColorSpace(NULL,pBitmapColorSpace,FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#if TRACE_SURFACE_ALLOCS
|
|
PULONG pUserAlloc;
|
|
|
|
PSHARED_GET_VALIDATE(pUserAlloc, hbm, SURF_TYPE);
|
|
|
|
if (pUserAlloc != NULL)
|
|
{
|
|
pUserAlloc[1] = RtlWalkFrameChain((PVOID *)&pUserAlloc[2], pUserAlloc[0], 0);
|
|
}
|
|
#endif
|
|
|
|
if (pBitmapColorSpace && bCreatedColorSpace)
|
|
{
|
|
//
|
|
// if we created new color space for this bitmap,
|
|
// set owner of this colorspace to the created bitmap.
|
|
//
|
|
pBitmapColorSpace->hObj = hbm;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Assign the appropriate value to the caller's pointer
|
|
//
|
|
|
|
if (ppvBits != NULL)
|
|
{
|
|
*ppvBits = pjBits;
|
|
}
|
|
|
|
if (pbmiNew && (pbmiNew != pbmi))
|
|
{
|
|
LOCALFREE(pbmiNew);
|
|
}
|
|
|
|
return(hbm);
|
|
}
|