How to set tEXT chunk in PNG files?

Oct 13, 2014 at 6:46 PM
For a project I'm working on, I'm using Magick.NET to save PNG files that are smaller than what the default .NET encoder will save. One of the requirements is that I need to be able to set a few different tEXT comments in PNG files when I save the files. I found the MagickImage.Comment property, but that sets a tEXT chunk with Key = "Comment" and value equal to what I set in MagickImage.Comment.

Is there any way to set multiple such tEXT chunks, each with a different key name and value?

Also, after I've done that, is there any way to read this info back using Magick.NET? Well, in the worst case, I think I can read the info using the .NET PNG decoder, but I still need a way to write that info to the PNG file.
Coordinator
Oct 13, 2014 at 7:04 PM
You can add tEXT chunks with the SetAttribute method of MagickImage:
using (MagickImage input = new MagickImage("logo:"))
{
  input.SetAttribute("Magick.NET", "Rules");

  using (MemoryStream memStream = new MemoryStream())
  {
    input.Write(memStream, MagickFormat.Png);
    memStream.Position = 0;

    using (MagickImage output = new MagickImage(memStream))
    {
      string rules = output.GetAttribute("Magick.NET");
      Console.WriteLine(rules);
    }
  }
}
Oct 13, 2014 at 8:31 PM
Edited Oct 13, 2014 at 10:27 PM
dlemstra, thanks for the info. I tried it, and it mostly worked. However, I notice that longer text gets saved as zTXT chunks instead of regular tEXT chunks. It turns out this won't work with some legacy code in another project. The other project uses .NET's bitmap.GetPropertyItem to read the metadata, and the ones encoded as zTXT don't get read.

Do you know if there's any way to force the data to be tEXT instead of zTXT? Also, how do I write a tIME chunk?

Thanks for your help!
Coordinator
Oct 14, 2014 at 5:02 AM
Edited Oct 14, 2014 at 11:34 AM
According to the code of the png coder you should be able to do this (I have not tested it):
input.SetDefine(MagickFormat.Png, "exclude-chunk", "text");
I also found a todo about reading the tIME chunck. At this moment there is not support for it but I might be able to add support for it in the next release of Magick.NET. Why do you need to set a tIME chunk and are you aware you can only set one?
Oct 14, 2014 at 9:39 PM
The tIME chunk is for another legacy purpose: we have users who have been using this as the creation date/time, so we need to support it. Unfortunately, the bigger problem right now is speed: although the compression ratio is much better than the standard .NET PNG encoder, the speed is nowhere near what we need (something on the order of 0.7sec to save each PNG file, where the .NET encoder seems to be almost instant). Sigh. I was hoping this would be the easy answer to better compression for my project.
Coordinator
Oct 16, 2014 at 8:21 PM
Do you want to set the tIME chunk or do you just want to read it? There could be a couple of reasons why Magick.NET is slower then the .NET encoder. Magick.NET will always decode the pixels of an image I am not sure if the .NET encoder also does this. And as you noticed the compression is much better. You can control this with the -quality property of the image. Using another value might be quicker. I found the following detailed explanation in the code:
Untangle the "-quality" setting:

Undefined is 0; the default is used.
Default is 75

10's digit:

   0 or omitted: Use Z_HUFFMAN_ONLY strategy with the
      zlib default compression level

   1-9: the zlib compression level

1's digit:

   0-4: the PNG filter method

   5:   libpng adaptive filtering if compression level > 5
         libpng filter type "none" if compression level <= 5
            or if image is grayscale or palette

   6:   libpng adaptive filtering

   7:   "LOCO" filtering (intrapixel differing) if writing
         a MNG, otherwise "none".  Did not work in IM-6.7.0-9
         and earlier because of a missing "else".

   8:   Z_RLE strategy (or Z_HUFFMAN_ONLY if quality < 10), adaptive
         filtering. Unused prior to IM-6.7.0-10, was same as 6

   9:   Z_RLE strategy (or Z_HUFFMAN_ONLY if quality < 10), no PNG filters
         Unused prior to IM-6.7.0-10, was same as 6

Note that using the -quality option, not all combinations of
PNG filter type, zlib compression level, and zlib compression
strategy are possible.  This will be addressed soon in a
release that accomodates "-define png:compression-strategy", etc.