2345 lines
74 KiB
Plaintext
2345 lines
74 KiB
Plaintext
(* ImageEn Build 7.0.0.06.2637 @ 7-4-17 14:58:42.679 *)
|
|
(*
|
|
Copyright (c) 1998-2017 by Carlotta Calandra. All rights reserved.
|
|
Copyright (c) 2011-2017 by Xequte Software.
|
|
|
|
This software comes without express or implied warranty.
|
|
In no case shall the author be liable for any damage or unwanted behavior of any
|
|
computer hardware and/or software.
|
|
|
|
Author grants you the right to include the component
|
|
in your application, whether COMMERCIAL, SHAREWARE, or FREEWARE.
|
|
|
|
ImageEn, IEvolution and ImageEn ActiveX may not be included in any
|
|
commercial, shareware or freeware libraries or components.
|
|
|
|
www.ImageEn.com
|
|
*)
|
|
|
|
(*
|
|
File version 1006
|
|
*)
|
|
|
|
unit iewic;
|
|
|
|
{$R-}
|
|
{$Q-}
|
|
|
|
{$I ie.inc}
|
|
|
|
{$IFDEF IEINCLUDEWIC}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Messages, SysUtils, Classes, ActiveX, Graphics, Controls, imageenio, hyiedefs, iexBitmaps, ieds, iewia,
|
|
dialogs, hyieutils;
|
|
|
|
|
|
procedure IEHDPRead(Stream: TStream; Bitmap: TIEBitmap; var IOParams: TIOParams; var xProgress: TProgressRec; Preview: boolean);
|
|
procedure IEHDPWrite(Stream: TStream; Bitmap: TIEBitmap; var IOParams: TIOParams; var xProgress: TProgressRec);
|
|
function IEHDPFrameCount(const FileName: WideString): integer;
|
|
function IEWICAvailable: boolean;
|
|
procedure IEWICResample(SrcImg: TIEBaseBitmap; DstImg: TIEBaseBitmap; SrcAlpha: TIEBaseBitmap; FilterType: TResampleFilter; OnProgressFunction: TIEProgressEvent; OnProgressSender: TObject);
|
|
|
|
type
|
|
|
|
|
|
IE_ProgressNotificationCallback=function(pvData: pointer; uFrameNum: dword; operation: dword; dblProgress: double): HResult; stdcall;
|
|
|
|
|
|
IE_IWICBitmapCodecProgressNotification = interface(IUnknown)
|
|
['{64C1024E-C3CF-4462-8078-88C2B11C46D9}']
|
|
function RegisterProgressNotification(pfnProgressNotification: IE_ProgressNotificationCallback; pvData: pointer; dwProgressFlags: dword): HResult; stdcall;
|
|
end;
|
|
|
|
|
|
IE_IWICStream = interface(IStream)
|
|
['{135FF860-22B7-4ddf-B0F6-218F4F299A43}']
|
|
function InitializeFromIStream(pIStream: IIEStream): HResult; stdcall;
|
|
function InitializeFromFilename(wzFileName: pwchar; dwDesiredAccess: dword): HResult; stdcall;
|
|
function InitializeFromMemory(pbBuffer: pbyte; cbBufferSize: dword): HResult; stdcall;
|
|
function InitializeFromIStreamRegion: HResult; stdcall;
|
|
end;
|
|
|
|
|
|
IE_WICRect = record
|
|
X: longint;
|
|
Y: longint;
|
|
Width: longint;
|
|
Height: longint;
|
|
end;
|
|
|
|
|
|
IE_PWICRect = ^IE_WICRect;
|
|
|
|
|
|
IE_WICBitmapPaletteType = DWORD;
|
|
|
|
|
|
IE_WICColor = DWORD;
|
|
|
|
|
|
IE_PWICColor = ^IE_WICColor;
|
|
|
|
|
|
IE_IWICBitmapSource = interface;
|
|
|
|
|
|
IE_IWICPalette = interface(IUnknown)
|
|
['{00000040-a8f2-4877-ba0a-fd2b6645fb94}']
|
|
function InitializePredefined(ePaletteType: IE_WICBitmapPaletteType; fAddTransparentColor: longbool): HResult; stdcall;
|
|
function InitializeCustom(pColors: IE_PWICColor; cCount: DWORD): HResult; stdcall;
|
|
function InitializeFromBitmap(pISurface: IE_IWICBitmapSource; cCount: DWORD; fAddTransparentColor: longbool): HResult; stdcall;
|
|
function InitializeFromPalette(pIPalette: IE_IWICPalette): HResult; stdcall;
|
|
function GetType(out pePaletteType: IE_WICBitmapPaletteType): HResult; stdcall;
|
|
function GetColorCount(out pcCount: DWORD): HResult; stdcall;
|
|
function GetColors(cCount: DWORD; pColors: IE_PWICColor; out pcActualColors: DWORD): HResult; stdcall;
|
|
function IsBlackWhite(out pfIsBlackWhite: longbool): HResult; stdcall;
|
|
function IsGrayscale(out pfIsGrayscale: longbool): HResult; stdcall;
|
|
function HasAlpha(out pfHasAlpha: longbool): HResult; stdcall;
|
|
end;
|
|
|
|
|
|
IE_IWICBitmapSource = interface(IUnknown)
|
|
['{00000120-a8f2-4877-ba0a-fd2b6645fb94}']
|
|
function GetSize(out puiWidth: DWORD; out puiHeight: DWORD): HResult; stdcall;
|
|
function GetPixelFormat(out pPixelFormat: TGUID): HResult; stdcall;
|
|
function GetResolution(out pDpiX: double; out pDpiY: double): HResult; stdcall;
|
|
function CopyPalette(pIPalette: IE_IWICPalette): HResult; stdcall;
|
|
function CopyPixels(prc: IE_PWICRect; cbStride: DWORD; cbBufferSize: DWORD; pbBuffer: pbyte): HResult; stdcall;
|
|
end;
|
|
|
|
|
|
IE_IWICFormatConverter = interface(IE_IWICBitmapSource)
|
|
['{00000301-a8f2-4877-ba0a-fd2b6645fb94}']
|
|
function Initialize(pISource: IE_IWICBitmapSource; const dstFormat: TGUID; dither: dword; pIPalette: IE_IWICPalette; alphaThresholdPercent: double; paletteTranslate: dword): HResult; stdcall;
|
|
function CanConvert(const srcPixelFormat: TGUID; const dstPixelFormat: TGUID; out pfCanConvert: longbool): HResult; stdcall;
|
|
end;
|
|
|
|
|
|
IE_IWICMetadataQueryReader = interface(IUnknown)
|
|
['{30989668-E1C9-4597-B395-458EEDB808DF}']
|
|
function GetContainerFormat: HResult; stdcall;
|
|
function GetLocation: HResult; stdcall;
|
|
function GetMetadataByName(wzName: pwchar; var pvarValue: PROPVARIANT): HResult; stdcall;
|
|
function GetEnumerator: HResult; stdcall;
|
|
end;
|
|
|
|
|
|
IE_IWICMetadataQueryWriter = interface(IE_IWICMetadataQueryReader)
|
|
['{A721791A-0DEF-4d06-BD91-2118BF1DB10B}']
|
|
function SetMetadataByName(wzName: pwchar; const pvarValue: PROPVARIANT): HResult; stdcall;
|
|
function RemoveMetadataByName(wzName: pwchar): HResult; stdcall;
|
|
end;
|
|
|
|
|
|
IE_IWICBitmapFrameDecode = interface(IE_IWICBitmapSource)
|
|
['{3B16811B-6A43-4ec9-A813-3D930C13B940}']
|
|
function GetMetadataQueryReader(out ppIMetadataQueryReader: IE_IWICMetadataQueryReader): HResult; stdcall;
|
|
function GetColorContexts: HResult; stdcall;
|
|
function GetThumbnail(out ppIThumbnail: IE_IWICBitmapSource): HResult; stdcall;
|
|
end;
|
|
|
|
|
|
IE_IWICBitmapDecoder = interface(IUnknown)
|
|
['{9EDDE9E7-8DEE-47ea-99DF-E6FAF2ED44BF}']
|
|
function QueryCapability: HResult; stdcall;
|
|
function Initialize: HResult; stdcall;
|
|
function GetContainerFormat: HResult; stdcall;
|
|
function GetDecoderInfo: HResult; stdcall;
|
|
function CopyPalette: HResult; stdcall;
|
|
function GetMetadataQueryReader: HResult; stdcall;
|
|
function GetPreview: HResult; stdcall;
|
|
function GetColorContexts: HResult; stdcall;
|
|
function GetThumbnail: HResult; stdcall;
|
|
function GetFrameCount(out pCount: longint): HResult; stdcall;
|
|
function GetFrame(index: dword; out ppIBitmapFrame: IE_IWICBitmapFrameDecode): HResult; stdcall;
|
|
end;
|
|
|
|
|
|
IE_PROPBAG2 = record
|
|
dwType: dword;
|
|
vt: word;
|
|
cfType: word;
|
|
dwHint: dword;
|
|
pstrName: pwchar;
|
|
clsid: TGUID;
|
|
end;
|
|
|
|
IE_PPROPBAG2 = ^IE_PROPBAG2;
|
|
|
|
IE_PPROPVARIANT = ^PROPVARIANT;
|
|
|
|
IE_IPropertyBag2 = interface(IUnknown)
|
|
['{22F55882-280B-11d0-A8A9-00A0C90C2004}']
|
|
function Read: HResult; stdcall;
|
|
function Write(cProperties: dword; pPropBag: IE_PPROPBAG2; pvarValue: IE_PPROPVARIANT): HResult; stdcall;
|
|
function CountProperties: HResult; stdcall;
|
|
function GetPropertyInfo: HResult; stdcall;
|
|
function LoadObject: HResult; stdcall;
|
|
end;
|
|
|
|
|
|
IE_IWICBitmapFrameEncode = interface(IUnknown)
|
|
['{00000105-a8f2-4877-ba0a-fd2b6645fb94}']
|
|
function Initialize(pIEncoderOptions: IE_IPropertyBag2): HResult; stdcall;
|
|
function SetSize(uiWidth: dword; uiHeight: dword): HResult; stdcall;
|
|
function SetResolution(dpiX: double; dpiY: double): HResult; stdcall;
|
|
function SetPixelFormat(const pPixelFormat: TGUID): HResult; stdcall;
|
|
function SetColorContexts: HResult; stdcall;
|
|
function SetPalette: HResult; stdcall;
|
|
function SetThumbnail: HResult; stdcall;
|
|
function WritePixels(lineCount: dword; cbStride: dword; cbBufferSize: dword; pbPixels: pbyte): HResult; stdcall;
|
|
function WriteSource: HResult; stdcall;
|
|
function Commit: HResult; stdcall;
|
|
function GetMetadataQueryWriter(out ppIMetadataQueryWriter: IE_IWICMetadataQueryWriter): HResult; stdcall;
|
|
end;
|
|
|
|
|
|
IE_IWICBitmapEncoder = interface(IUnknown)
|
|
['{00000103-a8f2-4877-ba0a-fd2b6645fb94}']
|
|
function Initialize(pIStream: IStream; cacheOption: dword): HResult; stdcall;
|
|
function GetContainerFormat: HResult; stdcall;
|
|
function GetEncoderInfo: HResult; stdcall;
|
|
function SetColorContexts: HResult; stdcall;
|
|
function SetPalette: HResult; stdcall;
|
|
function SetThumbnail: HResult; stdcall;
|
|
function SetPreview: HResult; stdcall;
|
|
function CreateNewFrame(out ppIFrameEncode: IE_IWICBitmapFrameEncode; out ppIEncoderOptions: IE_IPropertyBag2): HResult; stdcall;
|
|
function Commit: HResult; stdcall;
|
|
function GetMetadataQueryWriter: HResult; stdcall;
|
|
end;
|
|
|
|
|
|
IE_WICInProcPointer = pbyte;
|
|
|
|
|
|
IE_IWICBitmapLock = interface(IUnknown)
|
|
['{00000123-a8f2-4877-ba0a-fd2b6645fb94}']
|
|
function GetSize(out puiWidth: DWORD; out puiHeight: DWORD): HResult; stdcall;
|
|
function GetStride(out pcbStride: DWORD): HResult; stdcall;
|
|
function GetDataPointer(out pcbBufferSize: DWORD; out ppbData: IE_WICInProcPointer): HResult; stdcall;
|
|
function GetPixelFormat(out pPixelFormat: TGUID): HResult; stdcall;
|
|
end;
|
|
|
|
|
|
IE_IWICBitmap = interface(IE_IWICBitmapSource)
|
|
['{00000121-a8f2-4877-ba0a-fd2b6645fb94}']
|
|
function Lock(prcLock: IE_PWICRect; flags: DWORD; out ppILock: IE_IWICBitmapLock): HResult; stdcall;
|
|
function SetPalette(pIPalette: IE_IWICPalette): HResult; stdcall;
|
|
function SetResolution(dpiX: double; dpiY: double): HResult; stdcall;
|
|
end;
|
|
|
|
|
|
IE_WICBitmapCreateCacheOption = DWORD;
|
|
|
|
|
|
IE_WICBitmapInterpolationMode = DWORD;
|
|
|
|
|
|
IE_IWICBitmapScaler = interface(IE_IWICBitmapSource)
|
|
['{00000302-a8f2-4877-ba0a-fd2b6645fb94}']
|
|
function Initialize(pISource: IE_IWICBitmapSource; uiWidth: DWORD; uiHeight: DWORD; mode: IE_WICBitmapInterpolationMode): HResult; stdcall;
|
|
end;
|
|
|
|
|
|
|
|
IE_IWICImagingFactory = interface(IUnknown)
|
|
['{ec5ec8a9-c395-4314-9c77-54d7a935ff70}']
|
|
function CreateDecoderFromFilename: HResult; stdcall;
|
|
function CreateDecoderFromStream(pIStream: IStream; const pguidVendor: TGUID; metadataOptions: dword; out ppIDecoder: IE_IWICBitmapDecoder): HResult; stdcall;
|
|
function CreateDecoderFromFileHandle: HResult; stdcall;
|
|
function CreateComponentInfo: HResult; stdcall;
|
|
function CreateDecoder(const guidContainerFormat: TGuid; const pguidVendor: TGuid; out ppIDecoder: IE_IWICBitmapDecoder): HResult; stdcall;
|
|
function CreateEncoder(const guidContainerFormat: TGUID; const pguidVendor: TGUID; out ppIEncoder: IE_IWICBitmapEncoder): HResult; stdcall;
|
|
function CreatePalette(out ppIPalette: IE_IWICPalette): HResult; stdcall;
|
|
function CreateFormatConverter(out ppIFormatConverter: IE_IWICFormatConverter): HResult; stdcall;
|
|
function CreateBitmapScaler(out ppIBitmapScaler: IE_IWICBitmapScaler): HResult; stdcall;
|
|
function CreateBitmapClipper: HResult; stdcall;
|
|
function CreateBitmapFlipRotator: HResult; stdcall;
|
|
function CreateStream(out ppIWICStream: IE_IWICStream): HResult; stdcall;
|
|
function CreateColorContext: HResult; stdcall;
|
|
function CreateColorTransformer: HResult; stdcall;
|
|
function CreateBitmap: HResult; stdcall;
|
|
function CreateBitmapFromSource(pIBitmapSource: IE_IWICBitmapSource; option: IE_WICBitmapCreateCacheOption; out ppIBitmap: IE_IWICBitmap): HResult; stdcall;
|
|
function CreateBitmapFromSourceRect: HResult; stdcall;
|
|
function CreateBitmapFromMemory: HResult; stdcall;
|
|
function CreateBitmapFromHBITMAP: HResult; stdcall;
|
|
function CreateBitmapFromHICON: HResult; stdcall;
|
|
function CreateComponentEnumerator: HResult; stdcall;
|
|
function CreateFastMetadataEncoderFromDecoder: HResult; stdcall;
|
|
function CreateFastMetadataEncoderFromFrameDecode: HResult; stdcall;
|
|
function CreateQueryWriter: HResult; stdcall;
|
|
function CreateQueryWriterFromReader: HResult; stdcall;
|
|
end;
|
|
|
|
|
|
const
|
|
|
|
// WICBitmapDitherType
|
|
IE_WICBitmapDitherTypeNone = $00000000;
|
|
IE_WICBitmapDitherTypeSolid = $00000000;
|
|
IE_WICBitmapDitherTypeOrdered4x4 = $00000001;
|
|
IE_WICBitmapDitherTypeOrdered8x8 = $00000002;
|
|
IE_WICBitmapDitherTypeOrdered16x16 = $00000003;
|
|
IE_WICBitmapDitherTypeSpiral4x4 = $00000004;
|
|
IE_WICBitmapDitherTypeSpiral8x8 = $00000005;
|
|
IE_WICBitmapDitherTypeDualSpiral4x4 = $00000006;
|
|
IE_WICBitmapDitherTypeDualSpiral8x8 = $00000007;
|
|
IE_WICBitmapDitherTypeErrorDiffusion = $00000008;
|
|
|
|
|
|
// WICBitmapPaletteType
|
|
IE_WICBitmapPaletteTypeCustom = $0;
|
|
IE_WICBitmapPaletteTypeMedianCut = $1;
|
|
IE_WICBitmapPaletteTypeFixedBW = $2;
|
|
IE_WICBitmapPaletteTypeFixedHalftone8 = $3;
|
|
IE_WICBitmapPaletteTypeFixedHalftone27 = $4;
|
|
IE_WICBitmapPaletteTypeFixedHalftone64 = $5;
|
|
IE_WICBitmapPaletteTypeFixedHalftone125 = $6;
|
|
IE_WICBitmapPaletteTypeFixedHalftone216 = $7;
|
|
IE_WICBitmapPaletteTypeFixedWebPalette = IE_WICBitmapPaletteTypeFixedHalftone216;
|
|
IE_WICBitmapPaletteTypeFixedHalftone252 = $8;
|
|
IE_WICBitmapPaletteTypeFixedHalftone256 = $9;
|
|
IE_WICBitmapPaletteTypeFixedGray4 = $a;
|
|
IE_WICBitmapPaletteTypeFixedGray16 = $b;
|
|
IE_WICBitmapPaletteTypeFixedGray256 = $c;
|
|
IE_WICBITMAPPALETTETYPE_FORCE_DWORD = $7fffffff;
|
|
|
|
|
|
// WICBitmapInterpolationMode
|
|
IE_WICBitmapInterpolationModeNearestNeighbor = 0;
|
|
IE_WICBitmapInterpolationModeLinear = $1;
|
|
IE_WICBitmapInterpolationModeCubic = $2;
|
|
IE_WICBitmapInterpolationModeFant = $3;
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
type
|
|
|
|
{!!
|
|
<FS>TIEWICTIFFCompressionMethod
|
|
|
|
<FM>Declaration<FC>
|
|
TIEWICTIFFCompressionMethod = (ieWICTiffCompressionNone, ieWICTiffCompressionCCITT3, ieWICTiffCompressionCCITT4, ieWICTiffCompressionLZW, ieWICTiffCompressionRLE, ieWICTiffCompressionZIP);
|
|
|
|
<FM>Description<FN>
|
|
Specifies the Tagged Image File Format (TIFF) compression options.
|
|
|
|
<TABLE>
|
|
<R> <H>Value</H> <H>Description</H> </R>
|
|
<R> <C><FC>ieWICTiffCompressionNone<FN></C> <C>No compression.</C> </R>
|
|
<R> <C><FC>ieWICTiffCompressionCCITT3<FN></C> <C>A CCITT3 compression algorithm. This algorithm is only valid for 1bpp pixel formats.</C> </R>
|
|
<R> <C><FC>ieWICTiffCompressionCCITT4<FN></C> <C>A CCITT4 compression algorithm. This algorithm is only valid for 1bpp pixel formats.</C> </R>
|
|
<R> <C><FC>ieWICTiffCompressionLZW<FN></C> <C>A LZW compression algorithm.</C> </R>
|
|
<R> <C><FC>ieWICTiffCompressionRLE<FN></C> <C>A RLE compression algorithm. This algorithm is only valid for 1bpp pixel formats.</C> </R>
|
|
<R> <C><FC>ieWICTiffCompressionZIP<FN></C> <C>A ZIP compression algorithm.</C> </R>
|
|
</TABLE>
|
|
!!}
|
|
TIEWICTIFFCompressionMethod = (
|
|
ieWICTiffCompressionDontCare , // don't use
|
|
ieWICTiffCompressionNone,
|
|
ieWICTiffCompressionCCITT3,
|
|
ieWICTiffCompressionCCITT4,
|
|
ieWICTiffCompressionLZW,
|
|
ieWICTiffCompressionRLE,
|
|
ieWICTiffCompressionZIP);
|
|
|
|
|
|
{!!
|
|
<FS>TIEWICReader
|
|
|
|
<FM>Description<FN>
|
|
TIEWICReader class encapsulates some Microsoft Windows Imaging Component (WIC) interfaces and allows you to load Microsoft HD Photo and other WIC installed file formats.
|
|
WIC preinstalled decoders are TIFF, PNG, GIF, ICO, BMP, JPEG, HDP.
|
|
|
|
Note: Requires Windows XP (SP2) with .Net 3.0, Windows Vista or newer.
|
|
|
|
<FM>Examples<FC>
|
|
// loads input.hdp in ImageEnView1, which is the same as ImageEnView1.IO.LoadFromFile('input.hdp')
|
|
with TIEWICReader.Create do
|
|
begin
|
|
Open('input.hdp', ioHDP);
|
|
GetFrame(0, ImageEnView1.IEBitmap, ImageEnView1.IO.Params);
|
|
Free;
|
|
end;
|
|
ImageEnView1.Update;
|
|
|
|
// loads input.jpg in ImageEnView1
|
|
with TIEWICReader.Create do
|
|
begin
|
|
Open('input.jpg', ioJPEG);
|
|
GetFrame(0, ImageEnView1.IEBitmap, ImageEnView1.IO.Params);
|
|
Free;
|
|
end;
|
|
ImageEnView1.Update;
|
|
|
|
|
|
// loads page 2 from input.tif to ImageEnView1
|
|
with TIEWICReader.Create do
|
|
begin
|
|
Open('input.tif', ioTIFF);
|
|
GetFrame(2, ImageEnView1.IEBitmap, ImageEnView1.IO.Params);
|
|
Free;
|
|
end;
|
|
ImageEnView1.Update;
|
|
|
|
<FM>Methods and Properties<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_METHOD> <C><A TIEWICReader.Close></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEWICReader.DPIX></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEWICReader.DPIY></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEWICReader.FrameCount></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEWICReader.FrameHeight></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEWICReader.FrameWidth></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEWICReader.GetFrame></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEWICReader.IsAvailable></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEWICReader.Open></C> </R>
|
|
</TABLE>
|
|
|
|
!!}
|
|
TIEWICReader = class
|
|
private
|
|
fOLEInitialized: boolean;
|
|
fWICImagingFactory: IE_IWICImagingFactory;
|
|
fDecoder: IE_IWICBitmapDecoder;
|
|
fFrame: IE_IWICBitmapFrameDecode;
|
|
fQueryReader: IE_IWICMetadataQueryReader;
|
|
fDPIX: double;
|
|
fDPIY: double;
|
|
fStream: TStream;
|
|
fStreamBase: int64;
|
|
fFileStream: TIEWideFileStream;
|
|
function GetFrameCount: integer;
|
|
|
|
public
|
|
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
|
|
function IsAvailable: boolean;
|
|
|
|
function Open(Stream: TStream; fileType: TIOFileType): boolean; overload;
|
|
function Open(const FileName: WideString; fileType: TIOFileType = ioUnknown): boolean; overload;
|
|
procedure Close;
|
|
|
|
procedure GetFrame(frameIndex: integer; destBitmap: TIEBitmap; IOParams: TIOParams=nil; Aborting: pboolean=nil);
|
|
property FrameCount: integer read GetFrameCount;
|
|
function FrameWidth(): DWORD; // call after GetFrame
|
|
function FrameHeight(): DWORD; // call after GetFrame
|
|
|
|
{!!
|
|
<FS>TIEWICReader.DPIX
|
|
|
|
<FM>Declaration<FC>
|
|
property DPIX: double;
|
|
|
|
<FM>Description<FN>
|
|
X-axis dots per inch (dpi) resolution. This property is filled by <A TIEWICReader.GetFrame> method.
|
|
|
|
See also: <A TIEWICReader.DPIY>
|
|
!!}
|
|
property DPIX: double read fDPIX write fDPIX;
|
|
|
|
{!!
|
|
<FS>TIEWICReader.DPIY
|
|
|
|
<FM>Declaration<FC>
|
|
property DPIY: double;
|
|
|
|
<FM>Description<FN>
|
|
Y-axis dots per inch (dpi) resolution. This property is filled by <A TIEWICReader.GetFrame> method.
|
|
|
|
See also: <A TIEWICReader.DPIX>
|
|
!!}
|
|
property DPIY: double read fDPIY write fDPIY;
|
|
|
|
function QueryMetadata(const query: string): PROPVARIANT;
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{!!
|
|
<FS>TIEWICWriter
|
|
|
|
<FM>Description<FN>
|
|
TIEWICWriter class encapsulates some Microsoft Windows Imaging Component (WIC) interfaces and allows you to write Microsoft HD Photo and other WIC installed file formats.
|
|
WIC preinstalled encoders are TIFF, PNG, GIF, BMP, JPEG, HDP.
|
|
|
|
Note: Requires Windows XP (SP2) with .Net 3.0, Windows Vista or newer.
|
|
|
|
<FM>Examples<FC>
|
|
// saves ImageEnView1 to output.hdp, which is the same as ImageEnView1.IO.SaveToFile('output.hdp')
|
|
with TIEWICWriter.Create do
|
|
begin
|
|
Open('output.hdp', ioHDP);
|
|
PutFrame(ImageEnView1.IEBitmap, ImageEnView1.IO.Params);
|
|
Free;
|
|
end;
|
|
|
|
// saves ImageEnView1 to output.jpg
|
|
with TIEWICWriter.Create do
|
|
begin
|
|
Open('output.jpg', ioJPEG);
|
|
PutFrame(ImageEnView1.IEBitmap, ImageEnView1.IO.Params);
|
|
Free;
|
|
end;
|
|
|
|
// saves ImageEnView1 and ImageEnView2 as two pages in output.tif
|
|
with TIEWICWriter.Create do
|
|
begin
|
|
Open('output.tif', ioTIFF);
|
|
PutFrame(ImageEnView1.IEBitmap, ImageEnView1.IO.Params);
|
|
PutFrame(ImageEnView2.IEBitmap, ImageEnView2.IO.Params);
|
|
Free;
|
|
end;
|
|
|
|
|
|
|
|
<FM>Methods and Properties<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_METHOD> <C><A TIEWICWriter.Close></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEWICWriter.DPIX></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEWICWriter.DPIY></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEWICWriter.IsAvailable></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEWICWriter.Open></C> </R>
|
|
<R> <C_IMG_METHOD> <C><A TIEWICWriter.PutFrame></C> </R>
|
|
</TABLE>
|
|
|
|
<FI>Canonical Encoder Parameter Properties<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEWICWriter.CompressionQuality></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEWICWriter.ImageQuality></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEWICWriter.Lossless></C> </R>
|
|
</TABLE>
|
|
|
|
<FI>Specific HD Photo Encoder Parameter Properties<FN>
|
|
<TABLE2>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEWICWriter.FrequencyOrder></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEWICWriter.HorizontalTileSlices></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEWICWriter.Overlap></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEWICWriter.Quality></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEWICWriter.Subsampling></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEWICWriter.UseCodecOptions></C> </R>
|
|
<R> <C_IMG_PROPERTY> <C><A TIEWICWriter.VerticalTileSlices></C> </R>
|
|
</TABLE>
|
|
!!}
|
|
TIEWICWriter = class
|
|
private
|
|
fOLEInitialized: boolean;
|
|
fWICImagingFactory: IE_IWICImagingFactory;
|
|
fEncoder: IE_IWICBitmapEncoder;
|
|
fDPIX: double;
|
|
fDPIY: double;
|
|
fImageQuality: double; // -1 = encoder default
|
|
fCompressionQuality: double; // -1 = encoder default
|
|
fLossless: boolean;
|
|
fUseCodecOptions: boolean;
|
|
fQuality: integer; // enabled if fUseCodecOptions=true
|
|
fOverlap: integer; // enabled if fUseCodecOptions=true
|
|
fSubsampling: integer; // enabled if fUseCodecOptions=true
|
|
fHorizontalTileSlices: integer;
|
|
fVerticalTileSlices: integer;
|
|
fFrequencyOrder: boolean;
|
|
fTIFFCompressionMethod: TIEWICTIFFCompressionMethod;
|
|
fStream: TStream;
|
|
fStreamBase: int64;
|
|
fFileStream: TIEWideFileStream;
|
|
|
|
protected
|
|
|
|
public
|
|
constructor Create;
|
|
destructor Destroy; override;
|
|
|
|
function IsAvailable: boolean;
|
|
|
|
function Open(const FileName: WideString; fileType: TIOFileType): boolean; overload;
|
|
function Open(Stream: TStream; fileType: TIOFileType): boolean; overload;
|
|
procedure Close;
|
|
|
|
procedure PutFrame(srcBitmap: TIEBitmap; IOParams: TIOParams = nil);
|
|
|
|
{!!
|
|
<FS>TIEWICWriter.DPIX
|
|
|
|
<FM>Declaration<FC>
|
|
property DPIX: double;
|
|
|
|
<FM>Description<FN>
|
|
X-axis dots per inch (dpi) resolution. You must set this property before each <A TIEWICWriter.PutFrame> call.
|
|
|
|
See also: <A TIEWICWriter.DPIY>
|
|
!!}
|
|
property DPIX: double read fDPIX write fDPIX;
|
|
|
|
{!!
|
|
<FS>TIEWICWriter.DPIY
|
|
|
|
<FM>Declaration<FC>
|
|
property DPIY: double;
|
|
|
|
<FM>Description<FN>
|
|
Y-axis dots per inch (dpi) resolution. You must set this property before each <A TIEWICWriter.PutFrame> call.
|
|
|
|
See also: <A TIEWICWriter.DPIX>
|
|
!!}
|
|
property DPIY: double read fDPIY write fDPIY;
|
|
|
|
//// Canonical Encoder Parameter Properties ////
|
|
|
|
{!!
|
|
<FS>TIEWICWriter.ImageQuality
|
|
|
|
<FM>Declaration<FC>
|
|
property ImageQuality: double;
|
|
|
|
<FM>Description<FN>
|
|
0.0 specifies the lowest possible fidelity rendition and 1.0 specifies the highest fidelity, which for HD Photo results in mathematically lossless compression.
|
|
You must set this property before each <A TIEWICWriter.PutFrame> call.
|
|
|
|
<FM>Example<FC>
|
|
with TIEWICWriter.Create do
|
|
begin
|
|
Open('output.hdp', ioHDP);
|
|
ImageQuality := 0.7;
|
|
PutFrame(ImageEnView1.IEBitmap);
|
|
Free;
|
|
end;
|
|
!!}
|
|
property ImageQuality: double read fImageQuality write fImageQuality;
|
|
|
|
{!!
|
|
<FS>TIEWICWriter.CompressionQuality
|
|
|
|
<FM>Declaration<FC>
|
|
property CompressionQuality: double;
|
|
|
|
<FM>Description<FN>
|
|
0.0 specifies the least efficient compression scheme available, typically resulting in a fast encode but larger output.
|
|
A value of 1.0 specifies the most efficient scheme available, typically taking more time to encode but producing smaller output.
|
|
HD Photo does not support this encoder option.
|
|
You must set this property before each <A TIEWICWriter.PutFrame> call.
|
|
!!}
|
|
property CompressionQuality: double read fCompressionQuality write fCompressionQuality;
|
|
|
|
{!!
|
|
<FS>TIEWICWriter.Lossless
|
|
|
|
<FM>Declaration<FC>
|
|
property Lossless: boolean;
|
|
|
|
<FM>Description<FN>
|
|
Setting this parameter to <FC>true<FN> enables mathematically lossless compression mode and overrides the <A TIEWICWriter.ImageQuality> parameter setting.
|
|
|
|
Default: False
|
|
|
|
Note: You must set this property before each <A TIEWICWriter.PutFrame> call.
|
|
|
|
<FM>Example<FC>
|
|
with TIEWICWriter.Create do
|
|
begin
|
|
Open('output.hdp', ioHDP);
|
|
Lossless := true;
|
|
PutFrame(ImageEnView1.IEBitmap);
|
|
Free;
|
|
end;
|
|
!!}
|
|
property Lossless: boolean read fLossless write fLossless;
|
|
|
|
//// Specific HD Photo encoder parameter properties ////
|
|
|
|
|
|
{!!
|
|
<FS>TIEWICWriter.UseCodecOptions
|
|
|
|
<FM>Declaration<FC>
|
|
property UseCodecOptions: boolean;
|
|
|
|
<FM>Description<FN>
|
|
If this parameter is <FC>true<FN>, the <A TIEWICWriter.Quality>, <A TIEWICWriter.Overlap> and <A TIEWICWriter.Subsampling> parameters are used in place of the <A TIEWICWriter.ImageQuality> encoder canonical parameter.
|
|
When <FC>false<FN>, the <A TIEWICWriter.Quality>, <A TIEWICWriter.Overlap> and <A TIEWICWriter.Subsampling> parameters are set based on a table lookup determined by the <A TIEWICWriter.ImageQuality> parameter.
|
|
|
|
Default: False
|
|
|
|
Note: You must set this property before each <A TIEWICWriter.PutFrame> call.
|
|
|
|
<FM>Example<FC>
|
|
with TIEWICWriter.Create do
|
|
begin
|
|
Open('output.hdp', ioHDP);
|
|
UseCodecOptions := true;
|
|
Quality := 10;
|
|
PutFrame(ImageEnView1.IEBitmap);
|
|
Free;
|
|
end;
|
|
!!}
|
|
property UseCodecOptions: boolean read fUseCodecOptions write fUseCodecOptions;
|
|
|
|
{!!
|
|
<FS>TIEWICWriter.Quality
|
|
|
|
<FM>Declaration<FC>
|
|
property Quality: integer;
|
|
|
|
<FM>Description<FN>
|
|
This parameter controls the compression quality for the main image. A value of 1 sets lossless mode.
|
|
Increasing values result in higher compression ratios and lower image quality.
|
|
|
|
Default: 1
|
|
|
|
Notes:
|
|
- <A TIEWICWriter.UseCodecOptions> must be <FC>true<FN>
|
|
- You must set this property before each <A TIEWICWriter.PutFrame> call
|
|
|
|
<FM>Example<FC>
|
|
with TIEWICWriter.Create do
|
|
begin
|
|
Open('output.hdp', ioHDP);
|
|
UseCodecOptions := true;
|
|
Quality := 10;
|
|
PutFrame(ImageEnView1.IEBitmap);
|
|
Free;
|
|
end;
|
|
!!}
|
|
property Quality: integer read fQuality write fQuality;
|
|
|
|
{!!
|
|
<FS>TIEWICWriter.Overlap
|
|
|
|
<FM>Declaration<FC>
|
|
property Overlap: integer;
|
|
|
|
<FM>Description<FN>
|
|
This parameter selects the optional overlap processing level:
|
|
<TABLE>
|
|
<R> <H>Value</H> <H>Description</H> </R>
|
|
<R> <C>0</C> <C>No overlap processing is enabled.</C> </R>
|
|
<R> <C>1</C> <C>One level of overlap processing is enabled, modifying 4x4 block encoded values based on values of neighboring blocks.</C> </R>
|
|
<R> <C>2</C> <C>Two levels of overlap processing are enabled; in addition to the first level processing, encoded values of 16x16 macro blocks are modified based on the values of neighboring macro blocks.</C> </R>
|
|
</TABLE>
|
|
|
|
Default: 1
|
|
|
|
Notes:
|
|
- <A TIEWICWriter.UseCodecOptions> must be <FC>true<FN>
|
|
- You must set this property before each <A TIEWICWriter.PutFrame> call
|
|
!!}
|
|
property Overlap: integer read fOverlap write fOverlap;
|
|
|
|
{!!
|
|
<FS>TIEWICWriter.Subsampling
|
|
|
|
<FM>Declaration<FC>
|
|
property Subsampling: integer;
|
|
|
|
<FM>Description<FN>
|
|
This parameter only applies to RGB images. It enables additional compression in the chroma space, preserving luminance detail at the expense of color detail:
|
|
|
|
<TABLE>
|
|
<R> <H>Value</H> <H>Description</H> </R>
|
|
<R> <C>3</C> <C>4: 4: 4 encoding preserves full chroma resolution.</C> </R>
|
|
<R> <C>2</C> <C>4: 2: 2 encoding reduces chroma resolution to 1/2 of luminance resolution.</C> </R>
|
|
<R> <C>1</C> <C>4: 2: 0 encoding reduces chroma resolution to 1/4 of luminance resolution.</C> </R>
|
|
<R> <C>0</C> <C>4: 0: 0 encoding discards all chroma content, preserving luminance only. Because the codec uses a slightly modified definition of luminance to improve performance, it is preferred to convert an RGB image to monochrome before encoding rather than use this chroma subsampling mode.</C> </R>
|
|
</TABLE>
|
|
|
|
Any value greater than 3 returns an error. The default value is 3.
|
|
|
|
<A TIEWICWriter.UseCodecOptions> must be <FC>true<FN>.
|
|
You must set this property before each <A TIEWICWriter.PutFrame> call.
|
|
!!}
|
|
property Subsampling: integer read fSubsampling write fSubsampling;
|
|
|
|
{!!
|
|
<FS>TIEWICWriter.HorizontalTileSlices
|
|
|
|
<FM>Declaration<FC>
|
|
property HorizontalTileSlices: integer;
|
|
|
|
<FM>Description<FN>
|
|
HorizontalTileSlices and <A TIEWICWriter.VerticalTileSlices> specify the horizontal and vertical tiling of the image prior to compression encoding for the most optimal region decode performance.
|
|
Dividing the image into rectangular tiles during encoding makes it possible to decode regions of the image without the need to process the entire compressed data stream.
|
|
The default value of 0 specifies no subdivision, so the entire image is treated as a single tile.
|
|
A value of 1 for each parameter will create a single horizontal and a single vertical division, effectively dividing the image into four equally sized tiles.
|
|
The maximum value of 4095 for each parameter divides the image into 4096 tile rows with 4096 tiles per row.
|
|
In other words, the parameter values equal the number of horizontal and vertical tiles (respectively) minus 1.
|
|
A tile can never be smaller than 16 pixels in width or height, so the HD Photo encoder may adjust this parameter to maintain the required minimum tile size.
|
|
Because there is storage and processing overhead associated with each tile, these values should be chosen carefully to meet the specific scenario and unless there is a very specific reason, large numbers of small tiles should be avoided.
|
|
|
|
The default value for both parameters is 0.
|
|
|
|
You must set this property before each <A TIEWICWriter.PutFrame> call.
|
|
!!}
|
|
property HorizontalTileSlices: integer read fHorizontalTileSlices write fHorizontalTileSlices;
|
|
|
|
{!!
|
|
<FS>TIEWICWriter.VerticalTileSlices
|
|
|
|
<FM>Declaration<FC>
|
|
property VerticalTileSlices: integer;
|
|
|
|
<FM>Description<FN>
|
|
<A TIEWICWriter.HorizontalTileSlices> and VerticalTileSlices specify the horizontal and vertical tiling of the image prior to compression encoding for the most optimal region decode performance.
|
|
Dividing the image into rectangular tiles during encoding makes it possible to decode regions of the image without the need to process the entire compressed data stream.
|
|
The default value of 0 specifies no subdivision, so the entire image is treated as a single tile.
|
|
A value of 1 for each parameter will create a single horizontal and a single vertical division, effectively dividing the image into four equally sized tiles.
|
|
The maximum value of 4095 for each parameter divides the image into 4096 tile rows with 4096 tiles per row.
|
|
In other words, the parameter values equal the number of horizontal and vertical tiles (respectively) minus 1.
|
|
A tile can never be smaller than 16 pixels in width or height, so the HD Photo encoder may adjust this parameter to maintain the required minimum tile size.
|
|
Because there is storage and processing overhead associated with each tile, these values should be chosen carefully to meet the specific scenario and unless there is a very specific reason, large numbers of small tiles should be avoided.
|
|
|
|
The default value for both parameters is 0.
|
|
|
|
You must set this property before each <A TIEWICWriter.PutFrame> call.
|
|
!!}
|
|
property VerticalTileSlices: integer read fVerticalTileSlices write fVerticalTileSlices;
|
|
|
|
{!!
|
|
<FS>TIEWICWriter.FrequencyOrder
|
|
|
|
<FM>Declaration<FC>
|
|
property FrequencyOrder: boolean;
|
|
|
|
<FM>Description<FN>
|
|
This parameter specifies that the image must be encoded in frequency order, with the lowest frequency data appearing first in the file, and image content grouped by its frequency rather than its spatial orientation.
|
|
Organizing a file by frequency order provides the highest performance results for any frequency-based decoding, and is the preferred option.
|
|
Device implementations of HD Photo encoders may choose to organize a file in spatial order to reduce the memory footprint required during encoding.
|
|
The default value is <FC>true<FN> and it is recommended that applications and devices always use frequency order unless there are performance or application-specific reasons to use spatial order.
|
|
|
|
You must set this property before each <A TIEWICWriter.PutFrame> call.
|
|
!!}
|
|
property FrequencyOrder: boolean read fFrequencyOrder write fFrequencyOrder;
|
|
|
|
///// TIFF specific compression parameters /////
|
|
|
|
{!!
|
|
<FS>TIEWICWriter.TIFFCompressionMethod
|
|
|
|
<FM>Declaration<FC>
|
|
property TIFFCompressionMethod: <A TIEWICTIFFCompressionMethod>;
|
|
|
|
<FM>Description<FN>
|
|
Specifies the Tagged Image File Format (TIFF) compression options.
|
|
|
|
You must set this property before each <A TIEWICWriter.PutFrame> call.
|
|
|
|
<FM>Example<FC>
|
|
// writes a TIFF using CCITT4 compression (make sure ImageEnView1.IEBitmap.PixelFormat=ie1g)
|
|
with TIEWICWriter.Create do
|
|
begin
|
|
Open('output.tif', ioTIFF);
|
|
TIFFCompressionMethod := ieWICTiffCompressionCCITT4;
|
|
PutFrame(ImageEnView1.IEBitmap);
|
|
Free;
|
|
end;
|
|
!!}
|
|
property TIFFCompressionMethod: TIEWICTIFFCompressionMethod read fTIFFCompressionMethod write fTIFFCompressionMethod;
|
|
|
|
end;
|
|
|
|
|
|
|
|
// Exposes TIEBitmap as IWICBitmapSource
|
|
TIEWICBitmapWrapper = class(TInterfacedObject, IE_IWICBitmapSource)
|
|
private
|
|
m_bitmap: TIEBaseBitmap;
|
|
m_alpha: TIEBaseBitmap;
|
|
public
|
|
constructor Create(Bitmap: TIEBaseBitmap; Alpha: TIEBaseBitmap);
|
|
destructor Destroy(); override;
|
|
|
|
// implements IE_IWICBitmapSource
|
|
function GetSize(out puiWidth: DWORD; out puiHeight: DWORD): HResult; stdcall;
|
|
function GetPixelFormat(out pPixelFormat: TGUID): HResult; stdcall;
|
|
function GetResolution(out pDpiX: double; out pDpiY: double): HResult; stdcall;
|
|
function CopyPalette(pIPalette: IE_IWICPalette): HResult; stdcall;
|
|
function CopyPixels(prc: IE_PWICRect; cbStride: DWORD; cbBufferSize: DWORD; pbBuffer: pbyte): HResult; stdcall;
|
|
end;
|
|
|
|
|
|
// provides common base functionality for format converters, scaler, etc...
|
|
TIEWICBaseFunctionality = class
|
|
private
|
|
m_OLEInitialized: boolean;
|
|
m_WICImagingFactory: IE_IWICImagingFactory;
|
|
public
|
|
constructor Create();
|
|
destructor Destroy; override;
|
|
function IsAvailable(): boolean;
|
|
end;
|
|
|
|
|
|
|
|
// Encapsulates IWICFormatConverter functionality
|
|
TIEWICFormatConverter = class(TIEWICBaseFunctionality)
|
|
private
|
|
m_paletteType: DWORD;
|
|
m_ditherType: DWORD;
|
|
m_palette: IE_IWICPalette;
|
|
public
|
|
constructor Create();
|
|
function Convert(Source: TIEBitmap; Dest: TIEBitmap; DestPixelFormat: TIEPixelFormat; CheckParametersOnly: boolean; OnProgressFunction: TIEProgressEvent = nil; OnProgressSender: TObject = nil): boolean;
|
|
procedure SetPalette(Palette: array of TRGB);
|
|
property PaletteType: DWORD read m_paletteType write m_paletteType;
|
|
property DitherType: DWORD read m_ditherType write m_ditherType;
|
|
end;
|
|
|
|
|
|
|
|
// Encapsulates IWICBitmapScaler functionality
|
|
TIEWICBitmapScaler = class(TIEWICBaseFunctionality)
|
|
public
|
|
//constructor Create();
|
|
function Resample(Source: TIEBaseBitmap; SourceAlpha: TIEBaseBitmap; Dest: TIEBaseBitmap; DestAlpha: TIEBaseBitmap; Width: DWORD; Height: DWORD; Mode: IE_WICBitmapInterpolationMode; OnProgressFunction: TIEProgressEvent = nil; OnProgressSender: TObject = nil): boolean;
|
|
end;
|
|
|
|
|
|
|
|
implementation
|
|
|
|
uses
|
|
ieview, tiffilt, iesettings, imageenproc;
|
|
|
|
const
|
|
ole32 = 'ole32.dll';
|
|
|
|
function CoCreateInstance(const clsid: TGUID; unkOuter: IUnknown; dwClsContext: Longint; const iid: TGUID; out pv): HResult; stdcall; external ole32 name 'CoCreateInstance';
|
|
function OleInitialize(pwReserved: Pointer): HResult; stdcall; external ole32 name 'OleInitialize';
|
|
procedure OleUninitialize; stdcall; external ole32 name 'OleUninitialize';
|
|
|
|
|
|
const
|
|
|
|
CLSCTX_INPROC_SERVER = 1;
|
|
|
|
CLSID_WICImagingFactory: TGUID = (D1:$cacaf262; D2:$9370; D3:$4615; D4:($a1, $3b, $9f, $55, $39, $da, $4c, $a));
|
|
|
|
CLSID_WICBmpDecoder: TGUID = (D1:$6b462062; D2:$7cbf; D3:$400d; D4:($9f, $db, $81, $3d, $d1, $f, $27, $78));
|
|
CLSID_WICPngDecoder: TGUID = (D1:$389ea17b; D2:$5078; D3:$4cde; D4:($b6, $ef, $25, $c1, $51, $75, $c7, $51));
|
|
CLSID_WICIcoDecoder: TGUID = (D1:$c61bfcdf; D2:$2e0f; D3:$4aad; D4:($a8, $d7, $e0, $6b, $af, $eb, $cd, $fe));
|
|
CLSID_WICJpegDecoder: TGUID = (D1:$9456a480; D2:$e88b; D3:$43ea; D4:($9e, $73, $b, $2d, $9b, $71, $b1, $ca));
|
|
CLSID_WICGifDecoder: TGUID = (D1:$381dda3c; D2:$9ce9; D3:$4834; D4:($a2, $3e, $1f, $98, $f8, $fc, $52, $be));
|
|
CLSID_WICTiffDecoder: TGUID = (D1:$b54e85d9; D2:$fe23; D3:$499f; D4:($8b, $88, $6a, $ce, $a7, $13, $75, $2b));
|
|
CLSID_WICWmpDecoder: TGUID = (D1:$a26cec36; D2:$234c; D3:$4950; D4:($ae, $16, $e3, $4a, $ac, $e7, $1d, $0d));
|
|
|
|
CLSID_WICBmpEncoder: TGUID = (D1:$69be8bb4; D2:$d66d; D3:$47c8; D4:($86, $5a, $ed, $15, $89, $43, $37, $82));
|
|
CLSID_WICPngEncoder: TGUID = (D1:$27949969; D2:$876a; D3:$41d7; D4:($94, $47, $56, $8f, $6a, $35, $a4, $dc));
|
|
CLSID_WICJpegEncoder: TGUID = (D1:$1a34f5c1; D2:$4a5a; D3:$46dc; D4:($b6, $44, $1f, $45, $67, $e7, $a6, $76));
|
|
CLSID_WICGifEncoder: TGUID = (D1:$114f5598; D2:$0b22; D3:$40a0; D4:($86, $a1, $c8, $3e, $a4, $95, $ad, $bd));
|
|
CLSID_WICTiffEncoder: TGUID = (D1:$0131be10; D2:$2001; D3:$4c5f; D4:($a9, $b0, $cc, $88, $fa, $b6, $4c, $e8));
|
|
CLSID_WICWmpEncoder: TGUID = (D1:$ac4ce3cb; D2:$e1c1; D3:$44cd; D4:($82, $15, $5a, $16, $65, $50, $9e, $c2));
|
|
|
|
|
|
GUID_WICPixelFormatDontCare: TGUID = (D1:$6fddc324; D2:$4e03; D3:$4bfe; D4:($b1, $85, $3d, $77, $76, $8d, $c9, $00));
|
|
GUID_WICPixelFormat1bppIndexed: TGUID = (D1:$6fddc324; D2:$4e03; D3:$4bfe; D4:($b1, $85, $3d, $77, $76, $8d, $c9, $01));
|
|
GUID_WICPixelFormat8bppIndexed: TGUID = (D1:$6fddc324; D2:$4e03; D3:$4bfe; D4:($b1, $85, $3d, $77, $76, $8d, $c9, $04));
|
|
GUID_WICPixelFormatBlackWhite: TGUID = (D1:$6fddc324; D2:$4e03; D3:$4bfe; D4:($b1, $85, $3d, $77, $76, $8d, $c9, $05));
|
|
GUID_WICPixelFormat8bppGray: TGUID = (D1:$6fddc324; D2:$4e03; D3:$4bfe; D4:($b1, $85, $3d, $77, $76, $8d, $c9, $08));
|
|
GUID_WICPixelFormat16bppGray: TGUID = (D1:$6fddc324; D2:$4e03; D3:$4bfe; D4:($b1, $85, $3d, $77, $76, $8d, $c9, $0b));
|
|
GUID_WICPixelFormat24bppBGR: TGUID = (D1:$6fddc324; D2:$4e03; D3:$4bfe; D4:($b1, $85, $3d, $77, $76, $8d, $c9, $0c));
|
|
GUID_WICPixelFormat24bppRGB: TGUID = (D1:$6fddc324; D2:$4e03; D3:$4bfe; D4:($b1, $85, $3d, $77, $76, $8d, $c9, $0d));
|
|
GUID_WICPixelFormat32bppBGRA: TGUID = (D1:$6fddc324; D2:$4e03; D3:$4bfe; D4:($b1, $85, $3d, $77, $76, $8d, $c9, $0f));
|
|
GUID_WICPixelFormat32bppPBGRA: TGUID = (D1:$6fddc324; D2:$4e03; D3:$4bfe; D4:($b1, $85, $3d, $77, $76, $8d, $c9, $10));
|
|
GUID_WICPixelFormat32bppRGBA: TGUID = (D1:$f5c7ad2d; D2:$6a8d; D3:$43dd; D4:($a7, $a8, $a2, $99, $35, $26, $1a, $e9));
|
|
GUID_WICPixelFormat32bppPRGBA: TGUID = (D1:$3cc4a650; D2:$a527; D3:$4d37; D4:($a9, $16, $31, $42, $c7, $eb, $ed, $ba));
|
|
GUID_WICPixelFormat48bppRGB: TGUID = (D1:$6fddc324; D2:$4e03; D3:$4bfe; D4:($b1, $85, $3d, $77, $76, $8d, $c9, $15));
|
|
GUID_WICPixelFormat32bppCMYK: TGUID = (D1:$6fddc324; D2:$4e03; D3:$4bfe; D4:($b1, $85, $3d, $77, $76, $8d, $c9, $1c));
|
|
|
|
GUID_ContainerFormatBmp: TGUID = (D1:$0af1d87e; D2:$fcfe; D3:$4188; D4:($bd, $eb, $a7, $90, $64, $71, $cb, $e3));
|
|
GUID_ContainerFormatPng: TGUID = (D1:$1b7cfaf4; D2:$713f; D3:$473c; D4:($bb, $cd, $61, $37, $42, $5f, $ae, $af));
|
|
GUID_ContainerFormatIco: TGUID = (D1:$a3a860c4; D2:$338f; D3:$4c17; D4:($91, $9a, $fb, $a4, $b5, $62, $8f, $21));
|
|
GUID_ContainerFormatJpeg: TGUID = (D1:$19e4a5aa; D2:$5662; D3:$4fc5; D4:($a0, $c0, $17, $58, $02, $8e, $10, $57));
|
|
GUID_ContainerFormatTiff: TGUID = (D1:$163bcc30; D2:$e2e9; D3:$4f0b; D4:($96, $1d, $a3, $e9, $fd, $b7, $88, $a3));
|
|
GUID_ContainerFormatGif: TGUID = (D1:$1f8a5601; D2:$7d4d; D3:$4cbd; D4:($9c, $82, $1b, $c8, $d4, $ee, $b9, $a5));
|
|
GUID_ContainerFormatWmp: TGUID = (D1:$57a37caa; D2:$367a; D3:$4540; D4:($91, $6b, $f1, $83, $c5, $09, $3a, $4b));
|
|
|
|
GUID_VendorMicrosoft: TGUID = (D1:$f0e749ca; D2:$edef; D3:$4589; D4:($a7, $3a, $ee, $e, $62, $6a, $2a, $2b));
|
|
|
|
|
|
|
|
// WICDecodeOptions
|
|
WICDecodeMetadataCacheOnDemand = $00000000;
|
|
WICDecodeMetadataCacheOnLoad = $00000001;
|
|
|
|
|
|
// WICBitmapEncoderCacheOption
|
|
WICBitmapEncoderCacheInMemory = $00000000;
|
|
WICBitmapEncoderCacheTempFile = $00000001;
|
|
WICBitmapEncoderNoCache = $00000002;
|
|
|
|
|
|
// IE_WICBitmapCreateCacheOption
|
|
WICBitmapNoCache = $00000000;
|
|
WICBitmapCacheOnDemand = $00000001;
|
|
WICBitmapCacheOnLoad = $00000002;
|
|
|
|
|
|
// STREAM_SEEK
|
|
STREAM_SEEK_SET = 0;
|
|
STREAM_SEEK_CUR = 1;
|
|
STREAM_SEEK_END = 2;
|
|
|
|
PROPBAG2_TYPE_UNDEFINED = 0;
|
|
PROPBAG2_TYPE_DATA = 1;
|
|
PROPBAG2_TYPE_URL = 2;
|
|
PROPBAG2_TYPE_OBJECT = 3;
|
|
PROPBAG2_TYPE_STREAM = 4;
|
|
PROPBAG2_TYPE_STORAGE = 5;
|
|
PROPBAG2_TYPE_MONIKER = 6;
|
|
|
|
WINCODEC_ERR_PALETTEUNAVAILABLE = HResult($88982f45);
|
|
|
|
|
|
|
|
function ConvertWICPixelFormatToIEBitmapPixelFormat(wicFactory: IE_IWICImagingFactory; source: IE_IWICBitmapSource; out hasAlpha: boolean): TIEPixelFormat;
|
|
var
|
|
wicPixelFormat: TGUID;
|
|
palette: IE_IWICPalette;
|
|
lbHasAlpha: longbool;
|
|
begin
|
|
source.GetPixelFormat(wicPixelFormat);
|
|
hasAlpha := false;
|
|
if CompareGUID(wicPixelFormat, GUID_WICPixelFormat1bppIndexed) then
|
|
result := ie1g // to check!
|
|
else
|
|
if CompareGUID(wicPixelFormat, GUID_WICPixelFormat8bppIndexed) then
|
|
begin
|
|
result := ie8p;
|
|
palette := nil;
|
|
wicFactory.CreatePalette(palette);
|
|
source.CopyPalette(palette);
|
|
palette.HasAlpha(lbHasAlpha);
|
|
hasAlpha := lbHasAlpha;
|
|
end
|
|
else
|
|
if CompareGUID(wicPixelFormat, GUID_WICPixelFormatBlackWhite) then
|
|
result := ie1g
|
|
else
|
|
if CompareGUID(wicPixelFormat, GUID_WICPixelFormat8bppGray) then
|
|
result := ie8g
|
|
else
|
|
if CompareGUID(wicPixelFormat, GUID_WICPixelFormat16bppGray) then
|
|
result := ie16g
|
|
else
|
|
if CompareGUID(wicPixelFormat, GUID_WICPixelFormat24bppBGR) then
|
|
result := ie24RGB
|
|
else
|
|
if CompareGUID(wicPixelFormat, GUID_WICPixelFormat32bppBGRA) then
|
|
begin
|
|
hasAlpha := true;
|
|
result := ie24RGB;
|
|
end
|
|
else
|
|
if CompareGUID(wicPixelFormat, GUID_WICPixelFormat48bppRGB) then
|
|
result := ie48RGB
|
|
else
|
|
if CompareGUID(wicPixelFormat, GUID_WICPixelFormat32bppCMYK) then
|
|
result := ieCMYK
|
|
else
|
|
result := ieNull;
|
|
end;
|
|
|
|
|
|
function ConvertIEBitmapPixelFormatToWICPixelFormat(IEBitmapPixelFormat: TIEPixelFormat): TGUID;
|
|
begin
|
|
case IEBitmapPixelFormat of
|
|
ie1g:
|
|
result := GUID_WICPixelFormatBlackWhite;
|
|
ie8p:
|
|
result := GUID_WICPixelFormat8bppIndexed;
|
|
ie8g:
|
|
result := GUID_WICPixelFormat8bppGray;
|
|
ie16g:
|
|
result := GUID_WICPixelFormat16bppGray;
|
|
ie24RGB:
|
|
result := GUID_WICPixelFormat24bppBGR;
|
|
ieCMYK:
|
|
result := GUID_WICPixelFormat32bppCMYK;
|
|
ie48RGB:
|
|
result := GUID_WICPixelFormat48bppRGB;
|
|
else
|
|
raise EIEException.Create('Unsupported pixel format');
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure ConvertWICBitmapToIEBitmap(wicFactory: IE_IWICImagingFactory; source: IE_IWICBitmapSource; dest: TIEBitmap; nativePixelFormat: boolean = true);
|
|
var
|
|
converter: IE_IWICFormatConverter;
|
|
pixelFormatGUID: TGUID;
|
|
pixelFormat: TIEPixelFormat;
|
|
i, j: longint;
|
|
w, h: DWORD;
|
|
rc: IE_WICRect;
|
|
pb: pbyte;
|
|
hasAlpha: boolean;
|
|
rgbaBuf: array of TRGBA;
|
|
byteBuf: array of byte;
|
|
pb_dstalpha: pbyte;
|
|
palette: IE_IWICPalette;
|
|
paletteColors: array of IE_WICColor;
|
|
colorCount: DWORD;
|
|
begin
|
|
source.GetPixelFormat(pixelFormatGUID);
|
|
pixelFormat := ConvertWICPixelFormatToIEBitmapPixelFormat(wicFactory, source, hasAlpha);
|
|
if nativePixelFormat then
|
|
begin
|
|
// special cases
|
|
if CompareGUID(pixelFormatGUID, GUID_WICPixelFormat1bppIndexed) then
|
|
begin
|
|
pixelFormatGUID := GUID_WICPixelFormat8bppIndexed;
|
|
pixelFormat := ie8p;
|
|
end
|
|
else
|
|
if CompareGUID(pixelFormatGUID, GUID_WICPixelFormat8bppIndexed) then
|
|
begin
|
|
// palette not supported at the moment
|
|
pixelFormatGUID := GUID_WICPixelFormat24bppBGR;
|
|
pixelFormat := ie24RGB;
|
|
end;
|
|
if pixelFormat = ieNull then
|
|
begin
|
|
pixelFormatGUID := GUID_WICPixelFormat24bppBGR;
|
|
pixelFormat := ie24RGB;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
// only 1bit and 24bitRGB are supported
|
|
if CompareGUID(pixelFormatGUID, GUID_WICPixelFormatBlackWhite) then
|
|
pixelFormat := ie1g
|
|
else
|
|
begin
|
|
pixelFormatGUID := GUID_WICPixelFormat24bppBGR;
|
|
pixelFormat := ie24RGB;
|
|
end;
|
|
end;
|
|
|
|
converter := nil;
|
|
wicFactory.CreateFormatConverter(converter);
|
|
converter.Initialize(source, pixelFormatGUID, IE_WICBitmapDitherTypeNone, nil, 0.0, 0);
|
|
|
|
converter.GetSize(w, h);
|
|
dest.Allocate(w, h, pixelFormat);
|
|
rc.X := 0;
|
|
rc.Width := w;
|
|
rc.Height := 1;
|
|
for i := 0 to h - 1 do
|
|
begin
|
|
rc.Y := i;
|
|
converter.CopyPixels(@rc, dest.Rowlen, dest.Rowlen, dest.ScanLine[i]);
|
|
end;
|
|
|
|
if dest.PixelFormat = ieCMYK then
|
|
begin
|
|
// CMYK channels need to be inverted
|
|
for i := 0 to h - 1 do
|
|
begin
|
|
pb := dest.ScanLine[i];
|
|
for j := w * 4 - 1 downto 0 do
|
|
begin
|
|
pb^ := 255 - pb^;
|
|
inc(pb);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
source.GetPixelFormat(pixelFormatGUID); // read again pixelFormatGUID (can be changed by previous code)
|
|
if hasAlpha then
|
|
begin
|
|
if CompareGUID(pixelFormatGUID, GUID_WICPixelFormat32bppBGRA) then
|
|
begin
|
|
SetLength(rgbaBuf, w);
|
|
rc.X := 0;
|
|
rc.Width := w;
|
|
rc.Height := 1;
|
|
for i := 0 to h - 1 do
|
|
begin
|
|
rc.Y := i;
|
|
source.CopyPixels(@rc, w * 4, w * 4, @rgbaBuf[0]);
|
|
pb_dstalpha := dest.AlphaChannel.ScanLine[i];
|
|
for j := 0 to w - 1 do
|
|
begin
|
|
pb_dstalpha^ := rgbaBuf[j].a;
|
|
inc(pb_dstalpha);
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
if CompareGUID(pixelFormatGUID, GUID_WICPixelFormat8bppIndexed) then
|
|
begin
|
|
SetLength(byteBuf, w);
|
|
rc.X := 0;
|
|
rc.Width := w;
|
|
rc.Height := 1;
|
|
palette := nil;
|
|
|
|
wicFactory.CreatePalette(palette);
|
|
source.CopyPalette(palette);
|
|
palette.GetColorCount(colorCount);
|
|
SetLength(paletteColors, colorCount);
|
|
palette.GetColors(colorCount, @paletteColors[0], colorCount);
|
|
|
|
for i := 0 to h - 1 do
|
|
begin
|
|
rc.Y := i;
|
|
source.CopyPixels(@rc, w, w, @byteBuf[0]);
|
|
|
|
pb_dstalpha := dest.AlphaChannel.ScanLine[i];
|
|
|
|
for j := 0 to w - 1 do
|
|
begin
|
|
pb_dstalpha^ := (paletteColors[byteBuf[j]] shr 24) and $FF;
|
|
inc(pb_dstalpha);
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
dest.AlphaChannel.SyncFull();
|
|
end;
|
|
|
|
converter := nil;
|
|
end;
|
|
|
|
|
|
// DestAlpha can be nil
|
|
procedure CopyWICBitmapSourceToIEBitmap(WICImagingFactory: IE_IWICImagingFactory; bitmapSource: IE_IWICBitmapSource; Dest: TIEBaseBitmap; DestAlpha: TIEBaseBitmap; OnProgressFunction: TIEProgressEvent = nil; OnProgressSender: TObject = nil);
|
|
var
|
|
iePixelFormat: TIEPixelFormat;
|
|
hasAlpha: boolean;
|
|
i, j: integer;
|
|
w, h, colorCount: DWORD;
|
|
paletteColors: array of IE_WICColor;
|
|
palette: IE_IWICPalette;
|
|
rc: IE_WICRect;
|
|
lper, per: integer;
|
|
pb_src: pbyte;
|
|
pb_dst: pbyte;
|
|
pb_dstalpha: pbyte;
|
|
rowbuf: array of byte;
|
|
begin
|
|
// get actual pixel format
|
|
iePixelFormat := ConvertWICPixelFormatToIEBitmapPixelFormat(WICImagingFactory, bitmapSource, hasAlpha);
|
|
|
|
// copy pixels
|
|
bitmapSource.GetSize(w, h);
|
|
if assigned(DestAlpha) and (Dest is TIEBitmap) and ((Dest as TIEBitmap).AlphaChannel = DestAlpha) then
|
|
begin
|
|
// DestAlpha belongs to Dest (that is a TIEBitmap, so Dest.AlphaChannel == DestAlpha)
|
|
Dest.Allocate(w, h, iePixelFormat);
|
|
DestAlpha := (Dest as TIEBitmap).AlphaChannel;
|
|
end
|
|
else
|
|
Dest.Allocate(w, h, iePixelFormat);
|
|
rc.X := 0;
|
|
rc.Width := w;
|
|
rc.Height := 1;
|
|
lper := -1;
|
|
for i := 0 to h - 1 do
|
|
begin
|
|
rc.Y := i;
|
|
if hasAlpha and (iePixelFormat = ie24RGB) then
|
|
begin
|
|
SetLength(rowbuf, w * 4);
|
|
bitmapSource.CopyPixels(@rc, w * 4, w * 4, @rowbuf[0]);
|
|
pb_src := @rowbuf[0];
|
|
pb_dst := Dest.ScanLine[i];
|
|
if assigned(DestAlpha) then
|
|
begin
|
|
pb_dstalpha := DestAlpha.ScanLine[i];
|
|
for j := 0 to w - 1 do
|
|
begin
|
|
pb_dst^ := pb_src^; inc(pb_dst); inc(pb_src); // b
|
|
pb_dst^ := pb_src^; inc(pb_dst); inc(pb_src); // g
|
|
pb_dst^ := pb_src^; inc(pb_dst); inc(pb_src); // r
|
|
pb_dstalpha^ := pb_src^; inc(pb_dstalpha); inc(pb_src); // a
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
for j := 0 to w - 1 do
|
|
begin
|
|
pb_dst^ := pb_src^; inc(pb_dst); inc(pb_src); // b
|
|
pb_dst^ := pb_src^; inc(pb_dst); inc(pb_src); // g
|
|
pb_dst^ := pb_src^; inc(pb_dst); inc(pb_src); // r
|
|
inc(pb_src); // bypass alpha
|
|
end;
|
|
end;
|
|
end
|
|
else
|
|
bitmapSource.CopyPixels(@rc, Dest.Rowlen, Dest.Rowlen, Dest.ScanLine[i]);
|
|
if assigned(OnProgressFunction) then
|
|
begin
|
|
per := trunc(i / h * 100.0);
|
|
if per <> lper then
|
|
begin
|
|
lper := per;
|
|
OnProgressFunction(OnProgressSender, per);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// copy palette
|
|
if iePixelFormat = ie8p then
|
|
begin
|
|
palette := nil;
|
|
WICImagingFactory.CreatePalette(palette);
|
|
bitmapSource.CopyPalette(palette);
|
|
palette.GetColorCount(colorCount);
|
|
SetLength(paletteColors, colorCount);
|
|
palette.GetColors(colorCount, @paletteColors[0], colorCount);
|
|
Dest.PaletteUsed := colorCount;
|
|
for i := 0 to colorCount - 1 do
|
|
Dest.Palette[i] := CreateRGB((paletteColors[i] shr 16) and $FF, (paletteColors[i] shr 8) and $FF, paletteColors[i] and $FF);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// TIEWICReader
|
|
|
|
constructor TIEWICReader.Create;
|
|
begin
|
|
inherited Create;
|
|
|
|
fOLEInitialized := Succeeded(OleInitialize(nil));
|
|
|
|
fWICImagingFactory := nil;
|
|
fDecoder := nil;
|
|
fFrame := nil;
|
|
fQueryReader := nil;
|
|
fStream := nil;
|
|
fStreamBase := 0;
|
|
fFileStream := nil;
|
|
|
|
fDPIX := IEGlobalSettings().DefaultDPIX;
|
|
fDPIY := IEGlobalSettings().DefaultDPIY;
|
|
|
|
CoCreateInstance(CLSID_WICImagingFactory, nil, CLSCTX_INPROC_SERVER, IE_IWICImagingFactory, fWICImagingFactory);
|
|
end;
|
|
|
|
|
|
destructor TIEWICReader.Destroy;
|
|
begin
|
|
Close();
|
|
fWICImagingFactory := nil;
|
|
|
|
if fOLEInitialized then
|
|
OleUninitialize;
|
|
|
|
inherited;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEWICReader.Close
|
|
|
|
<FM>Declaration<FC>
|
|
procedure Close;
|
|
|
|
<FM>Description<FN>
|
|
Closes currently open stream or file freeing allocated resources.
|
|
This method is implicitly called by <FC>Free<FN> method.
|
|
|
|
<FM>Example<FC>
|
|
with TIEWICReader.Create do
|
|
begin
|
|
Open('input.hdp', ioHDP);
|
|
GetFrame(0, ImageEnView1.IEBitmap, ImageEnView1.IO.Params);
|
|
Free; // Calls Close() implicitly
|
|
end;
|
|
ImageEnView1.Update;
|
|
!!}
|
|
procedure TIEWICReader.Close;
|
|
begin
|
|
if assigned(fFileStream) then
|
|
FreeAndNil(fFileStream);
|
|
fQueryReader := nil;
|
|
fFrame := nil;
|
|
fDecoder := nil;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEWICReader.IsAvailable
|
|
|
|
<FM>Declaration<FC>
|
|
function IsAvailable: boolean;
|
|
|
|
<FM>Description<FN>
|
|
Returns true if WIC is available. This should always be true on Windows Vista or newer (or Windows XP SP2 with .NET 3.0).
|
|
|
|
See also: <A IEWICAvailable>
|
|
|
|
<FM>Example<FC>
|
|
with TIEWICReader.Create do
|
|
if IsAvailable then
|
|
begin
|
|
Open('input.hdp', ioHDP);
|
|
GetFrame(0, ImageEnView1.IEBitmap, ImageEnView1.IO.Params);
|
|
Free;
|
|
end;
|
|
ImageEnView1.Update;
|
|
!!}
|
|
function TIEWICReader.IsAvailable: boolean;
|
|
begin
|
|
result := (fWICImagingFactory<>nil) and IEWICAvailable();
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEWICReader.Open
|
|
|
|
<FM>Declaration<FC>
|
|
function Open(Stream: TStream; fileType: <A TIOFileType>): boolean; overload;
|
|
function Open(const FileName: WideString; fileType: <A TIOFileType> = ioUnknown): boolean; overload;
|
|
|
|
<FM>Description<FN>
|
|
Opens a stream or file, enabling subsequent calls to <A TIEWICReader.GetFrame>. For streams, the <A TIOFileType> must be specified (one of: ioBMP, ioPNG, ioICO, ioJPEG, ioGIF, ioTIFF, ioHDP). For files, the <A TIOFileType> is based on the file extension if not specified.
|
|
You should call <FC>Free<FN> or <A TIEWICReader.Close> in order to terminate reading.
|
|
|
|
<FM>Example<FC>
|
|
with TIEWICReader.Create do
|
|
begin
|
|
Open('input.hdp', ioHDP);
|
|
GetFrame(0, ImageEnView1.IEBitmap, ImageEnView1.IO.Params);
|
|
Free; // Calls Close() implicitly
|
|
end;
|
|
ImageEnView1.Update;
|
|
!!}
|
|
function TIEWICReader.Open(Stream: TStream; fileType: TIOFileType): boolean;
|
|
var
|
|
DecoderGuid: TGUID;
|
|
begin
|
|
result := false;
|
|
if not IsAvailable() then
|
|
exit;
|
|
|
|
fStream := Stream;
|
|
fStreamBase := Stream.Position;
|
|
|
|
case fileType of
|
|
ioBMP: DecoderGuid := CLSID_WICBmpDecoder;
|
|
ioPNG: DecoderGuid := CLSID_WICPngDecoder;
|
|
ioICO: DecoderGuid := CLSID_WICIcoDecoder;
|
|
ioJPEG: DecoderGuid := CLSID_WICJpegDecoder;
|
|
ioGIF: DecoderGuid := CLSID_WICGifDecoder;
|
|
ioTIFF: DecoderGuid := CLSID_WICTiffDecoder;
|
|
ioHDP: DecoderGuid := CLSID_WICWmpDecoder;
|
|
else
|
|
exit;
|
|
end;
|
|
fDecoder := nil;
|
|
fWICImagingFactory.CreateDecoderFromStream(TStreamAdapter.Create(Stream), DecoderGuid, WICDecodeMetadataCacheOnLoad, fDecoder);
|
|
|
|
if fDecoder = nil then
|
|
exit;
|
|
|
|
result := true;
|
|
end;
|
|
|
|
|
|
function TIEWICReader.Open(const FileName: WideString; fileType: TIOFileType = ioUnknown): boolean;
|
|
begin
|
|
if fileType = ioUnknown then
|
|
fileType := IEFilenameToInternalFileType( Filename );
|
|
fFileStream := TIEWideFileStream.create(FileName, fmOpenRead or fmShareDenyWrite);
|
|
result := Open(fFileStream, fileType);
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEWICReader.FrameCount
|
|
|
|
<FM>Declaration<FC>
|
|
property FrameCount: integer;
|
|
|
|
<FM>Description<FN>
|
|
Returns the total number of frames in the image.
|
|
|
|
<FM>Example<FC>
|
|
with TIEWICReader.Create do
|
|
begin
|
|
Open('input.tif', ioTIFF);
|
|
fCount := FrameCount;
|
|
for i := 0 to fCount-1 do
|
|
GetFrame(i, bitmap[i]);
|
|
Free;
|
|
end;
|
|
!!}
|
|
function TIEWICReader.GetFrameCount: integer;
|
|
begin
|
|
result := 0;
|
|
if not IsAvailable() or not assigned(fDecoder) then
|
|
exit;
|
|
fDecoder.GetFrameCount(result);
|
|
end;
|
|
|
|
|
|
|
|
{!!
|
|
<FS>TIEWICReader.GetFrame
|
|
|
|
<FM>Declaration<FC>
|
|
procedure GetFrame(frameIndex: integer; destBitmap: <A TIEBitmap>; IOParams: <A TIOParams> = nil; Aborting: pboolean = nil);
|
|
|
|
<FM>Description<FN>
|
|
Retrieves the specified frame of the image.
|
|
If <FC>IOParams<FN> is specified then it is filled also with EXIF metatags.
|
|
|
|
See also: <A TIEWICReader.Open>
|
|
|
|
<FM>Example<FC>
|
|
with TIEWICReader.Create do
|
|
begin
|
|
Open('input.tif', ioTIFF);
|
|
fCount := FrameCount;
|
|
for i := 0 to fCount-1 do
|
|
GetFrame(i, bitmap[i]);
|
|
Free;
|
|
end;
|
|
!!}
|
|
// IOParams can be nil
|
|
// Aborting can be nil
|
|
procedure TIEWICReader.GetFrame(frameIndex: integer; destBitmap: TIEBitmap; IOParams: TIOParams; Aborting: pboolean);
|
|
var
|
|
thumb: IE_IWICBitmapSource;
|
|
lp: int64;
|
|
nativePixelFormat: boolean;
|
|
begin
|
|
if not IsAvailable() or not assigned(fDecoder) then
|
|
begin
|
|
if assigned(Aborting) then
|
|
Aborting^ := true;
|
|
exit;
|
|
end;
|
|
|
|
// load frame "frameIndex"
|
|
fFrame := nil;
|
|
fDecoder.GetFrame(frameIndex, fFrame);
|
|
|
|
// get info
|
|
fFrame.GetResolution(fDPIX, fDPIY);
|
|
|
|
// get metadata
|
|
fQueryReader := nil;
|
|
fFrame.GetMetadataQueryReader(fQueryReader);
|
|
|
|
if assigned(IOParams) and not IOParams.IsNativePixelFormat then
|
|
nativePixelFormat := false
|
|
else
|
|
nativePixelFormat := true;
|
|
|
|
if assigned(IOParams) and IOParams.GetThumbnail then
|
|
begin
|
|
// get thumbnail of this frame
|
|
thumb := nil;
|
|
fFrame.GetThumbnail(thumb);
|
|
if assigned(thumb) then
|
|
// thumb available, get it
|
|
ConvertWICBitmapToIEBitmap(fWICImagingFactory, thumb, destBitmap, nativePixelFormat)
|
|
else
|
|
// thumb not available, get full frame
|
|
ConvertWICBitmapToIEBitmap(fWICImagingFactory, fFrame, destBitmap, nativePixelFormat);
|
|
end
|
|
else
|
|
// get full image
|
|
ConvertWICBitmapToIEBitmap(fWICImagingFactory, fFrame, destBitmap, nativePixelFormat);
|
|
|
|
if assigned(IOParams) then
|
|
begin
|
|
lp := fStream.Position;
|
|
fStream.Position := fStreamBase;
|
|
IELoadParamsFromTIFF(fStream, IOParams, IOParams.ImageIndex); // load EXIF and other TIFF compatible tags
|
|
fStream.Position := lp; // restores as WIC expects
|
|
// assign non exif tags
|
|
IOParams.BitsPerSample := destBitmap.BitCount div destBitmap.ChannelCount;
|
|
IOParams.SamplesPerPixel := destBitmap.ChannelCount;
|
|
IOParams.OriginalWidth := FrameWidth;
|
|
IOParams.OriginalHeight := FrameHeight;
|
|
IOParams.Width := destBitmap.Width;
|
|
IOParams.Height := destBitmap.Height;
|
|
IOParams.DpiX := trunc(DPIX);
|
|
IOParams.DpiY := trunc(DPIY);
|
|
end;
|
|
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEWICReader.FrameWidth
|
|
|
|
<FM>Declaration<FC>
|
|
function FrameWidth(): DWORD;
|
|
|
|
<FM>Description<FN>
|
|
Retrieves the width of the frame.
|
|
!!}
|
|
function TIEWICReader.FrameWidth(): DWORD;
|
|
var
|
|
h: DWORD;
|
|
begin
|
|
result := 0;
|
|
if assigned(fFrame) then
|
|
fFrame.GetSize(result, h);
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEWICReader.FrameHeight
|
|
|
|
<FM>Declaration<FC>
|
|
function FrameHeight(): DWORD;
|
|
|
|
<FM>Description<FN>
|
|
Retrieves the height of the frame.
|
|
!!}
|
|
function TIEWICReader.FrameHeight(): DWORD;
|
|
var
|
|
w: DWORD;
|
|
begin
|
|
result := 0;
|
|
if assigned(fFrame) then
|
|
fFrame.GetSize(w, result);
|
|
end;
|
|
|
|
|
|
function TIEWICReader.QueryMetadata(const query: string): PROPVARIANT;
|
|
begin
|
|
if not IsAvailable() or not assigned(fDecoder) then
|
|
exit;
|
|
|
|
if assigned(fQueryReader) then
|
|
begin
|
|
FillChar(result, sizeof(PROPVARIANT), 0);
|
|
fQueryReader.GetMetadataByName(pwchar(WideString(query)), result);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// TIEWICWriter
|
|
|
|
constructor TIEWICWriter.Create;
|
|
begin
|
|
inherited Create;
|
|
|
|
fOLEInitialized := Succeeded(OleInitialize(nil));
|
|
|
|
fWICImagingFactory := nil;
|
|
fDPIX := IEGlobalSettings().DefaultDPIX;
|
|
fDPIY := IEGlobalSettings().DefaultDPIY;
|
|
fImageQuality := -1;
|
|
fCompressionQuality := -1;
|
|
fLossless := false;
|
|
UseCodecOptions := false;
|
|
fQuality := 1;
|
|
fOverlap := 1;
|
|
fSubsampling := 3;
|
|
fHorizontalTileSlices := 0;
|
|
fVerticalTileSlices := 0;
|
|
fFrequencyOrder := true;
|
|
fTIFFCompressionMethod := ieWICTiffCompressionNone;
|
|
fEncoder := nil;
|
|
fStream := nil;
|
|
fStreamBase := 0;
|
|
fFileStream := nil;
|
|
|
|
CoCreateInstance(CLSID_WICImagingFactory, nil, CLSCTX_INPROC_SERVER, IE_IWICImagingFactory, fWICImagingFactory);
|
|
end;
|
|
|
|
|
|
destructor TIEWICWriter.Destroy;
|
|
begin
|
|
Close();
|
|
fWICImagingFactory := nil;
|
|
|
|
if fOLEInitialized then
|
|
OleUninitialize;
|
|
|
|
inherited;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEWICWriter.IsAvailable
|
|
|
|
<FM>Declaration<FC>
|
|
function IsAvailable: boolean;
|
|
|
|
<FM>Description<FN>
|
|
Returns true if WIC is available. This should always be true on Windows Vista or newer (or Windows XP SP2 with .NET 3.0).
|
|
|
|
See also: <A IEWICAvailable>
|
|
|
|
<FM>Example<FC>
|
|
with TIEWICWriter.Create do
|
|
if IsAvailable then
|
|
begin
|
|
Open('output.hdp', ioHDP);
|
|
PutFrame(ImageEnView1.IEBitmap, ImageEnView1.IO.Params);
|
|
Free;
|
|
end;
|
|
!!}
|
|
function TIEWICWriter.IsAvailable: boolean;
|
|
begin
|
|
result := fWICImagingFactory <> nil;
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEWICWriter.Open
|
|
|
|
<FM>Declaration<FC>
|
|
function Open(Stream: TStream; fileType: <A TIOFileType>): boolean;
|
|
function Open(const FileName: WideString; fileType: <A TIOFileType>): boolean;
|
|
|
|
<FM>Description<FN>
|
|
Creates specified image format in stream or file, enabling subsequent calls to <A TIEWICWriter.PutFrame> calls.
|
|
You should call <FC>Free<FN> or <A TIEWICWriter.Close> in order to commit changes.
|
|
|
|
<FM>Example<FC>
|
|
// saves ImageEnView1 to output.hdp, which is the same as ImageEnView1.IO.SaveToFile('output.hdp')
|
|
with TIEWICWriter.Create do
|
|
begin
|
|
Open('output.hdp', ioHDP);
|
|
PutFrame(ImageEnView1.IEBitmap, ImageEnView1.IO.Params);
|
|
Free;
|
|
end;
|
|
!!}
|
|
function TIEWICWriter.Open(Stream: TStream; fileType: TIOFileType): boolean;
|
|
var
|
|
ContainerGuid: TGUID;
|
|
begin
|
|
result := false;
|
|
if not IsAvailable() then
|
|
exit;
|
|
|
|
fStream := Stream;
|
|
fStreamBase := Stream.Position;
|
|
|
|
case fileType of
|
|
ioBMP: ContainerGuid := GUID_ContainerFormatBmp;
|
|
ioPNG: ContainerGuid := GUID_ContainerFormatPng;
|
|
ioJPEG: ContainerGuid := GUID_ContainerFormatJpeg;
|
|
ioGIF: ContainerGuid := GUID_ContainerFormatGif;
|
|
ioTIFF: ContainerGuid := GUID_ContainerFormatTiff;
|
|
ioHDP: ContainerGuid := GUID_ContainerFormatWmp;
|
|
else
|
|
exit;
|
|
end;
|
|
fEncoder := nil;
|
|
fWICImagingFactory.CreateEncoder(ContainerGuid, GUID_VendorMicrosoft, fEncoder);
|
|
|
|
if fEncoder = nil then
|
|
exit;
|
|
|
|
fEncoder.Initialize(TStreamAdapter.Create(Stream), WICBitmapEncoderNoCache);
|
|
|
|
result := true;
|
|
end;
|
|
|
|
|
|
function TIEWICWriter.Open(const FileName: WideString; fileType: TIOFileType): boolean;
|
|
begin
|
|
fFileStream := TIEWideFileStream.Create(FileName, fmCreate);
|
|
result := Open(fFileStream, fileType);
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEWICWriter.Close
|
|
|
|
<FM>Declaration<FC>
|
|
procedure Close;
|
|
|
|
<FM>Description<FN>
|
|
Commit changes to output stream or file.
|
|
This method is implicitly called by <FC>Free<FN> method.
|
|
!!}
|
|
procedure TIEWICWriter.Close;
|
|
begin
|
|
if assigned(fEncoder) then
|
|
begin
|
|
fEncoder.Commit;
|
|
fEncoder := nil;
|
|
end;
|
|
if assigned(fFileStream) then
|
|
FreeAndNil(fFileStream);
|
|
end;
|
|
|
|
|
|
procedure SetPropertyBag(prop: IE_IPropertyBag2; const name: string; value: variant; propType: TVarType);
|
|
var
|
|
propName: IE_PROPBAG2;
|
|
propValue: PROPVARIANT;
|
|
begin
|
|
FillChar(propName, sizeof(IE_PROPBAG2), 0);
|
|
propName.dwType := PROPBAG2_TYPE_DATA;
|
|
propName.vt := propType;
|
|
propName.pstrName := pwchar(WideString(name));
|
|
propValue.vt := propType;
|
|
case propType of
|
|
VT_R4: propValue.fltVal := value;
|
|
VT_BOOL: propValue.boolVal := value;
|
|
VT_UI1: propValue.bVal := value;
|
|
VT_UI2: propValue.uiVal := value;
|
|
else
|
|
assert(false); // unsupported property type
|
|
end;
|
|
prop.Write(1, @propName, @propValue);
|
|
end;
|
|
|
|
|
|
{!!
|
|
<FS>TIEWICWriter.PutFrame
|
|
|
|
<FM>Declaration<FC>
|
|
procedure PutFrame(srcBitmap: <A TIEBitmap>; IOParams: <A TIOParams> = nil);
|
|
|
|
<FM>Description<FN>
|
|
Adds a new frame to current open stream or file.
|
|
You can call multiple <FC>PutFrame<FN> only if the writing file format accepts more than one frame.
|
|
If <FC>IOParams<FN> is specified parameters (DPI, compression) are read from it.
|
|
<FC>PutFrame<FN> doesn't write EXIF metatags: you must use <A TImageEnIO.InjectTIFFEXIF> to inject EXIF in HDPhoto or TIFF files.
|
|
It is important that you close the stream/file before inject EXIF metatags.
|
|
|
|
<FM>Example<FC>
|
|
// saves ImageEnView1 to output.hdp, which is the same as ImageEnView1.IO.SaveToFile('output.hdp')
|
|
with TIEWICWriter.Create do
|
|
begin
|
|
Open('output.hdp', ioHDP);
|
|
PutFrame(ImageEnView1.IEBitmap, ImageEnView1.IO.Params);
|
|
Free;
|
|
end;
|
|
ImageEnView1.IO.InjectTIFFEXIF('output.hdp');
|
|
!!}
|
|
// IOParams can be nil
|
|
// doesn't save/inject exif info
|
|
// Note: for some unknown reason it is not possible to include multiple frames in HDP files
|
|
procedure TIEWICWriter.PutFrame(srcBitmap: TIEBitmap; IOParams: TIOParams);
|
|
const
|
|
TIFFCOMPRESSIONMETHODTOINT: array [TIEWICTIFFCompressionMethod] of integer = (0, 1, 2, 3, 4, 5, 6);
|
|
var
|
|
frame: IE_IWICBitmapFrameEncode;
|
|
prop: IE_IPropertyBag2;
|
|
w, h, i: integer;
|
|
pixelFormatGUID: TGUID;
|
|
begin
|
|
frame := nil;
|
|
prop := nil;
|
|
fEncoder.CreateNewFrame(frame, prop);
|
|
|
|
if assigned(frame) and assigned(prop) then
|
|
begin
|
|
|
|
if assigned(IOParams) then
|
|
begin
|
|
DPIX := IOParams.DpiX;
|
|
DPIY := IOParams.DpiY;
|
|
ImageQuality := IOParams.HDP_ImageQuality;
|
|
Lossless := IOParams.HDP_Lossless;
|
|
end;
|
|
|
|
// Canonical codec properties
|
|
if fImageQuality>=0.0 then
|
|
SetPropertyBag(prop, 'ImageQuality', fImageQuality, VT_R4);
|
|
if fCompressionQuality>=0.0 then
|
|
SetPropertyBag(prop, 'CompressionQuality', fCompressionQuality, VT_R4);
|
|
SetPropertyBag(prop, 'Lossless', fLossless, VT_BOOL);
|
|
|
|
// HDP codec properties
|
|
if fUseCodecOptions then
|
|
begin
|
|
SetPropertyBag(prop, 'UseCodecOptions', fUseCodecOptions, VT_BOOL);
|
|
SetPropertyBag(prop, 'Quality', fQuality, VT_UI1);
|
|
SetPropertyBag(prop, 'Overlap', fOverlap, VT_UI1);
|
|
SetPropertyBag(prop, 'Subsampling', fSubsampling, VT_UI1);
|
|
end;
|
|
SetPropertyBag(prop, 'HorizontalTileSlices', fHorizontalTileSlices, VT_UI2);
|
|
SetPropertyBag(prop, 'VerticalTileSlices', fVerticalTileSlices, VT_UI2);
|
|
SetPropertyBag(prop, 'FrequencyOrder', fFrequencyOrder, VT_BOOL);
|
|
|
|
// TIFF codec properties
|
|
SetPropertyBag(prop, 'TiffCompressionMethod', TIFFCOMPRESSIONMETHODTOINT[fTIFFCompressionMethod], VT_UI1);
|
|
|
|
frame.Initialize(prop);
|
|
|
|
w := srcBitmap.Width;
|
|
h := srcBitmap.Height;
|
|
frame.SetSize(w, h);
|
|
|
|
frame.SetResolution(fDPIX, fDPIY);
|
|
|
|
case srcBitmap.PixelFormat of
|
|
ie1g: pixelFormatGUID := GUID_WICPixelFormatBlackWhite;
|
|
ie8p: assert(false); // unsupported
|
|
ie8g: pixelFormatGUID := GUID_WICPixelFormat8bppGray;
|
|
ie16g: pixelFormatGUID := GUID_WICPixelFormat16bppGray;
|
|
ie24RGB: pixelFormatGUID := GUID_WICPixelFormat24bppBGR;
|
|
ie32f: assert(false); // unsupported
|
|
ieCMYK: pixelFormatGUID := GUID_WICPixelFormat32bppCMYK;
|
|
ie48RGB: pixelFormatGUID := GUID_WICPixelFormat48bppRGB;
|
|
ieCIELab: assert(false); // unsupported
|
|
ie32RGB: assert(false); // unsupported
|
|
end;
|
|
frame.SetPixelFormat(pixelFormatGUID);
|
|
|
|
for i := 0 to h-1 do
|
|
frame.WritePixels(1, srcBitmap.Rowlen, srcBitmap.Rowlen, srcBitmap.ScanLine[i]);
|
|
|
|
frame.Commit;
|
|
|
|
end;
|
|
|
|
frame := nil;
|
|
prop := nil;
|
|
|
|
end;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
procedure IEHDPRead(Stream: TStream; Bitmap: TIEBitmap; var IOParams: TIOParams; var xProgress: TProgressRec; Preview: boolean);
|
|
|
|
procedure DoProgress(val: integer);
|
|
begin
|
|
with xProgress do
|
|
if assigned(fOnProgress) then
|
|
fOnProgress(Sender, 0);
|
|
end;
|
|
|
|
var
|
|
wic: TIEWICReader;
|
|
begin
|
|
DoProgress(0);
|
|
wic := TIEWICReader.Create;
|
|
try
|
|
wic.Open(Stream, ioHDP);
|
|
wic.GetFrame(IOParams.ImageIndex, Bitmap, IOParams, xProgress.Aborting); // exif loaded in GetFrame
|
|
finally
|
|
wic.Free; // wic.Close called in Free
|
|
DoProgress(100);
|
|
end;
|
|
end;
|
|
|
|
|
|
// support writing of a single page
|
|
procedure IEHDPWrite(Stream: TStream; Bitmap: TIEBitmap; var IOParams: TIOParams; var xProgress: TProgressRec);
|
|
|
|
procedure DoProgress(val: integer);
|
|
begin
|
|
with xProgress do
|
|
if assigned(fOnProgress) then
|
|
fOnProgress(Sender, 0);
|
|
end;
|
|
|
|
var
|
|
wic: TIEWICWriter;
|
|
lp: int64;
|
|
begin
|
|
if not IEWICAvailable() then
|
|
begin
|
|
xProgress.Aborting^ := true;
|
|
exit;
|
|
end;
|
|
|
|
DoProgress(0);
|
|
lp := Stream.Position;
|
|
wic := TIEWICWriter.Create;
|
|
try
|
|
wic.Open(Stream, ioHDP);
|
|
wic.PutFrame(Bitmap, IOParams); // exif not written in PutFrame
|
|
finally
|
|
wic.Free;
|
|
Stream.Position := lp;
|
|
{$ifdef IEINCLUDETIFFHANDLER}
|
|
IEInjectTIFFEXIF(Stream, Stream, '', '', 0, IOParams);
|
|
{$endif}
|
|
DoProgress(100);
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
function IEHDPFrameCount(const FileName: WideString): integer;
|
|
var
|
|
wic: TIEWICReader;
|
|
fs: TIEWideFileStream;
|
|
begin
|
|
if IEWICAvailable() then
|
|
begin
|
|
wic := TIEWICReader.Create;
|
|
fs := TIEWideFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
|
|
try
|
|
wic.Open(fs, ioHDP);
|
|
result := wic.FrameCount;
|
|
finally
|
|
wic.Free;
|
|
fs.Free;
|
|
end;
|
|
end
|
|
else
|
|
result := 0;
|
|
end;
|
|
|
|
var iegWICAvailable: boolean = false;
|
|
iegWICTested: boolean = false;
|
|
|
|
|
|
{!!
|
|
<FS>IEWICAvailable
|
|
|
|
<FM>Declaration<FC>
|
|
function IEWICAvailable: boolean;
|
|
|
|
<FM>Description<FN>
|
|
Returns True if WIC interfaces are available. This means that Microsoft HD Photo is also available.
|
|
!!}
|
|
{$ifdef IEDOTNETVERSION}
|
|
function IEWICAvailable: boolean;
|
|
begin
|
|
iegWICTested := true;
|
|
iegWICAvailable := true;
|
|
result := true;
|
|
end;
|
|
{$else}
|
|
function IEWICAvailable: boolean;
|
|
var
|
|
factory: IE_IWICImagingFactory;
|
|
oleInit: boolean;
|
|
begin
|
|
if not iegWICTested then
|
|
begin
|
|
oleInit := Succeeded(OleInitialize(nil));
|
|
|
|
try
|
|
factory := nil;
|
|
CoCreateInstance(CLSID_WICImagingFactory, nil, CLSCTX_INPROC_SERVER, IE_IWICImagingFactory, factory);
|
|
iegWICAvailable := assigned(factory);
|
|
factory := nil;
|
|
|
|
finally
|
|
if oleInit then
|
|
OleUninitialize;
|
|
end;
|
|
|
|
iegWICTested := true;
|
|
end;
|
|
result := iegWICAvailable;
|
|
end;
|
|
{$endif}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
constructor TIEWICBitmapWrapper.Create(Bitmap: TIEBaseBitmap; Alpha: TIEBaseBitmap);
|
|
begin
|
|
inherited Create();
|
|
m_bitmap := Bitmap;
|
|
m_alpha := Alpha;
|
|
end;
|
|
|
|
destructor TIEWICBitmapWrapper.Destroy();
|
|
begin
|
|
inherited;
|
|
end;
|
|
|
|
function TIEWICBitmapWrapper.GetSize(out puiWidth: DWORD; out puiHeight: DWORD): HResult;
|
|
begin
|
|
puiWidth := m_bitmap.Width;
|
|
puiHeight := m_bitmap.Height;
|
|
result := S_OK;
|
|
end;
|
|
|
|
function TIEWICBitmapWrapper.GetPixelFormat(out pPixelFormat: TGUID): HResult;
|
|
begin
|
|
result := S_OK;
|
|
case m_bitmap.PixelFormat of
|
|
ie1g: pPixelFormat := GUID_WICPixelFormatBlackWhite;
|
|
ie8g: pPixelFormat := GUID_WICPixelFormat8bppGray;
|
|
ie8p: pPixelFormat := GUID_WICPixelFormat8bppIndexed;
|
|
ie16g: pPixelFormat := GUID_WICPixelFormat16bppGray;
|
|
ie24RGB:
|
|
begin
|
|
if assigned(m_alpha) then
|
|
pPixelFormat := GUID_WICPixelFormat32bppBGRA
|
|
else
|
|
pPixelFormat := GUID_WICPixelFormat24bppBGR;
|
|
end;
|
|
ieCMYK: pPixelFormat := GUID_WICPixelFormat32bppCMYK;
|
|
ie48RGB: pPixelFormat := GUID_WICPixelFormat48bppRGB;
|
|
else
|
|
result := E_NOTIMPL;
|
|
end;
|
|
end;
|
|
|
|
function TIEWICBitmapWrapper.GetResolution(out pDpiX: double; out pDpiY: double): HResult;
|
|
begin
|
|
pDpiX := IEGlobalSettings().DefaultDPIX;
|
|
pDpiY := IEGlobalSettings().DefaultDPIY;
|
|
result := S_OK;
|
|
end;
|
|
|
|
function TIEWICBitmapWrapper.CopyPalette(pIPalette: IE_IWICPalette): HResult;
|
|
var
|
|
colors: array of IE_WICColor;
|
|
i: integer;
|
|
begin
|
|
if m_bitmap.PixelFormat = ie8p then
|
|
begin
|
|
SetLength(colors, m_bitmap.PaletteUsed);
|
|
for i := 0 to m_bitmap.PaletteUsed - 1 do
|
|
colors[i] := m_bitmap.Palette[i].b or (m_bitmap.Palette[i].g shl 8) or (m_bitmap.Palette[i].r shl 16);
|
|
pIPalette.InitializeCustom(@colors[0], m_bitmap.PaletteUsed);
|
|
result := S_OK;
|
|
end
|
|
else
|
|
result := WINCODEC_ERR_PALETTEUNAVAILABLE;
|
|
end;
|
|
|
|
function TIEWICBitmapWrapper.CopyPixels(prc: IE_PWICRect; cbStride: DWORD; cbBufferSize: DWORD; pbBuffer: pbyte): HResult;
|
|
var
|
|
x, y, width, height: integer;
|
|
row: integer;
|
|
dstrow: DWORD;
|
|
dst, src: pbyte;
|
|
i: integer;
|
|
pb: pbyte;
|
|
begin
|
|
if prc <> nil then
|
|
begin
|
|
x := prc^.X;
|
|
y := prc^.Y;
|
|
width := prc^.Width;
|
|
height := prc^.Height;
|
|
end
|
|
else
|
|
begin
|
|
x := 0;
|
|
y := 0;
|
|
width := m_bitmap.Width;
|
|
height := m_bitmap.Height;
|
|
end;
|
|
dstrow := 0;
|
|
for row := y to y + height - 1 do
|
|
begin
|
|
dst := pbBuffer;
|
|
inc(dst, dstrow * cbStride);
|
|
if m_bitmap.PixelFormat = ie1g then
|
|
begin
|
|
IECopyBits_large(dst, m_bitmap.ScanLine[row], 0, x, width, cbStride);
|
|
end
|
|
else
|
|
if (m_bitmap.PixelFormat = ie24RGB) and assigned(m_alpha) then
|
|
begin
|
|
src := m_bitmap.ScanLine[row];
|
|
inc(src, x * sizeof(TRGB));
|
|
pb := m_alpha.ScanLine[row]; // alpha channel
|
|
inc(pb, x);
|
|
for i := 0 to width - 1 do
|
|
begin
|
|
dst^ := src^; inc(dst); inc(src); // b
|
|
dst^ := src^; inc(dst); inc(src); // g
|
|
dst^ := src^; inc(dst); inc(src); // r
|
|
dst^ := pb^; inc(dst); inc(pb); // a
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
src := m_bitmap.ScanLine[row];
|
|
inc(src, x * m_bitmap.BitCount div 8);
|
|
CopyMemory(dst, src, width * m_bitmap.BitCount div 8);
|
|
if m_bitmap.PixelFormat = ieCMYK then
|
|
begin
|
|
// CMYK channels need to be inverted
|
|
pb := dst;
|
|
for i := width * 4 - 1 downto 0 do
|
|
begin
|
|
pb^ := 255 - pb^;
|
|
inc(pb);
|
|
end;
|
|
end;
|
|
end;
|
|
inc(dstrow);
|
|
end;
|
|
result := S_OK;
|
|
end;
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// TIEWICBaseFunctionality
|
|
|
|
constructor TIEWICBaseFunctionality.Create();
|
|
begin
|
|
inherited Create();
|
|
m_OLEInitialized := Succeeded(OleInitialize(nil));
|
|
m_WICImagingFactory := nil;
|
|
CoCreateInstance(CLSID_WICImagingFactory, nil, CLSCTX_INPROC_SERVER, IE_IWICImagingFactory, m_WICImagingFactory);
|
|
end;
|
|
|
|
|
|
destructor TIEWICBaseFunctionality.Destroy();
|
|
begin
|
|
m_WICImagingFactory := nil;
|
|
if m_OLEInitialized then
|
|
OleUninitialize();
|
|
inherited;
|
|
end;
|
|
|
|
|
|
function TIEWICBaseFunctionality.IsAvailable(): boolean;
|
|
begin
|
|
result := m_WICImagingFactory <> nil;
|
|
end;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// TIEWICFormatConverter
|
|
|
|
constructor TIEWICFormatConverter.Create();
|
|
begin
|
|
inherited Create();
|
|
m_paletteType := IE_WICBitmapPaletteTypeMedianCut;
|
|
m_ditherType := IE_WICBitmapDitherTypeSolid;
|
|
m_palette := nil;
|
|
end;
|
|
|
|
|
|
procedure TIEWICFormatConverter.SetPalette(Palette: array of TRGB);
|
|
var
|
|
paletteColors: array of IE_WICColor;
|
|
paletteLength: integer;
|
|
i: integer;
|
|
begin
|
|
paletteLength := length(Palette);
|
|
if paletteLength > 0 then
|
|
begin
|
|
m_WICImagingFactory.CreatePalette(m_palette);
|
|
SetLength(paletteColors, paletteLength);
|
|
for i := 0 to paletteLength - 1 do
|
|
paletteColors[i] := Palette[i].b or (Palette[i].g shl 8) or (Palette[i].r shl 16);
|
|
m_palette.InitializeCustom(@paletteColors[0], paletteLength);
|
|
end
|
|
else
|
|
m_palette := nil;
|
|
end;
|
|
|
|
|
|
// cannot convert to CMYK (from CMYK is supported)
|
|
function TIEWICFormatConverter.Convert(Source: TIEBitmap; Dest: TIEBitmap; DestPixelFormat: TIEPixelFormat; CheckParametersOnly: boolean; OnProgressFunction: TIEProgressEvent; OnProgressSender: TObject): boolean;
|
|
var
|
|
sourceWrapper: TIEWICBitmapWrapper;
|
|
converter: IE_IWICFormatConverter;
|
|
dstPixelFormat: TGUID;
|
|
begin
|
|
result := false;
|
|
|
|
converter := nil;
|
|
m_WICImagingFactory.CreateFormatConverter(converter);
|
|
|
|
sourceWrapper := TIEWICBitmapWrapper.Create(Source, Source.AlphaChannelOpt);
|
|
dstPixelFormat := ConvertIEBitmapPixelFormatToWICPixelFormat(DestPixelFormat);
|
|
if SUCCEEDED(converter.Initialize(sourceWrapper, dstPixelFormat, m_ditherType, m_palette, 0.0, m_paletteType)) then
|
|
begin
|
|
if not CheckParametersOnly then
|
|
CopyWICBitmapSourceToIEBitmap(m_WICImagingFactory, converter, Dest, nil, OnProgressFunction, OnProgressSender);
|
|
result := true;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// TIEWICBitmapScaler
|
|
|
|
function TIEWICBitmapScaler.Resample(Source: TIEBaseBitmap; SourceAlpha: TIEBaseBitmap; Dest: TIEBaseBitmap; DestAlpha: TIEBaseBitmap; Width: DWORD; Height: DWORD; Mode: IE_WICBitmapInterpolationMode; OnProgressFunction: TIEProgressEvent; OnProgressSender: TObject): boolean;
|
|
var
|
|
sourceWrapper: TIEWICBitmapWrapper;
|
|
scaler: IE_IWICBitmapScaler;
|
|
begin
|
|
result := false;
|
|
|
|
scaler := nil;
|
|
m_WICImagingFactory.CreateBitmapScaler(scaler);
|
|
|
|
sourceWrapper := TIEWICBitmapWrapper.Create(Source, SourceAlpha);
|
|
if SUCCEEDED(scaler.Initialize(sourceWrapper, Width, Height, Mode)) then
|
|
begin
|
|
CopyWICBitmapSourceToIEBitmap(m_WICImagingFactory, scaler, Dest, DestAlpha, OnProgressFunction, OnProgressSender);
|
|
result := true;
|
|
end;
|
|
end;
|
|
|
|
|
|
// just an helper for TIEWICBitmapScaler
|
|
// FilterType can be: rfWICNearestNeighbor, rfWICLinear, rfWICCubic, rfWICFant
|
|
procedure IEWICResample(SrcImg: TIEBaseBitmap; DstImg: TIEBaseBitmap; SrcAlpha: TIEBaseBitmap; FilterType: TResampleFilter; OnProgressFunction: TIEProgressEvent; OnProgressSender: TObject);
|
|
var
|
|
scaler: TIEWICBitmapScaler;
|
|
mode: IE_WICBitmapInterpolationMode;
|
|
begin
|
|
scaler := TIEWICBitmapScaler.Create();
|
|
try
|
|
mode := 0;
|
|
case FilterType of
|
|
rfWICNearestNeighbor: mode := IE_WICBitmapInterpolationModeNearestNeighbor;
|
|
rfWICLinear: mode := IE_WICBitmapInterpolationModeLinear;
|
|
rfWICCubic: mode := IE_WICBitmapInterpolationModeCubic;
|
|
rfWICFant: mode := IE_WICBitmapInterpolationModeFant;
|
|
end;
|
|
scaler.Resample(SrcImg, SrcAlpha, DstImg, nil, DstImg.Width, DstImg.Height, Mode, OnProgressFunction, OnProgressSender);
|
|
finally
|
|
scaler.Free();
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
{$ELSE} // {$ifdef IEINCLUDEWIC}
|
|
|
|
interface
|
|
|
|
function IEWICAvailable: boolean;
|
|
|
|
|
|
implementation
|
|
|
|
|
|
function IEWICAvailable: boolean;
|
|
begin
|
|
result := false;
|
|
end;
|
|
|
|
{$ENDIF}
|
|
|
|
|
|
end.
|
|
|