2015-03-13 29 views
6

Yüklenen görüntülere bir meta veri etiketi (açıklama) eklemem gerekiyor.Hem jpg hem de png için meta verileri yaz

Bu yanıtı şu buldu: JPG dosyaları için harika, ancak PNG için uygun olmayan https://stackoverflow.com/a/1764913/6776.

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; 
} 

Bir jpg yüklediğinizde O inşaat büyük, ancak bir png ile metaData.Subject = Tag çizgisinde, bir System.NotSupportedException atar (bu codec'i belirtilen özelliği desteklemez).

Güncelleme Ben görüntü formatına dayalı farklı bir yöntem kullanmak zorunda görünüyor

:

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

the available formats' queries dayanarak ilk iki biçim için çalışmalıdır. İkincisi de gerçekten işe yaramıyor (görüntüdeki meta verileri yaratıyor ama değerini kaydetmiyor).

PNG için ilk yöntemi (/app1/ifd/exif) kullanmaya çalışırsam, encoder.Save satırında "destekleyici bileşen uygun değil" destekli bir istisna kabul ediyorum.

+0

alakalı değil, ama Sanırım isJpg = ifadesinde bir hata var. ".jpg" veya ".jpeg" için test etmek istediğinizi varsayalım, ancak ".jpg" yi iki kez test ettiniz. – RenniePet

+0

Evet, o zamandan beri kodda düzeltildi, ancak soruda değil. Teşekkürler! – thomasb

cevap

-1

PNG biçiminde desteklemiyor meta :(

Ama XMP yapar, EXIF-meta veri ile, JPEG arasında dönüştürme ve PNG zaman yardımcı olabilir.

+0

Vikipedi'de [Taşınabilir Ağ Grafikleri] (https://en.wikipedia.org/wiki/Portable_Network_Graphics#Ancillary_chunks) konusuna göre, PNG Meta Veri saklayabilir. Bu yüzden neden imkansız olduğunu düşündüğünüzden emin değilim. –

+1

Bunun nedeni PngBitmapEncoder'ın Metadata üyesinin ayarlanamaz olduğundan şüpheleniyorum. Özellikle 'encoder.Metadata = yeni BitmapMetadata (" png ");' bir istisna oluşturur "Belirtilen BitmapEncoder global meta verileri desteklemez." – Eponymous

2

Ben pngcs kitaplığı kullanarak çözüldü bunu hayata nasıl

İşte

ise (siz "pngcs.dll" indirilen dll adlandırmak gerekir): sorunuza

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); 
     } 


    } 
} 
İlgili konular