tiff: read 1-bit white/black images, fixes mantis #23959

git-svn-id: trunk@23664 -
This commit is contained in:
Mattias Gaertner 2013-02-26 14:58:51 +00:00
parent 5812cf3b46
commit e5f60c6229
2 changed files with 78 additions and 41 deletions

View File

@ -1,6 +1,6 @@
{
This file is part of the Free Pascal run time library.
Copyright (c) 2012 by the Free Pascal development team
Copyright (c) 2012-2013 by the Free Pascal development team
Tiff reader for fpImage.
@ -14,6 +14,7 @@
**********************************************************************
Working:
Black and white 1 bit,
Grayscale 8,16bit (optional alpha),
RGB 8,16bit (optional alpha),
Orientation,
@ -212,8 +213,8 @@ begin
for i:=0 to SampleCnt-1 do begin
if SampleBits[i]>64 then
TiffError('Samples bigger than 64 bit not supported');
if not (SampleBits[i] in [8, 16]) then
TiffError('Only samples of 8 and 16 bit are supported');
if not (SampleBits[i] in [1, 8, 16]) then
TiffError('Only samples of 1, 8 and 16 bit are supported');
inc(SampleBitsPerPixel, SampleBits[i]);
end;
case IFD.PhotoMetricInterpretation of
@ -227,8 +228,8 @@ begin
IFD.AlphaBits:=AlphaBits;
end;
end;
if not (GrayBits in [8, 16]) then
TiffError('gray image only supported with gray BitsPerSample 8 or 16');
if not (GrayBits in [1, 8, 16]) then
TiffError('gray image only supported with gray BitsPerSample 1, 8 or 16');
if not (AlphaBits in [0, 8, 16]) then
TiffError('gray image only supported with alpha BitsPerSample 8 or 16');
end;
@ -358,26 +359,44 @@ end;
procedure TFPReaderTiff.ReadImgValue(BitCount: Word; var Run: Pointer; x: dword;
Predictor: word; var LastValue: word; out Value: Word); inline;
var
BitNumber: byte;
begin
if BitCount=8 then begin
Value:=PCUInt8(Run)^;
if Predictor=2 then begin
// horizontal difference
if x>0 then
Value:=(Value+LastValue) and $ff;
LastValue:=Value;
case BitCount of
1:
begin
//Get the value of the right bit depending on x value and scale it to dword.
BitNumber:=7-(x mod 8); //Leftmost pixel starts with bit 7
Value:=$ffff*((PCUInt8(Run)^) and (1 shl BitNumber) shr BitNumber);
if Predictor=2 then begin
TiffError('predictor 2 not supported for bilevel images');
end;
if ((x+1) mod 8)=0 then
inc(Run); //next byte when all bits read
end;
Value:=Value shl 8+Value;
inc(Run);
end else if BitCount=16 then begin
Value:=FixEndian(PCUInt16(Run)^);
if Predictor=2 then begin
// horizontal difference
if x>0 then
Value:=(Value+LastValue) and $ffff;
LastValue:=Value;
8:
begin
Value:=PCUInt8(Run)^;
if Predictor=2 then begin
// horizontal difference
if x>0 then
Value:=(Value+LastValue) and $ff;
LastValue:=Value;
end;
Value:=Value shl 8+Value;
inc(Run);
end;
16:
begin
Value:=FixEndian(PCUInt16(Run)^);
if Predictor=2 then begin
// horizontal difference
if x>0 then
Value:=(Value+LastValue) and $ffff;
LastValue:=Value;
end;
inc(Run,2);
end;
inc(Run,2);
end;
end;
@ -630,7 +649,7 @@ begin
end;
257:
begin
// ImageLength
// ImageLength according to TIFF spec, here used as imageheight
IFD.ImageHeight:=ReadEntryUnsigned;
{$ifdef FPC_Debug_Image}
if Debug then
@ -822,11 +841,11 @@ begin
end;
273:
begin
// StripOffsets
IFD.StripOffsets:=GetPos;
// StripOffsets (store offset to entity, not the actual contents of the offsets)
IFD.StripOffsets:=GetPos; //Store position of entity so we can look up multiple offsets later
{$ifdef FPC_Debug_Image}
if Debug then
writeln('TFPReaderTiff.ReadDirectoryEntry Tag 273: StripOffsets=',IFD.StripOffsets);
writeln('TFPReaderTiff.ReadDirectoryEntry Tag 273: StripOffsets, offset for entry=',IFD.StripOffsets);
{$endif}
end;
274:
@ -886,11 +905,12 @@ begin
end;
279:
begin
// StripByteCounts
// StripByteCounts (the number of bytes in each strip).
// We're storing the position of the tag, not the various bytecounts themselves
IFD.StripByteCounts:=GetPos;
{$ifdef FPC_Debug_Image}
if Debug then
writeln('TFPReaderTiff.ReadDirectoryEntry Tag 279: StripByteCounts=',IFD.StripByteCounts);
writeln('TFPReaderTiff.ReadDirectoryEntry Tag 279: StripByteCounts, offset for entry=',IFD.StripByteCounts);
{$endif}
end;
280:
@ -914,8 +934,12 @@ begin
// XResolution
IFD.XResolution:=ReadEntryRational;
{$ifdef FPC_Debug_Image}
if Debug then
writeln('TFPReaderTiff.ReadDirectoryEntry Tag 282: XResolution=',IFD.XResolution.Numerator,',',IFD.XResolution.Denominator);
try
if Debug then
writeln('TFPReaderTiff.ReadDirectoryEntry Tag 282: XResolution=',IFD.XResolution.Numerator,'/',IFD.XResolution.Denominator,'=',IFD.XResolution.Numerator/IFD.XResolution.Denominator);
except
//ignore division by 0
end;
{$endif}
end;
283:
@ -923,17 +947,20 @@ begin
// YResolution
IFD.YResolution:=ReadEntryRational;
{$ifdef FPC_Debug_Image}
if Debug then
writeln('TFPReaderTiff.ReadDirectoryEntry Tag 283: YResolution=',IFD.YResolution.Numerator,',',IFD.YResolution.Denominator);
{$endif}
try
if Debug then
writeln('TFPReaderTiff.ReadDirectoryEntry Tag 283: YResolution=',IFD.YResolution.Numerator,'/',IFD.YResolution.Denominator,'=',IFD.YResolution.Numerator/IFD.YResolution.Denominator);
except
//ignore division by 0
end; {$endif}
end;
284:
begin
// PlanarConfiguration
SValue:=ReadEntrySigned;
case SValue of
1: ; // chunky format
2: ; // planar format
TiffPlanarConfigurationChunky: ; // 1
TiffPlanarConfigurationPlanar: ; // 2
else
TiffError('expected PlanarConfiguration, but found '+IntToStr(SValue));
end;
@ -942,8 +969,8 @@ begin
if Debug then begin
write('TFPReaderTiff.ReadDirectoryEntry Tag 284: PlanarConfiguration=');
case SValue of
1: write('chunky format');
2: write('planar format');
TiffPlanarConfigurationChunky: write('chunky format');
TiffPlanarConfigurationPlanar: write('planar format');
end;
writeln;
end;
@ -1651,7 +1678,7 @@ begin
ReadShortOrLongValues(IFD.TileByteCounts,ChunkByteCounts,CurCount);
if CurCount<>ChunkCount then
TiffError('number of TileByteCounts is wrong');
end else begin
end else begin //strip
ChunkCount:=((IFD.ImageHeight-1) div IFD.RowsPerStrip)+1;
ReadShortOrLongValues(IFD.StripOffsets,ChunkOffsets,CurCount);
if CurCount<>ChunkCount then
@ -1724,7 +1751,7 @@ begin
// boundary tiles have padding
ChunkBytesPerLine:=(SampleBitsPerPixel*IFD.TileWidth+7) div 8;
end;
end else begin
end else begin //tctStrip
ChunkLeft:=0;
ChunkTop:=IFD.RowsPerStrip*ChunkIndex;
ChunkWidth:=IFD.ImageWidth;
@ -1774,7 +1801,7 @@ begin
x:=sx;
for cx:=0 to ChunkWidth-1 do begin
case IFD.PhotoMetricInterpretation of
0,1:
0,1: // 0:bilevel grayscale 0 is white; 1:0 is black
begin
ReadImgValue(GrayBits,Run,cx,IFD.Predictor,LastGrayValue,GrayValue);
if IFD.PhotoMetricInterpretation=0 then

View File

@ -94,6 +94,10 @@ const
TiffCompressionSGILog = 34676; { SGILOG }
TiffCompressionSGILog24 = 34677; { SGILOG24 }
TiffCompressionJPEG2000 = 34712; { JP2000 }
// Planar configuration - TIFF 6.0 spec p. 38
TiffPlanarConfigurationChunky = 1; //Chunky format
TiffPlanarConfigurationPlanar = 2; //Planar format
type
TTiffChunkType = (
tctStrip,
@ -160,6 +164,7 @@ type
procedure Assign(IFD: TTiffIFD);
procedure ReadFPImgExtras(Src: TFPCustomImage);
function ImageLength: DWord; inline;
constructor Create;
destructor Destroy; override;
end;
@ -258,7 +263,7 @@ begin
IFDStart:=0;
IFDNext:=0;
PhotoMetricInterpretation:=High(PhotoMetricInterpretation);
PlanarConfiguration:=0;
PlanarConfiguration:=TiffPlanarConfigurationChunky;
Compression:=TiffCompressionNone;
Predictor:=1;
ImageHeight:=0;
@ -408,6 +413,11 @@ begin
Result:=ImageHeight;
end;
constructor TTiffIFD.Create;
begin
PlanarConfiguration:=TiffPlanarConfigurationChunky;
end;
destructor TTiffIFD.Destroy;
begin
if FreeImg then