[英]How can I change the color profile of a BufferedImage without changing the pixel values?
我有一個帶有無效顏色配置文件的 BufferedImage。 我想用 ICC_Profile 替換顏色配置文件而不重新計算圖像中的像素值。 我怎樣才能做到這一點?
特別是 com.sun.imageio.plugins.png.PNGImageReader 讀取具有 DCI-P3 ICC 配置文件的圖像並生成具有 CS_sRGB ColorSpace 的 BufferedImage 但像素值對應於原始 DCI-P3 顏色空間並且生成的圖像具有錯誤的顏色。
如果我可以將 sRGB ColorSpace 與 ICC 配置文件中的 DCI-P3 ColorSpace 交換,顏色將是正確的。 如果我在圖像上運行帶有目標 ICC_Profile 的 ColorConvertOp,則生成的顏色(不同地)是錯誤的,因為它使用錯誤的 sRGB ColorSpace 解釋源像素。
我實際上還沒有嘗試過這個,因為問題中沒有代碼可以驗證,但我相信這應該有效:
如果您有可用的 DCI-P3 配置文件,您可以從中創建一個 Java ColorSpace
,然后使用該顏色空間創建一個ColorModel
。 新的顏色模型需要與原始圖像具有相同的類型和相同數量的組件。 最后,使用此顏色模型和原始圖像的Raster
創建一個新的BufferedImage
。 是這樣的:
BufferedImage original; // with incorrect color profile
ColorSpace dciP3 = new ICC_ColorSpace(ICC_Profile.getInstance(dciP3ProfilePath));
ColorModel cm = new ComponentColorModel(dciP3, new int[] {8, 8, 8},
false, false, Transparency.OPAQUE,
DataBuffer.TYPE_BYTE);
BufferedImage corrected = new BufferedImage(cm, original.getRaster(), cm.isAlphaPremultiplied(), null);
以上假設您的圖像是 RGB(無 alpha/透明度)、8 位/樣本並且原始圖像具有ComponentColorModel
。 如果這是不正確的,您需要相應地修改顏色模型。 一些常見的例子:
帶 alpha 的ComponentColorModel
,16 位/樣本:
new ComponentColorModel(dciP3, new int[] {16, 16, 16, 16},
true, false, Transparency.TRANSLUCENT,
DataBuffer.TYPE_USHORT);
具有 alpha、8 位/樣本、ARGB 順序的DirectColorModel
:
new DirectColorModel(dciP3, 32, 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000,
false, DataBuffer.TYPE_INT)
由於在這種情況下沒有像素數據的復制或轉換,因此該操作應該非常快。 但由於非標准 ICC 配置文件,它會生成TYPE_CUSTOM
BufferedImage
。 它看起來是正確的,但在屏幕上繪制可能會很慢。 如果您需要快速繪制的圖像,使用ColorConvertOp
可能是更好的選擇。
應該可以在光柵上進行就地轉換,直接從 DCI-P3 配置文件到 sRGB,如下所示:
BufferedImage original; // with incorrect sRGB profile
ICC_Profile dciP3 = ICC_Profile.getInstance(dciP3ProfilePath);
ICC_Profile sRGB = ICC_Profile.getInstance(ColorSpace.CS_sRGB);
ColorConvertOp convert = new ColorConvertOp(new ICC_Profile[] {dciP3, sRGB}, null);
WritableRaster raster = original.getRaster();
if (raster.getNumNamds() > 3) { // or > profile.getNumComponents()
// Create raster that filters out the color components and leaves alpha untouched
raster = raster.createWritableChild(0, 0, raster.getWidth(), raster.getHeight(),
0, 0, new int[] {0, 1, 2});
}
convert.filter(raster, raster);
// original now have corrected pixels in sRGB profile
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.