2010.03.22 17:45 "[Tiff] "Re: Delphi TIFF visualization"", by Mircea Malarski

2010.03.22 17:45 "[Tiff] "Re: Delphi TIFF visualization"", by Mircea Malarski

Hi,

I have a question about the code to read the Tiff into a bitmanp:

its about the lines:

  TIFFReadRGBAImage(OpenTiff,FirstPageWidth,FirstPageHeight,
               FirstPageBitmap.Scanline[FirstPageHeight-1],0);
  TIFFClose(OpenTiff);
  TIFFReadRGBAImageSwapRB(FirstPageWidth,FirstPageheight,
               FirstPageBitmap.Scanline[FirstPageHeight-1]);

Why here is used FirstPageBitmap.Scanline[FirstPageHeight-1] and not FirstPageBitmap.Scanline[0]?

Especially the call of TIFFReadRGBAImageSwapRB is mytirous to me: if one put FirstPageBitmap.Scanline[FirstPageHeight-1] to pointer "Memory" then tere should be only "Width" entries left in the bitmap and the code of TIFFReadRGBAImageSwapRB will change data far outside from FirstPageBitmap's raster.

Can onyone explain me that?

Thanks in advace and regards
Mrices

here the oly post from 2005:

2005.02.28 12:41 "Re: Delphi TIFF visualization", by Joris Van Damme Sure. The easiest way is to use the LibTiff RGBA interface to read the TIFF into

a TBitmap, and next assign that TBitmap to the TImage.Picture property.

It's easy this way, but there is a price to pay. The big dissadvantage of this

method is that the RGBA interface always returns 32bits RGBA, which we'll transfer to a pf32bit TBitmap next. This means that a huge singlebit black and

white image will be read as a 32*huge full color TBitmap. Bad practice, especially if you plan to work with big images, but then again, for big images a

single DIB chunck is no good anyway, and one has to start somewhere.

First thing you have to know is that TIFFReadRGBAImage returns 32bit RGBA in

exactly that order, R-G-B-A, that is. A Windows DIB and thus a Delphi TBitmap

stores things in the slightly different order B-G-R-A. So here's example code

for a swopping procedure that will do this conversion.

procedure TIFFReadRGBAImageSwapRB(Width,Height: Cardinal; Memory:

Pointer);
{$IFDEF DELPHI_5}
type
  PCardinal = ^Cardinal;
{$ENDIF}
var
  m: PCardinal;
  n: Cardinal;
  o: Cardinal;
begin
  m:=Memory;
  for n:=0 to Width*Height-1 do
  begin
    o:=m^;

    m^:= (o and $FF00FF00) or                {G and A}
        ((o and $00FF0000) shr 16) or        {B}
        ((o and $000000FF) shl 16);          {R}

    Inc(m);
  end;
end;

Strangely, TIFFReadRGBAImage returns the same default scanline order as is used

in a Windows DIB and thus Delphi TBitmap, bottom-up that is. So there's no need

for scanline swopping. Here's example code for creating a suitable TBitmap and

reading a TIFF image into it.

function ReadTiffIntoBitmap(Filename: String): TBitmap;
var
  OpenTiff: PTIFF;
  FirstPageWidth,FirstPageHeight: Cardinal;
  FirstPageBitmap: TBitmap;
begin
  OpenTiff:=TIFFOpen(Filename,'r');
  TIFFGetField(OpenTiff,TIFFTAG_IMAGEWIDTH,@FirstPageWidth);
  TIFFGetField(OpenTiff,TIFFTAG_IMAGELENGTH,@FirstPageHeight);
  FirstPageBitmap:=TBitmap.Create;
  FirstPageBitmap.PixelFormat:=pf32bit;
  FirstPageBitmap.Width:=FirstPageWidth;
  FirstPageBitmap.Height:=FirstPageHeight;
  TIFFReadRGBAImage(OpenTiff,FirstPageWidth,FirstPageHeight,
               FirstPageBitmap.Scanline[FirstPageHeight-1],0);
  TIFFClose(OpenTiff);
  TIFFReadRGBAImageSwapRB(FirstPageWidth,FirstPageheight,
               FirstPageBitmap.Scanline[FirstPageHeight-1]);
  Result:=FirstPageBitmap;
end;

There's no error handling in the above procedure, for clearity. If you prefer

code that is ready for copy-and-paste over clear understanding, here's a version with error handling in the normal Delphi exception raising way. (I don't

usually use that system, if anyone sees a way to improve the code below I'll

gladly stand corrected.)

function ReadTiffIntoBitmap(Filename: String): TBitmap;
var
  OpenTiff: PTIFF;
  FirstPageWidth,FirstPageHeight: Cardinal;
  FirstPageBitmap: TBitmap;
begin
  OpenTiff:=TIFFOpen(Filename,'r');
  if OpenTiff=nil then raise Exception.Create(
           'Unable to open file '''+Filename+'''');
  TIFFGetField(OpenTiff,TIFFTAG_IMAGEWIDTH,@FirstPageWidth);
  TIFFGetField(OpenTiff,TIFFTAG_IMAGELENGTH,@FirstPageHeight);
  FirstPageBitmap:=nil;
  try
    FirstPageBitmap:=TBitmap.Create;
    FirstPageBitmap.PixelFormat:=pf32bit;
    FirstPageBitmap.Width:=FirstPageWidth;
    FirstPageBitmap.Height:=FirstPageHeight;
  except
    if FirstPageBitmap<>nil then FirstPageBitmap.Destroy;
    TIFFClose(OpenTiff);
    raise Exception.Create('Unable to create TBitmap buffer');
  end;
  TIFFReadRGBAImage(OpenTiff,FirstPageWidth,FirstPageHeight,
               FirstPageBitmap.Scanline[FirstPageHeight-1],0);
  TIFFClose(OpenTiff);
  TIFFReadRGBAImageSwapRB(FirstPageWidth,FirstPageheight,
               FirstPageBitmap.Scanline[FirstPageHeight-1]);
  Result:=FirstPageBitmap;
end;

Joris Van Damme
info@awaresystems.be
http://www.awaresystems.be/

Download your free TIFF tag viewer for windows here: http://www.awaresystems.be/imaging/tiff/astifftagviewer.html

--

Tout le trouble du monde vient de ce qu'on ne sait pas rester seul dans sa chambre. (B. Pascal)

PGP FP: E0FC F889 0B27 DD8E 2015 1146 8C9A E2E3 9DC1 4844