fpwritepng.pp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 2003 by the Free Pascal development team
  5. XPM writer class.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {$mode objfpc}{$h+}
  13. unit FPWritePNG;
  14. interface
  15. uses sysutils, classes, FPImage, FPImgCmn, PNGComn, ZStream;
  16. type
  17. TGetPixelFunc = function (x,y : LongWord) : TColorData of object;
  18. TColorFormatFunction = function (color:TFPColor) : TColorData of object;
  19. TFPWriterPNG = class (TFPCustomImageWriter)
  20. private
  21. FUsetRNS, FCompressedText, FWordSized, FIndexed,
  22. FUseAlpha, FGrayScale : boolean;
  23. FByteWidth : byte;
  24. FChunk : TChunk;
  25. CFmt : TColorFormat; // format of the colors to convert from
  26. FFmtColor : TColorFormatFunction;
  27. FTransparentColor : TFPColor;
  28. FSwitchLine, FCurrentLine, FPreviousLine : pByteArray;
  29. FPalette : TFPPalette;
  30. FHeader : THeaderChunk;
  31. FGetPixel : TGetPixelFunc;
  32. FDatalineLength : longword;
  33. ZData : TMemoryStream; // holds uncompressed data until all blocks are written
  34. Compressor : TCompressionStream; // compresses the data
  35. procedure WriteChunk;
  36. function GetColorPixel (x,y:longword) : TColorData;
  37. function GetPalettePixel (x,y:longword) : TColorData;
  38. function GetColPalPixel (x,y:longword) : TColorData;
  39. procedure InitWriteIDAT;
  40. procedure Gatherdata;
  41. procedure WriteCompressedData;
  42. procedure FinalWriteIDAT;
  43. protected
  44. property Header : THeaderChunk read FHeader;
  45. procedure InternalWrite (Str:TStream; Img:TFPCustomImage); override;
  46. procedure WriteIHDR; virtual;
  47. procedure WritePLTE; virtual;
  48. procedure WritetRNS; virtual;
  49. procedure WriteIDAT; virtual;
  50. procedure WriteTexts; virtual;
  51. procedure WriteIEND; virtual;
  52. function CurrentLine (x:longword) : byte;
  53. function PrevSample (x:longword): byte;
  54. function PreviousLine (x:longword) : byte;
  55. function PrevLinePrevSample (x:longword): byte;
  56. function DoFilter (LineFilter:byte;index:longword; b:byte) : byte; virtual;
  57. procedure SetChunkLength (aValue : longword);
  58. procedure SetChunkType (ct : TChunkTypes);
  59. procedure SetChunkType (ct : TChunkCode);
  60. function DecideGetPixel : TGetPixelFunc; virtual;
  61. procedure DetermineHeader (var AHeader : THeaderChunk); virtual;
  62. function DetermineFilter (Current, Previous:PByteArray; linelength:longword):byte; virtual;
  63. procedure FillScanLine (y : integer; ScanLine : pByteArray); virtual;
  64. function ColorDataGrayB(color:TFPColor) : TColorData;
  65. function ColorDataColorB(color:TFPColor) : TColorData;
  66. function ColorDataGrayW(color:TFPColor) : TColorData;
  67. function ColorDataColorW(color:TFPColor) : TColorData;
  68. function ColorDataGrayAB(color:TFPColor) : TColorData;
  69. function ColorDataColorAB(color:TFPColor) : TColorData;
  70. function ColorDataGrayAW(color:TFPColor) : TColorData;
  71. function ColorDataColorAW(color:TFPColor) : TColorData;
  72. property ChunkDataBuffer : pByteArray read FChunk.data;
  73. property UsetRNS : boolean read FUsetRNS;
  74. property SingleTransparentColor : TFPColor read FTransparentColor;
  75. property ThePalette : TFPPalette read FPalette;
  76. property ColorFormat : TColorformat read CFmt;
  77. property ColorFormatFunc : TColorFormatFunction read FFmtColor;
  78. property byteWidth : byte read FByteWidth;
  79. property DatalineLength : longword read FDatalineLength;
  80. public
  81. constructor create; override;
  82. destructor destroy; override;
  83. property GrayScale : boolean read FGrayscale write FGrayScale;
  84. property Indexed : boolean read FIndexed write FIndexed;
  85. property CompressedText : boolean read FCompressedText write FCompressedText;
  86. property WordSized : boolean read FWordSized write FWordSized;
  87. property UseAlpha : boolean read FUseAlpha write FUseAlpha;
  88. end;
  89. implementation
  90. constructor TFPWriterPNG.create;
  91. begin
  92. inherited;
  93. Fchunk.acapacity := 0;
  94. Fchunk.data := nil;
  95. FGrayScale := False;
  96. FIndexed := True;
  97. FCompressedText := True;
  98. FWordSized := True;
  99. FUseAlpha := False;
  100. end;
  101. destructor TFPWriterPNG.destroy;
  102. begin
  103. with Fchunk do
  104. if acapacity > 0 then
  105. freemem (data);
  106. inherited;
  107. end;
  108. procedure TFPWriterPNG.WriteChunk;
  109. var chead : TChunkHeader;
  110. c : longword;
  111. begin
  112. with FChunk do
  113. begin
  114. chead.CLength := swap (alength);
  115. if (ReadType = '') then
  116. if atype <> ctUnknown then
  117. chead.CType := ChunkTypes[aType]
  118. else
  119. raise PNGImageException.create ('Doesn''t have a chunktype to write')
  120. else
  121. chead.CType := ReadType;
  122. c := CalculateCRC (All1Bits, ReadType, sizeOf(ReadType));
  123. c := CalculateCRC (c, data^, alength);
  124. crc := swap(c xor All1Bits);
  125. with TheStream do
  126. begin
  127. Write (chead, sizeof(chead));
  128. Write (data^[0], alength);
  129. Write (crc, sizeof(crc));
  130. end;
  131. end;
  132. end;
  133. procedure TFPWriterPNG.SetChunkLength(aValue : longword);
  134. begin
  135. with Fchunk do
  136. begin
  137. alength := aValue;
  138. if aValue > acapacity then
  139. begin
  140. if acapacity > 0 then
  141. freemem (data);
  142. GetMem (data, alength);
  143. acapacity := alength;
  144. end;
  145. end;
  146. end;
  147. procedure TFPWriterPNG.SetChunkType (ct : TChunkTypes);
  148. begin
  149. with Fchunk do
  150. begin
  151. aType := ct;
  152. ReadType := ChunkTypes[ct];
  153. end;
  154. end;
  155. procedure TFPWriterPNG.SetChunkType (ct : TChunkCode);
  156. begin
  157. with FChunk do
  158. begin
  159. ReadType := ct;
  160. aType := low(TChunkTypes);
  161. while (aType < high(TChunkTypes)) and (ChunkTypes[aType] <> ct) do
  162. inc (aType);
  163. end;
  164. end;
  165. function TFPWriterPNG.CurrentLine(x:longword):byte;
  166. begin
  167. result := FCurrentLine^[x];
  168. end;
  169. function TFPWriterPNG.PrevSample (x:longword): byte;
  170. begin
  171. if x < byteWidth then
  172. result := 0
  173. else
  174. result := FCurrentLine^[x - bytewidth];
  175. end;
  176. function TFPWriterPNG.PreviousLine (x:longword) : byte;
  177. begin
  178. result := FPreviousline^[x];
  179. end;
  180. function TFPWriterPNG.PrevLinePrevSample (x:longword): byte;
  181. begin
  182. if x < byteWidth then
  183. result := 0
  184. else
  185. result := FPreviousLine^[x - bytewidth];
  186. end;
  187. function TFPWriterPNG.DoFilter(LineFilter:byte;index:longword; b:byte) : byte;
  188. var diff : byte;
  189. procedure FilterSub;
  190. begin
  191. diff := PrevSample(index);
  192. end;
  193. procedure FilterUp;
  194. begin
  195. diff := PreviousLine(index);
  196. end;
  197. procedure FilterAverage;
  198. var l, p : word;
  199. begin
  200. l := PrevSample(index);
  201. p := PreviousLine(index);
  202. Diff := (l + p) div 2;
  203. end;
  204. procedure FilterPaeth;
  205. var dl, dp, dlp : word; // index for previous and distances for:
  206. l, p, lp : byte; // r:predictor, Left, Previous, LeftPrevious
  207. r : integer;
  208. begin
  209. l := PrevSample(index);
  210. lp := PrevLinePrevSample(index);
  211. p := PreviousLine(index);
  212. r := l + p - lp;
  213. dl := abs (r - l);
  214. dlp := abs (r - lp);
  215. dp := abs (r - p);
  216. if (dl <= dp) and (dl <= dlp) then
  217. diff := l
  218. else if dp <= dlp then
  219. diff := p
  220. else
  221. diff := lp;
  222. end;
  223. begin
  224. case LineFilter of
  225. 0 : diff := 0;
  226. 1 : FilterSub;
  227. 2 : FilterUp;
  228. 3 : FilterAverage;
  229. 4 : FilterPaeth;
  230. end;
  231. if diff > b then
  232. result := (b + $100 - diff)
  233. else
  234. result := b - diff;
  235. end;
  236. procedure TFPWriterPNG.DetermineHeader (var AHeader : THeaderChunk);
  237. var c : integer;
  238. function CountAlphas : integer;
  239. var none, half : boolean;
  240. x,y : longword;
  241. p : integer;
  242. c : TFPColor;
  243. a : word;
  244. begin
  245. half := false;
  246. none := false;
  247. with TheImage do
  248. if UsePalette then
  249. with Palette do
  250. begin
  251. p := count-1;
  252. FTransparentColor.alpha := alphaOpaque;
  253. while (p >= 0) do
  254. begin
  255. c := color[p];
  256. a := c.Alpha;
  257. if a = alphaTransparent then
  258. begin
  259. none := true;
  260. FTransparentColor := c;
  261. end
  262. else if a <> alphaOpaque then
  263. begin
  264. half := true;
  265. if FtransparentColor.alpha < a then
  266. FtransparentColor := c;
  267. end;
  268. dec (p);
  269. end;
  270. end
  271. else
  272. begin
  273. x := width-1;
  274. y := height-1;
  275. FTransparentColor.alpha := alphaOpaque;
  276. while (y >= 0) and not (half and none) do
  277. begin
  278. c := colors[x,y];
  279. a := c.Alpha;
  280. if a = alphaTransparent then
  281. begin
  282. none := true;
  283. FTransparentColor := c;
  284. end
  285. else if a <> alphaOpaque then
  286. begin
  287. half := true;
  288. if FtransparentColor.alpha < a then
  289. FtransparentColor := c;
  290. end;
  291. dec (x);
  292. if (x < 0) then
  293. begin
  294. dec (y);
  295. x := width-1;
  296. end;
  297. end;
  298. end;
  299. result := 1;
  300. if none then
  301. inc (result);
  302. if half then
  303. inc (result);
  304. end;
  305. procedure DetermineColorFormat;
  306. begin
  307. with AHeader do
  308. case colortype of
  309. 0 : if FWordSized then
  310. begin
  311. FFmtColor := @ColorDataGrayW;
  312. FByteWidth := 2;
  313. //CFmt := cfGray16
  314. end
  315. else
  316. begin
  317. FFmtColor := @ColorDataGrayB;
  318. FByteWidth := 1;
  319. //CFmt := cfGray8;
  320. end;
  321. 2 : if FWordSized then
  322. begin
  323. FFmtColor := @ColorDataColorW;
  324. FByteWidth := 6;
  325. //CFmt := cfBGR48
  326. end
  327. else
  328. begin
  329. FFmtColor := @ColorDataColorB;
  330. FByteWidth := 3;
  331. //CFmt := cfBGR24;
  332. end;
  333. 4 : if FWordSized then
  334. begin
  335. FFmtColor := @ColorDataGrayAW;
  336. FByteWidth := 4;
  337. //CFmt := cfGrayA32
  338. end
  339. else
  340. begin
  341. FFmtColor := @ColorDataGrayAB;
  342. FByteWidth := 2;
  343. //CFmt := cfGrayA16;
  344. end;
  345. 6 : if FWordSized then
  346. begin
  347. FFmtColor := @ColorDataColorAW;
  348. FByteWidth := 8;
  349. //CFmt := cfABGR64
  350. end
  351. else
  352. begin
  353. FFmtColor := @ColorDataColorAB;
  354. FByteWidth := 4;
  355. //CFmt := cfABGR32;
  356. end;
  357. end;
  358. end;
  359. begin
  360. with AHeader do
  361. begin
  362. // problem: TheImage has integer width, PNG header longword width.
  363. // Integer Swap can give negative value
  364. Width := swap (longword(TheImage.Width));
  365. height := swap (longword(TheImage.Height));
  366. if FUseAlpha then
  367. c := CountAlphas
  368. else
  369. c := 0;
  370. if FIndexed then
  371. begin
  372. if TheImage.UsePalette then
  373. FPalette := TheImage.Palette
  374. else
  375. begin
  376. FPalette := TFPPalette.Create (16);
  377. FPalette.Build (TheImage);
  378. end;
  379. if ThePalette.count > 256 then
  380. raise PNGImageException.Create ('To many colors to use indexed PNG color type');
  381. ColorType := 3;
  382. FUsetRNS := C > 1;
  383. BitDepth := 8;
  384. FByteWidth := 1;
  385. end
  386. else
  387. begin
  388. if c = 3 then
  389. ColorType := 4;
  390. FUsetRNS := (c = 2);
  391. if not FGrayScale then
  392. ColorType := ColorType + 2;
  393. if FWordSized then
  394. BitDepth := 16
  395. else
  396. BitDepth := 8;
  397. DetermineColorFormat;
  398. end;
  399. Compression := 0;
  400. Filter := 0;
  401. Interlace := 0;
  402. end;
  403. end;
  404. procedure TFPWriterPNG.WriteIHDR;
  405. begin
  406. // signature for PNG
  407. TheStream.writeBuffer(Signature,sizeof(Signature));
  408. // Determine all settings for filling the header
  409. DetermineHeader (FHeader);
  410. // write the header chunk
  411. SetChunkLength (13); // (sizeof(FHeader)); gives 14 and is wrong !!
  412. move (FHeader, ChunkDataBuffer^, 13); // sizeof(FHeader));
  413. SetChunkType (ctIHDR);
  414. WriteChunk;
  415. end;
  416. { Color convertions }
  417. function TFPWriterPNG.ColorDataGrayB(color:TFPColor) : TColorData;
  418. var t : word;
  419. begin
  420. t := CalculateGray (color);
  421. result := hi(t);
  422. end;
  423. function TFPWriterPNG.ColorDataGrayW(color:TFPColor) : TColorData;
  424. begin
  425. result := CalculateGray (color);
  426. end;
  427. function TFPWriterPNG.ColorDataGrayAB(color:TFPColor) : TColorData;
  428. begin
  429. result := ColorDataGrayB (color);
  430. result := (result shl 8) and hi(color.Alpha);
  431. end;
  432. function TFPWriterPNG.ColorDataGrayAW(color:TFPColor) : TColorData;
  433. begin
  434. result := ColorDataGrayW (color);
  435. result := (result shl 16) and color.Alpha;
  436. end;
  437. function TFPWriterPNG.ColorDataColorB(color:TFPColor) : TColorData;
  438. begin
  439. with color do
  440. result := hi(red) + (green and $FF00) + (hi(blue) shl 16);
  441. end;
  442. function TFPWriterPNG.ColorDataColorW(color:TFPColor) : TColorData;
  443. begin
  444. with color do
  445. result := red + (green shl 16) + (blue shl 32);
  446. end;
  447. function TFPWriterPNG.ColorDataColorAB(color:TFPColor) : TColorData;
  448. begin
  449. with color do
  450. result := hi(red) + (green and $FF00) + (hi(blue) shl 16) + (hi(alpha) shl 24);
  451. end;
  452. function TFPWriterPNG.ColorDataColorAW(color:TFPColor) : TColorData;
  453. begin
  454. with color do
  455. result := red + (green shl 16) + (blue shl 32) + (alpha shl 48);
  456. end;
  457. { Data making routines }
  458. function TFPWriterPNG.GetColorPixel (x,y:longword) : TColorData;
  459. begin
  460. result := FFmtColor (TheImage[x,y]);
  461. //result := ConvertColorToData(TheImage.Colors[x,y],CFmt);
  462. end;
  463. function TFPWriterPNG.GetPalettePixel (x,y:longword) : TColorData;
  464. begin
  465. result := TheImage.Pixels[x,y];
  466. end;
  467. function TFPWriterPNG.GetColPalPixel (x,y:longword) : TColorData;
  468. begin
  469. result := ThePalette.IndexOf (TheImage.Colors[x,y]);
  470. end;
  471. function TFPWriterPNG.DecideGetPixel : TGetPixelFunc;
  472. begin
  473. case Fheader.colortype of
  474. 3 : if TheImage.UsePalette then
  475. begin
  476. result := @GetPalettePixel;
  477. end
  478. else
  479. begin
  480. result := @GetColPalPixel;
  481. end;
  482. else begin
  483. result := @GetColorPixel;
  484. end
  485. end;
  486. end;
  487. procedure TFPWriterPNG.WritePLTE;
  488. var r,t : integer;
  489. c : TFPColor;
  490. begin
  491. with ThePalette do
  492. begin
  493. SetChunkLength (count*3);
  494. SetChunkType (ctPLTE);
  495. t := 0;
  496. For r := 0 to count-1 do
  497. begin
  498. c := Color[r];
  499. ChunkdataBuffer^[t] := c.red div 256;
  500. inc (t);
  501. ChunkdataBuffer^[t] := c.green div 256;
  502. inc (t);
  503. ChunkdataBuffer^[t] := c.blue div 256;
  504. inc (t);
  505. end;
  506. end;
  507. WriteChunk;
  508. end;
  509. procedure TFPWriterPNG.InitWriteIDAT;
  510. begin
  511. FDatalineLength := TheImage.Width*ByteWidth;
  512. GetMem (FPreviousLine, FDatalineLength);
  513. GetMem (FCurrentLine, FDatalineLength);
  514. fillchar (FCurrentLine^,FDatalineLength,0);
  515. ZData := TMemoryStream.Create;
  516. Compressor := TCompressionStream.Create (clMax,ZData);
  517. FGetPixel := DecideGetPixel;
  518. end;
  519. procedure TFPWriterPNG.FinalWriteIDAT;
  520. begin
  521. ZData.Free;
  522. FreeMem (FPreviousLine);
  523. FreeMem (FCurrentLine);
  524. end;
  525. function TFPWriterPNG.DetermineFilter (Current, Previous:PByteArray; linelength:longword) : byte;
  526. begin
  527. result := 0;
  528. end;
  529. procedure TFPWriterPNG.FillScanLine (y : integer; ScanLine : pByteArray);
  530. var r, x : integer;
  531. cd : TColorData;
  532. index : longword;
  533. b : byte;
  534. begin
  535. index := 0;
  536. for x := 0 to pred(TheImage.Width) do
  537. begin
  538. cd := FGetPixel (x,y);
  539. move (cd, ScanLine^[index], FBytewidth);
  540. if WordSized then
  541. begin
  542. r := 1;
  543. while (r < FByteWidth) do
  544. begin
  545. b := Scanline^[index+r];
  546. Scanline^[index+r] := Scanline^[index+r-1];
  547. Scanline^[index+r-1] := b;
  548. inc (r,2);
  549. end;
  550. end;
  551. inc (index, FByteWidth);
  552. end;
  553. end;
  554. procedure TFPWriterPNG.GatherData;
  555. var x,y : integer;
  556. lf : byte;
  557. begin
  558. for y := 0 to pred(TheImage.height) do
  559. begin
  560. FSwitchLine := FCurrentLine;
  561. FCurrentLine := FPreviousLine;
  562. FPreviousLine := FSwitchLine;
  563. FillScanLine (y, FCurrentLine);
  564. lf := DetermineFilter (FCurrentLine, FpreviousLine, FDataLineLength);
  565. for x := 0 to FDatalineLength-1 do
  566. FCurrentLine^[x] := DoFilter (lf, x, FCurrentLine^[x]);
  567. Compressor.Write (lf, sizeof(lf));
  568. Compressor.Write (FCurrentLine^, FDataLineLength);
  569. end;
  570. end;
  571. procedure TFPWriterPNG.WriteCompressedData;
  572. var l : longword;
  573. begin
  574. Compressor.Free; // Close compression and finish the writing in ZData
  575. l := ZData.position;
  576. ZData.position := 0;
  577. SetChunkLength(l);
  578. SetChunkType (ctIDAT);
  579. ZData.Read (ChunkdataBuffer^, l);
  580. WriteChunk;
  581. end;
  582. procedure TFPWriterPNG.WriteIDAT;
  583. begin
  584. InitWriteIDAT;
  585. GatherData;
  586. WriteCompressedData;
  587. FinalWriteIDAT;
  588. end;
  589. procedure TFPWriterPNG.WritetRNS;
  590. procedure PaletteAlpha;
  591. var r : integer;
  592. begin
  593. with TheImage.palette do
  594. begin
  595. // search last palette entry with transparency
  596. r := count;
  597. repeat
  598. dec (r);
  599. until (r < 0) or (color[r].alpha <> alphaOpaque);
  600. if r >= 0 then // there is at least 1 transparent color
  601. begin
  602. // from this color we go to the first palette entry
  603. SetChunkLength (r+1);
  604. repeat
  605. chunkdatabuffer^[r] := (color[r].alpha shr 8);
  606. dec (r);
  607. until (r < 0);
  608. end;
  609. writechunk;
  610. end;
  611. end;
  612. procedure GrayAlpha;
  613. var g : word;
  614. begin
  615. SetChunkLength(2);
  616. if WordSized then
  617. g := CalculateGray (SingleTransparentColor)
  618. else
  619. g := hi (CalculateGray(SingleTransparentColor));
  620. g := swap (g);
  621. move (g,ChunkDataBuffer^[0],2);
  622. WriteChunk;
  623. end;
  624. procedure ColorAlpha;
  625. var g : TFPColor;
  626. begin
  627. SetChunkLength(6);
  628. g := SingleTransparentColor;
  629. with g do
  630. if WordSized then
  631. begin
  632. red := swap (red);
  633. green := swap (green);
  634. blue := swap (blue);
  635. move (g, ChunkDatabuffer^[0], 6);
  636. end
  637. else
  638. begin
  639. ChunkDataBuffer^[0] := 0;
  640. ChunkDataBuffer^[1] := red shr 8;
  641. ChunkDataBuffer^[2] := 0;
  642. ChunkDataBuffer^[3] := green shr 8;
  643. ChunkDataBuffer^[4] := 0;
  644. ChunkDataBuffer^[5] := blue shr 8;
  645. end;
  646. WriteChunk;
  647. end;
  648. begin
  649. SetChunkType (cttRNS);
  650. case fheader.colortype of
  651. 6,4 : raise PNGImageException.create ('tRNS chunk forbidden for full alpha channels');
  652. 3 : PaletteAlpha;
  653. 2 : ColorAlpha;
  654. 0 : GrayAlpha;
  655. end;
  656. end;
  657. procedure TFPWriterPNG.WriteTexts;
  658. begin
  659. end;
  660. procedure TFPWriterPNG.WriteIEND;
  661. begin
  662. SetChunkLength(0);
  663. SetChunkType (ctIEND);
  664. WriteChunk;
  665. end;
  666. procedure TFPWriterPNG.InternalWrite (Str:TStream; Img:TFPCustomImage);
  667. begin
  668. WriteIHDR;
  669. if Fheader.colorType = 3 then
  670. WritePLTE;
  671. if FUsetRNS then
  672. WritetRNS;
  673. WriteIDAT;
  674. WriteTexts;
  675. WriteIEND;
  676. end;
  677. initialization
  678. ImageHandlers.RegisterImageWriter ('Portable Network Graphics', 'png', TFPWriterPNG);
  679. end.