This project is read-only.

Any suggestion about ExtendedImage.Properties?

Oct 29, 2012 at 12:46 PM

[PNG encoder]

I found no handling about ExtendedImage.Properties in the Encode method.

And I'm confused about the W3C article (http://www.w3.org/TR/2003/REC-PNG-20031110/#11textinfo).

So can anyone give me an example how to process the  ExtendedImage.Properties in the Encode method?

 

Thank you very much!

Jerin

Nov 30, 2012 at 4:17 AM

My scenario is: add some international text to png with custom key.

I got a temporary solution -- only support png + ignore ExtendedImage.Properties:

0. append iTxt  to PngChunkTypes.

1. add a new property to ExtendedImage, e.g. Dictionary<string, string> SemanticProperties

2. generate a LatinEncoding( iso-8859-1 ) by http://www.hardcodet.net/2010/03/silverlight-text-encoding-class-generator

3.  reference of processing png's itxt metadata:

a. http://code.google.com/p/pngcs/

b.  http://www.w3.org/TR/2003/REC-PNG-20031110/#11textinfo

4. add 2 methods to PngEncoder class.

    /// <summary>
    /// write text to png as meta data.
    /// Jerin.2012.11.28
    /// </summary>
    private void WriteSemanticProperties() {
      if ( _image.SemanticProperties == null || _image.SemanticProperties.Count == 0 )
        return;
      MemoryStream memory = new MemoryStream();
      foreach ( var kvp in _image.SemanticProperties ) {
        if ( string.IsNullOrWhiteSpace( kvp.Key ) )
          continue;
        WriteITxtChunk( memory, kvp.Key, kvp.Value, "semantic info", "zh-cn" );
      }
    }

    /// <summary>
    /// Ref: Hjg.Pngcs, http://www.w3.org/TR/PNG/#11iTXt
    /// </summary>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <param name="translatedTag"></param>
    /// <param name="language"></param>
    private void WriteITxtChunk( MemoryStream memory, string key, string value, string translatedTag, string language ) {
      memory.SetLength( 0 );
      memory.Position = 0;

      // iTxt keyword
      var keyBytes = charsetLatin1.GetBytes( key );
      memory.Write( keyBytes, 0, keyBytes.Length );
      // separator
      memory.WriteByte( 0 );
      //_stream.WriteByte( compressed ? (byte)1 : (byte)0 ); -- always not compressed
      memory.WriteByte( 0 );
      // compression method (always 0)
      memory.WriteByte( 0 );
      // language tag
      var langBytes = charsetLatin1.GetBytes( language );
      memory.Write( langBytes, 0, langBytes.Length );
      // separator
      memory.WriteByte( 0 );
      // translatedTag
      var ttagBytes = charsetUtf8.GetBytes( translatedTag );
      memory.Write( ttagBytes, 0, ttagBytes.Length );
      // separator
      memory.WriteByte( 0 );
      // value
      byte[] textValueBytes = charsetUtf8.GetBytes( value );
      //if ( compressed ) {
      //  textbytes = ChunkHelper.compressBytes( textValueBytes, true );
      //}
      memory.Write( textValueBytes, 0, textValueBytes.Length );

      byte[] contentBytes = memory.ToArray();
      int length = contentBytes.Length;

      /////////////////////////////////////////////////////////
      // write length
      WriteInteger( _stream, length );

      string type = PngChunkTypes.iTxt;

      byte[] typeArray = new byte[4];
      typeArray[0] = (byte)type[0];
      typeArray[1] = (byte)type[1];
      typeArray[2] = (byte)type[2];
      typeArray[3] = (byte)type[3];
      // write iTxt tag
      _stream.Write( typeArray, 0, 4 );
      
      // write content
      if ( length > 0 )
        _stream.Write( contentBytes, 0, length );

      // write crc
      //Crc32 crc32 = new Crc32();
      ZipLib.Crc32 crc32 = new ZipLib.Crc32();
      crc32.Update( typeArray );
      if ( contentBytes != null ) {
        crc32.Update( contentBytes, 0, length );
      }
      WriteInteger( _stream, (uint)crc32.Value );
    }