source: trunk/Packages/bgrabitmap/bgrawritepng.pas

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