Einzelnen Beitrag anzeigen

Cosmin

Registriert seit: 19. Mär 2016
5 Beiträge
 
#1

extract frames from png animations

  Alt 19. Mär 2016, 15:29
Hi.

Sorry in advance for using english language.

Delphi version: XE8 update 1
OS: Windows 8.1 x64

I'm trying to build a code for extracting png frames from apng (png animation) files (preferably in a memory stream).
I found some examples on internet, but none in Delphi/Pascal language. Plus they weren't very well commented.

What I tried so far:

Delphi-Quellcode:
const
   PNG_SIG: array[0..7] of byte = ($89, $50, $4E, $47, $0D, $0A, $1A, $0A);
var
   i, j, n, nFrames, nrz, PrevPos: Integer;
   crc: Cardinal;
   png: TPngImage;
   // pngFrames: array of TPngImage;
   msHeader, msFooter, msOutput: TMemoryStream;
   strTemp: string;
begin
   png := Tpngimage.Create;
   msOutput := TMemoryStream.Create;
   png.LoadFromFile('test.png');
   msHeader := TMemoryStream.Create;
   msHeader.SetSize(Cardinal(Length(PNG_SIG)));
   msHeader.Position := 0;
   msHeader.WriteBuffer(PNG_SIG[0], Length(PNG_SIG));
   msHeader.Position := msHeader.Size;
   png.Header.SaveToStream(msHeader);
   msFooter := TMemoryStream.Create;
   i := png.Chunks.Count - 1;
   while i >= 0 do
   begin
      if png.Chunks.Item[i].Name = 'IENDthen
         Break;
      Dec(i);
   end;
   if i > 0 then
      png.Chunks.Item[i].SaveToStream(msFooter);
   nFrames := 0;
   for i := 0 to png.Chunks.Count - 1 do
      if png.Chunks.Item[i].Name = 'fcTLthen
         Inc(nFrames);
   n := 0;
   for i := 0 to png.Chunks.Count - 1 do
   begin
      // ShowMessage(string(png.Chunks.Item[i].Name) + #13 + IntToStr(png.Chunks.Item[i].Index) + #13 + IntToStr(png.Chunks.Item[i].DataSize));
      if png.Chunks.Item[i].Name = 'IDATthen
      begin
         msOutput.Position := msOutput.Size;
         png.Chunks.Item[i].SaveToStream(msOutput);
      end
      else if png.Chunks.Item[i].Name = 'fdATthen
      begin
         msOutput.Position := msOutput.Size;
         PrevPos := msOutput.Position;
         png.Chunks.Item[i].SaveToStream(msOutput);
         msOutput.Position := PrevPos + 4;
         msOutput.WriteBuffer(AnsiString('ID')[1], 2);
      end
      else if png.Chunks.Item[i].Name = 'fcTLthen
      begin
         if n > 0 then
         begin
            msOutput.Position := msOutput.Size;
            msFooter.Position := 0;
            msOutput.CopyFrom(msFooter, msFooter.Size);
            nrz := Length(IntToStr(nFrames)) - Length(IntToStr(n));
            strTemp := '';
            for j := 1 to nrZ do
               strTemp := strTemp + '0';
            msOutput.SaveToFile('Frames\Frame' + strTemp + IntToStr(n) + '.png');
         end;
         Inc(n);
         msOutput.Clear;
         msHeader.Position := 0;
         msOutput.LoadFromStream(msHeader);
      end;
   end;
   if n > 0 then
   begin
      msOutput.Position := msOutput.Size;
      msFooter.Position := 0;
      msOutput.CopyFrom(msFooter, msFooter.Size);
      nrz := Length(IntToStr(nFrames)) - Length(IntToStr(n));
      strTemp := '';
      for j := 1 to nrZ do
         strTemp := strTemp + '0';
      msOutput.SaveToFile('Frame' + strTemp + IntToStr(n) + '.png');
   end;
end;
I get only the first frame (well, only 281 KB from 309 KB, but you can view it), the others are only 60..70KB (from 300K+).
I'm guessing some fdAT pieces are shared between them and the first frame (IDAT), but I can't find the information on how to assemble them.

The code has to work with any png animation, not just this one.

Could you please help me?
It's very important for me.

Thank you.
  Mit Zitat antworten Zitat