Writing metadata in both jpg and png

I need to add a metadata tag (description) to the uploaded images.

I found this answer: https://stackoverflow.com/a/318216/2/ which is great for JPG files, but not PNG.

private string Tag = "test meta data"; private static Stream TagImage(Stream input, string type) { bool isJpg = type.EndsWith("jpg", StringComparison.InvariantCultureIgnoreCase) || type.EndsWith("jpeg", StringComparison.InvariantCultureIgnoreCase); bool isPng = type.EndsWith("png", StringComparison.InvariantCultureIgnoreCase); BitmapDecoder decoder = null; if (isJpg) { decoder = new JpegBitmapDecoder(input, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad); } else if (isPng) { decoder = new PngBitmapDecoder(input, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad); } else { return input; } // modify the metadata BitmapFrame bitmapFrame = decoder.Frames[0]; BitmapMetadata metaData = (BitmapMetadata)bitmapFrame.Metadata.Clone(); metaData.Subject = Tag; metaData.Comment = Tag; metaData.Title = Tag; // get an encoder to create a new jpg file with the new metadata. BitmapEncoder encoder = null; if (isJpg) { encoder = new JpegBitmapEncoder(); } else if (isPng) { encoder = new PngBitmapEncoder(); } encoder.Frames.Add(BitmapFrame.Create(bitmapFrame, bitmapFrame.Thumbnail, metaData, bitmapFrame.ColorContexts)); // Save the new image Stream output = new MemoryStream(); encoder.Save(output); output.Seek(0, SeekOrigin.Begin); return output; } 

It works fine when I load jpg, but with png in the metaData.Subject = Tag it throws a System.NotSupportedException (this codec does not support the specified property).

Update

It seems I need to use another method based on the image format:

 if (isJpg) { metaData.SetQuery("/app1/ifd/exif:{uint=270}", Tag); } else { metaData.SetQuery("/tEXt/{str=Description}", Tag); } 

Based on requests for available formats, the former should work for both formats. The second one does not work either (it creates metadata in the image, but does not save its value).

If I try to use the first method ( /app1/ifd/exif ) for PNG, in the encoder.Save line I get an exception that is not supported, "not suitable for image processing component".

+6
source share
2 answers

I solved this using the pngcs library (you need to rename the loaded dll to "pngcs.dll")

Here's how I implemented it:

  using Hjg.Pngcs; // https://code.google.com/p/pngcs/ using Hjg.Pngcs.Chunks; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MarkerGenerator.Utils { class PngUtils { public string getMetadata(string file, string key) { PngReader pngr = FileHelper.CreatePngReader(file); //pngr.MaxTotalBytesRead = 1024 * 1024 * 1024L * 3; // 3Gb! //pngr.ReadSkippingAllRows(); string data = pngr.GetMetadata().GetTxtForKey(key); pngr.End(); return data; ; } public static void addMetadata(String origFilename, Dictionary<string, string> data) { String destFilename = "tmp.png"; PngReader pngr = FileHelper.CreatePngReader(origFilename); // or you can use the constructor PngWriter pngw = FileHelper.CreatePngWriter(destFilename, pngr.ImgInfo, true); // idem //Console.WriteLine(pngr.ToString()); // just information int chunkBehav = ChunkCopyBehaviour.COPY_ALL_SAFE; // tell to copy all 'safe' chunks pngw.CopyChunksFirst(pngr, chunkBehav); // copy some metadata from reader foreach (string key in data.Keys) { PngChunk chunk = pngw.GetMetadata().SetText(key, data[key]); chunk.Priority = true; } int channels = pngr.ImgInfo.Channels; if (channels < 3) throw new Exception("This example works only with RGB/RGBA images"); for (int row = 0; row < pngr.ImgInfo.Rows; row++) { ImageLine l1 = pngr.ReadRowInt(row); // format: RGBRGB... or RGBARGBA... pngw.WriteRow(l1, row); } pngw.CopyChunksLast(pngr, chunkBehav); // metadata after the image pixels? can happen pngw.End(); // dont forget this pngr.End(); File.Delete(origFilename); File.Move(destFilename, origFilename); } public static void addMetadata(String origFilename,string key,string value) { Dictionary<string, string> data = new Dictionary<string, string>(); data.Add(key, value); addMetadata(origFilename, data); } } } 
+2
source

PNG format does not support metadata :(

But XMP , which can help with JPEG conversion, with EXIF ​​metadata and PNG.

-2
source

Source: https://habr.com/ru/post/983757/


All Articles