簡體   English   中英

如何在不更改像素值的情況下更改 BufferedImage 的顏色配置文件?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM