PNGDecoder.Mod 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. (* PNG 1.2 Portable Network Graphics *)
  2. (* TF 28.9.2000 *)
  3. (* TF 23.8.2004 updated with Codecs and Inflate *)
  4. (* ftp://ftp.uu.net/graphics/png/images/ *)
  5. MODULE PNGDecoder; (** AUTHOR "TF"; PURPOSE "PNG decoder"; *)
  6. IMPORT
  7. SYSTEM, KernelLog, CRC, Raster, Streams, Inflate, WMGraphics, Codecs, Kernel;
  8. CONST
  9. BufSize = 4096 * 8; Trace = FALSE;
  10. VAR
  11. StartingRow, StartingCol, RowIncrement, ColIncrement: ARRAY 7 OF LONGINT;
  12. TYPE
  13. (* lenght = Chunksize -ChunkHeader -ChunkChecksum*)
  14. ChunkHeader = RECORD length : LONGINT; name : ARRAY 5 (* ....+0H*) OF CHAR END;
  15. PNGHead = RECORD
  16. width : LONGINT;
  17. height : LONGINT;
  18. bitDepth : LONGINT; (* Byte *)
  19. colorType : LONGINT; (* Byte *)
  20. compressMethod : LONGINT; (* Byte *)
  21. filterMethod: LONGINT; (* Byte *)
  22. interlaceMethod: LONGINT; (* Byte *)
  23. END;
  24. IDATReader* = OBJECT
  25. VAR (* General vars: *)
  26. inR: Streams.Reader;
  27. remain: LONGINT;
  28. eof : BOOLEAN;
  29. PROCEDURE &Init*(firstChunk : LONGINT; inR : Streams.Reader; VAR outR: Streams.Reader);
  30. BEGIN
  31. SELF.inR := inR;
  32. Streams.OpenReader(outR, Receiver);
  33. eof := FALSE;
  34. remain := firstChunk;
  35. END Init;
  36. PROCEDURE Receiver(VAR buf: ARRAY OF CHAR; ofs, size, min: LONGINT; VAR len: LONGINT; VAR res: WORD);
  37. VAR i, crc, tag: LONGINT; ch: CHAR;
  38. BEGIN
  39. IF ~eof THEN
  40. ASSERT((size > 0) & (min <= size) & (min >= 0));
  41. len := 0; i := ofs; res := Streams.Ok;
  42. WHILE (res = Streams.Ok) & (len < size) & ~eof DO
  43. (* Read the chunk size *)
  44. IF remain = 0 THEN
  45. crc := inR.Net32();
  46. (* KernelLog.String("crc= "); KernelLog.Hex(crc, 0); KernelLog.Ln; *)
  47. remain := inR.Net32();
  48. (* KernelLog.String("remain= "); KernelLog.Int(remain, 0); KernelLog.Ln; *)
  49. tag := inR.Net32();
  50. (* KernelLog.String("tag= "); KernelLog.Hex(tag, 0); KernelLog.Ln; *)
  51. IF tag # 049444154H THEN eof := TRUE END;
  52. END;
  53. (* Fill data into out buffer *)
  54. WHILE (res = Streams.Ok) & (len < size) & (remain > 0) DO
  55. inR.Char(ch);
  56. res := inR.res;
  57. buf[i] := ch;
  58. INC(len); INC(i); DEC(remain);
  59. END;
  60. END;
  61. ELSE
  62. res := Streams.EOF
  63. END
  64. END Receiver;
  65. END IDATReader;
  66. PNGDecoder = OBJECT(Codecs.ImageDecoder)
  67. VAR
  68. in : Streams.Reader;
  69. errors : BOOLEAN;
  70. first, last, isIDAT : BOOLEAN;
  71. hdr : PNGHead;
  72. crc : CRC.CRC32Stream;
  73. pic : Raster.Image;
  74. format8 : Raster.Format;
  75. palette : Raster.Palette;
  76. bpp: LONGINT; (* bytes per complete pixel rounded up to bytes*)
  77. decoder : Inflate.Reader;
  78. (* bytes per line - filtertyp byte *)
  79. PROCEDURE GetLineSize(width : LONGINT) : LONGINT;
  80. BEGIN
  81. CASE hdr.colorType OF
  82. 0: RETURN (hdr.bitDepth * width + 7) DIV 8
  83. |2: RETURN (hdr.bitDepth DIV 8) * 3 * width
  84. |3: RETURN (hdr.bitDepth * width + 7) DIV 8
  85. |4: RETURN (hdr.bitDepth DIV 4) * width
  86. |6: RETURN (hdr.bitDepth DIV 2) * width
  87. END
  88. END GetLineSize;
  89. PROCEDURE Init;
  90. BEGIN
  91. NEW(pic);
  92. CASE hdr.colorType OF
  93. 0: (* grayscale possibly 1, 2, 4, 8, 16 bit *)
  94. (* neither 16 bit nor grayscale support in Raster *)
  95. Raster.Create(pic, hdr.width, hdr.height, Raster.BGR888);
  96. bpp := (hdr.bitDepth + 7) DIV 8
  97. |2: (* RGB, 8 or 16 bit*)
  98. (* no 16 bit support in Raster *)
  99. Raster.Create(pic, hdr.width, hdr.height, Raster.BGR888);
  100. bpp := (3 * hdr.bitDepth + 7) DIV 8
  101. |3: (* color mapped 1, 2, 4, 8 bit *)
  102. NEW(palette);
  103. Raster.InitPalette(palette, 256, 5);
  104. Raster.InitPaletteFormat(format8, palette);
  105. Raster.Create(pic, hdr.width, hdr.height, format8);
  106. bpp := 1
  107. |4: (* greyscale + alpha 8 or 16 bit *)
  108. (* neither 16 bit nor grayscale support in Raster *)
  109. Raster.Create(pic, hdr.width, hdr.height, Raster.BGRA8888);
  110. bpp := (hdr.bitDepth * 2) DIV 8
  111. |6: (* RGB + alpha 8 or 16 bit *)
  112. (* no 16 bit support in Raster *)
  113. Raster.Create(pic, hdr.width, hdr.height, Raster.BGRA8888);
  114. bpp := (4 * hdr.bitDepth) DIV 8
  115. ELSE Error("Unknown Color Type")
  116. END;
  117. END Init;
  118. PROCEDURE Decode;
  119. VAR x, y, cp : LONGINT;
  120. filter, ls : LONGINT;
  121. p : ADDRESS;
  122. c, dummy : CHAR;
  123. prior, current, temp : POINTER TO ARRAY OF CHAR;
  124. currentByte : CHAR;
  125. bitPos : LONGINT;
  126. lastRowStart : ADDRESS;
  127. len,time,t1,t2 : LONGINT;
  128. color: RECORD b,g,r,a: CHAR END;
  129. PROCEDURE GetNextBit() : LONGINT;
  130. BEGIN
  131. IF bitPos MOD 8 = 0 THEN currentByte := GetNextFilterByte(); bitPos := 0 END;
  132. INC(bitPos);
  133. RETURN ORD(LSH(currentByte, bitPos-8 )) MOD 2
  134. END GetNextBit;
  135. PROCEDURE GetNext2Bits() : LONGINT;
  136. BEGIN
  137. IF bitPos MOD 8 = 0 THEN currentByte := GetNextFilterByte(); bitPos := 0 END;
  138. INC(bitPos, 2);
  139. RETURN ORD(LSH(currentByte, bitPos-8)) MOD 4
  140. END GetNext2Bits;
  141. PROCEDURE GetNext4Bits() : LONGINT;
  142. BEGIN
  143. IF bitPos MOD 8 = 0 THEN currentByte := GetNextFilterByte(); bitPos := 0 END;
  144. INC(bitPos, 4);
  145. RETURN ORD(LSH(currentByte, bitPos-8)) MOD 16
  146. END GetNext4Bits;
  147. PROCEDURE GetNextFilterByte() : CHAR;
  148. VAR result:CHAR;
  149. t1, t2:LONGINT; f: LONGINT;
  150. BEGIN
  151. CASE filter OF
  152. | 0 : result := current[cp]
  153. |1 : result := CHR(ORD(current[cp])+ORD(current[cp-bpp]));
  154. |2 : result := CHR(ORD(current[cp])+ORD(prior[cp]))
  155. |3 : t1 := ORD(current[cp-bpp]); t2 := ORD(prior[cp]); result:=CHR(ORD(current[cp])+(t1+t2) DIV 2)
  156. |4 : result := CHR(ORD(current[cp])+
  157. ORD(PaethPredictor(ORD(current[cp-bpp]), ORD(prior[cp]), ORD(prior[cp-bpp]))))
  158. ELSE
  159. KernelLog.String("filter= "); KernelLog.Int(filter, 0);
  160. Error("illegal filter type")
  161. END; current[cp] := result;
  162. INC(cp);
  163. RETURN result
  164. END GetNextFilterByte;
  165. BEGIN
  166. time := Kernel.GetTicks();
  167. bitPos := 0;
  168. p := pic.adr;
  169. IF Trace THEN KernelLog.String("bpp:"); KernelLog.Int(bpp, 8); KernelLog.Ln; END;
  170. ls := GetLineSize(hdr.width); NEW(prior, ls + bpp); NEW(current, ls + bpp);
  171. IF hdr.interlaceMethod = 0 THEN
  172. FOR y := 0 TO hdr.height - 1 DO
  173. lastRowStart := p;
  174. filter := ORD(decoder.Get());
  175. cp := bpp;
  176. decoder.Bytes(current^, cp, ls, len);
  177. cp := bpp;
  178. CASE hdr.colorType OF
  179. |0: (* color type 0 grayscale*)
  180. FOR x := 0 TO hdr.width -1 DO
  181. CASE hdr.bitDepth OF
  182. |1 : c := CHR(GetNextBit() * 255)
  183. |2 : c := CHR(GetNext2Bits() * 85)
  184. |4 : c := CHR(GetNext4Bits() * 16)
  185. |8 : c := GetNextFilterByte()
  186. |16 : c := GetNextFilterByte(); dummy := GetNextFilterByte()
  187. END;
  188. SYSTEM.PUT8(p, c); INC(p);
  189. SYSTEM.PUT8(p, c); INC(p);
  190. SYSTEM.PUT8(p, c); INC(p);
  191. END
  192. |2:(* color type 2 rgb *)
  193. IF (hdr.bitDepth # 16) THEN
  194. CASE filter OF
  195. 0:
  196. FOR x:=0 TO hdr.width-1 DO
  197. color.r := CHR(ORD(current[cp])); INC(cp);
  198. color.g := CHR(ORD(current[cp])); INC(cp);
  199. color.b := CHR(ORD(current[cp])); INC(cp);
  200. SYSTEM.PUT8(p, color.b); INC(p);
  201. SYSTEM.PUT8(p, color.g); INC(p);
  202. SYSTEM.PUT8(p, color.r); INC(p);
  203. END;
  204. |1:
  205. FOR x:=0 TO hdr.width-1 DO
  206. color.r := CHR(ORD(current[cp])+ORD(current[cp-bpp])); current[cp] := color.r; INC(cp);
  207. color.g := CHR(ORD(current[cp])+ORD(current[cp-bpp])); current[cp] :=color.g; INC(cp);
  208. color.b := CHR(ORD(current[cp])+ORD(current[cp-bpp])); current[cp] := color.b; INC(cp);
  209. SYSTEM.PUT8(p, color.b); INC(p);
  210. SYSTEM.PUT8(p, color.g); INC(p);
  211. SYSTEM.PUT8(p, color.r); INC(p);
  212. END;
  213. |2:
  214. FOR x:=0 TO hdr.width-1 DO
  215. color.r := CHR(ORD(current[cp])+ORD(prior[cp])); current[cp] := color.r; INC(cp);
  216. color.g := CHR(ORD(current[cp])+ORD(prior[cp])); current[cp] := color.g;INC(cp);
  217. color.b := CHR(ORD(current[cp])+ORD(prior[cp])); current[cp] := color.b;INC(cp);
  218. SYSTEM.PUT8(p, color.b); INC(p);
  219. SYSTEM.PUT8(p, color.g); INC(p);
  220. SYSTEM.PUT8(p, color.r); INC(p);
  221. END;
  222. |3:
  223. FOR x:=0 TO hdr.width-1 DO
  224. 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);
  225. 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);
  226. 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);
  227. SYSTEM.PUT8(p, color.b); INC(p);
  228. SYSTEM.PUT8(p, color.g); INC(p);
  229. SYSTEM.PUT8(p, color.r); INC(p);
  230. END;
  231. |4:
  232. FOR x:=0 TO hdr.width-1 DO
  233. 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);
  234. 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);
  235. 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);
  236. SYSTEM.PUT8(p, color.b); INC(p);
  237. SYSTEM.PUT8(p, color.g); INC(p);
  238. SYSTEM.PUT8(p, color.r); INC(p);
  239. END;
  240. END;
  241. ELSE
  242. FOR x := 0 TO hdr.width-1 DO
  243. color.r := GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
  244. color.g := GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
  245. color.b := GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
  246. SYSTEM.PUT8(p, color.b); INC(p);
  247. SYSTEM.PUT8(p, color.g); INC(p);
  248. SYSTEM.PUT8(p, color.r); INC(p);
  249. END
  250. END;
  251. |3: (* color type 3 *)
  252. FOR x:=0 TO hdr.width -1 DO
  253. CASE hdr.bitDepth OF
  254. |1 : c := CHR(GetNextBit())
  255. |2 : c := CHR(GetNext2Bits())
  256. |4 : c := CHR(GetNext4Bits())
  257. |8 : c := GetNextFilterByte()
  258. END;
  259. SYSTEM.PUT8(p, c); INC(p)
  260. END
  261. |4:(* color type 4 grayscale + alpha *)
  262. FOR x:=0 TO hdr.width-1 DO
  263. c := GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
  264. color.a := GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
  265. c := CHR(ORD(c) * ORD(color.a) DIV 256);
  266. SYSTEM.PUT8(p, c); INC(p);
  267. SYSTEM.PUT8(p, c); INC(p);
  268. SYSTEM.PUT8(p, c); INC(p);
  269. SYSTEM.PUT8(p, color.a); INC(p)
  270. END;
  271. |6:(* color type 6 rgb + alpha *)
  272. IF (hdr.bitDepth # 16) THEN
  273. CASE filter OF
  274. 0: FOR x:=0 TO hdr.width-1 DO
  275. color.r := CHR(ORD(current[cp])); INC(cp);
  276. color.g := CHR(ORD(current[cp])); INC(cp);
  277. color.b := CHR(ORD(current[cp])); INC(cp);
  278. color.a := CHR(ORD(current[cp])); INC(cp);
  279. (*SYSTEM.GET(SYSTEM.ADR(current[cp]), SYSTEM.VAL(LONGINT, color)); INC(cp,4);*)
  280. IF ORD(color.a) = 255 THEN
  281. SYSTEM.PUT32(p,SYSTEM.VAL(LONGINT,color)); INC(p,4);
  282. ELSE
  283. SYSTEM.PUT8(p, CHR(ORD(color.b)*ORD(color.a) DIV 256)); INC(p);
  284. SYSTEM.PUT8(p, CHR(ORD(color.g)*ORD(color.a) DIV 256)); INC(p);
  285. SYSTEM.PUT8(p, CHR(ORD(color.r)*ORD(color.a) DIV 256)); INC(p);
  286. SYSTEM.PUT8(p, color.a); INC(p)
  287. END;
  288. END;
  289. |1:
  290. FOR x:=0 TO hdr.width-1 DO
  291. color.r := CHR(ORD(current[cp])+ORD(current[cp-bpp])); current[cp] := color.r; INC(cp);
  292. color.g := CHR(ORD(current[cp])+ORD(current[cp-bpp])); current[cp] :=color.g; INC(cp);
  293. color.b := CHR(ORD(current[cp])+ORD(current[cp-bpp])); current[cp] := color.b; INC(cp);
  294. color.a := CHR(ORD(current[cp])+ORD(current[cp-bpp])); current[cp] := color.a; INC(cp);
  295. IF ORD(color.a) = 255 THEN
  296. SYSTEM.PUT32(p,SYSTEM.VAL(LONGINT,color)); INC(p,4);
  297. ELSE
  298. SYSTEM.PUT8(p, CHR(ORD(color.b)*ORD(color.a) DIV 256)); INC(p);
  299. SYSTEM.PUT8(p, CHR(ORD(color.g)*ORD(color.a) DIV 256)); INC(p);
  300. SYSTEM.PUT8(p, CHR(ORD(color.r)*ORD(color.a) DIV 256)); INC(p);
  301. SYSTEM.PUT8(p, color.a); INC(p)
  302. END;
  303. END;
  304. |2:
  305. FOR x:=0 TO hdr.width-1 DO
  306. color.r := CHR(ORD(current[cp])+ORD(prior[cp])); current[cp] := color.r; INC(cp);
  307. color.g := CHR(ORD(current[cp])+ORD(prior[cp])); current[cp] := color.g;INC(cp);
  308. color.b := CHR(ORD(current[cp])+ORD(prior[cp])); current[cp] := color.b;INC(cp);
  309. color.a := CHR(ORD(current[cp])+ORD(prior[cp])); current[cp] := color.a;INC(cp);
  310. IF ORD(color.a) = 255 THEN
  311. SYSTEM.PUT32(p,SYSTEM.VAL(LONGINT,color)); INC(p,4);
  312. ELSE
  313. SYSTEM.PUT8(p, CHR(ORD(color.b)*ORD(color.a) DIV 256)); INC(p);
  314. SYSTEM.PUT8(p, CHR(ORD(color.g)*ORD(color.a) DIV 256)); INC(p);
  315. SYSTEM.PUT8(p, CHR(ORD(color.r)*ORD(color.a) DIV 256)); INC(p);
  316. SYSTEM.PUT8(p, color.a); INC(p)
  317. END;
  318. END;
  319. |3:
  320. FOR x:=0 TO hdr.width-1 DO
  321. 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);
  322. 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);
  323. 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);
  324. 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);
  325. IF ORD(color.a) = 255 THEN
  326. SYSTEM.PUT32(p,SYSTEM.VAL(LONGINT,color)); INC(p,4);
  327. ELSE
  328. SYSTEM.PUT8(p, CHR(ORD(color.b)*ORD(color.a) DIV 256)); INC(p);
  329. SYSTEM.PUT8(p, CHR(ORD(color.g)*ORD(color.a) DIV 256)); INC(p);
  330. SYSTEM.PUT8(p, CHR(ORD(color.r)*ORD(color.a) DIV 256)); INC(p);
  331. SYSTEM.PUT8(p, color.a); INC(p)
  332. END;
  333. END;
  334. |4:
  335. FOR x:=0 TO hdr.width-1 DO
  336. 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);
  337. 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);
  338. 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);
  339. 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);
  340. IF ORD(color.a) = 255 THEN
  341. SYSTEM.PUT32(p,SYSTEM.VAL(LONGINT,color)); INC(p,4);
  342. ELSE
  343. SYSTEM.PUT8(p, CHR(ORD(color.b)*ORD(color.a) DIV 256)); INC(p);
  344. SYSTEM.PUT8(p, CHR(ORD(color.g)*ORD(color.a) DIV 256)); INC(p);
  345. SYSTEM.PUT8(p, CHR(ORD(color.r)*ORD(color.a) DIV 256)); INC(p);
  346. SYSTEM.PUT8(p, color.a); INC(p)
  347. END;
  348. END;
  349. END;
  350. ELSE
  351. FOR x:=0 TO hdr.width-1 DO
  352. color.r:=GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
  353. color.g:=GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
  354. color.b:=GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
  355. color.a:=GetNextFilterByte(); IF hdr.bitDepth = 16 THEN dummy:=GetNextFilterByte() END;
  356. SYSTEM.PUT8(p, CHR(ORD(color.b)*ORD(color.a) DIV 256)); INC(p);
  357. SYSTEM.PUT8(p, CHR(ORD(color.g)*ORD(color.a) DIV 256)); INC(p);
  358. SYSTEM.PUT8(p, CHR(ORD(color.r)*ORD(color.a) DIV 256)); INC(p);
  359. SYSTEM.PUT8(p, color.a); INC(p)
  360. END
  361. END;
  362. END;
  363. bitPos := 0;
  364. p := lastRowStart + pic.bpr;
  365. temp := prior; prior := current; current := temp
  366. END
  367. ELSE Error("interlace not yet supported")
  368. END;
  369. END Decode;
  370. PROCEDURE ReadChunkHeader(VAR x: ChunkHeader);
  371. VAR i:LONGINT;
  372. BEGIN
  373. x.length := in.Net32(); (* NOT IN CRC ! *)
  374. crc.Reset;
  375. FOR i := 0 TO 3 DO x.name[i] := GetByte() END;
  376. x.name[4] := CHR(0)
  377. END ReadChunkHeader;
  378. PROCEDURE Error(x : ARRAY OF CHAR);
  379. BEGIN
  380. KernelLog.String("PNG Decoder : ");
  381. KernelLog.String(x); KernelLog.Ln;
  382. (* errors := TRUE *)
  383. END Error;
  384. PROCEDURE SkipChunk(x : ChunkHeader);
  385. VAR i : LONGINT; dummy : CHAR;
  386. BEGIN
  387. FOR i := 0 TO x.length - 1 DO dummy := GetByte() END
  388. END SkipChunk;
  389. PROCEDURE CheckCRC;
  390. VAR t, ccrc:LONGINT;
  391. BEGIN
  392. ccrc := crc.GetCRC();
  393. t := in.Net32();
  394. IF ccrc # t THEN Error("crc-error"); HALT(1234) END
  395. END CheckCRC;
  396. PROCEDURE ProcessChunk(x:ChunkHeader);
  397. VAR i: LONGINT;
  398. idatr : Streams.Reader;
  399. idatReader : IDATReader;
  400. BEGIN
  401. IF first & ~(x.name = "IHDR") THEN Error("IHDR chunk expected"); RETURN END;
  402. IF x.name = "IHDR" THEN
  403. first := FALSE;
  404. hdr.width := GetLongint();
  405. hdr.height := GetLongint();
  406. hdr.bitDepth := ORD(GetByte());
  407. hdr.colorType := ORD(GetByte());
  408. hdr.compressMethod := ORD(GetByte());
  409. hdr.filterMethod := ORD(GetByte());
  410. hdr.interlaceMethod := ORD(GetByte());
  411. Init;
  412. ELSIF x.name = "PLTE" THEN
  413. FOR i := 0 TO (x.length DIV 3) - 1 DO
  414. Raster.SetRGB(palette.col[i], ORD(GetByte()), ORD(GetByte()), ORD(GetByte()))
  415. END
  416. ELSIF x.name = "IDAT" THEN
  417. NEW(idatReader, x.length, in, idatr);
  418. idatr.SkipBytes(2); (* should handle zlib *)
  419. NEW(decoder, idatr);
  420. Decode;
  421. isIDAT:= TRUE;
  422. ELSIF x.name = "gAMA" THEN SkipChunk(x)
  423. ELSIF x.name = "sBIT" THEN SkipChunk(x)
  424. ELSIF x.name = "cHRM" THEN SkipChunk(x)
  425. ELSIF x.name = "tRNS" THEN
  426. IF Trace THEN KernelLog.String("Alpha-Palette!!") END;
  427. NEW(palette);
  428. FOR i := 0 TO (x.length)-1 DO
  429. palette.col[i][3] := GetByte();
  430. palette.col[i][0] := CHR(ORD(palette.col[i][0]) * ORD(palette.col[i][3]) DIV 256);
  431. palette.col[i][1] := CHR(ORD(palette.col[i][1]) * ORD(palette.col[i][3]) DIV 256);
  432. palette.col[i][2] := CHR(ORD(palette.col[i][2]) * ORD(palette.col[i][3]) DIV 256);
  433. END;
  434. ELSIF x.name = "bKGD" THEN SkipChunk(x)
  435. ELSIF x.name = "hIST" THEN SkipChunk(x)
  436. ELSIF x.name = "tEXt" THEN SkipChunk(x)
  437. ELSIF x.name = "zTXt" THEN SkipChunk(x)
  438. ELSIF x.name = "pHYs" THEN SkipChunk(x)
  439. ELSIF x.name = "oFFs" THEN SkipChunk(x)
  440. ELSIF x.name = "tIME" THEN SkipChunk(x)
  441. ELSIF x.name = "IEND" THEN last := TRUE; SkipChunk(x)
  442. ELSE SkipChunk(x) END;
  443. IF ~isIDAT THEN CheckCRC ELSE i := in.Net32() END (* should CRC this, too *)
  444. END ProcessChunk;
  445. PROCEDURE GetByte(): CHAR;
  446. VAR result : CHAR;
  447. BEGIN
  448. in.Char(result);
  449. crc.Char(result);
  450. RETURN result
  451. END GetByte;
  452. PROCEDURE GetLongint():LONGINT;
  453. VAR result:LONGINT;
  454. BEGIN
  455. result := ASH(ORD(GetByte()), 24);
  456. INC(result, ASH(ORD(GetByte()), 16));
  457. INC(result, ASH(ORD(GetByte()), 8));
  458. INC(result, ORD(GetByte()));
  459. RETURN result
  460. END GetLongint;
  461. PROCEDURE Open*(in : Streams.Reader; VAR res : WORD);
  462. VAR ch : ChunkHeader;
  463. i : LONGINT;
  464. isPNG : BOOLEAN;
  465. BEGIN
  466. res := -1;
  467. IF in = NIL THEN Error("Input Stream is NIL"); RETURN END;
  468. NEW(crc);
  469. SELF.in := in;
  470. errors := FALSE;
  471. isPNG := TRUE;
  472. FOR i := 0 TO 7 DO
  473. IF GetByte() # MagicID[i] THEN isPNG := FALSE END
  474. END;
  475. IF ~isPNG THEN Error("Not a PNG stream")
  476. ELSE
  477. ReadChunkHeader(ch);
  478. ProcessChunk(ch);
  479. IF ~errors THEN res := 0 END
  480. END
  481. END Open;
  482. PROCEDURE GetImageInfo*(VAR width, height, format, maxProgressionLevel : LONGINT);
  483. BEGIN
  484. width := hdr.width;
  485. height := hdr.height;
  486. format := 0;
  487. maxProgressionLevel := 0
  488. END GetImageInfo;
  489. PROCEDURE GetNativeImage*(VAR img : Raster.Image);
  490. VAR ch : ChunkHeader;
  491. BEGIN
  492. IF ~errors THEN
  493. REPEAT
  494. ReadChunkHeader(ch);
  495. ProcessChunk(ch)
  496. UNTIL isIDAT OR last OR errors;
  497. END;
  498. img := pic
  499. END GetNativeImage;
  500. PROCEDURE Render*(img : Raster.Image);
  501. VAR canvas : WMGraphics.BufferCanvas;
  502. BEGIN
  503. IF ~last & ~errors THEN GetNativeImage(pic) END;
  504. NEW(canvas, img);
  505. canvas.DrawImage(0, 0, pic, WMGraphics.ModeCopy);
  506. END Render;
  507. END PNGDecoder;
  508. VAR MagicID : ARRAY 8 OF CHAR;
  509. PROCEDURE PaethPredictor(a, b, c : LONGINT) : CHAR;
  510. VAR p, pa, pb, pc:LONGINT;
  511. BEGIN
  512. (*
  513. p := a + b - c; pa := ABS(p - a); pb := ABS(p - b); pc := ABS(p - c);
  514. *)
  515. pa := ABS(b-c); pb := ABS(a-c); pc := ABS(a+b-2*c);
  516. IF (pa <= pb) & (pa <= pc) THEN RETURN CHR(a)
  517. ELSIF (pb <= pc) THEN RETURN CHR(b)
  518. ELSE RETURN CHR(c)
  519. END
  520. END PaethPredictor;
  521. PROCEDURE Factory*(): Codecs.ImageDecoder;
  522. VAR p : PNGDecoder;
  523. BEGIN
  524. NEW(p);
  525. RETURN p
  526. END Factory;
  527. BEGIN
  528. MagicID[0]:=CHR(137); MagicID[1]:='P'; MagicID[2]:='N'; MagicID[3]:='G'; MagicID[4]:=CHR(13);
  529. MagicID[5]:=CHR(10); MagicID[6]:=CHR(26); MagicID[7]:=CHR(10);
  530. (* constants for incremental decoding *)
  531. StartingRow[0]:=0; StartingRow[1]:=0; StartingRow[2]:=4; StartingRow[3]:=0;
  532. StartingRow[4]:=2; StartingRow[5]:=0;StartingRow[6]:=1;
  533. StartingCol[0]:=0; StartingCol[1]:=4; StartingCol[2]:=0; StartingCol[3]:=2;
  534. StartingCol[4]:=0; StartingCol[5]:=1;StartingCol[6]:=0;
  535. RowIncrement[0]:=8; RowIncrement[1]:=8; RowIncrement[2]:=8; RowIncrement[3]:=4;
  536. RowIncrement[4]:=4; RowIncrement[5]:=2; RowIncrement[6]:=2;
  537. ColIncrement[0]:=8; ColIncrement[1]:=8; ColIncrement[2]:=4; ColIncrement[3]:=4;
  538. ColIncrement[4]:=2; ColIncrement[5]:=2; ColIncrement[6]:=1
  539. END PNGDecoder.
  540. System.Free PNGDecoder ~
  541. y.png ~