Frage

Ich versuche, eine Lösung zur Berechnung der Konvertierung zwischen RGB und CMYK zu implementieren und umgekehrt. Hier ist, was ich bisher habe:

  public static int[] rgbToCmyk(int red, int green, int blue)
    {
        int black = Math.min(Math.min(255 - red, 255 - green), 255 - blue);

        if (black!=255) {
            int cyan    = (255-red-black)/(255-black);
            int magenta = (255-green-black)/(255-black);
            int yellow  = (255-blue-black)/(255-black);
            return new int[] {cyan,magenta,yellow,black};
        } else {
            int cyan = 255 - red;
            int magenta = 255 - green;
            int yellow = 255 - blue;
            return new int[] {cyan,magenta,yellow,black};
        }
    }

    public static int[] cmykToRgb(int cyan, int magenta, int yellow, int black)
    {
        if (black!=255) {
            int R = ((255-cyan) * (255-black)) / 255; 
            int G = ((255-magenta) * (255-black)) / 255; 
            int B = ((255-yellow) * (255-black)) / 255;
            return new int[] {R,G,B};
        } else {
            int R = 255 - cyan;
            int G = 255 - magenta;
            int B = 255 - yellow;
            return new int[] {R,G,B};
        }
    }
War es hilfreich?

Lösung

Wie Lea Verou sagte, sollten Sie Farbrauminformationen verwenden, da es keinen Algorithmus gibt, der von RGB nach CMYK abgebildet werden kann. Adobe verfügt über einige ICC -Farbprofile zum Download zur Verfügung1, aber ich bin mir nicht sicher, wie sie lizenziert sind.

Sobald Sie die Farbprofile haben, würde die folgende Arbeit erledigen:

import java.awt.color.ColorSpace;
import java.awt.color.ICC_ColorSpace;
import java.awt.color.ICC_Profile;
import java.io.IOException;
import java.util.Arrays;


public class ColorConv {
    final static String pathToCMYKProfile = "C:\\UncoatedFOGRA29.icc";

    public static float[] rgbToCmyk(float... rgb) throws IOException {
        if (rgb.length != 3) {
            throw new IllegalArgumentException();
        }
        ColorSpace instance = new ICC_ColorSpace(ICC_Profile.getInstance(pathToCMYKProfile));
        float[] fromRGB = instance.fromRGB(rgb);
        return fromRGB;
    }
    public static float[] cmykToRgb(float... cmyk) throws IOException {
        if (cmyk.length != 4) {
            throw new IllegalArgumentException();
        }
        ColorSpace instance = new ICC_ColorSpace(ICC_Profile.getInstance(pathToCMYKProfile));
        float[] fromRGB = instance.toRGB(cmyk);
        return fromRGB;
    }

    public static void main(String... args) {
        try {
            float[] rgbToCmyk = rgbToCmyk(1.0f, 1.0f, 1.0f);
            System.out.println(Arrays.toString(rgbToCmyk));
            System.out.println(Arrays.toString(cmykToRgb(rgbToCmyk[0], rgbToCmyk[1], rgbToCmyk[2], rgbToCmyk[3])));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Andere Tipps

Um die Werte von RGB in CMYK genau umzuwandeln und umgekehrt, wie Photoshop es tut, müssen Sie ein ICC -Farbprofil verwenden. Alle einfachen algorithmischen Lösungen, die Sie in den Interwebs finden (wie oben veröffentlicht), sind inoklieren und produzieren Farben, die außerhalb des CMYK -Farbbands liegen (zum Beispiel konvertieren sie CMYK (100, 0, 0, 0) in RGB (0). , 255, 255), was offensichtlich falsch ist, da RGB (0, 255, 255) nicht mit CMYK reproduziert werden kann). Schauen Sie in die java.awt.color.icc_colorspace und java.awt.color.icc_profile Klassen zum Konvertieren von Farben mit ICC -Farbtonprofilen. Bei den Farbprofildateien selbst verteilt Adobe sie kostenlos.

Ein besserer Weg, es zu tun:

    try {
        // The "from" CMYK colorspace
        ColorSpace cmykColorspace = new ICC_ColorSpace(ICC_Profile.getInstance("icc/CoatedFOGRA27.icc"));
        // The "to" RGB colorspace
        ColorSpace rgbColorspace = new ICC_ColorSpace(ICC_Profile.getInstance("icc/AdobeRGB1998.icc"));

        // Bring in to CIEXYZ colorspace (refer to Java documentation: http://docs.oracle.com/javase/1.4.2/docs/api/java/awt/color/ColorSpace.html)
        float[] ciexyz = cmykColorspace.toCIEXYZ(cmyk);
        float[] thisColorspace = rgbColorspace.fromCIEXYZ(ciexyz);
        float[] rgb = thisColorspace;
        Color c = new Color(rgb[0], rgb[1], rgb[2]);

        // Format RGB as Hex and return
        return String.format("#%06x", c.getRGB() & 0xFFFFFF);
    } catch (IOException e) { e.printStackTrace(); }

Um korrekt angezeigt zu werden, sollte CMYK -Bilder enthalten Farbrauminformationen als ICC -Profil. Der beste Weg ist die Verwendung dieses ICC -Profils, das leicht extrahiert werden kann Sansselan:

ICC_Profile iccProfile = Sanselan.getICCProfile(new File("filename.jpg"));
ColorSpace cs = new ICC_ColorSpace(iccProfile);    

Wenn das Bild kein ICC -Profil angehängt ist, würde ich verwenden Adobe -Profile als Standard.

Das Problem ist nun, dass Sie die JPEG -Datei nicht einfach mit benutzerdefiniertem Farbton mithilfe von ImageIO laden können, da sie keine Ausnahme auswirft und sich darüber beschweren, dass sie keinen Farbraum oder einen solchen Sting unterstützt. Hense müssen Sie mit Rastern arbeiten:

JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(new ByteArrayInputStream(data));
Raster srcRaster = decoder.decodeAsRaster();

BufferedImage result = new BufferedImage(srcRaster.getWidth(), srcRaster.getHeight(), BufferedImage.TYPE_INT_RGB);
WritableRaster resultRaster = result.getRaster();

ColorConvertOp cmykToRgb = new ColorConvertOp(cs, result.getColorModel().getColorSpace(), null);
cmykToRgb.filter(srcRaster, resultRaster);

Sie können dann verwenden result Wo immer Sie brauchen und es werden Farben umgewandelt.

In der Praxis bin ich jedoch auf einige Bilder gestoßen (aufgenommen mit Kamera und mit Photoshop verarbeitet), die in irgendwie umgekehrte Farbwerte aufgenommen wurden, sodass das resultierende Bild immer invertiert war, und selbst nachdem sie sie erneut invertiert hatten, waren sie zu hell. Obwohl ich immer noch keine Ahnung habe, wie ich herausfinden soll, wann genau ich es verwenden soll (wenn ich Pixelwerte umkehren muss), habe ich einen Algorithmus, der diese Werte korrigiert und Farbpixel mit Pixel konvertiert:

JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(new ByteArrayInputStream(data));
Raster srcRaster =  decoder.decodeAsRaster();

BufferedImage ret = new BufferedImage(srcRaster.getWidth(), srcRaster.getHeight(), BufferedImage.TYPE_INT_RGB);
WritableRaster resultRaster = ret.getRaster();

for (int x = srcRaster.getMinX(); x < srcRaster.getWidth(); ++x)
    for (int y = srcRaster.getMinY(); y < srcRaster.getHeight(); ++y) {

        float[] p = srcRaster.getPixel(x, y, (float[])null);

        for (int i = 0; i < p.length; ++i)
            p[i] = 1 - p[i] / 255f;

        p = cs.toRGB(p);

        for (int i = 0; i < p.length; ++i)
            p[i] = p[i] * 255f;

        resultRaster.setPixel(x, y, p);
    }

Ich bin mir ziemlich sicher, dass Rasterop oder ColorConvertop verwendet werden könnten, um die Konversation effizienter zu gestalten, aber das war für mich genug.

Im Ernst, es ist nicht erforderlich, diese vereinfachten CMYK -zu -RGB -Konvertierungsalgorithmen zu verwenden, da Sie das ICC -Profil verwenden können, das in das Bild eingebettet oder kostenlos aus Adobe verfügbar ist. Das resultierende Bild wird besser aussehen, wenn nicht perfekt (mit eingebettetem Profil).

public static String makeCMYKString(int color) {
    double red = Color.red(color);
    double green = Color.green(color);
    double blue = Color.blue(color);
    double red1 = red / 255;
    double green1 = green / 255;
    double blue1 = blue / 255;
    double max = (Math.max(Math.max(red1, green1), blue1));
    double K = 1 - max;
    double C = (1 - red1 - K) / (1 - K);
    double M = (1 - green1 - K) / (1 - K);
    double Y = (1 - blue1 - K) / (1 - K);
    double CMYK[] = {C, M, Y, K};
    String cmyk = "CMYK = (" + Math.round(C * 100) + " , " + Math.round(M * 100) + " , " + Math.round(Y * 100) + " , " + Math.round(K * 100) + ")";
    return cmyk;
}

Hier ist eine identische Frage an Ihre

Hier ist eine Kopie/Pasta dieser Seite:

/** CMYK to RGB conversion */
/* Adobe PhotoShop algorithm */
cyan = Math.min(255, cyan + black); //black is from K
magenta = Math.min(255, magenta + black);
yellow = Math.min(255, yellow + black);
rgb[0] = 255 - cyan;
rgb[1] = 255 - magenta;
rgb[2] = 255 - yellow;


/* GNU Ghostscript algorithm -- this is better*/
int colors = 255 - black;
rgb[0] = colors * (255 - cyan)/255;
rgb[1] = colors * (255 - magenta)/255;
rgb[2] = colors * (255 - yellow)/255;

Hier ist mein Weg. Denken Sie daran, dass ich die RGB -Farben aus der Originalfarbe wiederhergestellt habe.

public static String getCMYK(int c){
     float computedC = 0;
     float computedM = 0;
     float computedY = 0;
     float computedK = 0;

     int r = (c >> 16) & 0xFF;
     int g = (c >> 8) & 0xFF;
     int b = (c >> 0) & 0xFF;

     // BLACK
     if (r==0 && g==0 && b==0) {
      computedK = 1;
      return "0 0 0 100";
     }

     computedC = 1 - (r/255f);
     computedM = 1 - (g/255f);
     computedY = 1 - (b/255f);

     float minCMY = Math.min(computedC,Math.min(computedM,computedY));

     if (1 - minCMY != 0){
         computedC = (computedC - minCMY) / (1 - minCMY) ;
         computedM = (computedM - minCMY) / (1 - minCMY) ;
         computedY = (computedY - minCMY) / (1 - minCMY) ;
     }
     computedK = minCMY;

     return (int)(computedC*100f) + " " + (int)(computedM*100f) + " " + (int)(computedY*100f) + " " + (int)(computedK*100f);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top