0

I am trying to port libpng/apng to Android platform, using libpng with apng patch to read animated png file.

My question is that I didn't find any 'skip' method declared in png.h. What I want to do is like to directly jump to a specific frame. But I cannot get a correct result unless I read from the beginning and perform png_read_frame_head() and png_read_image() for every frame ahead.

Is there any way that can jump to a specific frame by specifying the index without read all the frame info/data ahead?

The following code is from apng sample http://littlesvr.ca/apng/tutorial/x57.html You can see it reads the apng file in a loop. And it seems that you have to call png_read_frame_head() and png_read_image() in order to make the internal information in the png_ptr_read and info_ptr_read updated. So, if there is any way to simply modify these two struct to correct information prepared for reading a specific frame, my question is solved.

for(count = 0; count < png_get_num_frames(png_ptr_read, info_ptr_read); count++)
{
    sprintf(filename, "extracted-%02d.png", count);
    newImage = fopen(filename, "wb");
    if(newImage == NULL)
        fatalError("couldn't create png for writing");

    writeSetup(newImage, &png_ptr_write, &info_ptr_write);
    if(setjmp(png_ptr_write->jmpbuf))
        fatalError("something didn't work, jump 2");

    png_read_frame_head(png_ptr_read, info_ptr_read);

    if(png_get_valid(png_ptr_read, info_ptr_read, PNG_INFO_fcTL))
    {
        png_get_next_frame_fcTL(png_ptr_read, info_ptr_read,
                                &next_frame_width, &next_frame_height,
                                &next_frame_x_offset, &next_frame_y_offset,
                                &next_frame_delay_num, &next_frame_delay_den,
                                &next_frame_dispose_op, &next_frame_blend_op);
    }
    else
    {
        /* the first frame doesn't have an fcTL so it's expected to be hidden, 
        * but we'll extract it anyway */
        next_frame_width = png_get_image_width(png_ptr_read, info_ptr_read);
        next_frame_height = png_get_image_height(png_ptr_read, info_ptr_read);
    }

    writeSetup2(png_ptr_read, info_ptr_read, png_ptr_write, info_ptr_write,
                next_frame_width, next_frame_height);

    png_write_info(png_ptr_write, info_ptr_write);

    png_read_image(png_ptr_read, rowPointers);

    png_write_image(png_ptr_write, rowPointers);

    png_write_end(png_ptr_write, NULL);

    png_destroy_write_struct(&png_ptr_write, &info_ptr_write);

    fclose(newImage);

    printf("extracted frame %d into %s\n", count, filename);
}
Robin
  • 10,052
  • 6
  • 31
  • 52

1 Answers1

3

You can't. libpng was designed to treat PNG data as a stream, so it decodes chunks sequentially, one by one. Not sure why you need to skip APNG frames. Just like in video formats, one frame might be stored as "what changed after previous frame", instead of full frame, so you might need previous frame(s) too.

These code examples might be useful: https://sourceforge.net/projects/apng/files/libpng/examples/

maxst
  • 226
  • 1
  • 1
  • 1
    Thanks for your answer, some APNG only use disposeOP=0 and blendOP=0, so it is safe to skip. And those APNG convert from video often belong to this category. I can up vote to your answer but cannot accept it technically. – Robin Jan 06 '15 at 08:41
  • 1
    Even with disposeOP=0 and blendOP=0, that frame (rectangle) dimensions might be smaller than full frame. You would need to read frame headers to be sure. But libpng doesn't provide the way to read frame headers out of order. If you want to do it the hard way, you can always process the PNG chunks on your own (without libpng) and just read acTL chunks ignoring everything else. Build an index, remux fdAT into IDAT, the whole thin could be complicated but it's doable. – maxst Jan 06 '15 at 17:50
  • Yes, I fully understand that approach. But no one wants to reinvent the wheels, right? – Robin Jan 07 '15 at 01:40
  • 1
    That wheel was already invented (MNG) but was rejected in favor of APNG because of the complexity of things like the MNG SEEK chunk. – Glenn Randers-Pehrson Jan 07 '15 at 15:59