JPEGEncoder Windows Media Imaging не учитывает цветовой профиль изображения

У меня есть следующее изображение (я сделал снимок экрана, так как его размер превышает 2 МБ - оригинал можно загрузить с https://drive.google.com/file/d/1rC2QQBzMhZ8AG5Lp5PyrpkOxwlyP9QaE/view?usp= совместное использование

Я читаю изображение с помощью BitmapDecoderclass и сохраните его с помощью JPEG Encoder. Это приводит к тому, что следующее изображение блекло и блекло.

      var frame = BitmapDecoder.Create(new Uri(inputFilePath, UriKind.RelativeOrAbsolute),BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None).Frames[0];
    var encoder = new JpegBitmapEncoder();    
     encoder.Frames.Add(frame);
     using (var stream = File.OpenWrite(outputFilePath))
     {
     encoder.Save(stream);
     }

Изображение использует PhotoShop RGB Цветовая схема. Я попытался установить цветовой профиль, используя следующий код, но это привело к этой ошибке. The designated BitmapEncoder does not support ColorContexts

      encoder.ColorContexts = frame.ColorContexts;

1 ответ

Биты изображения идентичны. Это проблема метаданных. Этот файл изображения содержит множество метаданных (Xmp, Adobe, unknown и т. д.), и эти метаданные содержат два цветовых профиля/пространства/контекста :

  1. ProPhoto RG (обычно находится в C:\WINDOWS\system32\spool\drivers\color\ProPhoto.icm)
  2. sRGB IEC61966-2.1 (обычно находится в WINDOWS\system32\spool\drivers\color\sRGB Color Space Profile.icm)

Проблема возникает из-за того, что по какой-то причине порядок двух контекстов в целевом файле может отличаться. Средство просмотра изображений может либо не использовать цветовой профиль (Paint, Pain3D, Paint.NET, IrfanView и т. д.), либо использовать (по моему опыту) последний цветовой профиль в файле (Windows Photo Viewer, Photoshop и т. д.).

Вы можете решить свою проблему, если клонируете фрейм, то есть:

      var frame = BitmapDecoder.Create(new Uri(inputFilePath, UriKind.RelativeOrAbsolute),BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.None).Frames[0];
var encoder = new JpegBitmapEncoder();    
var copy = BitmapFrame.Create(frame);
encoder.Frames.Add(copy);
using (var stream = File.OpenWrite(outputFilePath))
{
    encoder.Save(stream);
}

Как и в этом случае, порядок сохраняется как есть.

Если вы воссоздаете кадр или преобразуете его каким-либо образом, вы можете скопировать метаданные и цветовые контексты следующим образом:

      var ctxs = new List<ColorContext>();
ctxs.Add(frame.ColorContexts[1]); // or just remove this
ctxs.Add(frame.ColorContexts[0]); // first color profile is ProPhoto RG, make sure it's last
var resized = BitmapFrame.Create(new TransformedBitmap(frame, transform), frame.Thumbnail, (BitmapMetadata)frame.Metadata, ctxs.AsReadOnly());
var encoder = new JpegBitmapEncoder();
encoder.Frames.Add(resized);
using (var stream = File.OpenWrite("resized.jpg"))
{
    encoder.Save(stream);
}

Обратите внимание, что изображение, имеющее более одного цветового контекста, болезненно (и ИМХО не должно создаваться/сохраняться). Цветовые профили предназначены для обеспечения правильного отображения, поэтому два или более (довольно конфликтующих! sRGB и ProPhoto) профилей, связанных с одним изображением, означают, что оно может отображаться... двумя или более способами.

Вам придется определить, какой цветовой профиль вы предпочитаете в этом странном случае.

Другие вопросы по тегам