InPlaceBitmapMetadataWriter.TrySave () возвращает true, но ничего не делает - PullRequest
6 голосов
/ 03 мая 2010

В некоторых файлах .JPG (превью EPS, созданные Adobe Illustrator) в Windows 7 InPlaceBitmapMetadataWriter.TrySave () возвращает true после некоторых вызовов SetQuery (), но ничего не делает.

Пример кода:

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.

Любые идеи приветствуются:)

Ответы [ 3 ]

4 голосов
/ 21 октября 2010

Две вещи:

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

Теперь вы можете использовать файл, расположенный по адресу _myoutputpath, в который добавлено заполнение метаданными для ваших операций InPlaceBitmapMetadataWriter.

Эта статья и прилагаемый код должны помочь вам.

3 голосов
/ 12 февраля 2016

Привет, я нашел эту статью о InPlaceBitmapMetadataWriter, где парень сказал, что TrySave () может испортить изображение, и поэтому он посоветовал сделать TrySave () для копии исходного файла, и если это не так t, добавьте отступ к копии исходного файла, а затем снова попробуйте TrySave () и, если он работает, удалите оригинал и переименуйте копию.

Я почесал голову и спросил себя, почему я должен беспокоиться о InPlaceBitmapMetadataWriter и записи 3х оригинального файла на диск в случае, если TrySave () не работает, потому что не хватает заполнения, если я могу клонировать метаданные, записать в них что угодно и соберите файл JPEG прямо сейчас.

Тогда я начал думать, что, возможно, благодаря InPlaceBitmapMetadataWriter я могу редактировать метаданные без потери качества, но, похоже, это «просто» помогает быстрее писать метаданные при достаточном заполнении.

Я написал небольшой тест, в котором много раз сжимаю один файл, чтобы увидеть снижение качества, и вы можете увидеть его в третьем-четвертом сжатии, что очень плохо.

Но, к счастью, если вы всегда используете один и тот же QualityLevel с JpegBitmapEncoder, ухудшение не происходит.

В этом примере я перезаписываю ключевые слова 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<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 голосов
/ 16 октября 2010

Я до сих пор не нашел ответ и должен написать оболочку для exiftool вместо того, чтобы использовать метод WPF для работы с метаданными ... Может быть, som1 найдет это полезным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...