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.
271 lines
8.9 KiB
271 lines
8.9 KiB
#ifndef UNIX
|
|
#pragma pack( push, PNG )
|
|
#pragma pack( 1 )
|
|
#endif
|
|
|
|
typedef struct _PNGCHUNKHEADER
|
|
{
|
|
ULONG nDataLength;
|
|
DWORD dwChunkType;
|
|
} PNGCHUNKHEADER;
|
|
|
|
typedef struct _PNGIHDRDATA
|
|
{
|
|
ULONG nWidth;
|
|
ULONG nHeight;
|
|
BYTE nBitDepth;
|
|
BYTE bColorType;
|
|
BYTE bCompressionMethod;
|
|
BYTE bFilterMethod;
|
|
BYTE bInterlaceMethod;
|
|
} PNGIHDRDATA;
|
|
|
|
#ifndef UNIX
|
|
#pragma pack( pop, PNG )
|
|
#endif
|
|
|
|
typedef struct _PNG_INTERLACE_INFO
|
|
{
|
|
ULONG nDeltaX;
|
|
ULONG nDeltaY;
|
|
ULONG nPixelWidth;
|
|
ULONG nPixelHeight;
|
|
ULONG iFirstX;
|
|
ULONG iFirstY;
|
|
BYTE anPixelsInPartialBlock[8];
|
|
BYTE anScanLinesInPartialBlock[8];
|
|
} PNG_INTERLACE_INFO;
|
|
|
|
typedef struct _FLOATRGB
|
|
{
|
|
float fRed;
|
|
float fGreen;
|
|
float fBlue;
|
|
} FLOATRGB;
|
|
|
|
typedef void (*PNGCOPYSCANLINEPROC)( void* pDest, const void* pSrc,
|
|
ULONG nPixels, ULONG nDeltaXDest, const FLOATRGB* pfrgbBackground,
|
|
BYTE* pXlate );
|
|
typedef void (*PNGDUPLICATESCANLINEPROC)( void* pScanLine, ULONG nDeltaX,
|
|
ULONG nFullPixels, ULONG nFullPixelWidth, ULONG nPartialPixelWidth );
|
|
|
|
typedef struct _PNG_FORMAT_INFO
|
|
{
|
|
ULONG nPossibleFormats;
|
|
const GUID* pPossibleFormats;
|
|
const PNGCOPYSCANLINEPROC* ppfnCopyScanLineProcs;
|
|
const PNGDUPLICATESCANLINEPROC* ppfnDuplicateScanLineProcs;
|
|
} PNG_FORMAT_INFO;
|
|
|
|
#define PNGCHUNK( a, b, c, d ) \
|
|
(MAKELONG( MAKEWORD( (a), (b) ), MAKEWORD( (c), (d) ) ))
|
|
|
|
const DWORD PNG_CHUNK_IHDR = PNGCHUNK( 'I', 'H', 'D', 'R' );
|
|
const DWORD PNG_CHUNK_IEND = PNGCHUNK( 'I', 'E', 'N', 'D' );
|
|
const DWORD PNG_CHUNK_IDAT = PNGCHUNK( 'I', 'D', 'A', 'T' );
|
|
const DWORD PNG_CHUNK_PLTE = PNGCHUNK( 'P', 'L', 'T', 'E' );
|
|
const DWORD PNG_CHUNK_BKGD = PNGCHUNK( 'b', 'K', 'G', 'D' );
|
|
const DWORD PNG_CHUNK_TRNS = PNGCHUNK( 't', 'R', 'N', 'S' );
|
|
const DWORD PNG_CHUNK_GAMA = PNGCHUNK( 'g', 'A', 'M', 'A' );
|
|
|
|
const DWORD PNG_CHUNK_ANCILLARY = 0x00000020;
|
|
|
|
const BYTE PNG_COMPRESSION_DEFLATE32K = 0;
|
|
const BYTE PNG_FILTER_ADAPTIVE = 0;
|
|
const BYTE PNG_INTERLACE_NONE = 0;
|
|
const BYTE PNG_INTERLACE_ADAM7 = 1;
|
|
|
|
const ULONG PNG_BUFFER_SIZE = 4096;
|
|
|
|
const DWORD CHUNK_IHDR = 0x01;
|
|
const DWORD CHUNK_PLTE = 0x02;
|
|
const DWORD CHUNK_POSTPLTE = 0x04;
|
|
const DWORD CHUNK_IDAT = 0x08;
|
|
const DWORD CHUNK_LASTIDAT = 0x10;
|
|
const DWORD CHUNK_IEND = 0x20;
|
|
const DWORD CHUNK_BKGD = 0x40;
|
|
const DWORD CHUNK_TRNS = 0x80;
|
|
const DWORD CHUNK_GAMA = 0x100;
|
|
|
|
const BYTE PNG_COLORTYPE_PALETTE_MASK = 0x01;
|
|
const BYTE PNG_COLORTYPE_COLOR_MASK = 0x02;
|
|
const BYTE PNG_COLORTYPE_ALPHA_MASK = 0x04;
|
|
const BYTE PNG_COLORTYPE_INDEXED = PNG_COLORTYPE_PALETTE_MASK|
|
|
PNG_COLORTYPE_COLOR_MASK;
|
|
const BYTE PNG_COLORTYPE_RGB = PNG_COLORTYPE_COLOR_MASK;
|
|
const BYTE PNG_COLORTYPE_GRAY = 0x00;
|
|
const BYTE PNG_COLORTYPE_RGBA = PNG_COLORTYPE_COLOR_MASK|
|
|
PNG_COLORTYPE_ALPHA_MASK;
|
|
const BYTE PNG_COLORTYPE_GRAYA = PNG_COLORTYPE_ALPHA_MASK;
|
|
|
|
class CPNGFilter :
|
|
public IImageDecodeFilter,
|
|
public CComObjectRoot,
|
|
public CComCoClass< CPNGFilter, &CLSID_CoPNGFilter >
|
|
{
|
|
public:
|
|
CPNGFilter();
|
|
~CPNGFilter();
|
|
|
|
BEGIN_COM_MAP( CPNGFilter )
|
|
COM_INTERFACE_ENTRY( IImageDecodeFilter )
|
|
END_COM_MAP()
|
|
|
|
DECLARE_NOT_AGGREGATABLE( CPNGFilter )
|
|
// Remove the comment from the line above if you don't want your object to
|
|
// support aggregation. The default is to support it
|
|
|
|
DECLARE_REGISTRY( CPNGFilter, _T( "PNGFilter.CoPNGFilter.1" ),
|
|
_T( "PNGFilter.CoPNGFilter" ), IDS_COPNGFILTER_DESC, THREADFLAGS_BOTH )
|
|
|
|
// DECLARE_NO_REGISTRY()
|
|
|
|
// IImageDecodeFilter
|
|
public:
|
|
STDMETHOD( Initialize )( IImageDecodeEventSink* pEventSink );
|
|
STDMETHOD( Process )( IStream* pStream );
|
|
STDMETHOD( Terminate )( HRESULT hrStatus );
|
|
|
|
protected:
|
|
HRESULT BeginImage();
|
|
HRESULT ChooseDestinationFormat( GUID* pBFID );
|
|
HRESULT DetermineSourceFormat();
|
|
HRESULT EatData();
|
|
HRESULT FireGetSurfaceEvent();
|
|
HRESULT FireOnProgressEvent();
|
|
HRESULT NextState();
|
|
HRESULT OutputBytes( const BYTE* pData, ULONG nBytes );
|
|
HRESULT ChooseBKGD();
|
|
HRESULT ProcessBKGD();
|
|
HRESULT ProcessIDAT();
|
|
HRESULT ProcessIEND();
|
|
HRESULT ProcessIHDR();
|
|
HRESULT ProcessPLTE();
|
|
HRESULT ProcessTRNS();
|
|
HRESULT ProcessGAMA();
|
|
HRESULT ReadChunkHeader();
|
|
HRESULT ReadChunkData();
|
|
HRESULT ReadChunkCRC();
|
|
HRESULT ReadFileHeader();
|
|
HRESULT ReadIDATData();
|
|
HRESULT NextPass();
|
|
HRESULT NextScanLine();
|
|
BOOL BeginPass( ULONG iPass );
|
|
HRESULT WriteScanLine();
|
|
|
|
HRESULT LockBits(RECT *prcBounds, DWORD dwLockFlags, void **ppBits, long *pPitch);
|
|
HRESULT UnlockBits(RECT *prcBounds, void *pBits);
|
|
|
|
void NoneFilterScanLine();
|
|
void SubFilterScanLine();
|
|
void UpFilterScanLine();
|
|
void AverageFilterScanLine();
|
|
void PaethFilterScanLine();
|
|
|
|
protected:
|
|
static const PNG_INTERLACE_INFO s_aInterlaceInfoNone[1];
|
|
static const PNG_INTERLACE_INFO s_aInterlaceInfoAdam7[7];
|
|
static const PNG_FORMAT_INFO s_aFormatInfo[15];
|
|
|
|
protected:
|
|
typedef enum _EInternalState
|
|
{
|
|
ISTATE_READFILEHEADER,
|
|
ISTATE_READCHUNKHEADER,
|
|
ISTATE_READCHUNKDATA,
|
|
ISTATE_READIDATDATA,
|
|
ISTATE_READCHUNKCRC,
|
|
ISTATE_PROCESSIHDR,
|
|
ISTATE_PROCESSIEND,
|
|
ISTATE_PROCESSPLTE,
|
|
ISTATE_PROCESSBKGD,
|
|
ISTATE_PROCESSTRNS,
|
|
ISTATE_PROCESSGAMA,
|
|
ISTATE_CHOOSEBKGD,
|
|
ISTATE_EATDATA,
|
|
ISTATE_DONE
|
|
} EInternalState;
|
|
typedef enum _ESrcFormat
|
|
{
|
|
SRC_GRAY_1,
|
|
SRC_GRAY_2,
|
|
SRC_GRAY_4,
|
|
SRC_GRAY_8,
|
|
SRC_GRAY_16,
|
|
SRC_RGB_24,
|
|
SRC_RGB_48,
|
|
SRC_INDEXED_RGB_1,
|
|
SRC_INDEXED_RGB_2,
|
|
SRC_INDEXED_RGB_4,
|
|
SRC_INDEXED_RGB_8,
|
|
SRC_GRAYA_16,
|
|
SRC_GRAYA_32,
|
|
SRC_RGBA_32,
|
|
SRC_RGBA_64
|
|
} ESrcFormat;
|
|
|
|
EInternalState m_eInternalState; // State of decode state machine
|
|
DWORD m_dwEvents; // Events the event sink wants to receive
|
|
PNGCOPYSCANLINEPROC m_pfnCopyScanLine;
|
|
PNGDUPLICATESCANLINEPROC m_pfnDuplicateScanLine;
|
|
const PNG_INTERLACE_INFO* m_pInterlaceInfo;
|
|
ULONG m_nFormats; // Number of formats the event sink supports
|
|
GUID* m_pFormats; // Formats supported by the event sink
|
|
BOOL m_bPalette; // Does image use a palette?
|
|
BOOL m_bColor; // Does image use color?
|
|
BOOL m_bAlpha; // Does image have an alpha channel
|
|
BOOL m_bSurfaceUsesAlpha;
|
|
BOOL m_bConvertAlpha;
|
|
BOOL m_bSkipData;
|
|
ESrcFormat m_eSrcFormat; // Source pixel format
|
|
DWORD m_dwCRC; // CRC accumulator
|
|
DWORD m_dwChunkCRC; // Stored CRC of current chunk
|
|
ULONG m_nColors; // Number of colors in palette
|
|
ULONG m_iBackgroundIndex; // Index of background color
|
|
RGBQUAD m_rgbBackground; // Background color
|
|
FLOATRGB m_frgbBackground; // Floating-point background color
|
|
DWORD m_dwTransKey; // Transparent color key (RGB or indexed
|
|
ULONG m_nTransparentColors; // # transparent indices
|
|
IStream* m_pStream; // Source stream
|
|
CComPtr< IImageDecodeEventSink > m_pEventSink; // Event sink
|
|
PNGCHUNKHEADER m_pngChunkHeader; // Header of current chunk
|
|
PNGIHDRDATA m_pngIHDR; // IHDR chunk
|
|
DWORD m_dwChunksEncountered; // CHUNK_* flags for what chunks have been
|
|
// encountered in the image stream so far
|
|
CComPtr< IDirectDrawSurface > m_pDDrawSurface;
|
|
BOOL m_bFinishedIDAT; // Have we finished the IDAT section?
|
|
ULONG m_nBytesLeftInCurrentTask; // Bytes remaining before we switch to a
|
|
// new state
|
|
ULONG m_nDataBytesRead; // Bytes of chunk data read
|
|
ULONG m_iAppend; // Where to append data in buffer
|
|
BYTE* m_pbScanLine; // Current decoded scan line (including filter byte)
|
|
BYTE* m_pbPrevScanLine; // Previous decoded scan line
|
|
ULONG m_iPass; // Current pass
|
|
ULONG m_nPasses; // Number of passes
|
|
ULONG m_nBytesInScanLine; // Number of bytes in one scan line
|
|
ULONG m_nPixelsInScanLine; // Number of pixels in one scan line
|
|
ULONG m_nBitsPerPixel; // Bits per pixel in source image
|
|
BOOL m_bExpandPixels; // Expand interlaced pixels?
|
|
ULONG m_iScanLine; // Current scan line
|
|
ULONG m_nScanLinesInPass; // Number of scan lines in current pass
|
|
ULONG m_iScanLineInPass; // Current scan line in pass
|
|
ULONG m_iFirstStaleScanLine; // First scan line whose progress has not been
|
|
// reported
|
|
ULONG m_nBPP; // Bytes per pixel
|
|
ULONG m_nDeltaX; // Horizontal distance between pixels
|
|
ULONG m_nDeltaY; // Vertical distance between pixels
|
|
ULONG m_nPixelWidth; // Width of a pixel
|
|
ULONG m_nPixelHeight; // Height of a pixel
|
|
ULONG m_iFirstX; // Horizontal position of first pixel in scan line
|
|
ULONG m_iFirstY; // Vertical position of first scan line in pass
|
|
ULONG m_nFullPixelsInScanLine;
|
|
ULONG m_nPartialPixelWidth;
|
|
z_stream m_zlibStream; // ZLib data
|
|
BYTE m_abData[PNG_BUFFER_SIZE]; // Data buffer
|
|
BYTE m_abTrans[256]; // table to collapse multiple transparent indices
|
|
BYTE m_abGamma[256]; // gamma correction table
|
|
RGBQUAD m_argbColors[256];
|
|
|
|
};
|
|
|
|
|