+ Fixed reading of pnm

This commit is contained in:
michael 2004-03-03 00:03:34 +00:00
parent 67f23651c2
commit 85f1c027f5

View File

@ -14,13 +14,17 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
} }
{*****************************************************************************} {*****************************************************************************}
{The PNM (Portable aNyMaps) is a generic name for :
{
The PNM (Portable aNyMaps) is a generic name for :
PBM : Portable BitMaps, PBM : Portable BitMaps,
PGM : Portable GrayMaps, PGM : Portable GrayMaps,
PPM : Portable PixMaps. PPM : Portable PixMaps.
There is no file format associated with PNM itself.} There is no file format associated with PNM itself.}
{$mode objfpc}{$h+} {$mode objfpc}{$h+}
unit FPReadPNM; unit FPReadPNM;
interface interface
uses FPImage, classes, sysutils; uses FPImage, classes, sysutils;
@ -28,113 +32,272 @@ uses FPImage, classes, sysutils;
type type
TFPReaderPNM=class (TFPCustomImageReader) TFPReaderPNM=class (TFPCustomImageReader)
private private
BitMapType:Integer; FBitMapType : Integer;
FWidth : Integer;
FHeight : Integer;
protected protected
FMaxVal : Integer;
FBPP : Byte;
FScanLineSize : Integer;
FScanLine : PByte;
procedure ReadHeader(Stream : TStream);
function InternalCheck (Stream:TStream):boolean;override; function InternalCheck (Stream:TStream):boolean;override;
procedure InternalRead(Stream:TStream;Img:TFPCustomImage);override; procedure InternalRead(Stream:TStream;Img:TFPCustomImage);override;
procedure ReadScanLine(Row : Integer; Stream:TStream);
procedure WriteScanLine(Row : Integer; Img : TFPCustomImage);
end; end;
implementation implementation
function TFPReaderPNM.InternalCheck(Stream:TStream):boolean; function TFPReaderPNM.InternalCheck(Stream:TStream):boolean;
var
StrBitMapType:String[3];
begin begin
InternalCheck:=False; InternalCheck:=True;
with stream do
StrBitMapType[0]:=Chr(Read(StrBitMapType[1],2));
BitMapType:=Ord(StrBitMapType[2])-Ord('0');
InternalCheck:=(Length(StrBitMapType)=2)and(StrBitMapType[1]='P')and(BitMapType in [1..6]);
end; end;
{TODO : real implementation of InternalRead}
procedure TFPReaderPNM.InternalRead(Stream:TStream;Img:TFPCustomImage);
const const
{Whitespace (TABs, CRs, LFs, blanks) are separators in the PNM Headers} WhiteSpaces=[#9,#10,#13,#32]; {Whitespace (TABs, CRs, LFs, blanks) are separators in the PNM Headers}
WhiteSpaces=[#9,#10,#13,#32];
function DropWhiteSpaces:Char; function DropWhiteSpaces(Stream : TStream) :Char;
begin begin
with Stream do with Stream do
begin begin
repeat repeat
Read(DropWhiteSpaces,1); ReadBuffer(DropWhiteSpaces,1);
until not(DropWhiteSpaces in WhiteSpaces); until not(DropWhiteSpaces in WhiteSpaces);
if DropWhiteSpaces='#' if DropWhiteSpaces='#' then
then
begin begin
repeat repeat
Read(DropWhiteSpaces,1); ReadBuffer(DropWhiteSpaces,1);
until DropWhiteSpaces=#10; until DropWhiteSpaces=#10;
Read(DropWhiteSpaces,1); ReadBuffer(DropWhiteSpaces,1);
end; end;
end; end;
end; end;
function ReadInteger:Integer;
function ReadInteger(Stream : TStream) :Integer;
var var
s:String[7]; s:String[7];
begin begin
s:=''; s:='';
s[1]:=DropWhiteSpaces; s[1]:=DropWhiteSpaces(Stream);
with Stream do with Stream do
repeat repeat
Inc(s[0]); Inc(s[0]);
Read(s[Length(s)+1],1) ReadBuffer(s[Length(s)+1],1)
until s[Length(s)+1] in WhiteSpaces; until s[Length(s)+1] in WhiteSpaces;
Val(s,ReadInteger); Result:=StrToInt(s);
end; end;
procedure TFPReaderPNM.ReadHeader(Stream : TStream);
Var
C : Char;
begin
Stream.ReadBuffer(C,1);
If (C<>'P') then
Raise Exception.Create('Not a valid PNM image.');
Stream.ReadBuffer(C,1);
FBitmapType:=Ord(C)-Ord('0');
If Not (FBitmapType in [2,3,5,6]) then
Raise Exception.CreateFmt('Unknown PNM subtype : %s',[C]);
FWidth:=ReadInteger(Stream);
FHeight:=ReadInteger(Stream);
FMaxVal:=ReadInteger(Stream);
If (FWidth<=0) or (FHeight<=0) or (FMaxVal<=0) then
Raise Exception.Create('Invalid PNM header data');
case FBitMapType of
2: FBPP:=SizeOf(Word); // Grayscale (text)
3: FBPP:=SizeOf(Word)*3; // RGB (text)
5: If (FMaxval>255) then // Grayscale (raw);
FBPP:=2
else
FBPP:=1;
6: if (FMaxVal>255) then // RGB (raw)
FBPP:=6
else
FBPP:=3
end;
// Writeln(FWidth,'x',Fheight,' Maxval: ',FMaxVal,' BPP: ',FBPP);
end;
procedure TFPReaderPNM.InternalRead(Stream:TStream;Img:TFPCustomImage);
var var
Row,Coulumn,nBpLine,ReadSize:Integer; Row,Coulumn,nBpLine,ReadSize:Integer;
aColor:TFPcolor; aColor:TFPcolor;
aLine:PByte; aLine:PByte;
begin begin
Row:=ReadInteger; ReadHeader(Stream);
Coulumn:=ReadInteger; Img.SetSize(FWidth,FHeight);
Img.SetSize(Row,Coulumn); FScanLineSize:=FBPP*FWidth;
WriteLn(ReadInteger); GetMem(FScanLine,FBPP*FWidth);
case BitMapType of try
1:nBpLine:=Img.Width*2;{p p p}
2:nBpLine:=Img.Width*4;{lll lll lll}
3:nBpLine:=Img.Width*3*4;{rrr ggg bbb rrr ggg bbb}
4:begin
nBpLine:=Img.Width SHR 3;
if(Img.Width AND $0F)<>0
then
Inc(nBpLine);
end;
5:nBpLine:=Img.Width;
6:nBpLine:=Img.Width*3;
end;
GetMem(aLine,nBpLine);
for Row:=0 to img.Height-1 do for Row:=0 to img.Height-1 do
begin begin
Stream.Read(aLine^,nBpLine); ReadScanLine(Row,Stream);
for Coulumn:=0 to img.Width-1 do WriteScanLine(Row,Img);
with aColor do end;
finally
FreeMem(FScanLine);
end;
end;
procedure TFPReaderPNM.ReadScanLine(Row : Integer; Stream:TStream);
Var
P : PWord;
I : Integer;
begin begin
case BitMapType of Case FBitmapType of
1:; 2 : begin
2:; P:=PWord(FScanLine);
3:; For I:=0 to FWidth-1 do
4:; begin
5:; P^:=ReadInteger(Stream);
6:begin Inc(P);
Red:=aLine[3*Coulumn] shl 8;
Green:=aLine[3*Coulumn+1] shl 8;
Blue:=aLine[3*Coulumn+2] shl 8;
end; end;
end; end;
alpha:=AlphaOpaque; 3 : begin
img.colors[Coulumn,Row]:=aColor; P:=PWord(FScanLine);
For I:=0 to FWidth-1 do
begin
P^:=ReadInteger(Stream); // Red
Inc(P);
P^:=ReadInteger(Stream); // Green
Inc(P);
P^:=ReadInteger(Stream); // Blue;
Inc(P)
end; end;
end; end;
FreeMem(aLine,nBpLine); 5,6 : Stream.ReadBuffer(FScanLine^,FScanLineSize);
end;
end;
procedure TFPReaderPNM.WriteScanLine(Row : Integer; Img : TFPCustomImage);
Var
C : TFPColor;
L : Cardinal;
FHalfMaxVal : Word;
Procedure WordGrayScanLine;
Var
P : PWord;
I : Integer;
begin
P:=PWord(FScanLine);
For I:=0 to FWidth-1 do
begin
L:=(((P^ shl 16)+FHalfMaxVal) div FMaxVal) and $FFFF;
C.Red:=L;
C.Green:=L;
C.Blue:=L;
Img.Colors[I,Row]:=C;
Inc(P);
end;
end;
Procedure WordRGBScanLine;
Var
P : PWord;
I : Integer;
begin
P:=PWord(FScanLine);
For I:=0 to FWidth-1 do
begin
L:=(((P^ shl 16)+FHalfMaxVal) div FMaxVal) and $FFFF;
C.Red:=L;
Inc(P);
L:=(((P^ shl 16)+FHalfMaxVal) div FMaxVal) and $FFFF;
C.Green:=L;
Inc(P);
L:=(((P^ shl 16)+FHalfMaxVal) div FMaxVal) and $FFFF;
C.Blue:=L;
Img.Colors[I,Row]:=C;
Inc(P);
end;
end;
Procedure ByteGrayScanLine;
Var
P : PByte;
I : Integer;
begin
P:=PByte(FScanLine);
For I:=0 to FWidth-1 do
begin
L:=(((P^ shl 16)+FHalfMaxVal) div FMaxVal) and $FFFF;
C.Red:=L;
C.Green:=L;
C.Blue:=L;
Img.Colors[I,Row]:=C;
Inc(P);
end;
end;
Procedure ByteRGBScanLine;
Var
P : PByte;
I : Integer;
begin
P:=PByte(FScanLine);
For I:=0 to FWidth-1 do
begin
L:=(((P^ shl 16)+FHalfMaxVal) div FMaxVal) and $FFFF;
C.Red:=L;
Inc(P);
L:=(((P^ shl 16)+FHalfMaxVal) div FMaxVal) and $FFFF;
C.Green:=L;
Inc(P);
L:=(((P^ shl 16)+FHalfMaxVal) div FMaxVal) and $FFFF;
C.Blue:=L;
Img.Colors[I,Row]:=C;
Inc(P);
end;
end;
begin
C.Alpha:=AlphaOpaque;
FHalfMaxVal:=(FMaxVal div 2);
Case FBitmapType of
2 : WordGrayScanline;
3 : WordRGBSCanline;
5 : If FBPP=1 then
ByteGrayScanLine
else
WordGrayScanLine;
6 : If FBPP=3 then
ByteRGBScanLine
else
WordRGBScanLine;
end;
end; end;
initialization initialization
ImageHandlers.RegisterImageReader ('PNM Format', 'PNM', TFPReaderPNM); ImageHandlers.RegisterImageReader ('PNM Format', 'PNM;PGM;PBM', TFPReaderPNM);
end. end.
{ {
$Log$ $Log$
Revision 1.2 2003-09-30 12:26:33 mazen Revision 1.3 2004-03-03 00:03:34 michael
+ Fixed reading of pnm
Revision 1.2 2003/09/30 12:26:33 mazen
+ reading P6 format implemented. + reading P6 format implemented.
Revision 1.1 2003/09/30 07:15:48 mazen Revision 1.1 2003/09/30 07:15:48 mazen