InPlaceBitmapMetadataWriter.TrySave()返回true但不执行任何操作

在Windows 7中的一些.JPG文件(EPS预览,由Adobe Illustrator生成)InPlaceBitmapMetadataWriter.TrySave()在一些SetQuery()调用之后返回true,但什么都不做。

代码示例:

BitmapDecoder decoder; BitmapFrame frame; BitmapMetadata metadata; InPlaceBitmapMetadataWriter writer; decoder = BitmapDecoder.Create(s, BitmapCreateOptions.PreservePixelFormat | BitmapCreateOptions.IgnoreColorProfile, BitmapCacheOption.Default); frame = decoder.Frames[0]; metadata = frame.Metadata as BitmapMetadata; writer = frame.CreateInPlaceBitmapMetadataWriter(); try { writer.SetQuery("System.Title", title); writer.SetQuery(@"/app1/ifd/{ushort=" + exiftagids[0] + "} ", (title + '\0').ToCharArray()); writer.SetQuery(@"/app13/irb/8bimiptc/iptc/object name", title); return writer.TrySave(); } catch { return false; } 

图像样本

您可以通过下载图像示例并使用此代码示例在此图像上设置标题来重现问题(如果您有Windows 7)。 图像有足够的空间容纳元数据 – 这个代码示例在我的WinXP上运行良好。 相同的代码在Win7上与其他.JPG文件一起正常工作。

欢迎任何想法:)

两件事情:

  1. 我认为您不能像这样写入metadata变量,因为它将是Frozen。 所以,你必须克隆它:

     BitmapMetadata metadata = frame.Metadata.Clone()as BitmapMetadata;
    
  2. 填充,你需要填充。 经过大约一天的修补工作,试图制作一些代码(类似于你的代码)后,我发现了这一点。 如果图像文件中没有元数据填充,则InPlaceBitmapMetadataWriter将不起作用。 所以你需要这样的东西:

     JpegBitmapEncoder encoder = new JpegBitmapEncoder();
     if(frame!= null && metadata!= null){
         metadata.SetQuery(“/ app1 / ifd / PaddingSchema:Padding”,padding);
         encoder.Frames.Add(BitmapFrame.Create(frame,frame.Thumbnail,metadata,frame.ColorContexts));
        使用(Stream outputFile = File.Open(_myoutputpath,FileMode.Create,FileAccess.ReadWrite)){
             encoder.Save(OUTPUTFILE);
         }
     }
    

现在,您可以使用位于_myoutputpath的文件,该文件为InPlaceBitmapMetadataWriter操作添加了元数据填充。

本文和附加代码应该可以帮到你。

嗨,我发现这篇关于InPlaceBitmapMetadataWriter的文章,其中的人说TrySave()可能会破坏图像,这就是他建议在原始文件的副本上执行TrySave()的原因,如果这不起作用,请将填充添加到副本中原始文件和TrySave(再次),如果它工作,删除原始文件并重命名副本。

我挠了挠头问自己为什么我要打扰InPlaceBitmapMetadataWriter并将3x原始文件写入磁盘,以防TrySave()因为没有足够的填充而无效,如果我可以克隆元数据,将任何内容写入其中并组装jpeg马上归档。

然后我开始认为也许多亏了InPlaceBitmapMetadataWriter我可以编辑元数据而不会降低质量,但看起来它“只是”它可以帮助你在有足够的填充时更快地编写元数据。

我写了一个小测试,我多次压缩一个文件以查看质量下降,你可以在第三次压缩中看到它,这是非常糟糕的。

但幸运的是,如果您始终使用与JpegBitmapEncoder相同的QualityLevel,则不会降级。

在这个例子中,我在元数据中重写关键字100x,质量似乎没有改变。

 private void LosslessJpegTest() { var original = "d:\\!test\\TestInTest\\20150205_123011.jpg"; var copy = original; const BitmapCreateOptions createOptions = BitmapCreateOptions.PreservePixelFormat | BitmapCreateOptions.IgnoreColorProfile; for (int i = 0; i < 100; i++) { using (Stream originalFileStream = File.Open(copy, FileMode.Open, FileAccess.Read)) { BitmapDecoder decoder = BitmapDecoder.Create(originalFileStream, createOptions, BitmapCacheOption.None); if (decoder.CodecInfo == null || !decoder.CodecInfo.FileExtensions.Contains("jpg") || decoder.Frames[0] == null) continue; BitmapMetadata metadata = decoder.Frames[0].Metadata == null ? new BitmapMetadata("jpg") : decoder.Frames[0].Metadata.Clone() as BitmapMetadata; if (metadata == null) continue; var keywords = metadata.Keywords == null ? new List() : new List(metadata.Keywords); keywords.Add($"Keyword {i:000}"); metadata.Keywords = new ReadOnlyCollection(keywords); JpegBitmapEncoder encoder = new JpegBitmapEncoder {QualityLevel = 80}; encoder.Frames.Add(BitmapFrame.Create(decoder.Frames[0], decoder.Frames[0].Thumbnail, metadata, decoder.Frames[0].ColorContexts)); copy = original.Replace(".", $"_{i:000}."); using (Stream newFileStream = File.Open(copy, FileMode.Create, FileAccess.ReadWrite)) { encoder.Save(newFileStream); } } } } 

我仍然没有找到答案,并且必须为exiftool编写包装器而不是使用WPF的方式来处理元数据…可能som1会发现它很有用。