Wednesday 17 August 2011

Improved PNG and ZIP merging

Following on from my post on displaying a zip as a png, I wanted to do a more robust job, to have the zip file properly enclosed as a non-critical png ancillary stream and to maybe even to have the png included as non-compressed member of the zip archive. ouch!

My main reason for doing this is compatibility reasons as I hear that windows zip-explorer cannot easily open zip files appended to a png.


Reading the PNG file standard I find that I should probably use the chunk type: ziPS making it a ancillary, private and unsafe to copy if the PNG is changed.

As the zip file must be at the end of the PNG it must be the last data stream in the PNG, however ancillary chunks are not allowed to have ordering restrictions, and IEND should be the last chunk.

Making the chunk unsafe to copy reduces the chances that a png editor could place the chunk in another position, however 14.2 c states A PNG editor is always allowed to copy all unrecognized ancillary chunks if it has only added, deleted, modified, or reordered ancillary chunks. This implies that it is not permissible for ancillary chunks to depend on other ancillary chunks.

Of course we are not attempting to preserve the zip in any major way if the png is edited, only to stop any zip stream being preserved in a way that prevents it being used.


The resource for the zip format was wikipedia ZIP_(file_format) where I learn the the final part of the zip central directory is a 2 byte comment length and then a comment.

This tells me that the IEND image trailer could be the last 4 bytes of the comment... but it would mean that the ziPS chunk of the png would not include the entire zip file, as the last 4 bytes of the comment would be external to the zip file.

It means that a zip file which was formally extracted from the png would be incomplete and not recognisable.

I can accept this as the ziPS chunk is not intended to be formally extracted by png-aware software, we only enclose it as a png chunk so that it may be preserved in... er... circumstances where anything after IEND might be removed.


I hear that some zip programs fail to work against zip archives that have been appended to a png. This is an error on the part of such zip programs, which seem to presume that the first item of the zip file is a zip File Entry.

Wikipedia ZIP_(file_format) states:
Often the first thing in a ZIP file is a ZIP entry, which can be identified easily by its signature. But it is not necessarily the case that a ZIP file begins with a ZIP entry, and is not required by the ZIP specification.
We cannot accommodate such demanding ZIP programs, as the ZIP entry signature is:

ZIP local file header
Offset Bytes Description[5]
0 4 Local file header signature = 0x04034b50 (read as a little-endian number)
4 2 Version needed to extract (minimum)
6 2 General purpose bit flag

and the first eight bytes of a PNG datastream always contain the following (decimal) values:  137 80 78 71 13 10 26 10


The method then seems to be:
  1. Modify the zip file, by adding 13 bytes to the zip comment
    1. a NULL to sort-of terminate any existing comment to try and hide IEND which we add
    2. 12 bytes of IEND
  2. Parse the PNG to find IEND
    (Probably the last 12 bytes of the file)
  3. replace with the crafted zip file
As this won't solve the compatibility problem, I don't feel inclined to write the necessary code unless it becomes important to stop streams after IEND from being removed by png uploaders, if you know what I mean. (An ancillary stream or critical stream in a png is part of the png. A stream after the IEND is not part of the png).

    1 comment: