I have an image file (.tiff) which has 4 images. I can not view or display these 4 images in a TImage. The TImage component display only the first frame.
how to display an image by image?
VCL supports tif images through Windows Imaging Component which is encapsulated by a TWICImage
. However, although trivial, VCL has left out frame support of WIC (which is the term MS documentation uses to refer to multiple images in an image).
Below quote is from 'Vcl.Graphics.pas' of XE2.
procedure TWICImage.LoadFromStream(Stream: TStream);
var
..
BitmapDecoder: IWICBitmapDecoder;
...
begin
...
WicCheck(BitmapDecoder.GetFrame(0, LBitmapFrame));
...
end;
I quoted only a single line which immediately displays the problem. The 'decoder' is able to provide total frame count information and to retrieve any single one of them. But, as coded, only the first one is ever used.
It is still possible to use TWICImage
itself to retrieve a frame and then assign it to the picture of an TImage
. Below is my attempt of doing so, it essentially duplicates the code in TWICImage.LoadFromStream
, with the difference that only the second frame is ever used :). Anyway, it should be easy to modularize to be able to get frame count and display the one required.
type
TForm1 = class(TForm)
Image1: TImage;
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
WICImage: TWICImage;
end;
var
Form1: TForm1;
implementation
uses
activex, wincodec, consts;
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
procedure Check(Result: HRESULT);
begin
if Failed(Result) then
raise EInvalidGraphic.Create(SInvalidImage);
end;
var
fs: TFileStream;
Adapter: IStream;
Decoder: IWICBitmapDecoder;
Frame: IWICBitmapFrameDecode;
WICBmp: IWICBitmap;
Width, Height: DWORD;
begin
fs := TFileStream.Create('....tif', fmShareDenyWrite);
try
Adapter := TStreamAdapter.Create(fs);
Check(WICImage.ImagingFactory.CreateDecoderFromStream(Adapter,
GUID_ContainerFormatTiff, WICDecodeMetadataCacheOnDemand, Decoder));
Check(Decoder.GetFrame(1, Frame));
Check(WICImage.ImagingFactory.CreateBitmapFromSource(Frame,
WICBitmapCacheOnLoad, WICBmp));
Check(WICBmp.GetSize(Width, Height));
Image1.Width := Width;
Image1.Height := Height;
WICImage.Handle := WICBmp;
Image1.Picture.Bitmap.Assign(WICImage);
finally
fs.Free;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
WICImage := TWICImage.Create;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
WICImage.Free;
end;
Note that it is not my preference to have the WIC image as a field of the form and not as a local variable. But I kept getting an AV and runtime error at program shutdown which I couldn't resolve when it is a local.