Reputation:
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?
Upvotes: 3
Views: 2346
Reputation: 88
In Delphi 11, you can use TWicImage
in unit Graphics.
First, you have to get the number of pages in the TIFF file to check if it's possible to load it, and then load the page (FrameIndex range is 0 to FrameCount-1).
It will be something like this:
procedure loadTiff(imagen:TImage; tiffFilename: String; pagenumber: integer);
var
wicImg: TWicImage;
begin
wicImg:= TWicImage.create;
wicImg.loadFromFile(tiffFilename);
if wicImg.frameCount > pageNumber then
begin
wicImg.frameIndex:= pageNumber-1;
wicImg.loadFromFile(tiffFilename);
end;
imagen.picture.bitmap.assign(wicImg);
wicImg.free;
end;
If you already know the number of pages, you can load the image without checking if its out of range.
Upvotes: 1
Reputation: 54832
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.
Upvotes: 4