TPNGImage help

TPNGImage

Example 2: Creating a new TChunk descendent


One of the powerful features from the component is the support to additional TChunk descendents. To do so, you have to create a new class descendent from TChunk. To read the data, there are two ways: if the chunk contains large amounts of data, override LoadFromStream and read data, crc and check if the crc is valid. If the data is not too large you might use the content from Data and DataSize property.

To save it, either override SaveToStream and write data manually, override SaveToStream, modify data property and call inherited SaveToStream. Also there other ways as modifying the data property directly when the user reads/writes a property.
Other important method to override is the Assign method to copy the chunk custom properties.

The essencial part is to register the chunk using RegisterChunk(ChunkClass: TChunkClass) from pngimage.pas.

The chunk bellow reads a text and shows a message box using the text.


type
 
TChunkcUSt = class(TChunk)
  private
   
fText: String;
  public
    function
SaveToStream(Stream: TStream): Boolean; override;
    function
LoadFromStream(Stream: TStream; const
      ChunkName: TChunkName; Size: Integer): Boolean; override;
    procedure
Assign(Source: TChunk); override;
    property
Text: String read fText write fText;
  end;

implementation

 
{Saving chunk to a stream}
function TChunkcUSt.SaveToStream(Stream: TStream): Boolean;
var
  ChunkLength, ChunkCRC: Cardinal;
begin
  {ChunkLength must be in network order}
  ChunkLength := ByteSwap(Length(fText));
  Stream.Write(ChunkLength, 4);
  {Writes chunk name}
  Stream.Write(fName[0], 4);
  ChunkCRC := update_crc($ffffffff, @fName[0], 4);
  {Writes data and finishes calculating crc}
  Stream.Write(fText[1], Length(fText));
  ChunkCRC := Byteswap(update_crc(ChunkCRC, @fText[1],
    Length(fText)) xor $ffffffff);
  {Writes crc}
  Stream.Write(ChunkCRC, 4);
  Result := TRUE;
end;

{Loading chunk from a stream}
function TChunkcUSt.LoadFromStream(Stream: TStream;
  const
ChunkName: TChunkName; Size: Integer): Boolean;
var
  ReadCRC, ChunkCRC: Cardinal;
begin
  {Prepares text to hold}
  SetLength(fText, Size);
  {Reads data}
  Stream.Read(fText[1], Size);
  {Calculates crc for data readed}
  ChunkCRC := update_crc($ffffffff, @ChunkName[0], 4);
  ChunkCRC := Byteswap(update_crc(ChunkCRC, @fText[1],
    Size) xor $ffffffff);
  {Reads crc and verify}
  Stream.Read(ReadCRC, 4);

  {Check if crc is valid}
  Result := (ReadCRC = ChunkCRC);
  if not Result then
    Owner.LoadError(EPngInvalidCRC,
      EPngInvalidCRCText)
  {If it's valid, show text using a message box}
  else ShowMessage(fText);
end;

{Assigns contents from another chunk}
procedure TChunkcUSt.Assign(Source: TChunk);
begin
 
fText := TChunkcUSt(Source.fText);
end;

initialization
 
RegisterChunk(TChunkcUSt);
finalization