InPlaceBitmapMetadataWriter.TrySave() returns true but does nothing

后端 未结 3 1562
生来不讨喜
生来不讨喜 2021-01-18 08:45

On some .JPG files (EPS previews, generated by Adobe Illustrator) in Windows 7 InPlaceBitmapMetadataWriter.TrySave() returns true after some SetQuery() calls, but does nothi

相关标签:
3条回答
  • 2021-01-18 09:29

    I still didn't find the answer and has to write wrapper for exiftool instead of using WPF's way to work with metadata... May be som1 will find it useful.

    0 讨论(0)
  • 2021-01-18 09:30

    Two things:

    1. I don't think you will be able to write to your metadata variable just like that, as it will be Frozen. So, you will have to clone it:

      BitmapMetadata metadata = frame.Metadata.Clone() as BitmapMetadata;
      
    2. Padding, you need padding. I found this out after about a day's worth of tinkering around trying to make some code (similar to yours) work. InPlaceBitmapMetadataWriter will not work if there is no metadata padding in your image file. So you need something like:

      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));
          using (Stream outputFile = File.Open(_myoutputpath, FileMode.Create, FileAccess.ReadWrite)) {
              encoder.Save(outputFile);
          }
      }
      

    Now you can use the file located at _myoutputpath which has added metadata padding for your InPlaceBitmapMetadataWriter operations.

    This article and attached code should help you out.

    0 讨论(0)
  • 2021-01-18 09:33

    Hi I found this article about InPlaceBitmapMetadataWriter where the guy said that TrySave() might corrupt the image and that's why he advised to do TrySave() on the copy of the original file and if this doesn't work, add padding to the copy of original file and than TrySave() again and if it works, delete the original and rename the copy.

    I scratched my head and asked myself why I should bother with InPlaceBitmapMetadataWriter and writing 3x original file to the disk in case TrySave() doesn't work because there is not enough padding, if I can clone metadata, write whatever into them and assemble jpeg file right away.

    Then I started to think that maybe thanks to InPlaceBitmapMetadataWriter I can edit metadata without losing quality, but it looks like it "just" helps you to write metadata more quickly if there is enough padding.

    I wrote a small test where I compress one file many times to see the quality degradation and you can see it in the third-fourth compression, which is very bad.

    But luckily, if you always use same QualityLevel with JpegBitmapEncoder there is no degradation.

    In this example I rewrite keywords 100x in metadata and the quality seems not to change.

    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<string>() : new List<string>(metadata.Keywords);
          keywords.Add($"Keyword {i:000}");
          metadata.Keywords = new ReadOnlyCollection<string>(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);
          }
        }
      }
    }
    
    0 讨论(0)
提交回复
热议问题