fpwritepng.pp 19 KB

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