3

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?

kobik
  • 21,001
  • 4
  • 61
  • 121
  • Perhaps you need to use `Stretch` and `Proportional` properties? Or do TIFF images allow multiple images in a single file? (I've never heard of this ability before) – Jerry Dodge Nov 09 '16 at 18:00
  • 1
    TIFF does support sequences of multiple images. – Remy Lebeau Nov 09 '16 at 18:06
  • Tiff file support multiple images in a single file Remy. –  Nov 09 '16 at 18:20
  • 1
    see this : [link]http://stackoverflow.com/questions/7845359/how-to-load-and-display-tiff-images-in-timage-control[link] – Christophe Fardeau Nov 09 '16 at 19:21
  • @JerryDodge: TIFF files store multiple images (commonly called *pages*). It's an imaging standard commonly used for faxes and scanners, including Windows Fax and Scan. – Ken White Nov 09 '16 at 20:09
  • There is no built-in support for multi-page TIFFs in Delphi. You'll need to find a third party library that supports them. (You cannot ask here for a recommendation for one; that is expressly off-topic as explained in the [help/on-topic]. You'll have to ask that at another site or find one via Google.) – Ken White Nov 09 '16 at 20:12
  • 1
    Interestingly enough, the rules pointed out by Ken White and followed by the letter by most moderators on Delphi side doesn't seem to apply to other areas of SO. Java question: http://stackoverflow.com/questions/17770071/splitting-a-multipage-tiff-image-into-individual-images-java Pyton question: http://stackoverflow.com/questions/9627652/split-multi-page-tiff-with-python Both are basically the same, asking for advice about libraries that would solve the problem "even if they are commercial". So, I definitely think that there is something fishy in the Delphi land. – Alexandre M Nov 09 '16 at 21:20
  • 1
    @Alexandre - See #4 [here](http://stackoverflow.com/help/on-topic). Site's view on these matters change in time as I observe. Currently recommendation for third party solutions is off topic. However you might have misunderstood Ken's comment, it's not about this question. – Sertac Akyuz Nov 09 '16 at 21:54
  • @SertacAkyuz - I've been accompanying new SO questions that show up in beginend.net for some time. The vast majority, if not all, questions closed as off-topic or systematically down voted by Delphi moderators have similar questions in other areas like Java, C# and C++ and they are all there, intact. Some have thousands of upvotes in other areas. Here they are deleted. If this doesn't say anything to you, it definitely says something to me. – Alexandre M Nov 09 '16 at 22:19
  • 1
    @Alexandre: Sertac pointed you to the [site guidelines](http://stackoverflow.com/help/on-topic) that discuss recommendations. It's the entire reason that there is now [softwarerecs.se] in beta - because recommendations are off-topic here. If you'd like to complain about the guidelines here or ask to have them changed, please do so in [meta] and not by creating comment clutter here in this post. (The Java link you provided was asked more than three years ago, BTW. Guidelines change over time. If you're going to post what you think are counter-links, at least make them up to date.) – Ken White Nov 10 '16 at 03:22
  • 1
    @SertacAkyuz, I have made an update to the question *Christophe Fardeau* linked to. GDI+ supports multiple frames for tiff. – kobik Nov 10 '16 at 11:41
  • 1
    @kobik - Thanks, I removed my comment which is/was now/then invalid. – Sertac Akyuz Nov 10 '16 at 17:30

1 Answers1

4

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.

Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • Hello, thanks a lot for your answers. I forgot to tell you that I'm on Delphi XE5 In my tif file, there are four images @ Sertac Akyuz: This code displays the second image only –  Nov 11 '16 at 07:24
  • 1
    @Bill - I know. If you read the answer, it already tells that the example code will display the second frame. The aim of the code in this answer is to demonstrate how you can access any tiff frame without using any third party library, not to present a finished component. You are free to modify the code in the question to your needs. – Sertac Akyuz Nov 11 '16 at 09:28
  • Thank you for your help. @ Sertac Akyuz: I work with tif images that can contain two or three or four or five or ... images. The number of images is variable. If I put in my code to see image number 3 and it does not exist in the file, is that a problem? So, first we need to know the number of images ... How to have the number of images contained in the tif file please? –  Nov 12 '16 at 20:51
  • 1
    @Bill - I linked in the answer, you call `GetFrameCount` of the `IWICBitmapDecoder`. IWICBitmapDecoder in the code example is the 'Decoder' as you can tell from the 'var' section. After you retrieve the "decoder", you call GetFrameCount instead of GetFrame. – Sertac Akyuz Nov 12 '16 at 23:59
  • 1
    Thank you for your help! –  Nov 14 '16 at 07:55