2011-02-01 94 views
10

Tôi đang cố triển khai giải pháp để tính toán chuyển đổi giữa RGB và CMYK và ngược lại. Dưới đây là những gì tôi có cho đến nay:RGB to CMYK và thuật toán ngược

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}; 
     } 
    } 
+0

Mọi người đều muốn có câu trả lời nhanh, vô dụng của nó để chỉ định – Eric

+0

Giải pháp này có hiệu quả với bạn như thế nào? Tôi thấy rằng bạn đã cố gắng để đi về nó mà không có ICC_Colorspace, bạn có thể giữ nó lên? – TacB0sS

Trả lời

6

Như Lea Verou đã nói bạn nên sử dụng thông tin không gian màu vì không có thuật toán để ánh xạ từ RGB sang CMYK. Adobe có một số hồ sơ màu ICC có sẵn để tải xuống 1, nhưng tôi không chắc chắn cách chúng được cấp phép.

Một khi bạn đã cấu hình màu sắc giống như sau sẽ thực hiện công việc:

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(); 
     } 
    } 
} 
-1

Here là một câu hỏi giống hệt như của bạn

Dưới đây là một bản sao/pasta của trang đó:

/** 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; 
+8

-1: Kết quả của các công thức chuyển đổi này quá kém, kết quả gần như vô dụng. Thực tế là họ được đăng trên tất cả các mạng không làm cho nó tốt hơn. Hãy ngừng lan rộng chúng nhiều hơn. – Codo

4

Để chuyển đổi một cách chính xác giá trị từ RGB sang CMYK và ngược lại, theo cách Photoshop, bạn cần sử dụng một hồ sơ màu ICC. Tất cả các giải pháp thuật toán đơn giản mà bạn sẽ tìm thấy trong interwebs (như được đăng ở trên) là inacurrate và tạo ra các màu ngoài gam màu CMYK (ví dụ: chúng chuyển đổi CMYK (100, 0, 0, 0) thành rgb (0 , 255, 255) rõ ràng là sai vì rgb (0, 255, 255) không thể được sao chép bằng CMYK). Nhìn vào các lớp java.awt.color.ICC_ColorSpacejava.awt.color.ICC_Profile để chuyển đổi màu sắc bằng cách sử dụng các cấu hình màu ICC. Đối với các tập tin cấu hình màu, Adobe phân phối chúng miễn phí.

+0

Các lớp ICC này có phải là JDK 7 không? Tôi không tìm thấy tham chiếu đến chúng trong tài liệu Java 6. –

+0

Trả lời chỉnh sửa bằng liên kết. Theo như tôi biết, chúng không phải là mới (tôi đã sử dụng chúng cách đây 2 năm), cũng như trong một số thư viện bên ngoài, chúng được xây dựng. –

0

Để được hiển thị một cách chính xác hình ảnh CMYK nên chứa color space information như ICC Profile. Vì vậy, cách tốt nhất là sử dụng mà ICC Profile mà có thể dễ dàng trích xuất với Sanselan:

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

Trong trường hợp không có hồ sơ ICC gắn liền với hình ảnh, tôi sẽ sử dụng Adobe profiles như mặc định.

Bây giờ vấn đề là bạn không thể tải tập tin JPEG với không gian màu tùy chỉnh bằng ImageIO vì nó sẽ không ném một ngoại lệ phàn nàn rằng nó không hỗ trợ một số không gian màu hoặc sthing như thế. Hense bạn sẽ phải làm việc với rasters:

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); 

Sau đó bạn có thể sử dụng result bất cứ nơi nào bạn cần và nó sẽ có màu chuyển đổi. Trong thực tế, tuy nhiên tôi đã đi qua một số hình ảnh (chụp bằng máy ảnh và xử lý bằng Photoshop) bằng cách nào đó đảo ngược giá trị màu để hình ảnh luôn đảo ngược và thậm chí sau khi đảo ngược chúng lại quá sáng. Mặc dù tôi vẫn không có ý tưởng làm thế nào để tìm hiểu chính xác khi sử dụng nó (khi tôi cần phải đảo ngược giá trị pixel), tôi có một thuật toán mà sửa chữa các giá trị và chuyển đổi màu từng pixel:

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); 
    } 

Tôi khá chắc chắn RasterOp hoặc ColorConvertOp có thể được sử dụng để làm cho cuộc trò chuyện hiệu quả hơn, nhưng điều này là đủ cho tôi.

Nghiêm túc, không cần phải sử dụng các thuật toán chuyển đổi CMYK đơn giản hóa sang RGB này vì bạn có thể sử dụng Hồ sơ ICC được nhúng vào hình ảnh hoặc có sẵn miễn phí từ Adobe. Hình ảnh kết quả sẽ trông đẹp hơn nếu không hoàn hảo (với hồ sơ được nhúng).

3

Một cách tốt hơn để làm điều đó:

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(); } 
-1

Đây là cách của tôi. Hãy nhớ rằng tôi đã thay đổi màu RGB từ màu gốc.

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); 
} 
+0

Nó vẫn chuyển đổi màu "sai" giống nhau. Không biết màu RGB và giá trị CMYK của bạn là gì, bạn không thể chuyển đổi. Bạn cần phải làm việc với hồ sơ ICC, như được mô tả trong 4 năm được chấp nhận trả lời trước khi đăng bài của bạn. –

Các vấn đề liên quan