/******************************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= 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= 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); }