Das Tagged Image File Format (TIFF oder auch kurz TIF) ist ein Dateiformat zur Speicherung von Bilddaten. Es wurde ursprünglich von Aldus (1994 von Adobe übernommen) und Microsoft für die Farbseparation bei gescannten Rastergrafiken entwickelt. TIFF-Dateien besitzen den MIME-Typ image/tiff.
unit ReadTiffTags;
interface
{Unit ReadTiffTags.pas}
uses WinProcs, SysUtils,Controls,Classes,Graphics, Dialogs;
const
// Byte Order
tiffLittleEndian=$4949; // II: least significant byte to the most significant byte
// e.g. Intel
tiffBigEndian=$4D4D; // MM: most significant byte to least significant byte
// e.g. Motorola
// identifies TIFF file
tiffConfirm=$002A;
// Tiff Tags
tiffTag_ImageWidth = $0100;
tiffTag_ImageLength = $0101;
tiffTag_BitsPerSample = $0102;
tiffTag_Compression = $0103;
tiffTag_PhotometricInterpretation = $0106;
tiffTag_StripOffsets = $0111;
tiffTag_SamplesPerPixels = $0115;
tiffTag_RowsPerStrip = $0116;
tiffTag_StripByteCounts = $0117;
tiffTag_ColorMapOffset = $0140;
type
// Header structure
THeaderTiff=record
Endian : Word;
Confirm : Word;
FirstIFD: LongInt;
end;
// Image file Directory element (IFD)
TTagTiff=record
Tag : Word;
VarType : Word;
Count : LongInt;
Value : LongInt;
end;
PTagTiff=^TTagTiff;
TListTag=array[0..0] of TTagTiff;
PListTag=^TListTag;
// StripOffsets and StripByteCounts Information List
TStripInfo=record
StripOffsets : LongInt;
StripByteCounts : LongInt;
end;
PStripInfo=^TStripInfo;
TListStripInfo=array[0..0] of TStripInfo;
PListStripInfo=^TListStripInfo;
// ------------------------------------------------------------------
// Class containing the graphic information
// ------------------------------------------------------------------
TFileTiff=class;
TGraphicTiff=class
private
FCountTag : Word;
FError : Boolean;
FFileTiff : TFileTiff;
FFilePosition : LongInt;
FListTag : PListTag;
FNextIFD : LongInt;
FListStripInfo: PListStripInfo;
FCountStripInfo: Word;
protected
procedure LoadIFD(AFileHandle:Integer);
public
constructor Create(AFileTiff:TFileTiff); virtual;
procedure QueryGraphic(AStringList:TStringList);
destructor Destroy; override;
property Error :Boolean read FError;
property NextIFD :LongInt read FNextIFD;
function QueryGraphicByTag( TagId : Word ) : PTagTiff;
function QueryGraphicByOffsets( OffsetId : Word ) : PStripInfo;
function GetNoOfOffsets : Word;
end;
// ------------------------------------------------------------------
// Class containing image independent information
// ------------------------------------------------------------------
TFileTiff=class(TPersistent)
private
FFileName : TFileName;
FFileSize : LongInt;
FGraphicsList : TList;
FLittleEndian : Boolean;
FValid : Boolean;
protected
function AddGraphicFromFile(AFileHandle:Integer;AFileOffset:LongInt):TGraphicTiff;
procedure DeleteAll;
function GetGraphicCount:Integer; virtual;
procedure SetFileName(AFileName:TFileName); virtual;
public
constructor Create; virtual;
function GetGraphicTiff(AGraphicID:Byte):TGraphicTiff; virtual;
procedure DeleteGraphic(AGraphicID:Byte);
procedure ExchangeGraphic(AIndex1,AIndex2:Byte);
destructor Destroy; override;
property FileSize:LongInt read FFileSize;
property GraphicTiff[AGraphicID:Byte]:TGraphicTiff read GetGraphicTiff;
property GraphicCount:Integer read GetGraphicCount;
property LittleEndian:Boolean read FLittleEndian;
property Valid:Boolean read FValid;
published
property FileName:TFileName read FFileName write SetFileName;
end;
function SwapLongInt(ALongInt:LongInt):LongInt;
implementation
function SwapLongInt(ALongInt:LongInt):LongInt;
var
WordA :Word;
WordB :Word;
begin
WordA := Swap(HiWord(ALongInt));
WordB := Swap(LoWord(ALongInt));
SwapLongInt := MakeLong(WordA,WordB);
end;
{$R-}
// ------------------------------------------------------------------
// Class containing the graphic information
// ------------------------------------------------------------------
(*---------------------------------------------------------------*)
procedure TGraphicTiff.LoadIFD(AFileHandle:Integer);
var
TagLoop : Word;
NoOfStripByteCounts : LongInt;
NoOfStripOffsets : LongInt;
I : Integer;
begin
if Assigned(FFileTiff) and (AFileHandle>-1) then
begin
try
FFilePosition := FileSeek(AFileHandle,0,1); // actual position
FileRead(AFileHandle, FCountTag, 2); // read no of tags in Image file Directory
if not FFileTiff.LittleEndian then FCountTag := Swap(FCountTag);
if FCountTag>0 then
begin
// get memory for all IFD entries
GetMem(FListTag,SizeOf(TTagTiff)*FCountTag);
// read all ifd entries
FileRead(AFileHandle, FListTag^, SizeOf(TTagTiff)*FCountTag );
FFilePosition := FileSeek(AFileHandle,0,1); // actual position
if not FFileTiff.LittleEndian then // Swap Bytes
begin
for TagLoop := 0 to FCountTag-1 do
begin
with FListTag^[TagLoop] do
begin
Tag := Swap(Tag);
VarType := Swap(VarType);
Count := SwapLongInt(Count);
Value := SwapLongInt(Value);
end;
end;
end;
// Check No of StripByteCounts and No of StripOffsets
NoOfStripByteCounts := 0;
NoOfStripOffsets := 0;
FCountStripInfo := 0;
for TagLoop := 0 to FCountTag-1 do
begin
// Strip Byte Counts
if FListTag^[TagLoop].Tag = tiffTag_StripByteCounts then
begin
NoOfStripByteCounts := FListTag^[TagLoop].Count;
end;
// StripOffsets
if FListTag^[TagLoop].Tag = tiffTag_StripOffsets then
begin
NoOfStripOffsets := FListTag^[TagLoop].Count;
end;
end;
if (NoOfStripByteCounts = NoOfStripOffsets) then
begin
FCountStripInfo := NoOfStripByteCounts;
GetMem(FListStripInfo, SizeOf(TListStripInfo)*FCountStripInfo);
// Read StripOffsets and StripByteCounts into Information List
for TagLoop := 0 to FCountTag-1 do
begin
// Strip Byte Counts
if FListTag^[TagLoop].Tag = tiffTag_StripByteCounts then
begin
if FListTag^[TagLoop].Count = 1 then
begin
FListStripInfo^[0].StripByteCounts := FListTag^[TagLoop].Value;
end
else
begin
// Scan the file for the list of Strip Bytes Counts
FileSeek(AFileHandle,FListTag^[TagLoop].Value,0);
for I := 0 to FCountStripInfo-1 do
begin
FileRead(AFileHandle, FListStripInfo^[I].StripByteCounts, 4);
end;
end;
end;
// StripOffsets
if FListTag^[TagLoop].Tag = tiffTag_StripOffsets then
begin
if FListTag^[TagLoop].Count = 1 then
begin
FListStripInfo^[0].StripOffsets := FListTag^[TagLoop].Value;
end
else
begin
// Scan the file for the list of StripOffsets
FileSeek(AFileHandle,FListTag^[TagLoop].Value,0);
for I := 0 to FCountStripInfo-1 do
begin
FileRead(AFileHandle, FListStripInfo^[I].StripOffsets, 4);
end;
end;
end;
end;
end;
end;
// Read offset to the following IFD (or $00 00 00 00)
try
FileSeek(AFileHandle,FFilePosition,0);
FileRead(AFileHandle, FNextIFD, 4);
if not FFileTiff.LittleEndian then FNextIFD := SwapLongInt(FNextIFD);
except
FNextIFD := 0;
end;
except
FError:=True;
end;
end;
end;
(*---------------------------------------------------------------*)
constructor TGraphicTiff.Create(AFileTiff:TFileTiff);
begin
inherited Create;
FCountTag := 0;
FError := False;
FFileTiff := AFileTiff;
FListTag := nil;
FListStripInfo := nil;
FNextIFD := 0;
FCountStripInfo:= 0;
end;
(*---------------------------------------------------------------*)
(* return all IFD Tags as StringList
(*---------------------------------------------------------------*)
procedure TGraphicTiff.QueryGraphic(AStringList:TStringList);
var
TagLoop : Word;
begin
if Assigned(AStringList) then
begin
AStringList.Clear;
if FCountTag>0 then
begin
AStringList.Add(' Tag VarType Count Value');
AStringList.Add('=====================================');
for TagLoop:=0 to FCountTag-1 do
begin
with FListTag^[TagLoop] do
begin
AStringList.Add(' $'+IntToHex(Tag,4)+
' $'+IntToHex(VarType,4)+
' $'+IntToHex(Count,8)+
' $'+IntToHex(Value,8) )
end;
end;
end;
end;
end;
(*---------------------------------------------------------------*)
function TGraphicTiff.QueryGraphicByTag( TagId : Word ) : PTagTiff;
var
TagLoop : Word;
begin
Result := nil;
if FCountTag>0 then
begin
for TagLoop:=0 to FCountTag-1 do
begin
if FListTag^[TagLoop].Tag = TagId then
begin
Result := @FListTag^[TagLoop];
end;
end;
end;
end;
(*---------------------------------------------------------------*)
function TGraphicTiff.QueryGraphicByOffsets( OffsetId : Word ) : PStripInfo;
begin
Result := nil;
if FListStripInfo = nil then exit;
if OffsetId >= FCountStripInfo then exit;
if FCountStripInfo > 0 then
begin
Result := @FListStripInfo^[OffsetId];
end;
end;
(*---------------------------------------------------------------*)
function TGraphicTiff.GetNoOfOffsets : Word;
begin
Result := FCountStripInfo;
end;
(*---------------------------------------------------------------*)
destructor TGraphicTiff.Destroy;
begin
if FListTag<>nil then FreeMem(FListTag,SizeOf(TTagTiff)*FCountTag);
if FListStripInfo<>nil then FreeMem(FListStripInfo);
inherited Destroy;
end;
// ------------------------------------------------------------------
// Class containing image independent information
// ------------------------------------------------------------------
(*---------------------------------------------------------------*)
function TFileTiff.AddGraphicFromFile( AFileHandle : Integer;
AFileOffset : LongInt):TGraphicTiff;
var
NewGraphic : TGraphicTiff;
begin
NewGraphic := TGraphicTiff.Create(Self);
FileSeek(AFileHandle,AFileOffset,0); // Reset FilePointer
NewGraphic.LoadIFD(AFileHandle); // Read Image File Directory
FGraphicsList.Add(NewGraphic); // Add List of IFD Tags
AddGraphicFromFile := NewGraphic; // Return list of IFD Tags
end;
(*---------------------------------------------------------------*)
procedure TFileTiff.DeleteAll;
var
GraphicLoop : Integer;
begin
if FGraphicsList.Count>0 then
begin
for GraphicLoop:=0 to FGraphicsList.Count-1 do
TGraphicTiff(FGraphicsList.Items[GraphicLoop]).Free;
end;
FGraphicsList.Clear;
end;
(*---------------------------------------------------------------*)
function TFileTiff.GetGraphicCount:Integer;
begin
GetGraphicCount := FGraphicsList.Count;
end;
(*---------------------------------------------------------------*)
function TFileTiff.GetGraphicTiff(AGraphicID:Byte):TGraphicTiff;
begin
Result:=nil;
if (FGraphicsList.Count>0) and (AGraphicID<FGraphicsList.Count)
then Result:=TGraphicTiff(FGraphicsList.Items[AGraphicID]);
end;
(*---------------------------------------------------------------*)
procedure TFileTiff.SetFileName(AFileName:TFileName);
var
TiffHandle:Integer;
SearchFile:TSearchRec;
HeaderTiff:THeaderTiff;
GraphicTiff:TGraphicTiff;
begin
// if it does not exists create it
if not FileExists(AFileName) and (AFileName<>'') then
begin
TiffHandle := FileCreate(AFileName);
if TiffHandle>-1 then
begin
if LittleEndian
then HeaderTiff.Endian := tiffLittleEndian
else HeaderTiff.Endian := tiffBigEndian;
HeaderTiff.Confirm := tiffConfirm;
if not LittleEndian then HeaderTiff.Confirm := Swap(HeaderTiff.Confirm);
HeaderTiff.FirstIFD:=0;
FileWrite(TiffHandle,HeaderTiff,SizeOf(THeaderTiff));
FileClose(TiffHandle);
end;
end;
// Try to Read Tiff Image
if (AFileName<>'') and (AFileName<>FFileName) then
begin
DeleteAll;
FValid := False;
SysUtils.FindFirst(AFileName,faAnyFile,SearchFile);
FFileSize:=SearchFile.Size;
SysUtils.FindClose(SearchFile);
if FFileSize>=SizeOf(THeaderTiff) then
begin
TiffHandle := FileOpen(AFileName,fmShareDenyNone);
// Read Header
FileRead(TiffHandle,HeaderTiff,SizeOf(THeaderTiff));
FValid := True;
if HeaderTiff.Endian=tiffLittleEndian then
begin
FLittleEndian:=True;
end
else
begin
if HeaderTiff.Endian=tiffBigEndian then
begin
FLittleEndian:=False;
end
else FValid:=False;
end;
// Header is a valid Tiff Header
if FValid then
begin
if not FLittleEndian then
begin
HeaderTiff.Confirm := Swap(HeaderTiff.Confirm);
HeaderTiff.FirstIFD := SwapLongInt(HeaderTiff.FirstIFD);
end;
if HeaderTiff.Confirm<>tiffConfirm then FValid:=False;
end;
// Header is a valid Tiff Header. Try to read IFD
FFileName:=AFileName;
if HeaderTiff.FirstIFD >= SizeOf(THeaderTiff) then
begin
// read Graphic Information of first image
GraphicTiff := AddGraphicFromFile(TiffHandle,HeaderTiff.FirstIFD);
// if present: read Graphic Information of all following images
while (GraphicTiff.NextIFD>=SizeOf(THeaderTiff)) do
GraphicTiff:=AddGraphicFromFile(TiffHandle,GraphicTiff.NextIFD);
end;
FileClose(TiffHandle);
end;
end
else
begin
if AFileName='' then
begin
// Reinitialization
DeleteAll;
FFileName := '';
FFileSize := 0;
FValid := False;
end;
end;
end;
(*---------------------------------------------------------------*)
constructor TFileTiff.Create;
begin
inherited Create;
FFileName := '';
FFileSize := 0;
FGraphicsList := TList.Create;
FLittleEndian := True;
FValid := False;
end;
(*---------------------------------------------------------------*)
procedure TFileTiff.DeleteGraphic(AGraphicID:Byte);
begin
if (FGraphicsList.Count>0) and (AGraphicID<FGraphicsList.Count) then
begin
TGraphicTiff(FGraphicsList).Free;
FGraphicsList.Delete(AGraphicID);
FGraphicsList.Pack;
end;
end;
(*---------------------------------------------------------------*)
procedure TFileTiff.ExchangeGraphic(AIndex1, AIndex2 : Byte);
begin
if (FGraphicsList.Count > 0) and
(AIndex1 < FGraphicsList.Count) and
(AIndex2 < FGraphicsList.Count)
then FGraphicsList.Exchange(AIndex1, AIndex2);
end;
(*---------------------------------------------------------------*)
destructor TFileTiff.Destroy;
begin
DeleteAll;
FGraphicsList.Free;
inherited Destroy;
end;
end.
Unit ReadTiff.pas
unit ReadTiff;
(*
10.10.1998: started with code of Jean Marc CARAYON and Daniel DROUIN, France
14.10.1998: Uncompressed Palette Image added by Wolfgang Krug
15.10.1998: Uncompressed Bilevel Image added by Wolfgang Krug
15.10.1998: Uncompressed Gray Scale Image added by Wolfgang Krug
15.10.1998: Uncompressed RGB Full Color Image added by Wolfgang Krug
*)
interface
uses Windows, SysUtils, Graphics, Dialogs, ReadTiffTags;
Type
ColorTableRed = array [0..256] of Word;
ColorTableGreen = array [0..256] of Word;
ColorTableBlue = array [0..256] of Word;
// File format functions
procedure LoadTiffFromFile (FileName : string; Bitmap : TBitmap);
procedure TIFFBilevelImage (FileName : string; GraphTiff : TGraphicTiff; var Bitmap : TBitmap);
procedure TIFFGrayScaleImage (FileName : string; GraphTiff : TGraphicTiff; var Bitmap : TBitmap);
procedure TIFFColorPaletImage (FileName : string; GraphTiff : TGraphicTiff; var Bitmap : TBitmap);
procedure TIFFRGBFullColorImage(FileName : string; GraphTiff : TGraphicTiff; var Bitmap : TBitmap);
// Internal Functions
procedure InitColTab;
procedure CreateGreyColTab( BitsPerSample : Integer);
procedure CreateBilevelColTab( White : Integer);
procedure ReadColTabFromFile( AFileName : string;
ACounter : LongInt;
AFileOffset : LongInt);
function ReadImageDataFromFile(AFileName : string;
var AImageBuffer : PChar;
AGraphTiff : TGraphicTiff):Integer;
procedure AlignBmpRows(var AImageBuffer : PChar; AGraphTiff : TGraphicTiff);
procedure ReadBitsPerSampleColor(AFileName : string;
AFileOffset : LongInt;
var BPSRed : Integer;
var BPSGreen : Integer;
var BPSBlue : Integer);
procedure DisplayImage(width : Word; height : Word;
BitCount : Word; buff : PChar;
Bitmap : TBitmap);
var
FColorTableRed : ColorTableRed;
FColorTableGreen : ColorTableGreen;
FColorTableBlue : ColorTableBlue;
implementation
uses Unit1;
//
// Internal Functions
//
(*---------------------------------------------------------------*)
procedure InitColTab;
var
I : Integer;
begin
// create Color Table of 256 shades of grey
for I:=0 to 255 do begin
FColorTableRed[I] := Word(I);
FColorTableGreen[I] := Word(I);
FColorTableBlue[I] := Word(I);
end;
end;
(*---------------------------------------------------------------*)
procedure CreateGreyColTab( BitsPerSample : Integer);
var
I : Integer;
begin
InitColTab;
if BitsPerSample = 4 then
begin
for I:=0 to 15 do begin
FColorTableRed[I] := Word(I * 255 div 15);
FColorTableGreen[I] := Word(I * 255 div 15);
FColorTableBlue[I] := Word(I * 255 div 15);
end;
end;
end;
(*---------------------------------------------------------------*)
procedure CreateBilevelColTab( White : Integer);
begin
InitColTab;
if White = 1 then
begin
FColorTableRed[0] := 0;
FColorTableGreen[0] := 0;
FColorTableBlue[0] := 0;
FColorTableRed[1] := 255;
FColorTableGreen[1] := 255;
FColorTableBlue[1] := 255;
end
else
begin
FColorTableRed[0] := 255;
FColorTableGreen[0] := 255;
FColorTableBlue[0] := 255;
FColorTableRed[1] := 0;
FColorTableGreen[1] := 0;
FColorTableBlue[1] := 0;
end;
end;
(*---------------------------------------------------------------*)
procedure ReadColTabFromFile( AFileName : string;
ACounter : LongInt;
AFileOffset : LongInt);
var
TiffHandle : Integer;
I : Integer;
begin
InitColTab;
ACounter := ACounter div 3;
if ACounter < 1 then exit;
if ACounter > 256 then exit;
TiffHandle := FileOpen(AFileName, fmShareDenyNone);
// read Color Table from file
FileSeek(TiffHandle, AFileOffset, 0);
FileRead(TiffHandle, FColorTableRed, ACounter*SizeOf(Word));
FileRead(TiffHandle, FColorTableGreen, ACounter*SizeOf(Word));
FileRead(TiffHandle, FColorTableBlue, ACounter*SizeOf(Word));
for I:=0 to ACounter do begin
FColorTableRed[I] := FColorTableRed[I] div 256;
FColorTableGreen[I] := FColorTableGreen[I] div 256;
FColorTableBlue[I] := FColorTableBlue[I] div 256;
end;
FileClose(TiffHandle);
end;
(*---------------------------------------------------------------*)
function ReadImageDataFromFile( AFileName : string;
var AImageBuffer : PChar;
AGraphTiff : TGraphicTiff) : Integer;
var
ImageSize : LongInt;
TiffHandle : Integer;
PStrpInfo : PStripInfo;
I : Integer;
BuffPtr : PChar;
Count : Integer;
Begin
Result := 0;
// Prepare Data buffer
ImageSize := 0;
for I:=0 to AGraphTiff.GetNoOfOffsets-1 do
begin
PStrpInfo := AGraphTiff.QueryGraphicByOffsets(I);
if PStrpInfo <> nil then
ImageSize := ImageSize + PStrpInfo^.StripByteCounts;
end;
GetMem(AImageBuffer, ImageSize);
BuffPtr := AImageBuffer;
TiffHandle := FileOpen(AFileName, fmShareDenyNone);
// Read Image Data
for I:=0 to AGraphTiff.GetNoOfOffsets-1 do
begin
PStrpInfo := AGraphTiff.QueryGraphicByOffsets(I);
if PStrpInfo <> nil then
begin
FileSeek(TiffHandle, PStrpInfo^.StripOffsets, 0);
Count := FileRead(TiffHandle, BuffPtr^, PStrpInfo^.StripByteCounts);
BuffPtr := BuffPtr + PStrpInfo^.StripByteCounts;
if Count <> PStrpInfo^.StripByteCounts then
begin
Result := 1;
FreeMem(AImageBuffer, ImageSize);
exit;
end;
end;
end;
FileClose(TiffHandle);
end;
(*---------------------------------------------------------------*)
procedure AlignBmpRows(var AImageBuffer : PChar; AGraphTiff : TGraphicTiff);
var
PTag : PTagTiff;
PStrpInfo : PStripInfo;
ImageHeight : LongInt;
RowsPerStrip : LongInt;
RowLength : LongInt;
AlignedRowLength : LongInt;
TargetBuffer : PChar;
TargetBufPtr : PChar;
SourceBufPtr : PChar;
I : Integer;
begin
// Keep in mind: The rows of a Bitmap are DWORD aligned !!!
PStrpInfo := AGraphTiff.QueryGraphicByOffsets(0);
// Read Image Height
PTag := AGraphTiff.QueryGraphicByTag( tiffTag_ImageLength );
ImageHeight := PTag^.Value;
// Read Rows Per Strip
PTag := AGraphTiff.QueryGraphicByTag( tiffTag_RowsPerStrip );
RowsPerStrip := PTag^.Value;
RowLength := PStrpInfo^.StripByteCounts div RowsPerStrip;
AlignedRowLength := ((RowLength+3) div 4) * 4;
if RowLength <> AlignedRowLength then
begin
GetMem(TargetBuffer, AlignedRowLength*ImageHeight);
SourceBufPtr := AImageBuffer;
TargetBufPtr := TargetBuffer;
for I:=0 to ImageHeight-1 do
begin
CopyMemory(TargetBufPtr, SourceBufPtr, RowLength*SizeOf(Byte));
SourceBufPtr := SourceBufPtr + RowLength;
TargetBufPtr := TargetBufPtr + AlignedRowLength;
end;
FreeMem(AImageBuffer);
AImageBuffer := TargetBuffer;
end;
end;
(*---------------------------------------------------------------*)
procedure ReadBitsPerSampleColor(AFileName : string;
AFileOffset : LongInt;
var BPSRed : Integer;
var BPSGreen : Integer;
var BPSBlue : Integer);
var
TiffHandle : Integer;
begin
// Read Bits per sample for Red green and Blue Color
TiffHandle := FileOpen(AFileName, fmShareDenyNone);
FileSeek(TiffHandle, AFileOffset, 0);
FileRead(TiffHandle, BPSRed, 2);
FileRead(TiffHandle, BPSGreen, 2);
FileRead(TiffHandle, BPSBlue, 2);
FileClose(TiffHandle);
end;
(*---------------------------------------------------------------*)
procedure ExchangeRedAndBlue(var AImageBuffer : PChar; Size : LongInt);
var
Bits : PChar;
BitsPtr : PChar;
I : LongInt;
Red, Blue : Char;
begin
// Keep in mind: The RGB-Pixels of a Bitmap are ordered BGR !!!
BitsPtr := AImageBuffer;
for I:=0 to Size-1 do
begin
Blue := (BitsPtr)^ ;
Red := (BitsPtr+2)^;
(BitsPtr)^ := Red;
(BitsPtr+2)^ := Blue;
BitsPtr := BitsPtr + 3;
end;
end;
(*---------------------------------------------------------------*)
procedure DisplayImage(width : Word; height : Word;
BitCount : Word; buff: PChar;
Bitmap : TBitmap);
var
I : Integer;
hBmp : HBITMAP;
BI : PBitmapInfo;
BIH : TBitmapInfoHeader;
Bmp : TBitmap;
ImagoDC : hDC;
begin
// Fill BitmapInfoHeader structure
BIH.biSize := Sizeof(BIH);
BIH.biWidth := width;
BIH.biHeight := -height;
BIH.biPlanes := 1;
BIH.biBitCount := BitCount;
BIH.biCompression := BI_RGB;
BIH.biSizeImage := 0;
BIH.biXPelsPerMeter := 0;
BIH.biYPelsPerMeter := 0;
BIH.biClrUsed := 0;
BIH.biClrImportant := 0;
{$P+,S-,W-,R-}
// Create DIB Bitmap Info with actual color table
BI := AllocMem(SizeOf(TBitmapInfoHeader) + 256*Sizeof(TRGBQuad));
try
BI^.bmiHeader := BIH;
for I:=0 to 255 do begin
BI^.bmiColors[I].rgbBlue := Byte(FColorTableBlue[I]);
BI^.bmiColors[I].rgbGreen := Byte(FColorTableGreen[I]);
BI^.bmiColors[I].rgbRed := Byte(FColorTableRed[I]);
BI^.bmiColors[I].rgbReserved := 0;
end;
Bitmap.Assign( nil ); // Clear actual Image
Bmp := TBitmap.Create;
Bmp.Height := width;
Bmp.Width := height;
ImagoDC := GetDC(Bitmap.Handle);
hBmp := CreateDIBitmap(
ImagoDC, // handle of device context
BIH, // address of bitmap size and format data
CBM_INIT, // initialization flag
buff, // address of initialization data
BI^, // address of bitmap color-format data
DIB_RGB_COLORS ); // color-data usage
Bmp.Handle := hBmp;
Bitmap.Assign( Bmp );
Bmp.Free;
except
showmessage('Out Of Memory ');
exit;
end;
FreeMem( BI, SizeOf(TBitmapInfoHeader) + 256*Sizeof(TRGBQuad));
{$P-,S+,W+,R+}
end;
(*---------------------------------------------------------------*)
(*---------------------------------------------------------------*)
(*-- Main Function: Load TIFF File and determine type of image --*)
(*---------------------------------------------------------------*)
(*---------------------------------------------------------------*)
procedure LoadTiffFromFile(FileName : string; Bitmap : TBitmap);
var
TiffFile : TFileTiff;
GraphTiff : TGraphicTiff;
I : Integer;
PTag : PTagTiff;
PhotometricInterpretation : LongInt;
BitsPerSample : LongInt;
begin
TiffFile := TFileTiff.Create;
TiffFile.FileName := FileName;
if NOT TiffFile.Valid then
begin
showmessage('<'+FileName+'> is not a valid TIFF file');
TiffFile.Free;
exit;
end;
// Go over all images within the TIFF file
for I := 0 to TiffFile.GraphicCount-1 do
begin
GraphTiff := TiffFile.GetGraphicTiff(I);
//
// Check the type of image
//
// Read Photometric interpretation
PTag := GraphTiff.QueryGraphicByTag( tiffTag_PhotometricInterpretation );
if PTag = nil then
begin
showmessage('Error reading tag Photometric interpretation');
TiffFile.Free;
exit;
end;
PhotometricInterpretation := PTag^.Value;
// Photometric interpretation should be:
// 0, 1 = Bilevel Image
// 2 = Palette color image
// 3 = RGB Full Color Image
if (PhotometricInterpretation < 0) or
(PhotometricInterpretation > 3) then
begin
showmessage('Error evaluating Photometric interpretation: '+IntToStr(PhotometricInterpretation));
TiffFile.Free;
exit;
end;
// Bilevel Image or Grayscale Image
if (PhotometricInterpretation = 0) or (PhotometricInterpretation = 1) then
begin
// Read Bits Per Sample
PTag := GraphTiff.QueryGraphicByTag( tiffTag_BitsPerSample );
if PTag = nil then
begin
TIFFBilevelImage(TiffFile.FileName, GraphTiff, Bitmap);
end
else
begin
BitsPerSample := PTag^.Value;
if BitsPerSample = 1 then
begin
TIFFBilevelImage(TiffFile.FileName, GraphTiff, Bitmap);
end
else
begin
if (BitsPerSample = 4) or (BitsPerSample = 8) then
begin
TIFFGrayScaleImage(TiffFile.FileName, GraphTiff, Bitmap);
end;
end;
end;
end;
// Color Palette Image
if (PhotometricInterpretation = 3) then
begin
TIFFColorPaletImage(TiffFile.FileName, GraphTiff, Bitmap);
end;
// RGB Full Color Image
if (PhotometricInterpretation = 2) then
begin
TIFFRGBFullColorImage(TiffFile.FileName, GraphTiff, Bitmap);
end;
end;
TiffFile.Free;
end;
(*---------------------------------------------------------------*)
(*---------------------------------------------------------------*)
(*--- Bilevel Image ---*)
(*---------------------------------------------------------------*)
(*---------------------------------------------------------------*)
procedure TIFFBilevelImage(FileName : string; GraphTiff : TGraphicTiff; var Bitmap : TBitmap);
var
PTag : PTagTiff;
ImageWidth : LongInt;
ImageHeight : LongInt;
Compression : LongInt;
PhotometricInterpretation : LongInt;
ImageBuffer : PChar;
begin
// Read Image Width
PTag := GraphTiff.QueryGraphicByTag( tiffTag_ImageWidth );
if PTag = nil then
begin
showmessage('Error reading tag Image Width');
exit;
end;
ImageWidth := PTag^.Value;
// Read Image Height
PTag := GraphTiff.QueryGraphicByTag( tiffTag_ImageLength );
if PTag = nil then
begin
showmessage('Error reading tag Image Height');
exit;
end;
ImageHeight := PTag^.Value;
// Read Photometric interpretation
PTag := GraphTiff.QueryGraphicByTag( tiffTag_PhotometricInterpretation );
if PTag = nil then
begin
showmessage('Error reading tag Photometric interpretation');
exit;
end;
PhotometricInterpretation := PTag^.Value;
// Read Compression
PTag := GraphTiff.QueryGraphicByTag( tiffTag_Compression );
if PTag = nil then
begin
showmessage('Error reading tag Compression');
exit;
end;
Compression := PTag^.Value;
// 1 = No Compression
// 2 = CCITT Group 3 (1-Dimensional Modified Huffman run length encoding)
// 32773 = PxckBits compression, a simple byte-oriented run length scheme.
if Compression = 1 then // NO Compression
begin
CreateBilevelColTab( PhotometricInterpretation );
// Read Image Data
if ReadImageDataFromFile( FileName, ImageBuffer, GraphTiff) = 0 then
begin
AlignBmpRows(ImageBuffer, GraphTiff);
DisplayImage(ImageWidth, ImageHeight, 1, ImageBuffer, Bitmap);
FreeMem(ImageBuffer);
end
else
begin
showmessage('Error reading image data');
end;
end
else
begin
showmessage('Cant read compressed bilevel image'+#13+#13+
'feel free to implement this type of image'+#13+
'and send it back to krug@sdm.de');
exit;
end;
end;
(*---------------------------------------------------------------*)
(*---------------------------------------------------------------*)
(*--- Gray Scale Image ---*)
(*---------------------------------------------------------------*)
(*---------------------------------------------------------------*)
procedure TIFFGrayScaleImage (FileName : string; GraphTiff : TGraphicTiff; var Bitmap : TBitmap);
var
PTag : PTagTiff;
ImageWidth : LongInt;
ImageHeight : LongInt;
Compression : LongInt;
BitsPerSample : LongInt;
ImageBuffer : PChar;
begin
// Read Image Width
PTag := GraphTiff.QueryGraphicByTag( tiffTag_ImageWidth );
if PTag = nil then
begin
showmessage('Error reading tag Image Width');
exit;
end;
ImageWidth := PTag^.Value;
// Read Image Height
PTag := GraphTiff.QueryGraphicByTag( tiffTag_ImageLength );
if PTag = nil then
begin
showmessage('Error reading tag Image Height');
exit;
end;
ImageHeight := PTag^.Value;
// Read Compression
PTag := GraphTiff.QueryGraphicByTag( tiffTag_Compression );
if PTag = nil then
begin
showmessage('Error reading tag Compression');
exit;
end;
Compression := PTag^.Value;
// 1 = No Compression
// 2 = CCITT Group 3 (1-Dimensional Modified Huffman run length encoding)
// 32773 = PxckBits compression, a simple byte-oriented run length scheme.
if Compression = 1 then // NO Compression
begin
// Read Bits Per Sample
PTag := GraphTiff.QueryGraphicByTag( tiffTag_BitsPerSample );
if PTag = nil then
begin
showmessage('Error reading tag Bits Per Sample');
exit;
end;
BitsPerSample := PTag^.Value;
// Check Value of BitsPerSample
if (BitsPerSample <> 4) and (BitsPerSample <> 8) then
begin
showmessage('Error: Bits Per Sample not 4 or 8');
exit;
end;
CreateGreyColTab( BitsPerSample );
// Read Image Data
if ReadImageDataFromFile( FileName, ImageBuffer, GraphTiff) = 0 then
begin
AlignBmpRows(ImageBuffer, GraphTiff);
DisplayImage(ImageWidth, ImageHeight, BitsPerSample, ImageBuffer, Bitmap);
FreeMem(ImageBuffer);
end
else
begin
showmessage('Error reading image data');
end;
end
else
begin
showmessage('Cant read compressed Gray Scale Image'+#13+#13+
'feel free to implement this type of image'+#13+
'and send it back to krug@sdm.de');
end;
end;
(*---------------------------------------------------------------*)
(*---------------------------------------------------------------*)
(*--- Color Palet Image ---*)
(*---------------------------------------------------------------*)
(*---------------------------------------------------------------*)
procedure TIFFColorPaletImage(FileName : string; GraphTiff : TGraphicTiff; var Bitmap : TBitmap);
var
PTag : PTagTiff;
ImageWidth : LongInt;
ImageHeight : LongInt;
Compression : LongInt;
BitsPerSample : LongInt;
ImageBuffer : PChar;
begin
// Read Image Width
PTag := GraphTiff.QueryGraphicByTag( tiffTag_ImageWidth );
if PTag = nil then
begin
showmessage('Error reading tag Image Width');
exit;
end;
ImageWidth := PTag^.Value;
// Read Image Height
PTag := GraphTiff.QueryGraphicByTag( tiffTag_ImageLength );
if PTag = nil then
begin
showmessage('Error reading tag Image Height');
exit;
end;
ImageHeight := PTag^.Value;
// Read Compression
PTag := GraphTiff.QueryGraphicByTag( tiffTag_Compression );
if PTag = nil then
begin
showmessage('Error reading tag Compression');
exit;
end;
Compression := PTag^.Value;
// 1 = No Compression
// 2 = CCITT Group 3 (1-Dimensional Modified Huffman run length encoding)
// 32773 = PxckBits compression, a simple byte-oriented run length scheme.
if Compression = 1 then // NO Compression
begin
// Read Bits Per Sample
PTag := GraphTiff.QueryGraphicByTag( tiffTag_BitsPerSample );
if PTag = nil then
begin
showmessage('Error reading tag Bits Per Sample');
exit;
end;
BitsPerSample := PTag^.Value;
// read Color Table Offset
PTag := GraphTiff.QueryGraphicByTag( tiffTag_ColorMapOffset );
if PTag = nil then
begin
showmessage('Error reading tag Color Table Offset');
exit;
end;
ReadColTabFromFile( FileName, PTag^.Count, PTag^.Value);
// Read Image Data
if ReadImageDataFromFile( FileName, ImageBuffer, GraphTiff) = 0 then
begin
AlignBmpRows(ImageBuffer, GraphTiff);
DisplayImage(ImageWidth, ImageHeight, BitsPerSample, ImageBuffer, Bitmap);
FreeMem(ImageBuffer);
end
else
begin
showmessage('Error reading image data');
end;
end
else
begin
showmessage('Cant read compressed ColorPaletImage'+#13+#13+
'feel free to implement this type of image'+#13+
'and send it back to krug@sdm.de');
end;
end;
(*---------------------------------------------------------------*)
(*---------------------------------------------------------------*)
(*--- RGB Full Color Image ---*)
(*---------------------------------------------------------------*)
(*---------------------------------------------------------------*)
procedure TIFFRGBFullColorImage(FileName : string; GraphTiff : TGraphicTiff; var Bitmap : TBitmap);
var
PTag : PTagTiff;
ImageWidth : LongInt;
ImageHeight : LongInt;
Compression : LongInt;
BitsPerSampleRed : Integer;
BitsPerSampleGreen : Integer;
BitsPerSampleBlue : Integer;
ImageBuffer : PChar;
begin
// Read Image Width
PTag := GraphTiff.QueryGraphicByTag( tiffTag_ImageWidth );
if PTag = nil then
begin
showmessage('Error reading tag Image Width');
exit;
end;
ImageWidth := PTag^.Value;
// Read Image Height
PTag := GraphTiff.QueryGraphicByTag( tiffTag_ImageLength );
if PTag = nil then
begin
showmessage('Error reading tag Image Height');
exit;
end;
ImageHeight := PTag^.Value;
// Read Compression
PTag := GraphTiff.QueryGraphicByTag( tiffTag_Compression );
if PTag = nil then
begin
showmessage('Error reading tag Compression');
exit;
end;
Compression := PTag^.Value;
// 1 = No Compression
// 2 = CCITT Group 3 (1-Dimensional Modified Huffman run length encoding)
// 32773 = PxckBits compression, a simple byte-oriented run length scheme.
if Compression = 1 then // NO Compression
begin
// Read Bits Per Sample
PTag := GraphTiff.QueryGraphicByTag( tiffTag_BitsPerSample );
if PTag = nil then
begin
showmessage('Error reading tag Bits Per Sample');
exit;
end;
if PTag^.Count = 1 then
begin
BitsPerSampleRed := PTag^.Value;
BitsPerSampleGreen := PTag^.Value;
BitsPerSampleBlue := PTag^.Value;
end
else
begin
ReadBitsPerSampleColor(FileName, PTag^.Value,
BitsPerSampleRed, BitsPerSampleGreen, BitsPerSampleBlue);
end;
if (BitsPerSampleRed <> 8) and
(BitsPerSampleGreen <> 8) and
(BitsPerSampleBlue <> 8) then
begin
showmessage('Error: Bits Per Sample (RGB) not 8');
exit;
end;
// Read Image Data
if ReadImageDataFromFile( FileName, ImageBuffer, GraphTiff) = 0 then
begin
ExchangeRedAndBlue(ImageBuffer, ImageWidth*ImageHeight);
AlignBmpRows(ImageBuffer, GraphTiff);
DisplayImage(ImageWidth, ImageHeight, 24, ImageBuffer, Bitmap);
FreeMem(ImageBuffer);
end
else
begin
showmessage('Error reading image data');
end;
end
else
begin
showmessage('Cant read compressed RGB Full Color Image'+#13+#13+
'feel free to implement this type of image'+#13+
'and send it back to krug@sdm.de');
end;
end;
end.
Beispiel :
uses ReadTiff
procedure TForm1.Button1Click(Sender: TObject);
begin
if OpenDialog1.Execute then
begin
LoadTiffFromFile(OpenDialog1.FileName, Image1.Picture.Bitmap);
Image1.Picture.Bitmap.SaveToFile(OpenDialog1.FileName + '.bmp');
Image1.Refresh;
end;
end;
Keine Kommentare:
Kommentar veröffentlichen