1

I'm trying to read an image from a specific URL and convert it from CMYK to RGB. I saved the image into a file manually and used the code from 'How to convert from CMYK to RGB in Java correctly?' to do this. It works correctly but what if I want to read it from the URL?

The code is below:

    public class JpegReader {

    public static final int COLOR_TYPE_RGB = 1;
    public static final int COLOR_TYPE_CMYK = 2;
    public static final int COLOR_TYPE_YCCK = 3;

    private int colorType = COLOR_TYPE_RGB;
    private boolean hasAdobeMarker = false;

    public BufferedImage readImage(File file) throws IOException, ImageReadException {
        colorType = COLOR_TYPE_RGB;
        hasAdobeMarker = false;

        ImageInputStream stream = ImageIO.createImageInputStream(file);
        Iterator<ImageReader> iter = ImageIO.getImageReaders(stream);
        while (iter.hasNext()) {
            ImageReader reader = iter.next();
            reader.setInput(stream);

            BufferedImage image;
            ICC_Profile profile = null;
            try {
                image = reader.read(0);
            } catch (IIOException e) {
                colorType = COLOR_TYPE_CMYK;
                checkAdobeMarker(file);
                profile = Sanselan.getICCProfile(file);
                WritableRaster raster = (WritableRaster) reader.readRaster(0, null);
                if (colorType == COLOR_TYPE_YCCK)
                    convertYcckToCmyk(raster);
                if (hasAdobeMarker)
                    convertInvertedColors(raster);
                image = convertCmykToRgb(raster, profile);
            }

            return image;
        }

        return null;
    }

    public void checkAdobeMarker(File file) throws IOException, ImageReadException {
        JpegImageParser parser = new JpegImageParser();
        ByteSource byteSource = new ByteSourceFile(file);
        @SuppressWarnings("rawtypes")
        ArrayList segments = parser.readSegments(byteSource, new int[] { 0xffee }, true);
        if (segments != null && segments.size() >= 1) {
            UnknownSegment app14Segment = (UnknownSegment) segments.get(0);
            byte[] data = app14Segment.bytes;
            if (data.length >= 12 && data[0] == 'A' && data[1] == 'd' && data[2] == 'o' && data[3] == 'b' && data[4] == 'e')
            {
                hasAdobeMarker = true;
                int transform = app14Segment.bytes[11] & 0xff;
                if (transform == 2)
                    colorType = COLOR_TYPE_YCCK;
            }
        }
    }

    public static void convertYcckToCmyk(WritableRaster raster) {
        int height = raster.getHeight();
        int width = raster.getWidth();
        int stride = width * 4;
        int[] pixelRow = new int[stride];
        for (int h = 0; h < height; h++) {
            raster.getPixels(0, h, width, 1, pixelRow);

            for (int x = 0; x < stride; x += 4) {
                int y = pixelRow[x];
                int cb = pixelRow[x + 1];
                int cr = pixelRow[x + 2];

                int c = (int) (y + 1.402 * cr - 178.956);
                int m = (int) (y - 0.34414 * cb - 0.71414 * cr + 135.95984);
                y = (int) (y + 1.772 * cb - 226.316);

                if (c < 0) c = 0; else if (c > 255) c = 255;
                if (m < 0) m = 0; else if (m > 255) m = 255;
                if (y < 0) y = 0; else if (y > 255) y = 255;

                pixelRow[x] = 255 - c;
                pixelRow[x + 1] = 255 - m;
                pixelRow[x + 2] = 255 - y;
            }

            raster.setPixels(0, h, width, 1, pixelRow);
        }
    }

    public static void convertInvertedColors(WritableRaster raster) {
        int height = raster.getHeight();
        int width = raster.getWidth();
        int stride = width * 4;
        int[] pixelRow = new int[stride];
        for (int h = 0; h < height; h++) {
            raster.getPixels(0, h, width, 1, pixelRow);
            for (int x = 0; x < stride; x++)
                pixelRow[x] = 255 - pixelRow[x];
            raster.setPixels(0, h, width, 1, pixelRow);
        }
    }

    public static BufferedImage convertCmykToRgb(Raster cmykRaster, ICC_Profile cmykProfile) throws IOException {
        if (cmykProfile == null)
            cmykProfile = ICC_Profile.getInstance(JpegReader.class.getResourceAsStream("/ISOcoated_v2_300_eci.icc"));

        if (cmykProfile.getProfileClass() != ICC_Profile.CLASS_DISPLAY) {
            byte[] profileData = cmykProfile.getData();

            if (profileData[ICC_Profile.icHdrRenderingIntent] == ICC_Profile.icPerceptual) {
                intToBigEndian(ICC_Profile.icSigDisplayClass, profileData, ICC_Profile.icHdrDeviceClass); // Header is first

                cmykProfile = ICC_Profile.getInstance(profileData);
            }
        }

        ICC_ColorSpace cmykCS = new ICC_ColorSpace(cmykProfile);
        BufferedImage rgbImage = new BufferedImage(cmykRaster.getWidth(), cmykRaster.getHeight(), BufferedImage.TYPE_INT_RGB);
        WritableRaster rgbRaster = rgbImage.getRaster();
        ColorSpace rgbCS = rgbImage.getColorModel().getColorSpace();
        ColorConvertOp cmykToRgb = new ColorConvertOp(cmykCS, rgbCS, null);
        cmykToRgb.filter(cmykRaster, rgbRaster);
        return rgbImage;
    }
}


static void intToBigEndian(int value, byte[] array, int index) {
    array[index]   = (byte) (value >> 24);
    array[index+1] = (byte) (value >> 16);
    array[index+2] = (byte) (value >>  8);
    array[index+3] = (byte) (value);
}
Community
  • 1
  • 1
T.Sh
  • 390
  • 2
  • 16
  • what have you tried yet? and post minimal code example rather than linking another site. – Abhinav Gauniyal May 24 '15 at 06:54
  • Sorry, I attached the code. My problem is that this code read the image from a file but I want to read it from a url and don't know how to do this. – T.Sh May 24 '15 at 08:16

3 Answers3

2

You don't need to change a lot in my answer. The method ImageIO.createImageInputStream can take an InputStream instead of a file.

So in the simplest case, you change the code like this:

public BufferedImage readImage(String imageUrl) throws IOException, ImageReadException {

    /* some code omitted */

    URL url = new URL(imageUrl;
    ImageInputStream stream = ImageIO.createImageInputStream(url.openStream());

Update

As the input data is required several times, it makes sense to first read it into a byte array and then continue to work with the byte array:

byte[] readIntoByteArray(URL url) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    InputStream is = url.openStream ();

    byte[] buffer = new byte[4096];
    int n;
    while ( (n = is.read(buffer)) > 0 ) {
        baos.write(bufer, 0, n);
    }

    return boas. toByteArray();
}

public BufferedImage readImage(String imageUrl) throws IOException, ImageReadException {

    /* code omitted */

    byte[] imageData = readIntoByteArray(imageUrl);
    ImageInputStream stream = ImageIO.createImageInputStream(new ByteArrayInputStream(imageData));

    /* code omitted */
}


public void checkAdobeMarker(byte[] imageData) throws IOException, ImageReadException {
    JpegImageParser parser = new JpegImageParser();
    ByteSource byteSource = new ByteSourceArray(imageData);

     /* code omitted */
}
Community
  • 1
  • 1
Codo
  • 75,595
  • 17
  • 168
  • 206
  • OK! but how to use it in the 'checkAdobeMarker(File file)' function. How can I access the ByteSource of the URL? – T.Sh May 24 '15 at 08:26
1

The accepted answer is fine, but if you want to make things easier for yourself, you could use the TwelveMonkeys JPEG plugin for ImageIO. It's pure Java, handles CMYK/YCCK to RGB automatically (as well as a number of other issues in "real-world" JPEGs) and comes with a very business-friendly BSD license.

With this plugin, your code could simply be:

URL yourURL;
BufferedImage image = ImageIO.read(yourURL);
Harald K
  • 26,314
  • 7
  • 65
  • 111
  • Unfortunately, not all of that code is available in a maven repository yet, in particular the webapp servlet listener code that registers and unregisters the imageIO during webapp reloads. – Thor Feb 09 '17 at 01:40
  • Sorry, my information was based on the comments in this issue; https://github.com/haraldk/TwelveMonkeys/issues/18. I see now that there is indeed a maven artifact available. – Thor Feb 14 '17 at 15:56
0

I use this to read images from url, hopefully it work for you

try{
        URL url = new URL("you link here");
        InputStream is = url.openStream();
        OutputStream os = new FileOutputStream("you local path to save");

        byte[] b = new byte[4096];
        int length;

        while ((length = is.read(b)) != -1) {
            os.write(b, 0, length);
        }

        is.close();
        os.close();

        }catch(Exception exp){
            exp.printStackTrace(); 

        }
Alaa Abuzaghleh
  • 1,023
  • 6
  • 11