WindowsXP-SP1/windows/advcore/gdiplus/engine/entry/gpbitmap.hpp
2020-09-30 16:53:49 +02:00

752 lines
20 KiB
C++

/**************************************************************************\
*
* Copyright (c) 1998 Microsoft Corporation
*
* Module Name:
*
* GpBitmap.hpp
*
* Abstract:
*
* Bitmap related declarations
*
* Revision History:
*
* 12/09/1998 davidx
* Created it.
*
\**************************************************************************/
#ifndef _GPBITMAP_HPP
#define _GPBITMAP_HPP
#define NEARCONSTANTALPHA 0x10
//--------------------------------------------------------------------------
// Abstract base class for bitmap image and metafile
//--------------------------------------------------------------------------
class GpImage : public GpObject
{
protected:
VOID SetValid(BOOL valid)
{
GpObject::SetValid(valid ? ObjectTagImage : ObjectTagInvalid);
}
public:
// Construct a GpImage object from a disk file
static GpImage* LoadImage(const WCHAR* filename);
// Construct a GpImage object from a data stream
static GpImage* LoadImage(IStream* stream);
virtual ObjectType GetObjectType() const { return ObjectTypeImage; }
// Make a copy of the image object
virtual GpImage* Clone() const= 0;
virtual GpImage* CloneColorAdjusted(
GpRecolor * recolor,
ColorAdjustType type = ColorAdjustTypeDefault
) const = 0;
// Get the encoder parameter list size
virtual GpStatus
GetEncoderParameterListSize(
CLSID* clsidEncoder,
UINT* size
) = 0;
// Get the encoder parameter list
virtual GpStatus
GetEncoderParameterList(
CLSID* clsidEncoder,
UINT size,
OUT EncoderParameters* pBuffer
) = 0;
// Save images
virtual GpStatus
SaveToStream(
IStream* stream,
CLSID* clsidEncoder,
EncoderParameters* encoderParams
) = 0;
virtual GpStatus
SaveToFile(
const WCHAR* filename,
CLSID* clsidEncoder,
EncoderParameters* encoderParams
) = 0;
virtual GpStatus
SaveAdd(
const EncoderParameters* encoderParams
) = 0;
virtual GpStatus
SaveAdd(
GpImage* newBits,
const EncoderParameters* encoderParams
) = 0;
// Dispose of the image object
virtual VOID Dispose() = 0;
// Derive a graphics context to draw into the GpImage object
virtual GpGraphics* GetGraphicsContext() = 0;
// Check if the GpImage object is valid
virtual BOOL IsValid() const
{
return GpObject::IsValid(ObjectTagImage);
}
virtual BOOL IsSolid()
{
return FALSE;
}
virtual BOOL IsOpaque()
{
return FALSE;
}
// Get image information:
// resolution
// physical dimension in 0.01mm units
// bounding rectangle
// structure ImageInfo
// thumbnail
virtual GpStatus GetResolution(REAL* xdpi, REAL* ydpi) const = 0;
virtual GpStatus GetPhysicalDimension(REAL* width, REAL* height) const = 0;
virtual GpStatus GetBounds(GpRectF* rect, GpPageUnit* unit) const = 0;
virtual GpStatus GetImageInfo(ImageInfo *imageInfo) const = 0;
virtual GpStatus GetFrameCount(const GUID* dimensionID,
UINT* count) const = 0;
virtual GpStatus GetFrameDimensionsCount(OUT UINT* count) const = 0;
virtual GpStatus GetFrameDimensionsList(OUT GUID* dimensionIDs,
IN UINT count) const = 0;
virtual GpStatus SelectActiveFrame(const GUID* dimensionID,
UINT frameIndex) = 0;
virtual GpImage* GetThumbnail(UINT thumbWidth, UINT thumbHeight,
GetThumbnailImageAbort callback, VOID *callbackData) = 0;
virtual GpStatus GetPalette(ColorPalette *palette, INT size) = 0;
virtual GpStatus SetPalette(ColorPalette *palette) = 0;
virtual INT GetPaletteSize() = 0;
// Rotate and Flip
virtual GpStatus RotateFlip(RotateFlipType rfType) = 0;
// Property related functions
virtual GpStatus GetPropertyCount(UINT* numOfProperty) = 0;
virtual GpStatus GetPropertyIdList(UINT numOfProperty, PROPID* list) = 0;
virtual GpStatus GetPropertyItemSize(PROPID propId, UINT* size) = 0;
virtual GpStatus GetPropertyItem(PROPID propId,UINT propSize,
PropertyItem* buffer) = 0;
virtual GpStatus GetPropertySize(UINT* totalBufferSize,
UINT* numProperties) = 0;
virtual GpStatus GetAllPropertyItems(UINT totalBufferSize,
UINT numProperties,
PropertyItem* allItems) = 0;
virtual GpStatus RemovePropertyItem(PROPID propId) = 0;
virtual GpStatus SetPropertyItem(PropertyItem* item) = 0;
// Determine the type of image object
GpImageType GetImageType() const
{
return ImgType;
}
GpLockable* GetObjectLock() const
{
return &Lockable;
}
// Default ICM mode is off. Default behaviour for this function is to
// do nothing.
// If a derived class supports embedded color correction, it needs
// to respect this call to turn ICM on or off.
virtual VOID SetICMConvert(BOOL icm) { }
private:
// Prevent apps from directly using new and delete operators
// on GpImage objects.
GpImage()
{
ImgType = ImageTypeUnknown;
// Set the tag in the object, even if IsValid overridden by
// GpBitmap or GpMetafile.
GpObject::SetValid(ObjectTagImage);
}
protected:
GpImage(GpImageType imgType)
{
ImgType = imgType;
// Set the tag in the object, even if IsValid overridden by
// GpBitmap or GpMetafile.
GpObject::SetValid(ObjectTagImage);
}
virtual ~GpImage() {}
GpImageType ImgType; // type of image object
// Object lock
mutable GpLockable Lockable;
};
//--------------------------------------------------------------------------
// Represent raster bitmap objects
//--------------------------------------------------------------------------
class GpDecodedImage;
class GpMemoryBitmap;
class CopyOnWriteBitmap;
class GpBitmap : public GpImage
{
friend class GpObject; // for empty constructor
friend class CopyOnWriteBitmap;
private:
CopyOnWriteBitmap * InternalBitmap;
LONG ScanBitmapRef; // ref count used for when a GpGraphics is wrapped around a GpBitmap
EpScanBitmap ScanBitmap;
VOID IncScanBitmapRef()
{
InterlockedIncrement(&ScanBitmapRef);
}
VOID DecScanBitmapRef()
{
InterlockedDecrement(&ScanBitmapRef);
}
GpBitmap(BOOL createInternalBitmap = TRUE);
GpBitmap(const GpBitmap * bitmap);
GpBitmap(const CopyOnWriteBitmap * internalBitmap);
// Destructor
// We don't want apps to use delete operator directly.
// Instead, they should use the Dispose method.
virtual ~GpBitmap();
protected:
CopyOnWriteBitmap * LockForWrite();
VOID Unlock() const;
VOID LockForRead() const;
public:
// Constructors
GpBitmap(const WCHAR* filename);
GpBitmap(IStream* stream);
GpBitmap(INT width, INT height, PixelFormatID format);
GpBitmap(INT width, INT height, PixelFormatID format, GpGraphics * graphics);
GpBitmap(
INT width,
INT height,
INT stride, // negative for bottom-up bitmaps
PixelFormatID format,
BYTE * scan0
);
GpBitmap(
BITMAPINFO* gdiBitmapInfo,
VOID* gdiBitmapData,
BOOL ownBitmapData
);
GpBitmap(IDirectDrawSurface7 *surface);
// Check if the GpBitmap object is valid
virtual BOOL IsValid() const;
GpImage*
Clone() const;
GpBitmap*
Clone(
const GpRect* rect,
PixelFormatID format = PixelFormat32bppPARGB
) const;
virtual GpImage*
CloneColorAdjusted(
GpRecolor * recolor,
ColorAdjustType type = ColorAdjustTypeDefault
) const;
// Similar to CloneColorAdjusted
GpStatus Recolor(
GpRecolor *recolor,
GpBitmap **dstBitmap,
DrawImageAbort callback,
VOID *callbackData,
GpRect *rect = NULL
);
GpStatus
GetEncoderParameterListSize(
IN CLSID* clsidEncoder,
OUT UINT* size
);
GpStatus
GetEncoderParameterList(
IN CLSID* clsidEncoder,
IN UINT size,
OUT EncoderParameters* pBuffer
);
GpStatus
SaveToStream(
IStream* stream,
CLSID* clsidEncoder,
EncoderParameters* encoderParams
);
GpStatus
SaveToFile(
const WCHAR* filename,
CLSID* clsidEncoder,
EncoderParameters* encoderParams
);
GpStatus
SaveAdd(
const EncoderParameters* encoderParams
);
GpStatus
SaveAdd(
GpImage* newBits,
const EncoderParameters* encoderParams
);
// Dispose the bitmap object
VOID Dispose();
// Get bitmap information
virtual GpStatus GetResolution(REAL* xdpi, REAL* ydpi) const;
virtual GpStatus GetPhysicalDimension(REAL* width, REAL* height) const;
virtual GpStatus GetBounds(GpRectF* rect, GpPageUnit* unit) const;
virtual GpStatus GetSize(Size* size) const;
virtual GpStatus GetImageInfo(ImageInfo *imageInfo) const;
virtual GpImage* GetThumbnail(UINT thumbWidth, UINT thumbHeight,
GetThumbnailImageAbort callback,
VOID *callbackData);
virtual GpStatus GetFrameCount(const GUID* dimensionID,
UINT* count) const;
virtual GpStatus GetFrameDimensionsCount(OUT UINT* count) const;
virtual GpStatus GetFrameDimensionsList(OUT GUID* dimensionIDs,
IN UINT count) const;
virtual GpStatus SelectActiveFrame(const GUID* dimensionID,
UINT frameIndex);
virtual GpStatus GetPalette(ColorPalette *palette, INT size);
virtual GpStatus SetPalette(ColorPalette *palette);
virtual INT GetPaletteSize();
GpStatus GetTransparencyHint(DpTransparency* transparency);
GpStatus SetTransparencyHint(DpTransparency transparency);
GpStatus GetTransparencyFlags(DpTransparency* transparency,
PixelFormatID loadFormat = PixelFormatDontCare,
BYTE* minAlpha = NULL,
BYTE* maxAlpha = NULL);
// Property related functions
virtual GpStatus GetPropertyCount(UINT* numOfProperty);
virtual GpStatus GetPropertyIdList(UINT numOfProperty, PROPID* list);
virtual GpStatus GetPropertyItemSize(PROPID propId, UINT* size);
virtual GpStatus GetPropertyItem(PROPID propId,UINT propSize,
PropertyItem* buffer);
virtual GpStatus GetPropertySize(UINT* totalBufferSize,UINT* numProperties);
virtual GpStatus GetAllPropertyItems(UINT totalBufferSize,
UINT numProperties,
PropertyItem* allItems);
virtual GpStatus RemovePropertyItem(PROPID propId);
virtual GpStatus SetPropertyItem(PropertyItem* item);
// Retrieve bitmap data
GpStatus
LockBits(
const GpRect* rect,
UINT flags,
PixelFormatID pixelFormat,
BitmapData* bmpdata,
INT width = 0,
INT height = 0
) const;
GpStatus
UnlockBits(
BitmapData* bmpdata,
BOOL Destroy=FALSE
) const;
// Flush batched drawing operations and optionally wait for drawing to
// complete. This is currently a nop operation. If the behavior
// of a GpBitmap changes to a model where rendering operations are
// non-immediate then this routine will need to be implemented.
VOID
Flush(GpFlushIntention intention) {};
// Get and set pixel on the bitmap.
GpStatus GetPixel(INT x, INT y, ARGB *color);
GpStatus SetPixel(INT x, INT y, ARGB color);
// Rotate and Flip
GpStatus RotateFlip(
RotateFlipType rfType
);
// Derive a graphics context on top of the bitmap object
GpGraphics* GetGraphicsContext();
GpStatus
GpBitmap::InitializeSurfaceForGdipBitmap(
DpBitmap * surface,
INT width,
INT height
);
// Derive an HDC for interop on top of the bitmap object
HDC GetHdc();
VOID ReleaseHdc(HDC hdc);
// Serialization
virtual UINT GetDataSize() const;
virtual GpStatus GetData(IStream * stream) const;
virtual GpStatus SetData(const BYTE * dataBuffer, UINT size);
GpStatus GetCompressedData(
DpCompressedData * compressed_data,
BOOL getJPEG = TRUE,
BOOL getPNG = TRUE,
HDC hdc = (HDC)NULL);
GpStatus DeleteCompressedData(
DpCompressedData * compressed_data);
BOOL IsDirty() const;
// Color adjust
virtual GpStatus ColorAdjust(
GpRecolor * recolor,
ColorAdjustType type
);
GpStatus
ColorAdjust(
GpRecolor * recolor,
PixelFormatID pixfmt,
DrawImageAbort callback,
VOID *callbackData
);
GpStatus GetPixelFormatID(PixelFormatID* pixfmt);
enum
{
Invalid = 0, // bitmap object is invalid
ImageRef = 1, // contains a reference only (e.g. filename)
ExtStream = 2, // contains a reference to a stream
DecodedImg = 3, // contains a decoded image object,
// but it's not decoded yet - name is misleading.
MemBitmap = 4 // contains an in-memory bitmap object
};
INT GetDecodeState();
GpStatus ForceValidation();
GpStatus SetResolution(REAL xdpi, REAL ydpi);
GpStatus
PreDraw(
INT numPoints,
GpPointF *dstPoints,
GpRectF *srcRect,
INT numBitsPerPixel
);
DWORD GetUniqueness() { return (DWORD)GetUid(); }
// Interop:
static GpStatus CreateFromHBITMAP(
HBITMAP hbm,
HPALETTE hpal,
GpBitmap** bitmap
);
static GpStatus CreateBitmapAndFillWithBrush(
InterpolationMode interpolationMode,
PixelOffsetMode pixelOffsetMode,
const GpMatrix * worldToDevice,
const GpRect * drawBounds,
GpBrush * brush,
GpBitmap ** bitmap,
PixelFormatID pixelFormat = PIXFMT_32BPP_ARGB
);
static GpStatus DrawAndHalftoneForStretchBlt(
HDC hdc,
BITMAPINFO * bmpInfo,
BYTE * bits,
INT srcX,
INT srcY,
INT srcWidth,
INT srcHeight,
INT destWidth,
INT destHeight,
BITMAPINFO ** destBmpInfo,
BYTE ** destBmpBits,
HBITMAP * destDIBSection,
InterpolationMode interpolationMode
);
GpStatus CreateHBITMAP(HBITMAP *phbm, ARGB background);
GpStatus ICMFrontEnd(
GpBitmap **dstBitmap,
DrawImageAbort callback,
VOID *callbackData,
GpRect *rect = NULL
);
static GpStatus CreateFromHICON(
HICON hicon,
GpBitmap** bitmap
);
GpStatus CreateHICON(HICON *phicon);
static GpStatus CreateFromResource(
HINSTANCE hInstance,
LPWSTR lpBitmapName,
GpBitmap** bitmap
);
// We need to know if the bitmap is associated with a display
// so we know how to handle the page transform when it is
// set to UnitDisplay.
BOOL IsDisplay() const;
VOID SetDisplay(BOOL display);
BOOL IsICMConvert() const;
virtual VOID SetICMConvert(BOOL icm);
};
// This is the base class for any class that implements the CopyOnWrite
// technology that enable cloning to be very light-weight when cloning for
// read access. It implements read and write locking for synchronization
// using a critical section, and it keeps track of reference counting
// the object so that it can be deleted at the right time.
class CopyOnWrite
{
protected:
// Constructor: notice that when an object is first
// created, its reference count is set to 1.
CopyOnWrite()
{
RefCount = 1;
#if DBG
Lock = NotLocked;
LockCount = 0;
#endif
InitializeCriticalSection(&Semaphore);
}
virtual ~CopyOnWrite()
{
DeleteCriticalSection(&Semaphore);
}
#if DBG
enum LockedType
{
NotLocked,
LockedForRead,
LockedForWrite
};
#endif
virtual CopyOnWrite * Clone() const = 0;
virtual BOOL IsValid() const = 0;
// Returns NULL if it fails to lock for writing
CopyOnWrite * LockForWrite()
{
EnterCriticalSection(&Semaphore);
CopyOnWrite * writeableObject = this;
// If there is more than one reference to this object, we must
// clone it before giving write access to it.
if (RefCount > 1)
{
writeableObject = this->Clone();
if (writeableObject == NULL)
{
LeaveCriticalSection(&Semaphore);
return NULL;
}
ASSERT(writeableObject->IsValid());
// else we succeeded in cloning the object
RefCount--;
EnterCriticalSection(&(writeableObject->Semaphore));
LeaveCriticalSection(&Semaphore);
}
#if DBG
writeableObject->Lock = LockedForWrite;
writeableObject->LockCount++;
#endif
return writeableObject;
}
VOID LockForRead() const
{
EnterCriticalSection(&Semaphore);
#if DBG
if (Lock == NotLocked)
{
Lock = LockedForRead;
}
LockCount++;
#endif
}
VOID Unlock() const
{
#if DBG
ASSERT(Lock != NotLocked);
if (--LockCount <= 0)
{
Lock = NotLocked;
LockCount = 0;
}
#endif
LeaveCriticalSection(&Semaphore);
}
// Increment reference count
// Note that we must use the critical section to control access, rather
// than using interlocked increment.
LONG AddRef() const
{
EnterCriticalSection(&Semaphore);
RefCount++;
LeaveCriticalSection(&Semaphore);
return RefCount;
}
// Decrement reference count
// Note that we must use the critical section to control access, rather
// than using interlocked decrement.
LONG Release() const
{
EnterCriticalSection(&Semaphore);
ULONG count = --RefCount;
// must leave the critical section before calling delete so that
// we don't try to access the freed memory.
LeaveCriticalSection(&Semaphore);
if (count == 0)
{
delete this;
}
return count;
}
private:
mutable LONG RefCount;
mutable CRITICAL_SECTION Semaphore;
#if DBG
mutable INT LockCount;
protected:
mutable LockedType Lock;
#endif
};
GpStatus
ConvertTo16BppAndFlip(
GpBitmap * sourceBitmap,
GpBitmap * & destBitmap
);
VOID
HalftoneColorRef_216(
COLORREF color, // color to halftone
UNALIGNED VOID *dib // packed 8 bpp DIB buffer with 8 colors
// The DIB buffer should be this size:
// sizeof(BITMAPINFOHEADER) + // DIB 8 bpp header
// (8 * sizeof(RGBQUAD)) + // DIB 8 colors
// (8 * 8) // DIB 8x8 pixels
);
#endif // !_GPBITMAP_HPP