Нарисуйте изображение, используя значения CYMK - PullRequest
0 голосов
/ 22 апреля 2019

Я хочу преобразовать буферизованное изображение из формата RGBA в формат CYMK без использования инструментов автоматического преобразования или библиотек, поэтому я попытался извлечь значения RGBA из отдельных пикселей, которые я получил с помощью BufferedImage.getRGB(), и вот что я сделал такдалеко:

BufferedImage img = new BufferedImage("image path")
int R,G,B,pixel,A;
float Rc,Gc,Bc,K,C,M,Y;
int height = img.getHeight();
int width = img.getWidth();
    for(int y = 0 ; y < height ; y++){
        for(int x = 0 ; x < width ; x++){
            pixel = img.getRGB(x, y);

            //I shifted the int bytes to get RGBA values
            A = (pixel>>24)&0xff;
            R = (pixel>>16)&0xff;
            G = (pixel>>8)&0xff;
            B = (pixel)&0xff;
            Rc = (float) ((float)R/255.0);
            Gc = (float) ((float)G/255.0);
            Bc = (float) ((float)B/255.0);

            // Equations i found on the internet to get CYMK values
            K = 1 - Math.max(Bc, Math.max(Rc, Gc));
            C = (1- Rc - K)/(1-K);
            Y = (1- Bc - K)/(1-K);
            M = (1- Gc - K)/(1-K);                                
        }
    }

Теперь, после того как я его извлек, я хочу нарисовать или построить изображение, используя значения тезисов. Можете ли вы рассказать мне о методе или способе сделать это, потому что я не думаю, BufferedImage.setRGB() будет работать, а также когда я напечатал значения C,Y,M у некоторых из них было NaN значение, может кто-нибудь сказать мне, что это значит и как с этим бороться?

1 Ответ

1 голос
/ 23 апреля 2019

Хотя это возможно, преобразование RGB в CMYK без правильного цветового профиля не даст наилучших результатов.Для лучшей производительности и более высокой точности цветопередачи я действительно рекомендую использовать цветовой профиль ICC (см. ICC_Profile и ICC_ColorSpace классы) и ColorConvertOp.: -)

В любом случае, вот как это сделать, используя ваше собственное преобразование.Важной частью является создание цветового пространства CMYK и использование ColorModel и BufferedImage с использованием этого цветового пространства (вы также можете загрузить цветовое пространство CMYK из профиля ICC, как упомянуто выше, но цвета, вероятно, будут выглядеть более непривычно, так какон использует другие расчеты, чем вы).

public static void main(String[] args) throws IOException {
    BufferedImage img = ImageIO.read(new File(args[0]));
    int height = img.getHeight();
    int width = img.getWidth();

    // Create a color model and image in CMYK color space (see custom class below)
    ComponentColorModel cmykModel = new ComponentColorModel(CMYKColorSpace.INSTANCE, false, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
    BufferedImage cmykImg = new BufferedImage(cmykModel, cmykModel.createCompatibleWritableRaster(width, height), cmykModel.isAlphaPremultiplied(), null);
    WritableRaster cmykRaster = cmykImg.getRaster();

    int R,G,B,pixel;
    float Rc,Gc,Bc,K,C,M,Y;

    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            pixel = img.getRGB(x, y);

            // Now, as cmykImg already is in CMYK color space, you could actually just invoke
            //cmykImg.setRGB(x, y, pixel);
            // and the method would perform automatic conversion to the dest color space (CMYK)

            // But, here you go... (I just cleaned up your code a little bit):
            R = (pixel >> 16) & 0xff;
            G = (pixel >> 8) & 0xff;
            B = (pixel) & 0xff;

            Rc = R / 255f;
            Gc = G / 255f;
            Bc = B / 255f;

            // Equations I found on the internet to get CMYK values
            K = 1 - Math.max(Bc, Math.max(Rc, Gc));
            if (K == 1f) {
                // All black (this is where you would get NaN values I think)
                C = M = Y = 0;
            }
            else { 
                C = (1- Rc - K)/(1-K);
                M = (1- Gc - K)/(1-K);
                Y = (1- Bc - K)/(1-K);
            }

            // ...and store the CMYK values (as bytes in 0..255 range) in the raster
            cmykRaster.setDataElements(x, y, new byte[] {(byte) (C * 255), (byte) (M * 255), (byte) (Y * 255), (byte) (K * 255)});
        }
    }

    // You should now have a CMYK buffered image
    System.out.println("cmykImg: " + cmykImg);
}

// A simple and not very accurate CMYK color space
// Full source at https://github.com/haraldk/TwelveMonkeys/blob/master/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/color/CMYKColorSpace.java
final static class CMYKColorSpace extends ColorSpace {

    static final ColorSpace INSTANCE = new CMYKColorSpace();

    final ColorSpace sRGB = getInstance(CS_sRGB);

    private CMYKColorSpace() {
        super(ColorSpace.TYPE_CMYK, 4);
    }

    public static ColorSpace getInstance() {
        return INSTANCE;
    }

    public float[] toRGB(float[] colorvalue) {
        return new float[]{
                (1 - colorvalue[0]) * (1 - colorvalue[3]),
                (1 - colorvalue[1]) * (1 - colorvalue[3]),
                (1 - colorvalue[2]) * (1 - colorvalue[3])
        };
    }

    public float[] fromRGB(float[] rgbvalue) {
        // NOTE: This is essentially the same equation you use, except 
        // this is slightly optimized, and values are already in range [0..1]

        // Compute CMY
        float c = 1 - rgbvalue[0];
        float m = 1 - rgbvalue[1];
        float y = 1 - rgbvalue[2];

        // Find K
        float k = Math.min(c, Math.min(m, y));

        // Convert to CMYK values
        return new float[]{(c - k), (m - k), (y - k), k};
    }

    public float[] toCIEXYZ(float[] colorvalue) {
        return sRGB.toCIEXYZ(toRGB(colorvalue));
    }

    public float[] fromCIEXYZ(float[] colorvalue) {
        return sRGB.fromCIEXYZ(fromRGB(colorvalue));
    }
}

PS: Ваш вопрос говорит о RGBA и CMYK, но ваш код просто игнорирует альфа-значение, поэтому я сделал то же самое.Если вы действительно хотите, вы можете просто оставить альфа-значение как есть и иметь изображение CMYK + A, чтобы разрешить альфа-композитинг в цветовом пространстве CMYK.Я оставлю это как упражнение.; -)

...