JPEGEncoder Windows 媒体成像不遵守图像的颜色配置文件
JPEGEncoder Windows Media Imaging not honoring color profile of Image
我有下面的图片(因为它的大小超过 2 MB,所以放了一张图片的屏幕截图 - 原件可以从 https://drive.google.com/file/d/1rC2QQBzMhZ8AG5Lp5PyrpkOxwlyP9QaE/view?usp=sharing
下载
我正在使用 BitmapDecoder
class 读取图像并使用 JPEG 编码器保存它。
这会导致以下图像变色和褪色。
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
颜色 scheme.I 尝试使用以下代码设置颜色配置文件,但这会导致此错误 The designated BitmapEncoder does not support ColorContexts
encoder.ColorContexts = frame.ColorContexts;
更新:
克隆图像似乎可以解决问题。但是当我使用以下代码调整图像大小时进行转换时,颜色配置文件不会保留
Transform transform = new ScaleTransform(width / frame.Width * 96 / frame.DpiX, height / frame.Height * 96 / frame.DpiY, 0, 0);
var copy = BitmapFrame.Create(frame);
var resized = BitmapFrame.Create(new
TransformedBitmap(copy, transform));
encoder.Frames.Add(resized);
using (var stream = File.OpenWrite(outputFilePath))
{
encoder.Save(stream);
}
图像位相同。这是一个元数据问题。此图像文件包含大量元数据(Xmp、Adobe、未知等)并且此元数据包含两个 color profiles/spaces/contexts:
- ProPhoto RG(通常在 C:\WINDOWS\system32\spool\drivers\color\ProPhoto.icm 中找到)
- sRGB IEC61966-2.1(通常出现在WINDOWS\system32\spool\drivers\color\sRGB颜色SpaceProfile.icm)
出现此问题是因为由于某种原因,目标文件中的两个上下文顺序可能不同。图像查看器可以不使用颜色配置文件(Paint、Pain3D、Paint.NET、IrfanView 等),或者使用(根据我的经验)文件中的 last 颜色配置文件(Windows 照片查看器、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)配置文件意味着它可以以两种或更多方式显示......
在这种奇怪的情况下,您必须确定您喜欢的颜色配置文件。
我有下面的图片(因为它的大小超过 2 MB,所以放了一张图片的屏幕截图 - 原件可以从 https://drive.google.com/file/d/1rC2QQBzMhZ8AG5Lp5PyrpkOxwlyP9QaE/view?usp=sharing
下载我正在使用 BitmapDecoder
class 读取图像并使用 JPEG 编码器保存它。
这会导致以下图像变色和褪色。
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
颜色 scheme.I 尝试使用以下代码设置颜色配置文件,但这会导致此错误 The designated BitmapEncoder does not support ColorContexts
encoder.ColorContexts = frame.ColorContexts;
更新: 克隆图像似乎可以解决问题。但是当我使用以下代码调整图像大小时进行转换时,颜色配置文件不会保留
Transform transform = new ScaleTransform(width / frame.Width * 96 / frame.DpiX, height / frame.Height * 96 / frame.DpiY, 0, 0);
var copy = BitmapFrame.Create(frame);
var resized = BitmapFrame.Create(new
TransformedBitmap(copy, transform));
encoder.Frames.Add(resized);
using (var stream = File.OpenWrite(outputFilePath))
{
encoder.Save(stream);
}
图像位相同。这是一个元数据问题。此图像文件包含大量元数据(Xmp、Adobe、未知等)并且此元数据包含两个 color profiles/spaces/contexts:
- ProPhoto RG(通常在 C:\WINDOWS\system32\spool\drivers\color\ProPhoto.icm 中找到)
- sRGB IEC61966-2.1(通常出现在WINDOWS\system32\spool\drivers\color\sRGB颜色SpaceProfile.icm)
出现此问题是因为由于某种原因,目标文件中的两个上下文顺序可能不同。图像查看器可以不使用颜色配置文件(Paint、Pain3D、Paint.NET、IrfanView 等),或者使用(根据我的经验)文件中的 last 颜色配置文件(Windows 照片查看器、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)配置文件意味着它可以以两种或更多方式显示......
在这种奇怪的情况下,您必须确定您喜欢的颜色配置文件。