2010-05-02 2 views
6

В некоторых файлах .JPG (предварительный просмотр EPS, созданных Adobe Illustrator) в Windows 7 InPlaceBitmapMetadataWriter.TrySave() возвращает true после некоторых вызовов SetQuery(), но ничего не делает.InPlaceBitmapMetadataWriter.TrySave() возвращает 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; 
} 

Image sample

Вы можете воспроизвести проблему (если у вас есть Windows 7), загрузив образец изображения и используя этот образец кода, чтобы установить название на этом изображении. У изображения достаточно места для метаданных - и этот пример кода отлично работает на моем WinXP. Тот же код отлично работает на Win7 с другими файлами .JPG.

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

ответ

0

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

4

Две вещи:

  1. Я не думаю, что вы сможете записать на свой metadata переменной так же, как это, так как он будет заморожен. Таким образом, вы должны клонировать его:

     
    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 операций.

This article и прилагаемый код должны помочь вам.

+2

TrySave() возвращает _true_! Но ничего не делает. Таким образом, нет способа узнать, записаны ли метаданные или нет. – mephisto123

+0

Lazo, нет метода сохранения для кодировщика в .NET 4. – Roger

3

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

Я поцарапал себе голову и спросил себя, почему я должен беспокоиться с InPlaceBitmapMetadataWriter и записать 3x исходный файл на диск в случае, если 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); 
     } 
    } 
    } 
} 
Смежные вопросы