pngimage.pas
上传用户:ctlcnc
上传日期:2021-12-10
资源大小:4933k
文件大小:166k
源码类别:

2D图形编程

开发平台:

Delphi

  1. {Portable Network Graphics Delphi 1.5       (29 June 2005)    }
  2. {This is the latest implementation for TPngImage component    }
  3. {It's meant to be a full replacement for the previous one.    }
  4. {There are lots of new improvements, including cleaner code,  }
  5. {full partial transparency support, speed improvements,       }
  6. {saving using ADAM 7 interlacing, better error handling, also }
  7. {the best compression for the final image ever. And now it's  }
  8. {truly able to read about any png image.                      }
  9. //---------------------------------------------------------------------------
  10. //   Notice from Lifepower (lifepower@mail333.com):
  11. //---------------------------------------------------------------------------
  12. // This file has modification - to use "asphyrezlib.pas" instead
  13. // of "pnglang.pas". This is used with the permission of the auhtor. 
  14. //---------------------------------------------------------------------------
  15. {
  16.   Version 1.5
  17.   2005-29-06 - Fixed a lot of bugs using tips from mails that I've
  18.        being receiving for some time
  19.                  BUG 1 - Loosing palette when assigning to TBitmap. fixed
  20.                  BUG 2 - SetPixels and GetPixels worked only with
  21.                          parameters in range 0..255. fixed
  22.                  BUG 3 - Force type address off using directive
  23.                  BUG 4 - TChunkzTXt contained an error
  24.                  BUG 5 - MaxIdatSize was not working correctly (fixed thanks
  25.                  to Gabriel Corneanu
  26.                  BUG 6 - Corrected german translation (thanks to Mael Horz)
  27.                And the following improvements:
  28.                  IMPROVE 1 - Create ImageHandleValue properties as public in
  29.                              TChunkIHDR to get access to this handle
  30.                  IMPROVE 2 - Using SetStretchBltMode to improve stretch quality
  31.                  IMPROVE 3 - Scale is now working for alpha transparent images
  32.                  IMPROVE 4 - GammaTable propery is now public to support an
  33.                              article in the help file
  34.   Version 1.4361
  35.   2003-03-04 - Fixed important bug for simple transparency when using
  36.                RGB, Grayscale color modes
  37.   Version 1.436
  38.   2003-03-04 - * NEW * Property Pixels for direct access to pixels
  39.                * IMPROVED * Palette property (TPngObject) (read only)
  40.                Slovenian traslation for the component (Miha Petelin)
  41.                Help file update (scanline article/png->jpg example)
  42.   Version 1.435
  43.   2003-11-03 - * NEW * New chunk implementation zTXt (method AddzTXt)
  44.                * NEW * New compiler flags to store the extra 8 bits
  45.                from 16 bits samples (when saving it is ignored), the
  46.                extra data may be acessed using ExtraScanline property
  47.                * Fixed * a bug on tIMe chunk
  48.                French translation included (Thanks to IBE Software)
  49.                Bugs fixed
  50.   Version 1.432
  51.   2002-08-24 - * NEW *  A new method, CreateAlpha will transform the
  52.                current image into partial transparency.
  53.                Help file updated with a new article on how to handle
  54.                partial transparency.
  55.   Version 1.431
  56.   2002-08-14 - Fixed and tested to work on:
  57.                C++ Builder 3
  58.                C++ Builder 5
  59.                Delphi 3
  60.                There was an error when setting TransparentColor, fixed
  61.                New method, RemoveTransparency to remove image
  62.                BIT TRANSPARENCY
  63.   Version 1.43
  64.   2002-08-01 - * NEW * Support for Delphi 3 and C++ Builder 3
  65.                Implements mostly some things that were missing,
  66.                a few tweaks and fixes.
  67.   Version 1.428
  68.   2002-07-24 - More minor fixes (thanks to Ian Boyd)
  69.                Bit transparency fixes
  70.                * NEW * Finally support to bit transparency
  71.                (palette / rgb / grayscale -> all)
  72.   Version 1.427
  73.   2002-07-19 - Lots of bugs and leaks fixed
  74.                * NEW * method to easy adding text comments, AddtEXt
  75.                * NEW * property for setting bit transparency,
  76.                        TransparentColor
  77.   Version 1.426
  78.   2002-07-18 - Clipboard finally fixed (hope)
  79.                Changed UseDelphi trigger to UseDelphi
  80.                * NEW * Support for bit transparency bitmaps
  81.                        when assigning from/to TBitmap objects
  82.                Altough it does not support drawing transparent
  83.                parts of bit transparency pngs (only partial)
  84.                it is closer than ever
  85.   Version 1.425
  86.   2002-07-01 - Clipboard methods implemented
  87.                Lots of bugs fixed
  88.   Version 1.424
  89.   2002-05-16 - Scanline and AlphaScanline are now working correctly.
  90.                New methods for handling the clipboard
  91.   Version 1.423
  92.   2002-05-16 - * NEW * Partial transparency for 1, 2, 4 and 8 bits is
  93.                also supported using the tRNS chunk (for palette and
  94.                grayscaling).
  95.                New bug fixes (Peter Haas).
  96.   Version 1.422
  97.   2002-05-14 - Fixed some critical leaks, thanks to Peter Haas tips.
  98.                New translation for German (Peter Haas).
  99.   Version 1.421
  100.   2002-05-06 - Now uses new ZLIB version, 1.1.4 with some security
  101.                fixes.
  102.                LoadFromResourceID and LoadFromResourceName added and
  103.                help file updated for that.
  104.                The resources strings are now located in pnglang.pas.
  105.                New translation for Brazilian Portuguese.
  106.                Bugs fixed.
  107.  IMPORTANT: I'm currently looking for bugs on the library. If
  108.             anyone has found one, please send me an email and
  109.             I will fix right away. Thanks for all the help and
  110.             ideias I'm receiving so far.}
  111. {My new email is: gubadaud@terra.com.br}
  112. {Website link   : pngdelphi.sourceforge.net}
  113. {Gustavo Huffenbacher Daud}
  114. unit pngimage;
  115. interface
  116. {Triggers avaliable (edit the fields bellow)}
  117. {$TYPEDADDRESS OFF}
  118. {$DEFINE UseDelphi}              //Disable fat vcl units (perfect to small apps)
  119. {$DEFINE ErrorOnUnknownCritical} //Error when finds an unknown critical chunk
  120. {$DEFINE CheckCRC}               //Enables CRC checking
  121. {.$DEFINE RegisterGraphic}        //Registers TPNGObject to use with TPicture
  122. {.$DEFINE PartialTransparentDraw} //Draws partial transparent images
  123. {.$DEFINE Store16bits}           //Stores the extra 8 bits from 16bits/sample
  124. {.$DEFINE Debug}                 //For programming purposes
  125. {$RANGECHECKS OFF} {$J+}
  126. uses
  127.  Windows {$IFDEF UseDelphi}, Classes, Graphics, SysUtils{$ENDIF} {$IFDEF Debug},
  128.  dialogs{$ENDIF}, asphyrezlib, pnglang;
  129. {$IFNDEF UseDelphi}
  130.   const
  131.     soFromBeginning = 0;
  132.     soFromCurrent = 1;
  133.     soFromEnd = 2;
  134. {$ENDIF}
  135. const
  136.   {ZLIB constants}
  137.   ZLIBErrors: Array[-6..2] of string = ('incompatible version (-6)',
  138.     'buffer error (-5)', 'insufficient memory (-4)', 'data error (-3)',
  139.     'stream error (-2)', 'file error (-1)', '(0)', 'stream end (1)',
  140.     'need dictionary (2)');
  141.   Z_NO_FLUSH      = 0;
  142.   Z_FINISH        = 4;
  143.   Z_STREAM_END    = 1;
  144.   {Avaliable PNG filters for mode 0}
  145.   FILTER_NONE    = 0;
  146.   FILTER_SUB     = 1;
  147.   FILTER_UP      = 2;
  148.   FILTER_AVERAGE = 3;
  149.   FILTER_PAETH   = 4;
  150.   {Avaliable color modes for PNG}
  151.   COLOR_GRAYSCALE      = 0;
  152.   COLOR_RGB            = 2;
  153.   COLOR_PALETTE        = 3;
  154.   COLOR_GRAYSCALEALPHA = 4;
  155.   COLOR_RGBALPHA       = 6;
  156. type
  157.   {$IFNDEF UseDelphi}
  158.     {Custom exception handler}
  159.     Exception = class(TObject)
  160.       constructor Create(Msg: String);
  161.     end;
  162.     ExceptClass = class of Exception;
  163.     TColor = ColorRef;
  164.   {$ENDIF}
  165.   {Error types}
  166.   EPNGOutMemory = class(Exception);
  167.   EPngError = class(Exception);
  168.   EPngUnexpectedEnd = class(Exception);
  169.   EPngInvalidCRC = class(Exception);
  170.   EPngInvalidIHDR = class(Exception);
  171.   EPNGMissingMultipleIDAT = class(Exception);
  172.   EPNGZLIBError = class(Exception);
  173.   EPNGInvalidPalette = class(Exception);
  174.   EPNGInvalidFileHeader = class(Exception);
  175.   EPNGIHDRNotFirst = class(Exception);
  176.   EPNGNotExists = class(Exception);
  177.   EPNGSizeExceeds = class(Exception);
  178.   EPNGMissingPalette = class(Exception);
  179.   EPNGUnknownCriticalChunk = class(Exception);
  180.   EPNGUnknownCompression = class(Exception);
  181.   EPNGUnknownInterlace = class(Exception);
  182.   EPNGNoImageData = class(Exception);
  183.   EPNGCouldNotLoadResource = class(Exception);
  184.   EPNGCannotChangeTransparent = class(Exception);
  185.   EPNGHeaderNotPresent = class(Exception);
  186. type
  187.   {Direct access to pixels using R,G,B}
  188.   TRGBLine = array[word] of TRGBTriple;
  189.   pRGBLine = ^TRGBLine;
  190.   {Same as TBitmapInfo but with allocated space for}
  191.   {palette entries}
  192.   TMAXBITMAPINFO = packed record
  193.     bmiHeader: TBitmapInfoHeader;
  194.     bmiColors: packed array[0..255] of TRGBQuad;
  195.   end;
  196.   {Transparency mode for pngs}
  197.   TPNGTransparencyMode = (ptmNone, ptmBit, ptmPartial);
  198.   {Pointer to a cardinal type}
  199.   pCardinal = ^Cardinal;
  200.   {Access to a rgb pixel}
  201.   pRGBPixel = ^TRGBPixel;
  202.   TRGBPixel = packed record
  203.     B, G, R: Byte;
  204.   end;
  205.   {Pointer to an array of bytes type}
  206.   TByteArray = Array[Word] of Byte;
  207.   pByteArray = ^TByteArray;
  208.   {Forward}
  209.   TPNGObject = class;
  210.   pPointerArray = ^TPointerArray;
  211.   TPointerArray = Array[Word] of Pointer;
  212.   {Contains a list of objects}
  213.   TPNGPointerList = class
  214.   private
  215.     fOwner: TPNGObject;
  216.     fCount : Cardinal;
  217.     fMemory: pPointerArray;
  218.     function GetItem(Index: Cardinal): Pointer;
  219.     procedure SetItem(Index: Cardinal; const Value: Pointer);
  220.   protected
  221.     {Removes an item}
  222.     function Remove(Value: Pointer): Pointer; virtual;
  223.     {Inserts an item}
  224.     procedure Insert(Value: Pointer; Position: Cardinal);
  225.     {Add a new item}
  226.     procedure Add(Value: Pointer);
  227.     {Returns an item}
  228.     property Item[Index: Cardinal]: Pointer read GetItem write SetItem;
  229.     {Set the size of the list}
  230.     procedure SetSize(const Size: Cardinal);
  231.     {Returns owner}
  232.     property Owner: TPNGObject read fOwner;
  233.   public
  234.     {Returns number of items}
  235.     property Count: Cardinal read fCount write SetSize;
  236.     {Object being either created or destroyed}
  237.     constructor Create(AOwner: TPNGObject);
  238.     destructor Destroy; override;
  239.   end;
  240.   {Forward declaration}
  241.   TChunk = class;
  242.   TChunkClass = class of TChunk;
  243.   {Same as TPNGPointerList but providing typecasted values}
  244.   TPNGList = class(TPNGPointerList)
  245.   private
  246.     {Used with property Item}
  247.     function GetItem(Index: Cardinal): TChunk;
  248.   public
  249.     {Removes an item}
  250.     procedure RemoveChunk(Chunk: TChunk); overload;
  251.     {Add a new chunk using the class from the parameter}
  252.     function Add(ChunkClass: TChunkClass): TChunk;
  253.     {Returns pointer to the first chunk of class}
  254.     function ItemFromClass(ChunkClass: TChunkClass): TChunk;
  255.     {Returns a chunk item from the list}
  256.     property Item[Index: Cardinal]: TChunk read GetItem;
  257.   end;
  258.   {$IFNDEF UseDelphi}
  259.     {The STREAMs bellow are only needed in case delphi provided ones is not}
  260.     {avaliable (UseDelphi trigger not set)}
  261.     {Object becomes handles}
  262.     TCanvas = THandle;
  263.     TBitmap = HBitmap;
  264.     {Trick to work}
  265.     TPersistent = TObject;
  266.     {Base class for all streams}
  267.     TStream = class
  268.     protected
  269.       {Returning/setting size}
  270.       function GetSize: Longint; virtual;
  271.       procedure SetSize(const Value: Longint); virtual; abstract;
  272.       {Returns/set position}
  273.       function GetPosition: Longint; virtual;
  274.       procedure SetPosition(const Value: Longint); virtual;
  275.     public
  276.       {Returns/sets current position}
  277.       property Position: Longint read GetPosition write SetPosition;
  278.       {Property returns/sets size}
  279.       property Size: Longint read GetSize write SetSize;
  280.       {Allows reading/writing data}
  281.       function Read(var Buffer; Count: Longint): Cardinal; virtual; abstract;
  282.       function Write(const Buffer; Count: Longint): Cardinal; virtual; abstract;
  283.       {Copies from another Stream}
  284.       function CopyFrom(Source: TStream;
  285.         Count: Cardinal): Cardinal; virtual;
  286.       {Seeks a stream position}
  287.       function Seek(Offset: Longint; Origin: Word): Longint; virtual; abstract;
  288.     end;
  289.     {File stream modes}
  290.     TFileStreamMode = (fsmRead, fsmWrite, fsmCreate);
  291.     TFileStreamModeSet = set of TFileStreamMode;
  292.     {File stream for reading from files}
  293.     TFileStream = class(TStream)
  294.     private
  295.       {Opened mode}
  296.       Filemode: TFileStreamModeSet;
  297.       {Handle}
  298.       fHandle: THandle;
  299.     protected
  300.       {Set the size of the file}
  301.       procedure SetSize(const Value: Longint); override;
  302.     public
  303.       {Seeks a file position}
  304.       function Seek(Offset: Longint; Origin: Word): Longint; override;
  305.       {Reads/writes data from/to the file}
  306.       function Read(var Buffer; Count: Longint): Cardinal; override;
  307.       function Write(const Buffer; Count: Longint): Cardinal; override;
  308.       {Stream being created and destroy}
  309.       constructor Create(Filename: String; Mode: TFileStreamModeSet);
  310.       destructor Destroy; override;
  311.     end;
  312.     {Stream for reading from resources}
  313.     TResourceStream = class(TStream)
  314.       constructor Create(Instance: HInst; const ResName: String; ResType:PChar);
  315.     private
  316.       {Variables for reading}
  317.       Size: Integer;
  318.       Memory: Pointer;
  319.       Position: Integer;
  320.     protected
  321.       {Set the size of the file}
  322.       procedure SetSize(const Value: Longint); override;
  323.     public
  324.       {Stream processing}
  325.       function Read(var Buffer; Count: Integer): Cardinal; override;
  326.       function Seek(Offset: Integer; Origin: Word): Longint; override;
  327.       function Write(const Buffer; Count: Longint): Cardinal; override;
  328.     end;
  329.   {$ENDIF}
  330.   {Forward}
  331.   TChunkIHDR = class;
  332.   {Interlace method}
  333.   TInterlaceMethod = (imNone, imAdam7);
  334.   {Compression level type}
  335.   TCompressionLevel = 0..9;
  336.   {Filters type}
  337.   TFilter = (pfNone, pfSub, pfUp, pfAverage, pfPaeth);
  338.   TFilters = set of TFilter;
  339.   {Png implementation object}
  340.   TPngObject = class{$IFDEF UseDelphi}(TGraphic){$ENDIF}
  341.   protected
  342.     {Inverse gamma table values}
  343.     InverseGamma: Array[Byte] of Byte;
  344.     procedure InitializeGamma;
  345.   private
  346.     {Temporary palette}
  347.     TempPalette: HPalette;
  348.     {Filters to test to encode}
  349.     fFilters: TFilters;
  350.     {Compression level for ZLIB}
  351.     fCompressionLevel: TCompressionLevel;
  352.     {Maximum size for IDAT chunks}
  353.     fMaxIdatSize: Integer;
  354.     {Returns if image is interlaced}
  355.     fInterlaceMethod: TInterlaceMethod;
  356.     {Chunks object}
  357.     fChunkList: TPngList;
  358.     {Clear all chunks in the list}
  359.     procedure ClearChunks;
  360.     {Returns if header is present}
  361.     function HeaderPresent: Boolean;
  362.     {Returns linesize and byte offset for pixels}
  363.     procedure GetPixelInfo(var LineSize, Offset: Cardinal);
  364.     procedure SetMaxIdatSize(const Value: Integer);
  365.     function GetAlphaScanline(const LineIndex: Integer): pByteArray;
  366.     function GetScanline(const LineIndex: Integer): Pointer;
  367.     {$IFDEF Store16bits}
  368.     function GetExtraScanline(const LineIndex: Integer): Pointer;
  369.     {$ENDIF}
  370.     function GetTransparencyMode: TPNGTransparencyMode;
  371.     function GetTransparentColor: TColor;
  372.     procedure SetTransparentColor(const Value: TColor);
  373.   protected
  374.     {Returns the image palette}
  375.     function GetPalette: HPALETTE; {$IFDEF UseDelphi}override;{$ENDIF}
  376.     {Returns/sets image width and height}
  377.     function GetWidth: Integer; {$IFDEF UseDelphi}override;{$ENDIF}
  378.     function GetHeight: Integer; {$IFDEF UseDelphi}override; {$ENDIF}
  379.     procedure SetWidth(Value: Integer);  {$IFDEF UseDelphi}override; {$ENDIF}
  380.     procedure SetHeight(Value: Integer);  {$IFDEF UseDelphi}override;{$ENDIF}
  381.     {Assigns from another TPNGObject}
  382.     procedure AssignPNG(Source: TPNGObject);
  383.     {Returns if the image is empty}
  384.     function GetEmpty: Boolean; {$IFDEF UseDelphi}override; {$ENDIF}
  385.     {Used with property Header}
  386.     function GetHeader: TChunkIHDR;
  387.     {Draws using partial transparency}
  388.     procedure DrawPartialTrans(DC: HDC; Rect: TRect);
  389.     {$IFDEF UseDelphi}
  390.     {Returns if the image is transparent}
  391.     function GetTransparent: Boolean; override;
  392.     {$ENDIF}
  393.     {Returns a pixel}
  394.     function GetPixels(const X, Y: Integer): TColor; virtual;
  395.     procedure SetPixels(const X, Y: Integer; const Value: TColor); virtual;
  396.   public
  397.     {Gamma table array}
  398.     GammaTable: Array[Byte] of Byte;
  399.     {Generates alpha information}
  400.     procedure CreateAlpha;
  401.     {Removes the image transparency}
  402.     procedure RemoveTransparency;
  403.     {Transparent color}
  404.     property TransparentColor: TColor read GetTransparentColor write
  405.       SetTransparentColor;
  406.     {Add text chunk, TChunkTEXT, TChunkzTXT}
  407.     procedure AddtEXt(const Keyword, Text: String);
  408.     procedure AddzTXt(const Keyword, Text: String);
  409.     {$IFDEF UseDelphi}
  410.     {Saves to clipboard format (thanks to Antoine Pottern)}
  411.     procedure SaveToClipboardFormat(var AFormat: Word; var AData: THandle;
  412.       var APalette: HPalette); override;
  413.     procedure LoadFromClipboardFormat(AFormat: Word; AData: THandle;
  414.       APalette: HPalette); override;
  415.     {$ENDIF}
  416.     {Calling errors}
  417.     procedure RaiseError(ExceptionClass: ExceptClass; Text: String);
  418.     {Returns a scanline from png}
  419.     property Scanline[const Index: Integer]: Pointer read GetScanline;
  420.     {$IFDEF Store16bits}
  421.     property ExtraScanline[const Index: Integer]: Pointer read GetExtraScanline;
  422.     {$ENDIF}
  423.     property AlphaScanline[const Index: Integer]: pByteArray read GetAlphaScanline;
  424.     {Returns pointer to the header}
  425.     property Header: TChunkIHDR read GetHeader;
  426.     {Returns the transparency mode used by this png}
  427.     property TransparencyMode: TPNGTransparencyMode read GetTransparencyMode;
  428.     {Assigns from another object}
  429.     procedure Assign(Source: TPersistent);{$IFDEF UseDelphi}override;{$ENDIF}
  430.     {Assigns to another object}
  431.     procedure AssignTo(Dest: TPersistent);{$IFDEF UseDelphi}override;{$ENDIF}
  432.     {Assigns from a windows bitmap handle}
  433.     procedure AssignHandle(Handle: HBitmap; Transparent: Boolean;
  434.       TransparentColor: ColorRef);
  435.     {Draws the image into a canvas}
  436.     procedure Draw(ACanvas: TCanvas; const Rect: TRect);
  437.       {$IFDEF UseDelphi}override;{$ENDIF}
  438.     {Width and height properties}
  439.     property Width: Integer read GetWidth;
  440.     property Height: Integer read GetHeight;
  441.     {Returns if the image is interlaced}
  442.     property InterlaceMethod: TInterlaceMethod read fInterlaceMethod
  443.       write fInterlaceMethod;
  444.     {Filters to test to encode}
  445.     property Filters: TFilters read fFilters write fFilters;
  446.     {Maximum size for IDAT chunks, default and minimum is 65536}
  447.     property MaxIdatSize: Integer read fMaxIdatSize write SetMaxIdatSize;
  448.     {Property to return if the image is empty or not}
  449.     property Empty: Boolean read GetEmpty;
  450.     {Compression level}
  451.     property CompressionLevel: TCompressionLevel read fCompressionLevel
  452.       write fCompressionLevel;
  453.     {Access to the chunk list}
  454.     property Chunks: TPngList read fChunkList;
  455.     {Object being created and destroyed}
  456.     constructor Create; {$IFDEF UseDelphi}override;{$ENDIF}
  457.     destructor Destroy; override;
  458.     {$IFNDEF UseDelphi}procedure LoadFromFile(const Filename: String);{$ENDIF}
  459.     {$IFNDEF UseDelphi}procedure SaveToFile(const Filename: String);{$ENDIF}
  460.     procedure LoadFromStream(Stream: TStream); {$IFDEF UseDelphi}override;{$ENDIF}
  461.     procedure SaveToStream(Stream: TStream); {$IFDEF UseDelphi}override;{$ENDIF}
  462.     {Loading the image from resources}
  463.     procedure LoadFromResourceName(Instance: HInst; const Name: String);
  464.     procedure LoadFromResourceID(Instance: HInst; ResID: Integer);
  465.     {Access to the png pixels}
  466.     property Pixels[const X, Y: Integer]: TColor read GetPixels write SetPixels;
  467.     {Palette property}
  468.     {$IFNDEF UseDelphi}property Palette: HPalette read GetPalette;{$ENDIF}
  469.   end;
  470.   {Chunk name object}
  471.   TChunkName = Array[0..3] of Char;
  472.   {Global chunk object}
  473.   TChunk = class
  474.   private
  475.     {Contains data}
  476.     fData: Pointer;
  477.     fDataSize: Cardinal;
  478.     {Stores owner}
  479.     fOwner: TPngObject;
  480.     {Stores the chunk name}
  481.     fName: TChunkName;
  482.     {Returns pointer to the TChunkIHDR}
  483.     function GetHeader: TChunkIHDR;
  484.     {Used with property index}
  485.     function GetIndex: Integer;
  486.     {Should return chunk class/name}
  487.     class function GetName: String; virtual;
  488.     {Returns the chunk name}
  489.     function GetChunkName: String;
  490.   public
  491.     {Returns index from list}
  492.     property Index: Integer read GetIndex;
  493.     {Returns pointer to the TChunkIHDR}
  494.     property Header: TChunkIHDR read GetHeader;
  495.     {Resize the data}
  496.     procedure ResizeData(const NewSize: Cardinal);
  497.     {Returns data and size}
  498.     property Data: Pointer read fData;
  499.     property DataSize: Cardinal read fDataSize;
  500.     {Assigns from another TChunk}
  501.     procedure Assign(Source: TChunk); virtual;
  502.     {Returns owner}
  503.     property Owner: TPngObject read fOwner;
  504.     {Being destroyed/created}
  505.     constructor Create(Owner: TPngObject); virtual;
  506.     destructor Destroy; override;
  507.     {Returns chunk class/name}
  508.     property Name: String read GetChunkName;
  509.     {Loads the chunk from a stream}
  510.     function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  511.       Size: Integer): Boolean; virtual;
  512.     {Saves the chunk to a stream}
  513.     function SaveData(Stream: TStream): Boolean;
  514.     function SaveToStream(Stream: TStream): Boolean; virtual;
  515.   end;
  516.   {Chunk classes}
  517.   TChunkIEND = class(TChunk);     {End chunk}
  518.   {IHDR data}
  519.   pIHDRData = ^TIHDRData;
  520.   TIHDRData = packed record
  521.     Width, Height: Cardinal;
  522.     BitDepth,
  523.     ColorType,
  524.     CompressionMethod,
  525.     FilterMethod,
  526.     InterlaceMethod: Byte;
  527.   end;
  528.   {Information header chunk}
  529.   TChunkIHDR = class(TChunk)
  530.   private
  531.     {Current image}
  532.     ImageHandle: HBitmap;
  533.     ImageDC: HDC;
  534.     {Output windows bitmap}
  535.     HasPalette: Boolean;
  536.     BitmapInfo: TMaxBitmapInfo;
  537.     BytesPerRow: Integer;
  538.     {Stores the image bytes}
  539.     {$IFDEF Store16bits}ExtraImageData: Pointer;{$ENDIF}
  540.     ImageData: pointer;
  541.     ImageAlpha: Pointer;
  542.     {Contains all the ihdr data}
  543.     IHDRData: TIHDRData;
  544.   protected
  545.     {Resizes the image data to fill the color type, bit depth, }
  546.     {width and height parameters}
  547.     procedure PrepareImageData;
  548.     {Release allocated ImageData memory}
  549.     procedure FreeImageData;
  550.   public
  551.     {Access to ImageHandle}
  552.     property ImageHandleValue: HBitmap read ImageHandle;
  553.     {Properties}
  554.     property Width: Cardinal read IHDRData.Width write IHDRData.Width;
  555.     property Height: Cardinal read IHDRData.Height write IHDRData.Height;
  556.     property BitDepth: Byte read IHDRData.BitDepth write IHDRData.BitDepth;
  557.     property ColorType: Byte read IHDRData.ColorType write IHDRData.ColorType;
  558.     property CompressionMethod: Byte read IHDRData.CompressionMethod
  559.       write IHDRData.CompressionMethod;
  560.     property FilterMethod: Byte read IHDRData.FilterMethod
  561.       write IHDRData.FilterMethod;
  562.     property InterlaceMethod: Byte read IHDRData.InterlaceMethod
  563.       write IHDRData.InterlaceMethod;
  564.     {Loads the chunk from a stream}
  565.     function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  566.       Size: Integer): Boolean; override;
  567.     {Saves the chunk to a stream}
  568.     function SaveToStream(Stream: TStream): Boolean; override;
  569.     {Destructor/constructor}
  570.     constructor Create(Owner: TPngObject); override;
  571.     destructor Destroy; override;
  572.     {Assigns from another TChunk}
  573.     procedure Assign(Source: TChunk); override;
  574.   end;
  575.   {Gamma chunk}
  576.   TChunkgAMA = class(TChunk)
  577.   private
  578.     {Returns/sets the value for the gamma chunk}
  579.     function GetValue: Cardinal;
  580.     procedure SetValue(const Value: Cardinal);
  581.   public
  582.     {Returns/sets gamma value}
  583.     property Gamma: Cardinal read GetValue write SetValue;
  584.     {Loading the chunk from a stream}
  585.     function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  586.       Size: Integer): Boolean; override;
  587.     {Being created}
  588.     constructor Create(Owner: TPngObject); override;
  589.     {Assigns from another TChunk}
  590.     procedure Assign(Source: TChunk); override;
  591.   end;
  592.   {ZLIB Decompression extra information}
  593.   TZStreamRec2 = packed record
  594.     {From ZLIB}
  595.     ZLIB: TZStreamRec;
  596.     {Additional info}
  597.     Data: Pointer;
  598.     fStream   : TStream;
  599.   end;
  600.   {Palette chunk}
  601.   TChunkPLTE = class(TChunk)
  602.   private
  603.     {Number of items in the palette}
  604.     fCount: Integer;
  605.     {Contains the palette handle}
  606.     function GetPaletteItem(Index: Byte): TRGBQuad;
  607.   public
  608.     {Returns the color for each item in the palette}
  609.     property Item[Index: Byte]: TRGBQuad read GetPaletteItem;
  610.     {Returns the number of items in the palette}
  611.     property Count: Integer read fCount;
  612.     {Loads the chunk from a stream}
  613.     function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  614.       Size: Integer): Boolean; override;
  615.     {Saves the chunk to a stream}
  616.     function SaveToStream(Stream: TStream): Boolean; override;
  617.     {Assigns from another TChunk}
  618.     procedure Assign(Source: TChunk); override;
  619.   end;
  620.   {Transparency information}
  621.   TChunktRNS = class(TChunk)
  622.   private
  623.     fBitTransparency: Boolean;
  624.     function GetTransparentColor: ColorRef;
  625.     {Returns the transparent color}
  626.     procedure SetTransparentColor(const Value: ColorRef);
  627.   public
  628.     {Palette values for transparency}
  629.     PaletteValues: Array[Byte] of Byte;
  630.     {Returns if it uses bit transparency}
  631.     property BitTransparency: Boolean read fBitTransparency;
  632.     {Returns the transparent color}
  633.     property TransparentColor: ColorRef read GetTransparentColor write
  634.       SetTransparentColor;
  635.     {Loads/saves the chunk from/to a stream}
  636.     function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  637.       Size: Integer): Boolean; override;
  638.     function SaveToStream(Stream: TStream): Boolean; override;
  639.     {Assigns from another TChunk}
  640.     procedure Assign(Source: TChunk); override;
  641.   end;
  642.   {Actual image information}
  643.   TChunkIDAT = class(TChunk)
  644.   private
  645.     {Holds another pointer to the TChunkIHDR}
  646.     Header: TChunkIHDR;
  647.     {Stores temporary image width and height}
  648.     ImageWidth, ImageHeight: Integer;
  649.     {Size in bytes of each line and offset}
  650.     Row_Bytes, Offset : Cardinal;
  651.     {Contains data for the lines}
  652.     Encode_Buffer: Array[0..5] of pByteArray;
  653.     Row_Buffer: Array[Boolean] of pByteArray;
  654.     {Variable to invert the Row_Buffer used}
  655.     RowUsed: Boolean;
  656.     {Ending position for the current IDAT chunk}
  657.     EndPos: Integer;
  658.     {Filter the current line}
  659.     procedure FilterRow;
  660.     {Filter to encode and returns the best filter}
  661.     function FilterToEncode: Byte;
  662.     {Reads ZLIB compressed data}
  663.     function IDATZlibRead(var ZLIBStream: TZStreamRec2; Buffer: Pointer;
  664.       Count: Integer; var EndPos: Integer; var crcfile: Cardinal): Integer;
  665.     {Compress and writes IDAT data}
  666.     procedure IDATZlibWrite(var ZLIBStream: TZStreamRec2; Buffer: Pointer;
  667.       const Length: Cardinal);
  668.     procedure FinishIDATZlib(var ZLIBStream: TZStreamRec2);
  669.     {Prepares the palette}
  670.     procedure PreparePalette;
  671.   protected
  672.     {Decode interlaced image}
  673.     procedure DecodeInterlacedAdam7(Stream: TStream;
  674.       var ZLIBStream: TZStreamRec2; const Size: Integer; var crcfile: Cardinal);
  675.     {Decode non interlaced imaged}
  676.     procedure DecodeNonInterlaced(Stream: TStream;
  677.       var ZLIBStream: TZStreamRec2; const Size: Integer;
  678.       var crcfile: Cardinal);
  679.   protected
  680.     {Encode non interlaced images}
  681.     procedure EncodeNonInterlaced(Stream: TStream;
  682.       var ZLIBStream: TZStreamRec2);
  683.     {Encode interlaced images}
  684.     procedure EncodeInterlacedAdam7(Stream: TStream;
  685.       var ZLIBStream: TZStreamRec2);
  686.   protected
  687.     {Memory copy methods to decode}
  688.     procedure CopyNonInterlacedRGB8(
  689.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  690.     procedure CopyNonInterlacedRGB16(
  691.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  692.     procedure CopyNonInterlacedPalette148(
  693.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  694.     procedure CopyNonInterlacedPalette2(
  695.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  696.     procedure CopyNonInterlacedGray2(
  697.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  698.     procedure CopyNonInterlacedGrayscale16(
  699.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  700.     procedure CopyNonInterlacedRGBAlpha8(
  701.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  702.     procedure CopyNonInterlacedRGBAlpha16(
  703.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  704.     procedure CopyNonInterlacedGrayscaleAlpha8(
  705.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  706.     procedure CopyNonInterlacedGrayscaleAlpha16(
  707.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  708.     procedure CopyInterlacedRGB8(const Pass: Byte;
  709.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  710.     procedure CopyInterlacedRGB16(const Pass: Byte;
  711.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  712.     procedure CopyInterlacedPalette148(const Pass: Byte;
  713.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  714.     procedure CopyInterlacedPalette2(const Pass: Byte;
  715.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  716.     procedure CopyInterlacedGray2(const Pass: Byte;
  717.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  718.     procedure CopyInterlacedGrayscale16(const Pass: Byte;
  719.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  720.     procedure CopyInterlacedRGBAlpha8(const Pass: Byte;
  721.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  722.     procedure CopyInterlacedRGBAlpha16(const Pass: Byte;
  723.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  724.     procedure CopyInterlacedGrayscaleAlpha8(const Pass: Byte;
  725.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  726.     procedure CopyInterlacedGrayscaleAlpha16(const Pass: Byte;
  727.       Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  728.   protected
  729.     {Memory copy methods to encode}
  730.     procedure EncodeNonInterlacedRGB8(Src, Dest, Trans: pChar);
  731.     procedure EncodeNonInterlacedRGB16(Src, Dest, Trans: pChar);
  732.     procedure EncodeNonInterlacedGrayscale16(Src, Dest, Trans: pChar);
  733.     procedure EncodeNonInterlacedPalette148(Src, Dest, Trans: pChar);
  734.     procedure EncodeNonInterlacedRGBAlpha8(Src, Dest, Trans: pChar);
  735.     procedure EncodeNonInterlacedRGBAlpha16(Src, Dest, Trans: pChar);
  736.     procedure EncodeNonInterlacedGrayscaleAlpha8(Src, Dest, Trans: pChar);
  737.     procedure EncodeNonInterlacedGrayscaleAlpha16(Src, Dest, Trans: pChar);
  738.     procedure EncodeInterlacedRGB8(const Pass: Byte; Src, Dest, Trans: pChar);
  739.     procedure EncodeInterlacedRGB16(const Pass: Byte; Src, Dest, Trans: pChar);
  740.     procedure EncodeInterlacedPalette148(const Pass: Byte;
  741.       Src, Dest, Trans: pChar);
  742.     procedure EncodeInterlacedGrayscale16(const Pass: Byte;
  743.       Src, Dest, Trans: pChar);
  744.     procedure EncodeInterlacedRGBAlpha8(const Pass: Byte;
  745.       Src, Dest, Trans: pChar);
  746.     procedure EncodeInterlacedRGBAlpha16(const Pass: Byte;
  747.       Src, Dest, Trans: pChar);
  748.     procedure EncodeInterlacedGrayscaleAlpha8(const Pass: Byte;
  749.       Src, Dest, Trans: pChar);
  750.     procedure EncodeInterlacedGrayscaleAlpha16(const Pass: Byte;
  751.       Src, Dest, Trans: pChar);
  752.   public
  753.     {Loads the chunk from a stream}
  754.     function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  755.       Size: Integer): Boolean; override;
  756.     {Saves the chunk to a stream}
  757.     function SaveToStream(Stream: TStream): Boolean; override;
  758.   end;
  759.   {Image last modification chunk}
  760.   TChunktIME = class(TChunk)
  761.   private
  762.     {Holds the variables}
  763.     fYear: Word;
  764.     fMonth, fDay, fHour, fMinute, fSecond: Byte;
  765.   public
  766.     {Returns/sets variables}
  767.     property Year: Word read fYear write fYear;
  768.     property Month: Byte read fMonth write fMonth;
  769.     property Day: Byte read fDay write fDay;
  770.     property Hour: Byte read fHour write fHour;
  771.     property Minute: Byte read fMinute write fMinute;
  772.     property Second: Byte read fSecond write fSecond;
  773.     {Loads the chunk from a stream}
  774.     function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  775.       Size: Integer): Boolean; override;
  776.     {Saves the chunk to a stream}
  777.     function SaveToStream(Stream: TStream): Boolean; override;
  778.   end;
  779.   {Textual data}
  780.   TChunktEXt = class(TChunk)
  781.   private
  782.     fKeyword, fText: String;
  783.   public
  784.     {Keyword and text}
  785.     property Keyword: String read fKeyword write fKeyword;
  786.     property Text: String read fText write fText;
  787.     {Loads the chunk from a stream}
  788.     function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  789.       Size: Integer): Boolean; override;
  790.     {Saves the chunk to a stream}
  791.     function SaveToStream(Stream: TStream): Boolean; override;
  792.     {Assigns from another TChunk}
  793.     procedure Assign(Source: TChunk); override;
  794.   end;
  795.   {zTXT chunk}
  796.   TChunkzTXt = class(TChunktEXt)
  797.     {Loads the chunk from a stream}
  798.     function LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  799.       Size: Integer): Boolean; override;
  800.     {Saves the chunk to a stream}
  801.     function SaveToStream(Stream: TStream): Boolean; override;
  802.   end;
  803. {Here we test if it's c++ builder or delphi version 3 or less}
  804. {$IFDEF VER110}{$DEFINE DelphiBuilder3Less}{$ENDIF}
  805. {$IFDEF VER100}{$DEFINE DelphiBuilder3Less}{$ENDIF}
  806. {$IFDEF VER93}{$DEFINE DelphiBuilder3Less}{$ENDIF}
  807. {$IFDEF VER90}{$DEFINE DelphiBuilder3Less}{$ENDIF}
  808. {$IFDEF VER80}{$DEFINE DelphiBuilder3Less}{$ENDIF}
  809. {Registers a new chunk class}
  810. procedure RegisterChunk(ChunkClass: TChunkClass);
  811. {Calculates crc}
  812. function update_crc(crc: {$IFNDEF DelphiBuilder3Less}Cardinal{$ELSE}Integer
  813.   {$ENDIF}; buf: pByteArray; len: Integer): Cardinal;
  814. {Invert bytes using assembly}
  815. function ByteSwap(const a: integer): integer;
  816. implementation
  817. var
  818.   ChunkClasses: TPngPointerList;
  819.   {Table of CRCs of all 8-bit messages}
  820.   crc_table: Array[0..255] of Cardinal;
  821.   {Flag: has the table been computed? Initially false}
  822.   crc_table_computed: Boolean;
  823. {Draw transparent image using transparent color}
  824. procedure DrawTransparentBitmap(dc: HDC; srcBits: Pointer;
  825.   var srcHeader: TBitmapInfoHeader;
  826.   srcBitmapInfo: pBitmapInfo; Rect: TRect; cTransparentColor: COLORREF);
  827. var
  828.   cColor:   COLORREF;
  829.   bmAndBack, bmAndObject, bmAndMem: HBITMAP;
  830.   bmBackOld, bmObjectOld, bmMemOld: HBITMAP;
  831.   hdcMem, hdcBack, hdcObject, hdcTemp: HDC;
  832.   ptSize, orgSize: TPOINT;
  833.   OldBitmap, DrawBitmap: HBITMAP;
  834. begin
  835.   hdcTemp := CreateCompatibleDC(dc);
  836.   // Select the bitmap
  837.   DrawBitmap := CreateDIBitmap(dc, srcHeader, CBM_INIT, srcBits, srcBitmapInfo^,
  838.     DIB_RGB_COLORS);
  839.   OldBitmap := SelectObject(hdcTemp, DrawBitmap);
  840.   // Sizes
  841.   OrgSize.x := abs(srcHeader.biWidth);
  842.   OrgSize.y := abs(srcHeader.biHeight);
  843.   ptSize.x := Rect.Right - Rect.Left;        // Get width of bitmap
  844.   ptSize.y := Rect.Bottom - Rect.Top;        // Get height of bitmap
  845.   // Create some DCs to hold temporary data.
  846.   hdcBack  := CreateCompatibleDC(dc);
  847.   hdcObject := CreateCompatibleDC(dc);
  848.   hdcMem   := CreateCompatibleDC(dc);
  849.   // Create a bitmap for each DC. DCs are required for a number of
  850.   // GDI functions.
  851.   // Monochrome DCs
  852.   bmAndBack  := CreateBitmap(ptSize.x, ptSize.y, 1, 1, nil);
  853.   bmAndObject := CreateBitmap(ptSize.x, ptSize.y, 1, 1, nil);
  854.   bmAndMem   := CreateCompatibleBitmap(dc, ptSize.x, ptSize.y);
  855.   // Each DC must select a bitmap object to store pixel data.
  856.   bmBackOld  := SelectObject(hdcBack, bmAndBack);
  857.   bmObjectOld := SelectObject(hdcObject, bmAndObject);
  858.   bmMemOld   := SelectObject(hdcMem, bmAndMem);
  859.   // Set the background color of the source DC to the color.
  860.   // contained in the parts of the bitmap that should be transparent
  861.   cColor := SetBkColor(hdcTemp, cTransparentColor);
  862.   // Create the object mask for the bitmap by performing a BitBlt
  863.   // from the source bitmap to a monochrome bitmap.
  864.   StretchBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0,
  865.     orgSize.x, orgSize.y, SRCCOPY);
  866.   // Set the background color of the source DC back to the original
  867.   // color.
  868.   SetBkColor(hdcTemp, cColor);
  869.   // Create the inverse of the object mask.
  870.   BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0,
  871.        NOTSRCCOPY);
  872.   // Copy the background of the main DC to the destination.
  873.   BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, dc, Rect.Left, Rect.Top,
  874.        SRCCOPY);
  875.   // Mask out the places where the bitmap will be placed.
  876.   BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND);
  877.   // Mask out the transparent colored pixels on the bitmap.
  878. //  BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
  879.   StretchBlt(hdcTemp, 0, 0, OrgSize.x, OrgSize.y, hdcBack, 0, 0,
  880.     PtSize.x, PtSize.y, SRCAND);
  881.   // XOR the bitmap with the background on the destination DC.
  882.   StretchBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0,
  883.     OrgSize.x, OrgSize.y, SRCPAINT);
  884.   // Copy the destination to the screen.
  885.   BitBlt(dc, Rect.Left, Rect.Top, ptSize.x, ptSize.y, hdcMem, 0, 0,
  886.        SRCCOPY);
  887.   // Delete the memory bitmaps.
  888.   DeleteObject(SelectObject(hdcBack, bmBackOld));
  889.   DeleteObject(SelectObject(hdcObject, bmObjectOld));
  890.   DeleteObject(SelectObject(hdcMem, bmMemOld));
  891.   DeleteObject(SelectObject(hdcTemp, OldBitmap));
  892.   // Delete the memory DCs.
  893.   DeleteDC(hdcMem);
  894.   DeleteDC(hdcBack);
  895.   DeleteDC(hdcObject);
  896.   DeleteDC(hdcTemp);
  897. end;
  898. {Make the table for a fast CRC.}
  899. procedure make_crc_table;
  900. var
  901.   c: Cardinal;
  902.   n, k: Integer;
  903. begin
  904.   {fill the crc table}
  905.   for n := 0 to 255 do
  906.   begin
  907.     c := Cardinal(n);
  908.     for k := 0 to 7 do
  909.     begin
  910.       if Boolean(c and 1) then
  911.         c := $edb88320 xor (c shr 1)
  912.       else
  913.         c := c shr 1;
  914.     end;
  915.     crc_table[n] := c;
  916.   end;
  917.   {The table has already being computated}
  918.   crc_table_computed := true;
  919. end;
  920. {Update a running CRC with the bytes buf[0..len-1]--the CRC
  921.  should be initialized to all 1's, and the transmitted value
  922.  is the 1's complement of the final running CRC (see the
  923.  crc() routine below)).}
  924. function update_crc(crc: {$IFNDEF DelphiBuilder3Less}Cardinal{$ELSE}Integer
  925.   {$ENDIF}; buf: pByteArray; len: Integer): Cardinal;
  926. var
  927.   c: Cardinal;
  928.   n: Integer;
  929. begin
  930.   c := crc;
  931.   {Create the crc table in case it has not being computed yet}
  932.   if not crc_table_computed then make_crc_table;
  933.   {Update}
  934.   for n := 0 to len - 1 do
  935.     c := crc_table[(c XOR buf^[n]) and $FF] XOR (c shr 8);
  936.   {Returns}
  937.   Result := c;
  938. end;
  939. {$IFNDEF UseDelphi}
  940.   function FileExists(Filename: String): Boolean;
  941.   var
  942.     FindFile: THandle;
  943.     FindData: TWin32FindData;
  944.   begin
  945.     FindFile := FindFirstFile(PChar(Filename), FindData);
  946.     Result := FindFile <> INVALID_HANDLE_VALUE;
  947.     if Result then Windows.FindClose(FindFile);
  948.   end;
  949. {$ENDIF}
  950. {$IFNDEF UseDelphi}
  951.   {Exception implementation}
  952.   constructor Exception.Create(Msg: String);
  953.   begin
  954.   end;
  955. {$ENDIF}
  956. {Calculates the paeth predictor}
  957. function PaethPredictor(a, b, c: Byte): Byte;
  958. var
  959.   pa, pb, pc: Integer;
  960. begin
  961.   { a = left, b = above, c = upper left }
  962.   pa := abs(b - c);      { distances to a, b, c }
  963.   pb := abs(a - c);
  964.   pc := abs(a + b - c * 2);
  965.   { return nearest of a, b, c, breaking ties in order a, b, c }
  966.   if (pa <= pb) and (pa <= pc) then
  967.     Result := a
  968.   else
  969.     if pb <= pc then
  970.       Result := b
  971.     else
  972.       Result := c;
  973. end;
  974. {Invert bytes using assembly}
  975. function ByteSwap(const a: integer): integer;
  976. asm
  977.   bswap eax
  978. end;
  979. function ByteSwap16(inp:word): word;
  980. asm
  981.   bswap eax
  982.   shr   eax, 16
  983. end;
  984. {Calculates number of bytes for the number of pixels using the}
  985. {color mode in the paramenter}
  986. function BytesForPixels(const Pixels: Integer; const ColorType,
  987.   BitDepth: Byte): Integer;
  988. begin
  989.   case ColorType of
  990.     {Palette and grayscale contains a single value, for palette}
  991.     {an value of size 2^bitdepth pointing to the palette index}
  992.     {and grayscale the value from 0 to 2^bitdepth with color intesity}
  993.     COLOR_GRAYSCALE, COLOR_PALETTE:
  994.       Result := (Pixels * BitDepth + 7) div 8;
  995.     {RGB contains 3 values R, G, B with size 2^bitdepth each}
  996.     COLOR_RGB:
  997.       Result := (Pixels * BitDepth * 3) div 8;
  998.     {Contains one value followed by alpha value booth size 2^bitdepth}
  999.     COLOR_GRAYSCALEALPHA:
  1000.       Result := (Pixels * BitDepth * 2) div 8;
  1001.     {Contains four values size 2^bitdepth, Red, Green, Blue and alpha}
  1002.     COLOR_RGBALPHA:
  1003.       Result := (Pixels * BitDepth * 4) div 8;
  1004.     else
  1005.       Result := 0;
  1006.   end {case ColorType}
  1007. end;
  1008. type
  1009.   pChunkClassInfo = ^TChunkClassInfo;
  1010.   TChunkClassInfo = record
  1011.     ClassName: TChunkClass;
  1012.   end;
  1013. {Register a chunk type}
  1014. procedure RegisterChunk(ChunkClass: TChunkClass);
  1015. var
  1016.   NewClass: pChunkClassInfo;
  1017. begin
  1018.   {In case the list object has not being created yet}
  1019.   if ChunkClasses = nil then ChunkClasses := TPngPointerList.Create(nil);
  1020.   {Add this new class}
  1021.   new(NewClass);
  1022.   NewClass^.ClassName := ChunkClass;
  1023.   ChunkClasses.Add(NewClass);
  1024. end;
  1025. {Free chunk class list}
  1026. procedure FreeChunkClassList;
  1027. var
  1028.   i: Integer;
  1029. begin
  1030.   if (ChunkClasses <> nil) then
  1031.   begin
  1032.     FOR i := 0 TO ChunkClasses.Count - 1 do
  1033.       Dispose(pChunkClassInfo(ChunkClasses.Item[i]));
  1034.     ChunkClasses.Free;
  1035.   end;
  1036. end;
  1037. {Registering of common chunk classes}
  1038. procedure RegisterCommonChunks;
  1039. begin
  1040.   {Important chunks}
  1041.   RegisterChunk(TChunkIEND);
  1042.   RegisterChunk(TChunkIHDR);
  1043.   RegisterChunk(TChunkIDAT);
  1044.   RegisterChunk(TChunkPLTE);
  1045.   RegisterChunk(TChunkgAMA);
  1046.   RegisterChunk(TChunktRNS);
  1047.   {Not so important chunks}
  1048.   RegisterChunk(TChunktIME);
  1049.   RegisterChunk(TChunktEXt);
  1050.   RegisterChunk(TChunkzTXt);
  1051. end;
  1052. {Creates a new chunk of this class}
  1053. function CreateClassChunk(Owner: TPngObject; Name: TChunkName): TChunk;
  1054. var
  1055.   i       : Integer;
  1056.   NewChunk: TChunkClass;
  1057. begin
  1058.   {Looks for this chunk}
  1059.   NewChunk := TChunk;  {In case there is no registered class for this}
  1060.   {Looks for this class in all registered chunks}
  1061.   if Assigned(ChunkClasses) then
  1062.     FOR i := 0 TO ChunkClasses.Count - 1 DO
  1063.     begin
  1064.       if pChunkClassInfo(ChunkClasses.Item[i])^.ClassName.GetName = Name then
  1065.       begin
  1066.         NewChunk := pChunkClassInfo(ChunkClasses.Item[i])^.ClassName;
  1067.         break;
  1068.       end;
  1069.     end;
  1070.   {Returns chunk class}
  1071.   Result := NewChunk.Create(Owner);
  1072.   Result.fName := Name;
  1073. end;
  1074. {ZLIB support}
  1075. const
  1076.   ZLIBAllocate = High(Word);
  1077. {Initializes ZLIB for decompression}
  1078. function ZLIBInitInflate(Stream: TStream): TZStreamRec2;
  1079. begin
  1080.   {Fill record}
  1081.   Fillchar(Result, SIZEOF(TZStreamRec2), #0);
  1082.   {Set internal record information}
  1083.   with Result do
  1084.   begin
  1085.     GetMem(Data, ZLIBAllocate);
  1086.     fStream := Stream;
  1087.   end;
  1088.   {Init decompression}
  1089.   InflateInit_(Result.zlib, zlib_version, SIZEOF(TZStreamRec));
  1090. end;
  1091. {Initializes ZLIB for compression}
  1092. function ZLIBInitDeflate(Stream: TStream;
  1093.   Level: TCompressionlevel; Size: Cardinal): TZStreamRec2;
  1094. begin
  1095.   {Fill record}
  1096.   Fillchar(Result, SIZEOF(TZStreamRec2), #0);
  1097.   {Set internal record information}
  1098.   with Result, ZLIB do
  1099.   begin
  1100.     GetMem(Data, Size);
  1101.     fStream := Stream;
  1102.     next_out := Data;
  1103.     avail_out := Size;
  1104.   end;
  1105.   {Inits compression}
  1106.   deflateInit_(Result.zlib, Level, zlib_version, sizeof(TZStreamRec));
  1107. end;
  1108. {Terminates ZLIB for compression}
  1109. procedure ZLIBTerminateDeflate(var ZLIBStream: TZStreamRec2);
  1110. begin
  1111.   {Terminates decompression}
  1112.   DeflateEnd(ZLIBStream.zlib);
  1113.   {Free internal record}
  1114.   FreeMem(ZLIBStream.Data, ZLIBAllocate);
  1115. end;
  1116. {Terminates ZLIB for decompression}
  1117. procedure ZLIBTerminateInflate(var ZLIBStream: TZStreamRec2);
  1118. begin
  1119.   {Terminates decompression}
  1120.   InflateEnd(ZLIBStream.zlib);
  1121.   {Free internal record}
  1122.   FreeMem(ZLIBStream.Data, ZLIBAllocate);
  1123. end;
  1124. {Decompresses ZLIB into a memory address}
  1125. function DecompressZLIB(const Input: Pointer; InputSize: Integer;
  1126.   var Output: Pointer; var OutputSize: Integer;
  1127.   var ErrorOutput: String): Boolean;
  1128. var
  1129.   StreamRec : TZStreamRec;
  1130.   Buffer    : Array[Byte] of Byte;
  1131.   InflateRet: Integer;
  1132. begin
  1133.   with StreamRec do
  1134.   begin
  1135.     {Initializes}
  1136.     Result := True;
  1137.     OutputSize := 0;
  1138.     {Prepares the data to decompress}
  1139.     FillChar(StreamRec, SizeOf(TZStreamRec), #0);
  1140.     InflateInit_(StreamRec, zlib_version, SIZEOF(TZStreamRec));
  1141.     next_in := Input;
  1142.     avail_in := InputSize;
  1143.     {Decodes data}
  1144.     repeat
  1145.       {In case it needs an output buffer}
  1146.       if (avail_out = 0) then
  1147.       begin
  1148.         next_out := @Buffer;
  1149.         avail_out := SizeOf(Buffer);
  1150.       end {if (avail_out = 0)};
  1151.       {Decompress and put in output}
  1152.       InflateRet := inflate(StreamRec, 0);
  1153.       if (InflateRet = Z_STREAM_END) or (InflateRet = 0) then
  1154.       begin
  1155.         {Reallocates output buffer}
  1156.         inc(OutputSize, total_out);
  1157.         if Output = nil then
  1158.           GetMem(Output, OutputSize) else ReallocMem(Output, OutputSize);
  1159.         {Copies the new data}
  1160.         CopyMemory(Ptr(Longint(Output) + OutputSize - total_out),
  1161.           @Buffer, total_out);
  1162.       end {if (InflateRet = Z_STREAM_END) or (InflateRet = 0)}
  1163.       {Now tests for errors}
  1164.       else if InflateRet < 0 then
  1165.       begin
  1166.         Result := False;
  1167.         ErrorOutput := StreamRec.msg;
  1168.         InflateEnd(StreamRec);
  1169.         Exit;
  1170.       end {if InflateRet < 0}
  1171.     until InflateRet = Z_STREAM_END;
  1172.     {Terminates decompression}
  1173.     InflateEnd(StreamRec);
  1174.   end {with StreamRec}
  1175. end;
  1176. {Compresses ZLIB into a memory address}
  1177. function CompressZLIB(Input: Pointer; InputSize, CompressionLevel: Integer;
  1178.   var Output: Pointer; var OutputSize: Integer;
  1179.   var ErrorOutput: String): Boolean;
  1180. var
  1181.   StreamRec : TZStreamRec;
  1182.   Buffer    : Array[Byte] of Byte;
  1183.   DeflateRet: Integer;
  1184. begin
  1185.   with StreamRec do
  1186.   begin
  1187.     Result := True; {By default returns TRUE as everything might have gone ok}
  1188.     OutputSize := 0; {Initialize}
  1189.     {Prepares the data to compress}
  1190.     FillChar(StreamRec, SizeOf(TZStreamRec), #0);
  1191.     DeflateInit_(StreamRec, CompressionLevel,zlib_version, SIZEOF(TZStreamRec));
  1192.     next_in := Input;
  1193.     avail_in := InputSize;
  1194.     while avail_in > 0 do
  1195.     begin
  1196.       {When it needs new buffer to stores the compressed data}
  1197.       if avail_out = 0 then
  1198.       begin
  1199.         {Restore buffer}
  1200.         next_out := @Buffer;
  1201.         avail_out := SizeOf(Buffer);
  1202.       end {if avail_out = 0};
  1203.       {Compresses}
  1204.       DeflateRet := deflate(StreamRec, Z_FINISH);
  1205.       if (DeflateRet = Z_STREAM_END) or (DeflateRet = 0) then
  1206.       begin
  1207.         {Updates the output memory}
  1208.         inc(OutputSize, total_out);
  1209.         if Output = nil then
  1210.           GetMem(Output, OutputSize) else ReallocMem(Output, OutputSize);
  1211.         {Copies the new data}
  1212.         CopyMemory(Ptr(Longint(Output) + OutputSize - total_out),
  1213.           @Buffer, total_out);
  1214.       end {if (InflateRet = Z_STREAM_END) or (InflateRet = 0)}
  1215.       {Now tests for errors}
  1216.       else if DeflateRet < 0 then
  1217.       begin
  1218.         Result := False;
  1219.         ErrorOutput := StreamRec.msg;
  1220.         DeflateEnd(StreamRec);
  1221.         Exit;
  1222.       end {if InflateRet < 0}
  1223.     end {while avail_in > 0};
  1224.     {Finishes compressing}
  1225.     DeflateEnd(StreamRec);
  1226.   end {with StreamRec}
  1227. end;
  1228. {TPngPointerList implementation}
  1229. {Object being created}
  1230. constructor TPngPointerList.Create(AOwner: TPNGObject);
  1231. begin
  1232.   inherited Create; {Let ancestor work}
  1233.   {Holds owner}
  1234.   fOwner := AOwner;
  1235.   {Memory pointer not being used yet}
  1236.   fMemory := nil;
  1237.   {No items yet}
  1238.   fCount := 0;
  1239. end;
  1240. {Removes value from the list}
  1241. function TPngPointerList.Remove(Value: Pointer): Pointer;
  1242. var
  1243.   I, Position: Integer;
  1244. begin
  1245.   {Gets item position}
  1246.   Position := -1;
  1247.   FOR I := 0 TO Count - 1 DO
  1248.     if Value = Item[I] then Position := I;
  1249.   {In case a match was found}
  1250.   if Position >= 0 then
  1251.   begin
  1252.     Result := Item[Position]; {Returns pointer}
  1253.     {Remove item and move memory}
  1254.     Dec(fCount);
  1255.     if Position < Integer(FCount) then
  1256.       System.Move(fMemory^[Position + 1], fMemory^[Position],
  1257.       (Integer(fCount) - Position) * SizeOf(Pointer));
  1258.   end {if Position >= 0} else Result := nil
  1259. end;
  1260. {Add a new value in the list}
  1261. procedure TPngPointerList.Add(Value: Pointer);
  1262. begin
  1263.   Count := Count + 1;
  1264.   Item[Count - 1] := Value;
  1265. end;
  1266. {Object being destroyed}
  1267. destructor TPngPointerList.Destroy;
  1268. begin
  1269.   {Release memory if needed}
  1270.   if fMemory <> nil then
  1271.     FreeMem(fMemory, fCount * sizeof(Pointer));
  1272.   {Free things}
  1273.   inherited Destroy;
  1274. end;
  1275. {Returns one item from the list}
  1276. function TPngPointerList.GetItem(Index: Cardinal): Pointer;
  1277. begin
  1278.   if (Index <= Count - 1) then
  1279.     Result := fMemory[Index]
  1280.   else
  1281.     {In case it's out of bounds}
  1282.     Result := nil;
  1283. end;
  1284. {Inserts a new item in the list}
  1285. procedure TPngPointerList.Insert(Value: Pointer; Position: Cardinal);
  1286. begin
  1287.   if (Position < Count) then
  1288.   begin
  1289.     {Increase item count}
  1290.     SetSize(Count + 1);
  1291.     {Move other pointers}
  1292.     if Position < Count then
  1293.       System.Move(fMemory^[Position], fMemory^[Position + 1],
  1294.         (Count - Position - 1) * SizeOf(Pointer));
  1295.     {Sets item}
  1296.     Item[Position] := Value;
  1297.   end;
  1298. end;
  1299. {Sets one item from the list}
  1300. procedure TPngPointerList.SetItem(Index: Cardinal; const Value: Pointer);
  1301. begin
  1302.   {If index is in bounds, set value}
  1303.   if (Index <= Count - 1) then
  1304.     fMemory[Index] := Value
  1305. end;
  1306. {This method resizes the list}
  1307. procedure TPngPointerList.SetSize(const Size: Cardinal);
  1308. begin
  1309.   {Sets the size}
  1310.   if (fMemory = nil) and (Size > 0) then
  1311.     GetMem(fMemory, Size * SIZEOF(Pointer))
  1312.   else
  1313.     if Size > 0 then  {Only realloc if the new size is greater than 0}
  1314.       ReallocMem(fMemory, Size * SIZEOF(Pointer))
  1315.     else
  1316.     {In case user is resize to 0 items}
  1317.     begin
  1318.       FreeMem(fMemory);
  1319.       fMemory := nil;
  1320.     end;
  1321.   {Update count}
  1322.   fCount := Size;
  1323. end;
  1324. {TPNGList implementation}
  1325. {Removes an item}
  1326. procedure TPNGList.RemoveChunk(Chunk: TChunk);
  1327. begin
  1328.   Remove(Chunk);
  1329.   Chunk.Free
  1330. end;
  1331. {Add a new item}
  1332. function TPNGList.Add(ChunkClass: TChunkClass): TChunk;
  1333. var
  1334.   IHDR: TChunkIHDR;
  1335.   IEND: TChunkIEND;
  1336.   IDAT: TChunkIDAT;
  1337.   PLTE: TChunkPLTE;
  1338. begin
  1339.   Result := nil; {Default result}
  1340.   {Adding these is not allowed}
  1341.   if (ChunkClass = TChunkIHDR) or (ChunkClass = TChunkIDAT) or
  1342.     (ChunkClass = TChunkPLTE) or (ChunkClass = TChunkIEND) then
  1343.     fOwner.RaiseError(EPngError, EPNGCannotAddChunkText)
  1344.   {Two of these is not allowed}
  1345.   else if ((ChunkClass = TChunkgAMA) and (ItemFromClass(TChunkgAMA) <> nil)) or
  1346.      ((ChunkClass = TChunktRNS) and (ItemFromClass(TChunktRNS) <> nil)) then
  1347.     fOwner.RaiseError(EPngError, EPNGCannotAddChunkText)
  1348.   {There must have an IEND and IHDR chunk}
  1349.   else if (ItemFromClass(TChunkIEND) = nil) or
  1350.     (ItemFromClass(TChunkIHDR) = nil) then
  1351.     fOwner.RaiseError(EPngError, EPNGCannotAddInvalidImageText)
  1352.   else
  1353.   begin
  1354.     {Get common chunks}
  1355.     IHDR := ItemFromClass(TChunkIHDR) as TChunkIHDR;
  1356.     IEND := ItemFromClass(TChunkIEND) as TChunkIEND;
  1357.     {Create new chunk}
  1358.     Result := ChunkClass.Create(Owner);
  1359.     {Add to the list}
  1360.     if (ChunkClass = TChunkgAMA) then
  1361.       Insert(Result, IHDR.Index + 1)
  1362.     {Transparency chunk (fix by Ian Boyd)}
  1363.     else if (ChunkClass = TChunktRNS) then
  1364.     begin
  1365.       {Transparecy chunk must be after PLTE; before IDAT}
  1366.       IDAT := ItemFromClass(TChunkIDAT) as TChunkIDAT;
  1367.       PLTE := ItemFromClass(TChunkPLTE) as TChunkPLTE;
  1368.       if Assigned(PLTE) then
  1369.         Insert(Result, PLTE.Index + 1)
  1370.       else if Assigned(IDAT) then
  1371.         Insert(Result, IDAT.Index)
  1372.       else
  1373.         Insert(Result, IHDR.Index + 1)
  1374.     end
  1375.     else {All other chunks}
  1376.       Insert(Result, IEND.Index);
  1377.   end {if}
  1378. end;
  1379. {Returns item from the list}
  1380. function TPNGList.GetItem(Index: Cardinal): TChunk;
  1381. begin
  1382.   Result := inherited GetItem(Index);
  1383. end;
  1384. {Returns first item from the list using the class from parameter}
  1385. function TPNGList.ItemFromClass(ChunkClass: TChunkClass): TChunk;
  1386. var
  1387.   i: Integer;
  1388. begin
  1389.   Result := nil; {Initial result}
  1390.   FOR i := 0 TO Count - 1 DO
  1391.     {Test if this item has the same class}
  1392.     if Item[i] is ChunkClass then
  1393.     begin
  1394.       {Returns this item and exit}
  1395.       Result := Item[i];
  1396.       break;
  1397.     end {if}
  1398. end;
  1399. {$IFNDEF UseDelphi}
  1400.   {TStream implementation}
  1401.   {Copies all from another stream}
  1402.   function TStream.CopyFrom(Source: TStream; Count: Cardinal): Cardinal;
  1403.   const
  1404.     MaxBytes = $f000;
  1405.   var
  1406.     Buffer:  PChar;
  1407.     BufSize, N: Cardinal;
  1408.   begin
  1409.     {If count is zero, copy everything from Source}
  1410.     if Count = 0 then
  1411.     begin
  1412.       Source.Seek(0, soFromBeginning);
  1413.       Count := Source.Size;
  1414.     end;
  1415.     Result := Count; {Returns the number of bytes readed}
  1416.     {Allocates memory}
  1417.     if Count > MaxBytes then BufSize := MaxBytes else BufSize := Count;
  1418.     GetMem(Buffer, BufSize);
  1419.     {Copy memory}
  1420.     while Count > 0 do
  1421.     begin
  1422.       if Count > BufSize then N := BufSize else N := Count;
  1423.       Source.Read(Buffer^, N);
  1424.       Write(Buffer^, N);
  1425.       dec(Count, N);
  1426.     end;
  1427.     {Deallocates memory}
  1428.     FreeMem(Buffer, BufSize);
  1429.   end;
  1430. {Set current stream position}
  1431. procedure TStream.SetPosition(const Value: Longint);
  1432. begin
  1433.   Seek(Value, soFromBeginning);
  1434. end;
  1435. {Returns position}
  1436. function TStream.GetPosition: Longint;
  1437. begin
  1438.   Result := Seek(0, soFromCurrent);
  1439. end;
  1440.   {Returns stream size}
  1441. function TStream.GetSize: Longint;
  1442.   var
  1443.     Pos: Cardinal;
  1444.   begin
  1445.     Pos := Seek(0, soFromCurrent);
  1446.     Result := Seek(0, soFromEnd);
  1447.     Seek(Pos, soFromCurrent);
  1448.   end;
  1449.   {TFileStream implementation}
  1450.   {Filestream object being created}
  1451.   constructor TFileStream.Create(Filename: String; Mode: TFileStreamModeSet);
  1452.     {Makes file mode}
  1453.     function OpenMode: DWORD;
  1454.     begin
  1455.       Result := 0;
  1456.       if fsmRead in Mode then Result := GENERIC_READ;
  1457.       if (fsmWrite in Mode) or (fsmCreate in Mode) then
  1458.         Result := Result OR GENERIC_WRITE;
  1459.     end;
  1460.   const
  1461.     IsCreate: Array[Boolean] of Integer = (OPEN_ALWAYS, CREATE_ALWAYS);
  1462.   begin
  1463.     {Call ancestor}
  1464.     inherited Create;
  1465.     {Create handle}
  1466.     fHandle := CreateFile(PChar(Filename), OpenMode, FILE_SHARE_READ or
  1467.       FILE_SHARE_WRITE, nil, IsCreate[fsmCreate in Mode], 0, 0);
  1468.     {Store mode}
  1469.     FileMode := Mode;
  1470.   end;
  1471.   {Filestream object being destroyed}
  1472.   destructor TFileStream.Destroy;
  1473.   begin
  1474.     {Terminates file and close}
  1475.     if FileMode = [fsmWrite] then
  1476.       SetEndOfFile(fHandle);
  1477.     CloseHandle(fHandle);
  1478.     {Call ancestor}
  1479.     inherited Destroy;
  1480.   end;
  1481.   {Writes data to the file}
  1482.   function TFileStream.Write(const Buffer; Count: Longint): Cardinal;
  1483.   begin
  1484.     if not WriteFile(fHandle, Buffer, Count, Result, nil) then
  1485.       Result := 0;
  1486.   end;
  1487.   {Reads data from the file}
  1488.   function TFileStream.Read(var Buffer; Count: Longint): Cardinal;
  1489.   begin
  1490.     if not ReadFile(fHandle, Buffer, Count, Result, nil) then
  1491.       Result := 0;
  1492.   end;
  1493.   {Seeks the file position}
  1494.   function TFileStream.Seek(Offset: Integer; Origin: Word): Longint;
  1495.   begin
  1496.     Result := SetFilePointer(fHandle, Offset, nil, Origin);
  1497.   end;
  1498.   {Sets the size of the file}
  1499.   procedure TFileStream.SetSize(const Value: Longint);
  1500.   begin
  1501.     Seek(Value, soFromBeginning);
  1502.     SetEndOfFile(fHandle);
  1503.   end;
  1504.   {TResourceStream implementation}
  1505.   {Creates the resource stream}
  1506.   constructor TResourceStream.Create(Instance: HInst; const ResName: String;
  1507.     ResType: PChar);
  1508.   var
  1509.     ResID: HRSRC;
  1510.     ResGlobal: HGlobal;
  1511.   begin
  1512.     {Obtains the resource ID}
  1513.     ResID := FindResource(hInstance, PChar(ResName), RT_RCDATA);
  1514.     if ResID = 0 then raise EPNGError.Create('');
  1515.     {Obtains memory and size}
  1516.     ResGlobal := LoadResource(hInstance, ResID);
  1517.     Size := SizeOfResource(hInstance, ResID);
  1518.     Memory := LockResource(ResGlobal);
  1519.     if (ResGlobal = 0) or (Memory = nil) then EPNGError.Create('');
  1520.   end;
  1521.   {Setting resource stream size is not supported}
  1522.   procedure TResourceStream.SetSize(const Value: Integer);
  1523.   begin
  1524.   end;
  1525.   {Writing into a resource stream is not supported}
  1526.   function TResourceStream.Write(const Buffer; Count: Integer): Cardinal;
  1527.   begin
  1528.     Result := 0;
  1529.   end;
  1530.   {Reads data from the stream}
  1531.   function TResourceStream.Read(var Buffer; Count: Integer): Cardinal;
  1532.   begin
  1533.     //Returns data
  1534.     CopyMemory(@Buffer, Ptr(Longint(Memory) + Position), Count);
  1535.     //Update position
  1536.     inc(Position, Count);
  1537.     //Returns
  1538.     Result := Count;
  1539.   end;
  1540.   {Seeks data}
  1541.   function TResourceStream.Seek(Offset: Integer; Origin: Word): Longint;
  1542.   begin
  1543.     {Move depending on the origin}
  1544.     case Origin of
  1545.       soFromBeginning: Position := Offset;
  1546.       soFromCurrent: inc(Position, Offset);
  1547.       soFromEnd: Position := Size + Offset;
  1548.     end;
  1549.     {Returns the current position}
  1550.     Result := Position;
  1551.   end;
  1552. {$ENDIF}
  1553. {TChunk implementation}
  1554. {Resizes the data}
  1555. procedure TChunk.ResizeData(const NewSize: Cardinal);
  1556. begin
  1557.   fDataSize := NewSize;
  1558.   ReallocMem(fData, NewSize + 1);
  1559. end;
  1560. {Returns index from list}
  1561. function TChunk.GetIndex: Integer;
  1562. var
  1563.   i: Integer;
  1564. begin
  1565.   Result := -1; {Avoiding warnings}
  1566.   {Searches in the list}
  1567.   FOR i := 0 TO Owner.Chunks.Count - 1 DO
  1568.     if Owner.Chunks.Item[i] = Self then
  1569.     begin
  1570.       {Found match}
  1571.       Result := i;
  1572.       exit;
  1573.     end {for i}
  1574. end;
  1575. {Returns pointer to the TChunkIHDR}
  1576. function TChunk.GetHeader: TChunkIHDR;
  1577. begin
  1578.   Result := Owner.Chunks.Item[0] as TChunkIHDR;
  1579. end;
  1580. {Assigns from another TChunk}
  1581. procedure TChunk.Assign(Source: TChunk);
  1582. begin
  1583.   {Copy properties}
  1584.   fName := Source.fName;
  1585.   {Set data size and realloc}
  1586.   ResizeData(Source.fDataSize);
  1587.   {Copy data (if there's any)}
  1588.   if fDataSize > 0 then CopyMemory(fData, Source.fData, fDataSize);
  1589. end;
  1590. {Chunk being created}
  1591. constructor TChunk.Create(Owner: TPngObject);
  1592. var
  1593.   ChunkName: String;
  1594. begin
  1595.   {Ancestor create}
  1596.   inherited Create;
  1597.   {If it's a registered class, set the chunk name based on the class}
  1598.   {name. For instance, if the class name is TChunkgAMA, the GAMA part}
  1599.   {will become the chunk name}
  1600.   ChunkName := Copy(ClassName, Length('TChunk') + 1, Length(ClassName));
  1601.   if Length(ChunkName) = 4 then CopyMemory(@fName[0], @ChunkName[1], 4);
  1602.   {Initialize data holder}
  1603.   GetMem(fData, 1);
  1604.   fDataSize := 0;
  1605.   {Record owner}
  1606.   fOwner := Owner;
  1607. end;
  1608. {Chunk being destroyed}
  1609. destructor TChunk.Destroy;
  1610. begin
  1611.   {Free data holder}
  1612.   FreeMem(fData, fDataSize + 1);
  1613.   {Let ancestor destroy}
  1614.   inherited Destroy;
  1615. end;
  1616. {Returns the chunk name 1}
  1617. function TChunk.GetChunkName: String;
  1618. begin
  1619.   Result := fName
  1620. end;
  1621. {Returns the chunk name 2}
  1622. class function TChunk.GetName: String;
  1623. begin
  1624.   {For avoid writing GetName for each TChunk descendent, by default for}
  1625.   {classes which don't declare GetName, it will look for the class name}
  1626.   {to extract the chunk kind. Example, if the class name is TChunkIEND }
  1627.   {this method extracts and returns IEND}
  1628.   Result := Copy(ClassName, Length('TChunk') + 1, Length(ClassName));
  1629. end;
  1630. {Saves the data to the stream}
  1631. function TChunk.SaveData(Stream: TStream): Boolean;
  1632. var
  1633.   ChunkSize, ChunkCRC: Cardinal;
  1634. begin
  1635.   {First, write the size for the following data in the chunk}
  1636.   ChunkSize := ByteSwap(DataSize);
  1637.   Stream.Write(ChunkSize, 4);
  1638.   {The chunk name}
  1639.   Stream.Write(fName, 4);
  1640.   {If there is data for the chunk, write it}
  1641.   if DataSize > 0 then Stream.Write(Data^, DataSize);
  1642.   {Calculates and write CRC}
  1643.   ChunkCRC := update_crc($ffffffff, @fName[0], 4);
  1644.   ChunkCRC := Byteswap(update_crc(ChunkCRC, Data, DataSize) xor $ffffffff);
  1645.   Stream.Write(ChunkCRC, 4);
  1646.   {Returns that everything went ok}
  1647.   Result := TRUE;
  1648. end;
  1649. {Saves the chunk to the stream}
  1650. function TChunk.SaveToStream(Stream: TStream): Boolean;
  1651. begin
  1652.   Result := SaveData(Stream)
  1653. end;
  1654. {Loads the chunk from a stream}
  1655. function TChunk.LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  1656.   Size: Integer): Boolean;
  1657. var
  1658.   CheckCRC: Cardinal;
  1659.   {$IFDEF CheckCRC}RightCRC: Cardinal;{$ENDIF}
  1660. begin
  1661.   {Copies data from source}
  1662.   ResizeData(Size);
  1663.   if Size > 0 then Stream.Read(fData^, Size);
  1664.   {Reads CRC}
  1665.   Stream.Read(CheckCRC, 4);
  1666.   CheckCrc := ByteSwap(CheckCRC);
  1667.   {Check if crc readed is valid}
  1668.   {$IFDEF CheckCRC}
  1669.     RightCRC := update_crc($ffffffff, @ChunkName[0], 4);
  1670.     RightCRC := update_crc(RightCRC, fData, Size) xor $ffffffff;
  1671.     Result := RightCRC = CheckCrc;
  1672.     {Handle CRC error}
  1673.     if not Result then
  1674.     begin
  1675.       {In case it coult not load chunk}
  1676.       Owner.RaiseError(EPngInvalidCRC, EPngInvalidCRCText);
  1677.       exit;
  1678.     end
  1679.   {$ELSE}Result := TRUE; {$ENDIF}
  1680. end;
  1681. {TChunktIME implementation}
  1682. {Chunk being loaded from a stream}
  1683. function TChunktIME.LoadFromStream(Stream: TStream;
  1684.   const ChunkName: TChunkName; Size: Integer): Boolean;
  1685. begin
  1686.   {Let ancestor load the data}
  1687.   Result := inherited LoadFromStream(Stream, ChunkName, Size);
  1688.   if not Result or (Size <> 7) then exit; {Size must be 7}
  1689.   {Reads data}
  1690.   fYear := ((pByte(Longint(Data) )^) * 256)+ (pByte(Longint(Data) + 1)^);
  1691.   fMonth := pByte(Longint(Data) + 2)^;
  1692.   fDay := pByte(Longint(Data) + 3)^;
  1693.   fHour := pByte(Longint(Data) + 4)^;
  1694.   fMinute := pByte(Longint(Data) + 5)^;
  1695.   fSecond := pByte(Longint(Data) + 6)^;
  1696. end;
  1697. {Saving the chunk to a stream}
  1698. function TChunktIME.SaveToStream(Stream: TStream): Boolean;
  1699. begin
  1700.   {Update data}
  1701.   ResizeData(7);  {Make sure the size is 7}
  1702.   pWord(Data)^ := Year;
  1703.   pByte(Longint(Data) + 2)^ := Month;
  1704.   pByte(Longint(Data) + 3)^ := Day;
  1705.   pByte(Longint(Data) + 4)^ := Hour;
  1706.   pByte(Longint(Data) + 5)^ := Minute;
  1707.   pByte(Longint(Data) + 6)^ := Second;
  1708.   {Let inherited save data}
  1709.   Result := inherited SaveToStream(Stream);
  1710. end;
  1711. {TChunkztXt implementation}
  1712. {Loading the chunk from a stream}
  1713. function TChunkzTXt.LoadFromStream(Stream: TStream;
  1714.   const ChunkName: TChunkName; Size: Integer): Boolean;
  1715. var
  1716.   ErrorOutput: String;
  1717.   CompressionMethod: Byte;
  1718.   Output: Pointer;
  1719.   OutputSize: Integer;
  1720. begin
  1721.   {Load data from stream and validate}
  1722.   Result := inherited LoadFromStream(Stream, ChunkName, Size);
  1723.   if not Result or (Size < 4) then exit;
  1724.   fKeyword := PChar(Data);  {Get keyword and compression method bellow}
  1725.   CompressionMethod := pByte(Longint(fKeyword) + Length(fKeyword))^;
  1726.   fText := '';
  1727.   {In case the compression is 0 (only one accepted by specs), reads it}
  1728.   if CompressionMethod = 0 then
  1729.   begin
  1730.     Output := nil;
  1731.     if DecompressZLIB(PChar(Longint(Data) + Length(fKeyword) + 2),
  1732.       Size - Length(fKeyword) - 2, Output, OutputSize, ErrorOutput) then
  1733.     begin
  1734.       SetLength(fText, OutputSize);
  1735.       CopyMemory(@fText[1], Output, OutputSize);
  1736.     end {if DecompressZLIB(...};
  1737.     FreeMem(Output);
  1738.   end {if CompressionMethod = 0}
  1739. end;
  1740. {Saving the chunk to a stream}
  1741. function TChunkztXt.SaveToStream(Stream: TStream): Boolean;
  1742. var
  1743.   Output: Pointer;
  1744.   OutputSize: Integer;
  1745.   ErrorOutput: String;
  1746. begin
  1747.   Output := nil; {Initializes output}
  1748.   if fText = '' then fText := ' ';
  1749.   {Compresses the data}
  1750.   if CompressZLIB(@fText[1], Length(fText), Owner.CompressionLevel, Output,
  1751.     OutputSize, ErrorOutput) then
  1752.   begin
  1753.     {Size is length from keyword, plus a null character to divide}
  1754.     {plus the compression method, plus the length of the text (zlib compressed)}
  1755.     ResizeData(Length(fKeyword) + 2 + OutputSize);
  1756.     Fillchar(Data^, DataSize, #0);
  1757.     {Copies the keyword data}
  1758.     if Keyword <> '' then
  1759.       CopyMemory(Data, @fKeyword[1], Length(Keyword));
  1760.     {Compression method 0 (inflate/deflate)}
  1761.     pByte(Ptr(Longint(Data) + Length(Keyword) + 1))^ := 0;
  1762.     if OutputSize > 0 then
  1763.       CopyMemory(Ptr(Longint(Data) + Length(Keyword) + 2), Output, OutputSize);
  1764.     {Let ancestor calculate crc and save}
  1765.     Result := SaveData(Stream);
  1766.   end {if CompressZLIB(...} else Result := False;
  1767.   {Frees output}
  1768.   if Output <> nil then FreeMem(Output)
  1769. end;
  1770. {TChunktEXt implementation}
  1771. {Assigns from another text chunk}
  1772. procedure TChunktEXt.Assign(Source: TChunk);
  1773. begin
  1774.   fKeyword := TChunktEXt(Source).fKeyword;
  1775.   fText := TChunktEXt(Source).fText;
  1776. end;
  1777. {Loading the chunk from a stream}
  1778. function TChunktEXt.LoadFromStream(Stream: TStream;
  1779.   const ChunkName: TChunkName; Size: Integer): Boolean;
  1780. begin
  1781.   {Load data from stream and validate}
  1782.   Result := inherited LoadFromStream(Stream, ChunkName, Size);
  1783.   if not Result or (Size < 3) then exit;
  1784.   {Get text}
  1785.   fKeyword := PChar(Data);
  1786.   SetLength(fText, Size - Length(fKeyword) - 1);
  1787.   CopyMemory(@fText[1], Ptr(Longint(Data) + Length(fKeyword) + 1),
  1788.     Length(fText));
  1789. end;
  1790. {Saving the chunk to a stream}
  1791. function TChunktEXt.SaveToStream(Stream: TStream): Boolean;
  1792. begin
  1793.   {Size is length from keyword, plus a null character to divide}
  1794.   {plus the length of the text}
  1795.   ResizeData(Length(fKeyword) + 1 + Length(fText));
  1796.   Fillchar(Data^, DataSize, #0);
  1797.   {Copy data}
  1798.   if Keyword <> '' then
  1799.     CopyMemory(Data, @fKeyword[1], Length(Keyword));
  1800.   if Text <> '' then
  1801.     CopyMemory(Ptr(Longint(Data) + Length(Keyword) + 1), @fText[1],
  1802.       Length(Text));
  1803.   {Let ancestor calculate crc and save}
  1804.   Result := inherited SaveToStream(Stream);
  1805. end;
  1806. {TChunkIHDR implementation}
  1807. {Chunk being created}
  1808. constructor TChunkIHDR.Create(Owner: TPngObject);
  1809. begin
  1810.   {Call inherited}
  1811.   inherited Create(Owner);
  1812.   {Prepare pointers}
  1813.   ImageHandle := 0;
  1814.   ImageDC := 0;
  1815. end;
  1816. {Chunk being destroyed}
  1817. destructor TChunkIHDR.Destroy;
  1818. begin
  1819.   {Free memory}
  1820.   FreeImageData();
  1821.   {Calls TChunk destroy}
  1822.   inherited Destroy;
  1823. end;
  1824. {Assigns from another IHDR chunk}
  1825. procedure TChunkIHDR.Assign(Source: TChunk);
  1826. begin
  1827.   {Copy the IHDR data}
  1828.   if Source is TChunkIHDR then
  1829.   begin
  1830.     {Copy IHDR values}
  1831.     IHDRData := TChunkIHDR(Source).IHDRData;
  1832.     {Prepare to hold data by filling BitmapInfo structure and}
  1833.     {resizing ImageData and ImageAlpha memory allocations}
  1834.     PrepareImageData();
  1835.     {Copy image data}
  1836.     CopyMemory(ImageData, TChunkIHDR(Source).ImageData,
  1837.       BytesPerRow * Integer(Height));
  1838.     CopyMemory(ImageAlpha, TChunkIHDR(Source).ImageAlpha,
  1839.       Integer(Width) * Integer(Height));
  1840.     {Copy palette colors}
  1841.     BitmapInfo.bmiColors := TChunkIHDR(Source).BitmapInfo.bmiColors;
  1842.   end
  1843.   else
  1844.     Owner.RaiseError(EPNGError, EPNGCannotAssignChunkText);
  1845. end;
  1846. {Release allocated image data}
  1847. procedure TChunkIHDR.FreeImageData;
  1848. begin
  1849.   {Free old image data}
  1850.   if ImageHandle <> 0  then DeleteObject(ImageHandle);
  1851.   if ImageDC     <> 0  then DeleteDC(ImageDC);
  1852.   if ImageAlpha <> nil then FreeMem(ImageAlpha);
  1853.   {$IFDEF Store16bits}
  1854.   if ExtraImageData <> nil then FreeMem(ExtraImageData);
  1855.   {$ENDIF}
  1856.   ImageHandle := 0; ImageDC := 0; ImageAlpha := nil; ImageData := nil;
  1857. end;
  1858. {Chunk being loaded from a stream}
  1859. function TChunkIHDR.LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  1860.   Size: Integer): Boolean;
  1861. begin
  1862.   {Let TChunk load it}
  1863.   Result := inherited LoadFromStream(Stream, ChunkName, Size);
  1864.   if not Result then Exit;
  1865.   {Now check values}
  1866.   {Note: It's recommended by png specification to make sure that the size}
  1867.   {must be 13 bytes to be valid, but some images with 14 bytes were found}
  1868.   {which could be loaded by internet explorer and other tools}
  1869.   if (fDataSize < SIZEOF(TIHdrData)) then
  1870.   begin
  1871.     {Ihdr must always have at least 13 bytes}
  1872.     Result := False;
  1873.     Owner.RaiseError(EPNGInvalidIHDR, EPNGInvalidIHDRText);
  1874.     exit;
  1875.   end;
  1876.   {Everything ok, reads IHDR}
  1877.   IHDRData := pIHDRData(fData)^;
  1878.   IHDRData.Width := ByteSwap(IHDRData.Width);
  1879.   IHDRData.Height := ByteSwap(IHDRData.Height);
  1880.   {The width and height must not be larger than 65535 pixels}
  1881.   if (IHDRData.Width > High(Word)) or (IHDRData.Height > High(Word)) then
  1882.   begin
  1883.     Result := False;
  1884.     Owner.RaiseError(EPNGSizeExceeds, EPNGSizeExceedsText);
  1885.     exit;
  1886.   end {if IHDRData.Width > High(Word)};
  1887.   {Compression method must be 0 (inflate/deflate)}
  1888.   if (IHDRData.CompressionMethod <> 0) then
  1889.   begin
  1890.     Result := False;
  1891.     Owner.RaiseError(EPNGUnknownCompression, EPNGUnknownCompressionText);
  1892.     exit;
  1893.   end;
  1894.   {Interlace must be either 0 (none) or 7 (adam7)}
  1895.   if (IHDRData.InterlaceMethod <> 0) and (IHDRData.InterlaceMethod <> 1) then
  1896.   begin
  1897.     Result := False;
  1898.     Owner.RaiseError(EPNGUnknownInterlace, EPNGUnknownInterlaceText);
  1899.     exit;
  1900.   end;
  1901.   {Updates owner properties}
  1902.   Owner.InterlaceMethod := TInterlaceMethod(IHDRData.InterlaceMethod);
  1903.   {Prepares data to hold image}
  1904.   PrepareImageData();
  1905. end;
  1906. {Saving the IHDR chunk to a stream}
  1907. function TChunkIHDR.SaveToStream(Stream: TStream): Boolean;
  1908. begin
  1909.   {Ignore 2 bits images}
  1910.   if BitDepth = 2 then BitDepth := 4;
  1911.   {It needs to do is update the data with the IHDR data}
  1912.   {structure containing the write values}
  1913.   ResizeData(SizeOf(TIHDRData));
  1914.   pIHDRData(fData)^ := IHDRData;
  1915.   {..byteswap 4 byte types}
  1916.   pIHDRData(fData)^.Width := ByteSwap(pIHDRData(fData)^.Width);
  1917.   pIHDRData(fData)^.Height := ByteSwap(pIHDRData(fData)^.Height);
  1918.   {..update interlace method}
  1919.   pIHDRData(fData)^.InterlaceMethod := Byte(Owner.InterlaceMethod);
  1920.   {..and then let the ancestor SaveToStream do the hard work}
  1921.   Result := inherited SaveToStream(Stream);
  1922. end;
  1923. {Resizes the image data to fill the color type, bit depth, }
  1924. {width and height parameters}
  1925. procedure TChunkIHDR.PrepareImageData();
  1926.   {Set the bitmap info}
  1927.   procedure SetInfo(const Bitdepth: Integer; const Palette: Boolean);
  1928.   begin
  1929.     {Copy if the bitmap contain palette entries}
  1930.     HasPalette := Palette;
  1931.     {Initialize the structure with zeros}
  1932.     fillchar(BitmapInfo, sizeof(BitmapInfo), #0);
  1933.     {Fill the strucutre}
  1934.     with BitmapInfo.bmiHeader do
  1935.     begin
  1936.       biSize := sizeof(TBitmapInfoHeader);
  1937.       biHeight := Height;
  1938.       biWidth := Width;
  1939.       biPlanes := 1;
  1940.       biBitCount := BitDepth;
  1941.       biCompression := BI_RGB;
  1942.     end {with BitmapInfo.bmiHeader}
  1943.   end;
  1944. begin
  1945.   {Prepare bitmap info header}
  1946.   Fillchar(BitmapInfo, sizeof(TMaxBitmapInfo), #0);
  1947.   {Release old image data}
  1948.   FreeImageData();
  1949.   {Obtain number of bits for each pixel}
  1950.   case ColorType of
  1951.     COLOR_GRAYSCALE, COLOR_PALETTE, COLOR_GRAYSCALEALPHA:
  1952.       case BitDepth of
  1953.         {These are supported by windows}
  1954.         1, 4, 8: SetInfo(BitDepth, TRUE);
  1955.         {2 bits for each pixel is not supported by windows bitmap}
  1956.         2      : SetInfo(4, TRUE);
  1957.         {Also 16 bits (2 bytes) for each pixel is not supported}
  1958.         {and should be transormed into a 8 bit grayscale}
  1959.         16     : SetInfo(8, TRUE);
  1960.       end;
  1961.     {Only 1 byte (8 bits) is supported}
  1962.     COLOR_RGB, COLOR_RGBALPHA:  SetInfo(24, FALSE);
  1963.   end {case ColorType};
  1964.   {Number of bytes for each scanline}
  1965.   BytesPerRow := (((BitmapInfo.bmiHeader.biBitCount * Width) + 31)
  1966.     and not 31) div 8;
  1967.   {Build array for alpha information, if necessary}
  1968.   if (ColorType = COLOR_RGBALPHA) or (ColorType = COLOR_GRAYSCALEALPHA) then
  1969.   begin
  1970.     GetMem(ImageAlpha, Integer(Width) * Integer(Height));
  1971.     FillChar(ImageAlpha^, Integer(Width) * Integer(Height), #0);
  1972.   end;
  1973.   {Build array for extra byte information}
  1974.   {$IFDEF Store16bits}
  1975.   if (BitDepth = 16) then
  1976.   begin
  1977.     GetMem(ExtraImageData, BytesPerRow * Integer(Height));
  1978.     FillChar(ExtraImageData^, BytesPerRow * Integer(Height), #0);
  1979.   end;
  1980.   {$ENDIF}
  1981.   {Creates the image to hold the data, CreateDIBSection does a better}
  1982.   {work in allocating necessary memory}
  1983.   ImageDC := CreateCompatibleDC(0);
  1984.   ImageHandle := CreateDIBSection(ImageDC, pBitmapInfo(@BitmapInfo)^,
  1985.     DIB_RGB_COLORS, ImageData, 0, 0);
  1986.   {Clears the old palette (if any)}
  1987.   with Owner do
  1988.     if  TempPalette <> 0 then
  1989.     begin
  1990.       DeleteObject(TempPalette);
  1991.       TempPalette := 0;
  1992.     end {with Owner, if TempPalette <> 0};
  1993.   {Build array and allocate bytes for each row}
  1994.   zeromemory(ImageData, BytesPerRow * Integer(Height));
  1995. end;
  1996. {TChunktRNS implementation}
  1997. {$IFNDEF UseDelphi}
  1998. function CompareMem(P1, P2: pByte; const Size: Integer): Boolean;
  1999. var i: Integer;
  2000. begin
  2001.   Result := True;
  2002.   for i := 1 to Size do
  2003.   begin
  2004.     if P1^ <> P2^ then Result := False;
  2005.     inc(P1); inc(P2);
  2006.   end {for i}
  2007. end;
  2008. {$ENDIF}
  2009. {Sets the transpararent color}
  2010. procedure TChunktRNS.SetTransparentColor(const Value: ColorRef);
  2011. var
  2012.   i: Byte;
  2013.   LookColor: TRGBQuad;
  2014. begin
  2015.   {Clears the palette values}
  2016.   Fillchar(PaletteValues, SizeOf(PaletteValues), #0);
  2017.   {Sets that it uses bit transparency}
  2018.   fBitTransparency := True;
  2019.   {Depends on the color type}
  2020.   with Header do
  2021.     case ColorType of
  2022.       COLOR_GRAYSCALE:
  2023.       begin
  2024.         Self.ResizeData(2);
  2025.         pWord(@PaletteValues[0])^ := ByteSwap16(GetRValue(Value));
  2026.       end;
  2027.       COLOR_RGB:
  2028.       begin
  2029.         Self.ResizeData(6);
  2030.         pWord(@PaletteValues[0])^ := ByteSwap16(GetRValue(Value));
  2031.         pWord(@PaletteValues[2])^ := ByteSwap16(GetGValue(Value));
  2032.         pWord(@PaletteValues[4])^ := ByteSwap16(GetBValue(Value));
  2033.       end;
  2034.       COLOR_PALETTE:
  2035.       begin
  2036.         {Creates a RGBQuad to search for the color}
  2037.         LookColor.rgbRed := GetRValue(Value);
  2038.         LookColor.rgbGreen := GetGValue(Value);
  2039.         LookColor.rgbBlue := GetBValue(Value);
  2040.         {Look in the table for the entry}
  2041.         for i := 0 to 255 do
  2042.           if CompareMem(@BitmapInfo.bmiColors[i], @LookColor, 3) then
  2043.             Break;
  2044.         {Fill the transparency table}
  2045.         Fillchar(PaletteValues, i, 255);
  2046.         Self.ResizeData(i + 1)
  2047.       end
  2048.     end {case / with};
  2049. end;
  2050. {Returns the transparent color for the image}
  2051. function TChunktRNS.GetTransparentColor: ColorRef;
  2052. var
  2053.   PaletteChunk: TChunkPLTE;
  2054.   i: Integer;
  2055. begin
  2056.   Result := 0; {Default: Unknown transparent color}
  2057.   {Depends on the color type}
  2058.   with Header do
  2059.     case ColorType of
  2060.       COLOR_GRAYSCALE:
  2061.           Result := RGB(PaletteValues[0], PaletteValues[0],
  2062.         PaletteValues[0]);
  2063.       COLOR_RGB:
  2064.           Result := RGB(PaletteValues[1], PaletteValues[3], PaletteValues[5]);
  2065.       COLOR_PALETTE:
  2066.       begin
  2067.         {Obtains the palette chunk}
  2068.         PaletteChunk := Owner.Chunks.ItemFromClass(TChunkPLTE) as TChunkPLTE;
  2069.         {Looks for an entry with 0 transparency meaning that it is the}
  2070.         {full transparent entry}
  2071.         for i := 0 to Self.DataSize - 1 do
  2072.           if PaletteValues[i] = 0 then
  2073.             with PaletteChunk.GetPaletteItem(i) do
  2074.             begin
  2075.               Result := RGB(rgbRed, rgbGreen, rgbBlue);
  2076.               break
  2077.             end
  2078.       end {COLOR_PALETTE}
  2079.     end {case Header.ColorType};
  2080. end;
  2081. {Saving the chunk to a stream}
  2082. function TChunktRNS.SaveToStream(Stream: TStream): Boolean;
  2083. begin
  2084.   {Copy palette into data buffer}
  2085.   if DataSize <= 256 then
  2086.     CopyMemory(fData, @PaletteValues[0], DataSize);
  2087.   Result := inherited SaveToStream(Stream);
  2088. end;
  2089. {Assigns from another chunk}
  2090. procedure TChunktRNS.Assign(Source: TChunk);
  2091. begin
  2092.   CopyMemory(@PaletteValues[0], @TChunkTrns(Source).PaletteValues[0], 256);
  2093.   fBitTransparency := TChunkTrns(Source).fBitTransparency;
  2094.   inherited Assign(Source);
  2095. end;
  2096. {Loads the chunk from a stream}
  2097. function TChunktRNS.LoadFromStream(Stream: TStream; const ChunkName: TChunkName;
  2098.   Size: Integer): Boolean;
  2099. var
  2100.   i, Differ255: Integer;
  2101. begin
  2102.   {Let inherited load}
  2103.   Result := inherited LoadFromStream(Stream, ChunkName, Size);
  2104.   if not Result then Exit;
  2105.   {Make sure size is correct}
  2106.   if Size > 256 then Owner.RaiseError(EPNGInvalidPalette,
  2107.     EPNGInvalidPaletteText);
  2108.   {The unset items should have value 255}
  2109.   Fillchar(PaletteValues[0], 256, 255);
  2110.   {Copy the other values}
  2111.   CopyMemory(@PaletteValues[0], fData, Size);
  2112.   {Create the mask if needed}
  2113.   case Header.ColorType of
  2114.     {Mask for grayscale and RGB}
  2115.     COLOR_RGB, COLOR_GRAYSCALE: fBitTransparency := True;
  2116.     COLOR_PALETTE:
  2117.     begin
  2118.       Differ255 := 0; {Count the entries with a value different from 255}
  2119.       {Tests if it uses bit transparency}
  2120.       for i := 0 to Size - 1 do
  2121.         if PaletteValues[i] <> 255 then inc(Differ255);
  2122.       {If it has one value different from 255 it is a bit transparency}
  2123.       fBitTransparency := (Differ255 = 1);
  2124.     end {COLOR_PALETTE}
  2125.   end {case Header.ColorType};
  2126. end;
  2127. {Prepares the image palette}
  2128. procedure TChunkIDAT.PreparePalette;
  2129. var
  2130.   Entries: Word;
  2131.   j      : Integer;
  2132. begin
  2133.   {In case the image uses grayscale, build a grayscale palette}
  2134.   with Header do
  2135.     if (ColorType = COLOR_GRAYSCALE) or (ColorType = COLOR_GRAYSCALEALPHA) then
  2136.     begin
  2137.       {Calculate total number of palette entries}
  2138.       Entries := (1 shl Byte(BitmapInfo.bmiHeader.biBitCount));
  2139.       FOR j := 0 TO Entries - 1 DO
  2140.         with BitmapInfo.bmiColors[j] do
  2141.         begin
  2142.           {Calculate each palette entry}
  2143.           rgbRed := fOwner.GammaTable[MulDiv(j, 255, Entries - 1)];
  2144.           rgbGreen := rgbRed;
  2145.           rgbBlue := rgbRed;
  2146.         end {with BitmapInfo.bmiColors[j]}
  2147.     end {if ColorType = COLOR_GRAYSCALE..., with Header}
  2148. end;
  2149. {Reads from ZLIB}
  2150. function TChunkIDAT.IDATZlibRead(var ZLIBStream: TZStreamRec2;
  2151.   Buffer: Pointer; Count: Integer; var EndPos: Integer;
  2152.   var crcfile: Cardinal): Integer;
  2153. var
  2154.   ProcResult : Integer;
  2155.   IDATHeader : Array[0..3] of char;
  2156.   IDATCRC    : Cardinal;
  2157. begin
  2158.   {Uses internal record pointed by ZLIBStream to gather information}
  2159.   with ZLIBStream, ZLIBStream.zlib do
  2160.   begin
  2161.     {Set the buffer the zlib will read into}
  2162.     next_out := Buffer;
  2163.     avail_out := Count;
  2164.     {Decode until it reach the Count variable}
  2165.     while avail_out > 0 do
  2166.     begin
  2167.       {In case it needs more data and it's in the end of a IDAT chunk,}
  2168.       {it means that there are more IDAT chunks}
  2169.       if (fStream.Position = EndPos) and (avail_out > 0) and
  2170.         (avail_in = 0) then
  2171.       begin
  2172.         {End this chunk by reading and testing the crc value}
  2173.         fStream.Read(IDATCRC, 4);
  2174.         {$IFDEF CheckCRC}
  2175.           if crcfile xor $ffffffff <> Cardinal(ByteSwap(IDATCRC)) then
  2176.           begin
  2177.             Result := -1;
  2178.             Owner.RaiseError(EPNGInvalidCRC, EPNGInvalidCRCText);
  2179.             exit;
  2180.           end;
  2181.         {$ENDIF}
  2182.         {Start reading the next chunk}
  2183.         fStream.Read(EndPos, 4);        {Reads next chunk size}
  2184.         fStream.Read(IDATHeader[0], 4); {Next chunk header}
  2185.         {It must be a IDAT chunk since image data is required and PNG}
  2186.         {specification says that multiple IDAT chunks must be consecutive}
  2187.         if IDATHeader <> 'IDAT' then
  2188.         begin
  2189.           Owner.RaiseError(EPNGMissingMultipleIDAT, EPNGMissingMultipleIDATText);
  2190.           result := -1;
  2191.           exit;
  2192.         end;
  2193.         {Calculate chunk name part of the crc}
  2194.         {$IFDEF CheckCRC}
  2195.           crcfile := update_crc($ffffffff, @IDATHeader[0], 4);
  2196.         {$ENDIF}
  2197.         EndPos := fStream.Position + ByteSwap(EndPos);
  2198.       end;
  2199.       {In case it needs compressed data to read from}
  2200.       if avail_in = 0 then
  2201.       begin
  2202.         {In case it's trying to read more than it is avaliable}
  2203.         if fStream.Position + ZLIBAllocate > EndPos then
  2204.           avail_in := fStream.Read(Data^, EndPos - fStream.Position)
  2205.          else
  2206.           avail_in := fStream.Read(Data^, ZLIBAllocate);
  2207.         {Update crc}
  2208.         {$IFDEF CheckCRC}
  2209.           crcfile := update_crc(crcfile, Data, avail_in);
  2210.         {$ENDIF}
  2211.         {In case there is no more compressed data to read from}
  2212.         if avail_in = 0 then
  2213.         begin
  2214.           Result := Count - avail_out;
  2215.           Exit;
  2216.         end;
  2217.         {Set next buffer to read and record current position}
  2218.         next_in := Data;
  2219.       end {if avail_in = 0};
  2220.       ProcResult := inflate(zlib, 0);
  2221.       {In case the result was not sucessfull}
  2222.       if (ProcResult < 0) then
  2223.       begin
  2224.         Result := -1;
  2225.         Owner.RaiseError(EPNGZLIBError,
  2226.           EPNGZLIBErrorText + zliberrors[procresult]);
  2227.         exit;
  2228.       end;
  2229.     end {while avail_out > 0};
  2230.   end {with};
  2231.   {If everything gone ok, it returns the count bytes}
  2232.   Result := Count;
  2233. end;
  2234. {TChunkIDAT implementation}
  2235. const
  2236.   {Adam 7 interlacing values}
  2237.   RowStart: array[0..6] of Integer = (0, 0, 4, 0, 2, 0, 1);
  2238.   ColumnStart: array[0..6] of Integer = (0, 4, 0, 2, 0, 1, 0);
  2239.   RowIncrement: array[0..6] of Integer = (8, 8, 8, 4, 4, 2, 2);
  2240.   ColumnIncrement: array[0..6] of Integer = (8, 8, 4, 4, 2, 2, 1);
  2241. {Copy interlaced images with 1 byte for R, G, B}
  2242. procedure TChunkIDAT.CopyInterlacedRGB8(const Pass: Byte;
  2243.   Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2244. var
  2245.   Col: Integer;
  2246. begin
  2247.   {Get first column and enter in loop}
  2248.   Col := ColumnStart[Pass];
  2249.   Dest := pChar(Longint(Dest) + Col * 3);
  2250.   repeat
  2251.     {Copy this row}
  2252.     Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 2)^]; inc(Dest);
  2253.     Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src) + 1)^]; inc(Dest);
  2254.     Byte(Dest^) := fOwner.GammaTable[pByte(Longint(Src)    )^]; inc(Dest);
  2255.     {Move to next column}
  2256.     inc(Src, 3);
  2257.     inc(Dest, ColumnIncrement[Pass] * 3 - 3);
  2258.     inc(Col, ColumnIncrement[Pass]);
  2259.   until Col >= ImageWidth;
  2260. end;
  2261. {Copy interlaced images with 2 bytes for R, G, B}
  2262. procedure TChunkIDAT.CopyInterlacedRGB16(const Pass: Byte;
  2263.   Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2264. var
  2265.   Col: Integer;
  2266. begin
  2267.   {Get first column and enter in loop}
  2268.   Col := ColumnStart[Pass];
  2269.   Dest := pChar(Longint(Dest) + Col * 3);
  2270.   repeat
  2271.     {Copy this row}
  2272.     Byte(Dest^) := Owner.GammaTable[pByte(Longint(Src) + 4)^]; inc(Dest);
  2273.     Byte(Dest^) := Owner.GammaTable[pByte(Longint(Src) + 2)^]; inc(Dest);
  2274.     Byte(Dest^) := Owner.GammaTable[pByte(Longint(Src)    )^]; inc(Dest);
  2275.     {$IFDEF Store16bits}
  2276.     {Copy extra pixel values}
  2277.     Byte(Extra^) := fOwner.GammaTable[pByte(Longint(Src) + 5)^]; inc(Extra);
  2278.     Byte(Extra^) := fOwner.GammaTable[pByte(Longint(Src) + 3)^]; inc(Extra);
  2279.     Byte(Extra^) := fOwner.GammaTable[pByte(Longint(Src) + 1)^]; inc(Extra);
  2280.     {$ENDIF}
  2281.     {Move to next column}
  2282.     inc(Src, 6);
  2283.     inc(Dest, ColumnIncrement[Pass] * 3 - 3);
  2284.     inc(Col, ColumnIncrement[Pass]);
  2285.   until Col >= ImageWidth;
  2286. end;
  2287. {Copy 韒ages with palette using bit depths 1, 4 or 8}
  2288. procedure TChunkIDAT.CopyInterlacedPalette148(const Pass: Byte;
  2289.   Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2290. const
  2291.   BitTable: Array[1..8] of Integer = ($1, $3, 0, $F, 0, 0, 0, $FF);
  2292.   StartBit: Array[1..8] of Integer = (7 , 0 , 0, 4,  0, 0, 0, 0);
  2293. var
  2294.   CurBit, Col: Integer;
  2295.   Dest2: PChar;
  2296. begin
  2297.   {Get first column and enter in loop}
  2298.   Col := ColumnStart[Pass];
  2299.   repeat
  2300.     {Copy data}
  2301.     CurBit := StartBit[Header.BitDepth];
  2302.     repeat
  2303.       {Adjust pointer to pixel byte bounds}
  2304.       Dest2 := pChar(Longint(Dest) + (Header.BitDepth * Col) div 8);
  2305.       {Copy data}
  2306.       Byte(Dest2^) := Byte(Dest2^) or
  2307.         ( ((Byte(Src^) shr CurBit) and BitTable[Header.BitDepth])
  2308.           shl (StartBit[Header.BitDepth] - (Col * Header.BitDepth mod 8)));
  2309.       {Move to next column}
  2310.       inc(Col, ColumnIncrement[Pass]);
  2311.       {Will read next bits}
  2312.       dec(CurBit, Header.BitDepth);
  2313.     until CurBit < 0;
  2314.     {Move to next byte in source}
  2315.     inc(Src);
  2316.   until Col >= ImageWidth;
  2317. end;
  2318. {Copy 韒ages with palette using bit depth 2}
  2319. procedure TChunkIDAT.CopyInterlacedPalette2(const Pass: Byte; Src, Dest,
  2320.   Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2321. var
  2322.   CurBit, Col: Integer;
  2323.   Dest2: PChar;
  2324. begin
  2325.   {Get first column and enter in loop}
  2326.   Col := ColumnStart[Pass];
  2327.   repeat
  2328.     {Copy data}
  2329.     CurBit := 6;
  2330.     repeat
  2331.       {Adjust pointer to pixel byte bounds}
  2332.       Dest2 := pChar(Longint(Dest) + Col div 2);
  2333.       {Copy data}
  2334.       Byte(Dest2^) := Byte(Dest2^) or (((Byte(Src^) shr CurBit) and $3)
  2335.          shl (4 - (4 * Col) mod 8));
  2336.       {Move to next column}
  2337.       inc(Col, ColumnIncrement[Pass]);
  2338.       {Will read next bits}
  2339.       dec(CurBit, 2);
  2340.     until CurBit < 0;
  2341.     {Move to next byte in source}
  2342.     inc(Src);
  2343.   until Col >= ImageWidth;
  2344. end;
  2345. {Copy 韒ages with grayscale using bit depth 2}
  2346. procedure TChunkIDAT.CopyInterlacedGray2(const Pass: Byte;
  2347.   Src, Dest, Trans{$IFDEF Store16bits}, Extra{$ENDIF}: pChar);
  2348. var
  2349.   CurBit, Col: Integer;
  2350.   Dest2: PChar;
  2351. begin
  2352.   {Get first column and enter in loop}
  2353.   Col := ColumnStart[Pass];
  2354.   repeat
  2355.     {Copy data}
  2356.     CurBit := 6;
  2357.     repeat
  2358.       {Adjust pointer to pixel byte bounds}