123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590 |
- (* PNG 1.2 Portable Network Graphics *)
- (* TF 28.9.2000 *)
- (* TF 23.8.2004 updated with Codecs and Inflate *)
- (* ftp://ftp.uu.net/graphics/png/images/ *)
- MODULE PNGDecoder; (** AUTHOR "TF"; PURPOSE "PNG decoder"; *)
- IMPORT
- SYSTEM, KernelLog, CRC, Raster, Streams, Inflate, WMGraphics, Codecs, Kernel;
- CONST
- BufSize = 4096 * 8; Trace = FALSE;
- VAR
- StartingRow, StartingCol, RowIncrement, ColIncrement: ARRAY 7 OF LONGINT;
- TYPE
- (* lenght = Chunksize -ChunkHeader -ChunkChecksum*)
- ChunkHeader = RECORD length : LONGINT; name : ARRAY 5 (* ....+0H*) OF CHAR END;
- PNGHead = RECORD
- width : LONGINT;
- height : LONGINT;
- bitDepth : LONGINT; (* Byte *)
- colorType : LONGINT; (* Byte *)
- compressMethod : LONGINT; (* Byte *)
- filterMethod: LONGINT; (* Byte *)
- interlaceMethod: LONGINT; (* Byte *)
- END;
- IDATReader* = OBJECT
- VAR (* General vars: *)
- inR: Streams.Reader;
- remain: LONGINT;
- eof : BOOLEAN;
- PROCEDURE &Init*(firstChunk : LONGINT; inR : Streams.Reader; VAR outR: Streams.Reader);
- BEGIN
- SELF.inR := inR;
- Streams.OpenReader(outR, Receiver);
- eof := FALSE;
- remain := firstChunk;
- END Init;
- PROCEDURE Receiver(VAR buf: ARRAY OF CHAR; ofs, size, min: LONGINT; VAR len: LONGINT; VAR res: WORD);
- VAR i, crc, tag: LONGINT; ch: CHAR;
- BEGIN
- IF ~eof THEN
- ASSERT((size > 0) & (min <= size) & (min >= 0));
- len := 0; i := ofs; res := Streams.Ok;
- WHILE (res = Streams.Ok) & (len < size) & ~eof DO
- (* Read the chunk size *)
- IF remain = 0 THEN
- crc := inR.Net32();
- (* KernelLog.String("crc= "); KernelLog.Hex(crc, 0); KernelLog.Ln; *)
- remain := inR.Net32();
- (* KernelLog.String("remain= "); KernelLog.Int(remain, 0); KernelLog.Ln; *)
- tag := inR.Net32();
- (* KernelLog.String("tag= "); KernelLog.Hex(tag, 0); KernelLog.Ln; *)
- IF tag # 049444154H THEN eof := TRUE END;
- END;
- (* Fill data into out buffer *)
- WHILE (res = Streams.Ok) & (len < size) & (remain > 0) DO
- inR.Char(ch);
- res := inR.res;
- buf[i] := ch;
- INC(len); INC(i); DEC(remain);
- END;
- END;
- ELSE
- res := Streams.EOF
- END
- END Receiver;
- END IDATReader;
- PNGDecoder = OBJECT(Codecs.ImageDecoder)
- VAR
- in : Streams.Reader;
- errors : BOOLEAN;
- first, last, isIDAT : BOOLEAN;
- hdr : PNGHead;
- crc : CRC.CRC32Stream;
- pic : Raster.Image;
- format8 : Raster.Format;
- palette : Raster.Palette;
- bpp: LONGINT; (* bytes per complete pixel rounded up to bytes*)
- decoder : Inflate.Reader;
- (* bytes per line - filtertyp byte *)
- PROCEDURE GetLineSize(width : LONGINT) : LONGINT;
- BEGIN
- CASE hdr.colorType OF
- 0: RETURN (hdr.bitDepth * width + 7) DIV 8
- |2: RETURN (hdr.bitDepth DIV 8) * 3 * width
- |3: RETURN (hdr.bitDepth * width + 7) DIV 8
- |4: RETURN (hdr.bitDepth DIV 4) * width
- |6: RETURN (hdr.bitDepth DIV 2) * width
- END
- END GetLineSize;
- PROCEDURE Init;
- BEGIN
- NEW(pic);
- CASE hdr.colorType OF
- 0: (* grayscale possibly 1, 2, 4, 8, 16 bit *)
- (* neither 16 bit nor grayscale support in Raster *)
- Raster.Create(pic, hdr.width, hdr.height, Raster.BGR888);
- bpp := (hdr.bitDepth + 7) DIV 8
- |2: (* RGB, 8 or 16 bit*)
- (* no 16 bit support in Raster *)
- Raster.Create(pic, hdr.width, hdr.height, Raster.BGR888);
- bpp := (3 * hdr.bitDepth + 7) DIV 8
- |3: (* color mapped 1, 2, 4, 8 bit *)
- NEW(palette);
- Raster.InitPalette(palette, 256, 5);
- Raster.InitPaletteFormat(format8, palette);
- Raster.Create(pic, hdr.width, hdr.height, format8);
- bpp := 1
- |4: (* greyscale + alpha 8 or 16 bit *)
- (* neither 16 bit nor grayscale support in Raster *)
- Raster.Create(pic, hdr.width, hdr.height, Raster.BGRA8888);
- bpp := (hdr.bitDepth * 2) DIV 8
- |6: (* RGB + alpha 8 or 16 bit *)
- (* no 16 bit support in Raster *)
- Raster.Create(pic, hdr.width, hdr.height, Raster.BGRA8888);
- bpp := (4 * hdr.bitDepth) DIV 8
- ELSE Error("Unknown Color Type")
- END;
- END Init;
- PROCEDURE Decode;
- VAR x, y, cp : LONGINT;
- filter, ls : LONGINT;
- p : ADDRESS;
- c, dummy : CHAR;
- prior, current, temp : POINTER TO ARRAY OF CHAR;
- currentByte : CHAR;
- bitPos : LONGINT;
- lastRowStart : ADDRESS;
- len,time,t1,t2 : LONGINT;
- color: RECORD b,g,r,a: CHAR END;
- PROCEDURE GetNextBit() : LONGINT;
- BEGIN
- IF bitPos MOD 8 = 0 THEN currentByte := GetNextFilterByte(); bitPos := 0 END;
- INC(bitPos);
- RETURN ORD(LSH(currentByte, bitPos-8 )) MOD 2
- END GetNextBit;
- PROCEDURE GetNext2Bits() : LONGINT;
- BEGIN
- IF bitPos MOD 8 = 0 THEN currentByte := GetNextFilterByte(); bitPos := 0 END;
- INC(bitPos, 2);
- RETURN ORD(LSH(currentByte, bitPos-8)) MOD 4
- END GetNext2Bits;
- PROCEDURE GetNext4Bits() : LONGINT;
- BEGIN
- IF bitPos MOD 8 = 0 THEN currentByte := GetNextFilterByte(); bitPos := 0 END;
- INC(bitPos, 4);
- RETURN ORD(LSH(currentByte, bitPos-8)) MOD 16
- END GetNext4Bits;
- PROCEDURE GetNextFilterByte() : CHAR;
- VAR result:CHAR;
- t1, t2:LONGINT; f: LONGINT;
- BEGIN
- CASE filter OF
- | 0 : result := current[cp]
- |1 : result := CHR(ORD(current[cp])+ORD(current[cp-bpp]));
- |2 : result := CHR(ORD(current[cp])+ORD(prior[cp]))
- |3 : t1 := ORD(current[cp-bpp]); t2 := ORD(prior[cp]); result:=CHR(ORD(current[cp])+(t1+t2) DIV 2)
- |4 : result := CHR(ORD(current[cp])+
- ORD(PaethPredictor(ORD(current[cp-bpp]), ORD(prior[cp]), ORD(prior[cp-bpp]))))
- ELSE
- KernelLog.String("filter= "); KernelLog.Int(filter, 0);
- Error("illegal filter type")
- END; current[cp] := result;
- INC(cp);
- RETURN result
- END GetNextFilterByte;
- BEGIN
- time := Kernel.GetTicks();
- bitPos := 0;
- p := pic.adr;
- IF Trace THEN KernelLog.String("bpp:"); KernelLog.Int(bpp, 8); KernelLog.Ln; END;
- ls := GetLineSize(hdr.width); NEW(prior, ls + bpp); NEW(current, ls + bpp);
- IF hdr.interlaceMethod = 0 THEN
- FOR y := 0 TO hdr.height - 1 DO
- lastRowStart := p;
- filter := ORD(decoder.Get());
- cp := bpp;
- decoder.Bytes(current^, cp, ls, len);
- cp := bpp;
- CASE hdr.colorType OF
- |0: (* color type 0 grayscale*)
- FOR x := 0 TO hdr.width -1 DO
- CASE hdr.bitDepth OF
- |1 : c := CHR(GetNextBit() * 255)
- |2 : c := CHR(GetNext2Bits() * 85)
- |4 : c := CHR(GetNext4Bits() * 16)
- |8 : c := GetNextFilterByte()
- |16 : c := GetNextFilterByte(); dummy := GetNextFilterByte()
- END;
- SYSTEM.PUT8(p, c); INC(p);
- SYSTEM.PUT8(p, c); INC(p);
- SYSTEM.PUT8(p, c); INC(p);
- END
- |2:(* color type 2 rgb *)
- IF (hdr.bitDepth # 16) THEN
- CASE filter OF
- 0:
- FOR x:=0 TO hdr.width-1 DO
- color.r := CHR(ORD(current[cp])); INC(cp);
- color.g := CHR(ORD(current[cp])); INC(cp);
- color.b := CHR(ORD(current[cp])); INC(cp);
- SYSTEM.PUT8(p, color.b); INC(p);
- SYSTEM.PUT8(p, color.g); INC(p);
- SYSTEM.PUT8(p, color.r); INC(p);
- END;
- |1:
- FOR x:=0 TO hdr.width-1 DO
- color.r := CHR(ORD(current[cp])+ORD(current[cp-bpp])); current[cp] := color.r; INC(cp);
- color.g := CHR(ORD(current[cp])+ORD(current[cp-bpp])); current[cp] :=color.g; INC(cp);
- color.b := CHR(ORD(current[cp])+ORD(current[cp-bpp])); current[cp] := color.b; INC(cp);
- SYSTEM.PUT8(p, color.b); INC(p);
- SYSTEM.PUT8(p, color.g); INC(p);
- SYSTEM.PUT8(p, color.r); INC(p);
- END;
- |2:
- FOR x:=0 TO hdr.width-1 DO
- color.r := CHR(ORD(current[cp])+ORD(prior[cp])); current[cp] := color.r; INC(cp);
- color.g := CHR(ORD(current[cp])+ORD(prior[cp])); current[cp] := color.g;INC(cp);
- color.b := CHR(ORD(current[cp])+ORD(prior[cp])); current[cp] := color.b;INC(cp);
- SYSTEM.PUT8(p, color.b); INC(p);
- SYSTEM.PUT8(p, color.g); INC(p);
- SYSTEM.PUT8(p, color.r); INC(p);
- END;
- |3:
- FOR x:=0 TO hdr.width-1 DO
- t1 := ORD(current[cp-bpp]); t2 := ORD(prior[cp]); color.r:=CHR(ORD(current[cp])+(t1+t2) DIV 2); current[cp] := color.r;INC(cp);
- t1 := ORD(current[cp-bpp]); t2 := ORD(prior[cp]); color.g:=CHR(ORD(current[cp])+(t1+t2) DIV 2); current[cp] := color.g;INC(cp);
- t1 := ORD(current[cp-bpp]); t2 := ORD(prior[cp]); color.b:=CHR(ORD(current[cp])+(t1+t2) DIV 2); current[cp] := color.b;INC(cp);
- SYSTEM.PUT8(p, color.b); INC(p);
- SYSTEM.PUT8(p, color.g); INC(p);
- SYSTEM.PUT8(p, color.r); INC(p);
- END;
- |4:
- FOR x:=0 TO hdr.width-1 DO
- color.r := CHR(ORD(current[cp])+ ORD(PaethPredictor(ORD(current[cp-bpp]), ORD(prior[cp]), ORD(prior[cp-bpp])))); current[cp] := color.r;INC(cp);
- color.g := CHR(ORD(current[cp])+ORD(PaethPredictor(ORD(current[cp-bpp]), ORD(prior[cp]), ORD(prior[cp-bpp])))); current[cp] := color.g;INC(cp);
- color.b := CHR(ORD(current[cp])+ORD(PaethPredictor(ORD(current[cp-bpp]), ORD(prior[cp]), ORD(prior[cp-bpp])))); current[cp] := color.b;INC(cp);
- SYSTEM.PUT8(p, color.b); INC(p);
- SYSTEM.PUT8(p, color.g); INC(p);
- SYSTEM.PUT8(p, color.r); INC(p);
- END;
- END;
- ELSE
- FOR x := 0 TO hdr.width-1 DO
- color.r := GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
- color.g := GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
- color.b := GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
- SYSTEM.PUT8(p, color.b); INC(p);
- SYSTEM.PUT8(p, color.g); INC(p);
- SYSTEM.PUT8(p, color.r); INC(p);
- END
- END;
- |3: (* color type 3 *)
- FOR x:=0 TO hdr.width -1 DO
- CASE hdr.bitDepth OF
- |1 : c := CHR(GetNextBit())
- |2 : c := CHR(GetNext2Bits())
- |4 : c := CHR(GetNext4Bits())
- |8 : c := GetNextFilterByte()
- END;
- SYSTEM.PUT8(p, c); INC(p)
- END
- |4:(* color type 4 grayscale + alpha *)
- FOR x:=0 TO hdr.width-1 DO
- c := GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
- color.a := GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
- c := CHR(ORD(c) * ORD(color.a) DIV 256);
- SYSTEM.PUT8(p, c); INC(p);
- SYSTEM.PUT8(p, c); INC(p);
- SYSTEM.PUT8(p, c); INC(p);
- SYSTEM.PUT8(p, color.a); INC(p)
- END;
- |6:(* color type 6 rgb + alpha *)
- IF (hdr.bitDepth # 16) THEN
- CASE filter OF
- 0: FOR x:=0 TO hdr.width-1 DO
- color.r := CHR(ORD(current[cp])); INC(cp);
- color.g := CHR(ORD(current[cp])); INC(cp);
- color.b := CHR(ORD(current[cp])); INC(cp);
- color.a := CHR(ORD(current[cp])); INC(cp);
- (*SYSTEM.GET(SYSTEM.ADR(current[cp]), SYSTEM.VAL(LONGINT, color)); INC(cp,4);*)
- IF ORD(color.a) = 255 THEN
- SYSTEM.PUT32(p,SYSTEM.VAL(LONGINT,color)); INC(p,4);
- ELSE
- SYSTEM.PUT8(p, CHR(ORD(color.b)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, CHR(ORD(color.g)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, CHR(ORD(color.r)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, color.a); INC(p)
- END;
- END;
- |1:
- FOR x:=0 TO hdr.width-1 DO
- color.r := CHR(ORD(current[cp])+ORD(current[cp-bpp])); current[cp] := color.r; INC(cp);
- color.g := CHR(ORD(current[cp])+ORD(current[cp-bpp])); current[cp] :=color.g; INC(cp);
- color.b := CHR(ORD(current[cp])+ORD(current[cp-bpp])); current[cp] := color.b; INC(cp);
- color.a := CHR(ORD(current[cp])+ORD(current[cp-bpp])); current[cp] := color.a; INC(cp);
- IF ORD(color.a) = 255 THEN
- SYSTEM.PUT32(p,SYSTEM.VAL(LONGINT,color)); INC(p,4);
- ELSE
- SYSTEM.PUT8(p, CHR(ORD(color.b)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, CHR(ORD(color.g)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, CHR(ORD(color.r)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, color.a); INC(p)
- END;
- END;
- |2:
- FOR x:=0 TO hdr.width-1 DO
- color.r := CHR(ORD(current[cp])+ORD(prior[cp])); current[cp] := color.r; INC(cp);
- color.g := CHR(ORD(current[cp])+ORD(prior[cp])); current[cp] := color.g;INC(cp);
- color.b := CHR(ORD(current[cp])+ORD(prior[cp])); current[cp] := color.b;INC(cp);
- color.a := CHR(ORD(current[cp])+ORD(prior[cp])); current[cp] := color.a;INC(cp);
- IF ORD(color.a) = 255 THEN
- SYSTEM.PUT32(p,SYSTEM.VAL(LONGINT,color)); INC(p,4);
- ELSE
- SYSTEM.PUT8(p, CHR(ORD(color.b)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, CHR(ORD(color.g)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, CHR(ORD(color.r)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, color.a); INC(p)
- END;
- END;
- |3:
- FOR x:=0 TO hdr.width-1 DO
- t1 := ORD(current[cp-bpp]); t2 := ORD(prior[cp]); color.r:=CHR(ORD(current[cp])+(t1+t2) DIV 2); current[cp] := color.r;INC(cp);
- t1 := ORD(current[cp-bpp]); t2 := ORD(prior[cp]); color.g:=CHR(ORD(current[cp])+(t1+t2) DIV 2); current[cp] := color.g;INC(cp);
- t1 := ORD(current[cp-bpp]); t2 := ORD(prior[cp]); color.b:=CHR(ORD(current[cp])+(t1+t2) DIV 2); current[cp] := color.b;INC(cp);
- t1 := ORD(current[cp-bpp]); t2 := ORD(prior[cp]); color.a:=CHR(ORD(current[cp])+(t1+t2) DIV 2); current[cp] := color.a;INC(cp);
- IF ORD(color.a) = 255 THEN
- SYSTEM.PUT32(p,SYSTEM.VAL(LONGINT,color)); INC(p,4);
- ELSE
- SYSTEM.PUT8(p, CHR(ORD(color.b)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, CHR(ORD(color.g)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, CHR(ORD(color.r)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, color.a); INC(p)
- END;
- END;
- |4:
- FOR x:=0 TO hdr.width-1 DO
- color.r := CHR(ORD(current[cp])+ ORD(PaethPredictor(ORD(current[cp-bpp]), ORD(prior[cp]), ORD(prior[cp-bpp])))); current[cp] := color.r;INC(cp);
- color.g := CHR(ORD(current[cp])+ORD(PaethPredictor(ORD(current[cp-bpp]), ORD(prior[cp]), ORD(prior[cp-bpp])))); current[cp] := color.g;INC(cp);
- color.b := CHR(ORD(current[cp])+ORD(PaethPredictor(ORD(current[cp-bpp]), ORD(prior[cp]), ORD(prior[cp-bpp])))); current[cp] := color.b;INC(cp);
- color.a := CHR(ORD(current[cp])+ORD(PaethPredictor(ORD(current[cp-bpp]), ORD(prior[cp]), ORD(prior[cp-bpp])))); current[cp] := color.a;INC(cp);
- IF ORD(color.a) = 255 THEN
- SYSTEM.PUT32(p,SYSTEM.VAL(LONGINT,color)); INC(p,4);
- ELSE
- SYSTEM.PUT8(p, CHR(ORD(color.b)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, CHR(ORD(color.g)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, CHR(ORD(color.r)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, color.a); INC(p)
- END;
- END;
- END;
- ELSE
- FOR x:=0 TO hdr.width-1 DO
- color.r:=GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
- color.g:=GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
- color.b:=GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
- color.a:=GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
- SYSTEM.PUT8(p, CHR(ORD(color.b)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, CHR(ORD(color.g)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, CHR(ORD(color.r)*ORD(color.a) DIV 256)); INC(p);
- SYSTEM.PUT8(p, color.a); INC(p)
- END
- END;
- END;
- bitPos := 0;
- p := lastRowStart + pic.bpr;
- temp := prior; prior := current; current := temp
- END
- ELSE Error("interlace not yet supported")
- END;
- END Decode;
- PROCEDURE ReadChunkHeader(VAR x: ChunkHeader);
- VAR i:LONGINT;
- BEGIN
- x.length := in.Net32(); (* NOT IN CRC ! *)
- crc.Reset;
- FOR i := 0 TO 3 DO x.name[i] := GetByte() END;
- x.name[4] := CHR(0)
- END ReadChunkHeader;
- PROCEDURE Error(x : ARRAY OF CHAR);
- BEGIN
- KernelLog.String("PNG Decoder : ");
- KernelLog.String(x); KernelLog.Ln;
- (* errors := TRUE *)
- END Error;
- PROCEDURE SkipChunk(x : ChunkHeader);
- VAR i : LONGINT; dummy : CHAR;
- BEGIN
- FOR i := 0 TO x.length - 1 DO dummy := GetByte() END
- END SkipChunk;
- PROCEDURE CheckCRC;
- VAR t, ccrc:LONGINT;
- BEGIN
- ccrc := crc.GetCRC();
- t := in.Net32();
- IF ccrc # t THEN Error("crc-error"); HALT(1234) END
- END CheckCRC;
- PROCEDURE ProcessChunk(x:ChunkHeader);
- VAR i: LONGINT;
- idatr : Streams.Reader;
- idatReader : IDATReader;
- BEGIN
- IF first & ~(x.name = "IHDR") THEN Error("IHDR chunk expected"); RETURN END;
- IF x.name = "IHDR" THEN
- first := FALSE;
- hdr.width := GetLongint();
- hdr.height := GetLongint();
- hdr.bitDepth := ORD(GetByte());
- hdr.colorType := ORD(GetByte());
- hdr.compressMethod := ORD(GetByte());
- hdr.filterMethod := ORD(GetByte());
- hdr.interlaceMethod := ORD(GetByte());
- Init;
- ELSIF x.name = "PLTE" THEN
- FOR i := 0 TO (x.length DIV 3) - 1 DO
- Raster.SetRGB(palette.col[i], ORD(GetByte()), ORD(GetByte()), ORD(GetByte()))
- END
- ELSIF x.name = "IDAT" THEN
- NEW(idatReader, x.length, in, idatr);
- idatr.SkipBytes(2); (* should handle zlib *)
- NEW(decoder, idatr);
- Decode;
- isIDAT:= TRUE;
- ELSIF x.name = "gAMA" THEN SkipChunk(x)
- ELSIF x.name = "sBIT" THEN SkipChunk(x)
- ELSIF x.name = "cHRM" THEN SkipChunk(x)
- ELSIF x.name = "tRNS" THEN
- IF Trace THEN KernelLog.String("Alpha-Palette!!") END;
- NEW(palette);
- FOR i := 0 TO (x.length)-1 DO
- palette.col[i][3] := GetByte();
- palette.col[i][0] := CHR(ORD(palette.col[i][0]) * ORD(palette.col[i][3]) DIV 256);
- palette.col[i][1] := CHR(ORD(palette.col[i][1]) * ORD(palette.col[i][3]) DIV 256);
- palette.col[i][2] := CHR(ORD(palette.col[i][2]) * ORD(palette.col[i][3]) DIV 256);
- END;
- ELSIF x.name = "bKGD" THEN SkipChunk(x)
- ELSIF x.name = "hIST" THEN SkipChunk(x)
- ELSIF x.name = "tEXt" THEN SkipChunk(x)
- ELSIF x.name = "zTXt" THEN SkipChunk(x)
- ELSIF x.name = "pHYs" THEN SkipChunk(x)
- ELSIF x.name = "oFFs" THEN SkipChunk(x)
- ELSIF x.name = "tIME" THEN SkipChunk(x)
- ELSIF x.name = "IEND" THEN last := TRUE; SkipChunk(x)
- ELSE SkipChunk(x) END;
- IF ~isIDAT THEN CheckCRC ELSE i := in.Net32() END (* should CRC this, too *)
- END ProcessChunk;
- PROCEDURE GetByte(): CHAR;
- VAR result : CHAR;
- BEGIN
- in.Char(result);
- crc.Char(result);
- RETURN result
- END GetByte;
- PROCEDURE GetLongint():LONGINT;
- VAR result:LONGINT;
- BEGIN
- result := ASH(ORD(GetByte()), 24);
- INC(result, ASH(ORD(GetByte()), 16));
- INC(result, ASH(ORD(GetByte()), 8));
- INC(result, ORD(GetByte()));
- RETURN result
- END GetLongint;
- PROCEDURE Open*(in : Streams.Reader; VAR res : WORD);
- VAR ch : ChunkHeader;
- i : LONGINT;
- isPNG : BOOLEAN;
- BEGIN
- res := -1;
- IF in = NIL THEN Error("Input Stream is NIL"); RETURN END;
- NEW(crc);
- SELF.in := in;
- errors := FALSE;
- isPNG := TRUE;
- FOR i := 0 TO 7 DO
- IF GetByte() # MagicID[i] THEN isPNG := FALSE END
- END;
- IF ~isPNG THEN Error("Not a PNG stream")
- ELSE
- ReadChunkHeader(ch);
- ProcessChunk(ch);
- IF ~errors THEN res := 0 END
- END
- END Open;
- PROCEDURE GetImageInfo*(VAR width, height, format, maxProgressionLevel : LONGINT);
- BEGIN
- width := hdr.width;
- height := hdr.height;
- format := 0;
- maxProgressionLevel := 0
- END GetImageInfo;
- PROCEDURE GetNativeImage*(VAR img : Raster.Image);
- VAR ch : ChunkHeader;
- BEGIN
- IF ~errors THEN
- REPEAT
- ReadChunkHeader(ch);
- ProcessChunk(ch)
- UNTIL isIDAT OR last OR errors;
- END;
- img := pic
- END GetNativeImage;
- PROCEDURE Render*(img : Raster.Image);
- VAR canvas : WMGraphics.BufferCanvas;
- BEGIN
- IF ~last & ~errors THEN GetNativeImage(pic) END;
- NEW(canvas, img);
- canvas.DrawImage(0, 0, pic, WMGraphics.ModeCopy);
- END Render;
- END PNGDecoder;
- VAR MagicID : ARRAY 8 OF CHAR;
- PROCEDURE PaethPredictor(a, b, c : LONGINT) : CHAR;
- VAR p, pa, pb, pc:LONGINT;
- BEGIN
- (*
- p := a + b - c; pa := ABS(p - a); pb := ABS(p - b); pc := ABS(p - c);
- *)
- pa := ABS(b-c); pb := ABS(a-c); pc := ABS(a+b-2*c);
- IF (pa <= pb) & (pa <= pc) THEN RETURN CHR(a)
- ELSIF (pb <= pc) THEN RETURN CHR(b)
- ELSE RETURN CHR(c)
- END
- END PaethPredictor;
- PROCEDURE Factory*(): Codecs.ImageDecoder;
- VAR p : PNGDecoder;
- BEGIN
- NEW(p);
- RETURN p
- END Factory;
- BEGIN
- MagicID[0]:=CHR(137); MagicID[1]:='P'; MagicID[2]:='N'; MagicID[3]:='G'; MagicID[4]:=CHR(13);
- MagicID[5]:=CHR(10); MagicID[6]:=CHR(26); MagicID[7]:=CHR(10);
- (* constants for incremental decoding *)
- StartingRow[0]:=0; StartingRow[1]:=0; StartingRow[2]:=4; StartingRow[3]:=0;
- StartingRow[4]:=2; StartingRow[5]:=0;StartingRow[6]:=1;
- StartingCol[0]:=0; StartingCol[1]:=4; StartingCol[2]:=0; StartingCol[3]:=2;
- StartingCol[4]:=0; StartingCol[5]:=1;StartingCol[6]:=0;
- RowIncrement[0]:=8; RowIncrement[1]:=8; RowIncrement[2]:=8; RowIncrement[3]:=4;
- RowIncrement[4]:=4; RowIncrement[5]:=2; RowIncrement[6]:=2;
- ColIncrement[0]:=8; ColIncrement[1]:=8; ColIncrement[2]:=4; ColIncrement[3]:=4;
- ColIncrement[4]:=2; ColIncrement[5]:=2; ColIncrement[6]:=1
- END PNGDecoder.
- System.Free PNGDecoder ~
- y.png ~
|