17

When I try to read an image using the following code

myPicture = ImageIO.read(new File("./src/javaassignment1b/Deck/Ace_Diamond_1.jpg"));

I get the following error

 Numbers of source Raster bands and source color space components do not match

On researching , there is a similar question and it appears its an issue with my JPEG image(It was cropped from a bigger picture which may have caused the error) and i have to work around the grayscale issue with I have no idea what it is about or how to implement it.

NOTE : At first i tried using ImageIcon to add to JPanel but it could not work hence i found this solution which lead to my current problem. I just starting programming in Java.

EDIT: Here are the link to the images and I am doing a Java Application

I need an alternative to add a image to a JPanel.

Community
  • 1
  • 1
Computernerd
  • 7,378
  • 18
  • 66
  • 95
  • Can you provide the exact JPG file that you are trying to load? May a "simple", specific workaround sufficient here, like loading the image with any image viewer program, and saving it again (then, probably, in a format that can be read without problems)? – Marco13 Apr 20 '14 at 12:26

2 Answers2

9

This question has already been answered here: https://stackoverflow.com/a/18400559/1042999 and this is a very elegant solution to the problem. The solution involves using a plugin for ImageIO with implemented support for multiple formats that are not supported by the default ImageIo implementation. Details on how to use the plugin in regular java apps, and servlet containers can be found: https://github.com/haraldk/TwelveMonkeys

Community
  • 1
  • 1
Sinisha Mihajlovski
  • 1,811
  • 1
  • 20
  • 34
4

Open the images with any image viewer/editor, and save them in a "standard" format

I wonder how the images have been created in the first place. My guess would be that you have used some fancy, sophisticated image manipulation program for the "cropping" that you mentioned, and that this program allows storing images in some unusual formats, and that you did (or did not) modify some options that have been available when saving the image, not knowing wha exactly these options meant (apologies if I underestimate your familiarity with image formats and color spaces here...).

However, the reason for the problem is that the images are stored with some strange form of an YPbPr or YCbCr color space (I did not manage to figure out that one exactly, but they are both not supported in ImageIO by default).

Neither of my attempts to apply the standard color conversions for YPbPb->RGB or YCbCb->RGB seemed to reproduce the exact original colors, but as you might notice when skimming over the Wikipedia articles: Quite some academic steam was let off in the world of color spaces....

Again: I'd strongly recommend you to open the images with any image viewer/editor, and save them in a "standard" format. And preferably as a PNG, because JPG is not really suitable for these kinds of images. JPG is more intended for "natural" images, like photos. For such "artificial" images, the compression must be very low to avoid artifacts.

However, this program shows the image with nearly correct colors, but the color conversion still seems to be not entirely correct.

import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class StrangeImageTest
{
    public static void main(String[] args) throws IOException
    {
        final BufferedImage image = readImage(new File("Ace_Diamond_1.jpg"));

        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                JFrame f = new JFrame();
                f.getContentPane().add(new JLabel(new ImageIcon(image)));
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.pack();
                f.setLocationRelativeTo(null);
                f.setVisible(true);
            }
        });
    }

    static BufferedImage readImage(File file) throws IOException
    {
        return readImage(new FileInputStream(file));
    }

    static BufferedImage readImage(InputStream stream) throws IOException
    {
        Iterator<ImageReader> imageReaders = 
            ImageIO.getImageReadersBySuffix("jpg");
        ImageReader imageReader = imageReaders.next();
        ImageInputStream iis = 
            ImageIO.createImageInputStream(stream);
        imageReader.setInput(iis, true, true);
        Raster raster = imageReader.readRaster(0, null);
        int w = raster.getWidth();
        int h = raster.getHeight();

        BufferedImage result = 
            new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        int rgb[] = new int[3];
        int pixel[] = new int[3];
        for (int x=0; x<w; x++)
        {
            for (int y=0; y<h; y++)
            {
                raster.getPixel(x, y, pixel);
                int Y = pixel[0];
                int CR = pixel[1];
                int CB = pixel[2];
                toRGB(Y, CB, CR, rgb);
                int r = rgb[0];
                int g = rgb[1];
                int b = rgb[2];
                int bgr = 
                    ((b & 0xFF) << 16) | 
                    ((g & 0xFF) <<  8) | 
                     (r & 0xFF);
                result.setRGB(x, y, bgr);
            }
        }
        return result;
    }

    // Based on http://www.equasys.de/colorconversion.html
    private static void toRGB(int y, int cb, int cr, int rgb[])
    {
        float Y = y / 255.0f;
        float Cb = (cb-128) / 255.0f;
        float Cr = (cr-128) / 255.0f;

        float R = Y + 1.4f * Cr;
        float G = Y -0.343f * Cb - 0.711f * Cr;
        float B = Y + 1.765f * Cb;

        R = Math.min(1.0f, Math.max(0.0f, R));
        G = Math.min(1.0f, Math.max(0.0f, G));
        B = Math.min(1.0f, Math.max(0.0f, B));

        int r = (int)(R * 255);
        int g = (int)(G * 255);
        int b = (int)(B * 255);

        rgb[0] = r;
        rgb[1] = g;
        rgb[2] = b;
    }
}

(Note: This could be implemented much simpler, with a ColorConvertOp that converts into the RGB color space from the color space that was used for the image. But as mentioned above, I did not manage to figure out which color space was used for saving the image, and even if I knew it, one would have to create an appropriate ColorSpace implementation. The first websearch results, like YCbCrColorSpace.java, did not work for the given input images...)

Marco13
  • 53,703
  • 9
  • 80
  • 159
  • 1
    MS Paint seems to spit out files that have this issue, at least for me. What would be a good free app or (even better) website for fixing this issue? – ArtOfWarfare Mar 02 '18 at 21:56
  • @ArtOfWarfare I wasn't aware (and didn't nearly expect) that MS Paint could create such files. (Swallowing a rant about "Microsoft and standards" here). Regarding the app: Basically any program should be able to create "proper" PNG files, I'm happy with http://www.irfanview.com/ , but you can pick the one you like, or (if you don't care about potential privacy/copyright issues), any of the results of websearching for something like "online png converter"... – Marco13 Mar 02 '18 at 23:40
  • I specifically need the files to remain as jpegs - that’s a requirement from the customer (I agree png would be better in every way, but they write the checks so I do what they say). Anyways, I found a solution - I opened the files in gimp and then exported as a jpeg with all the default settings. – ArtOfWarfare Mar 03 '18 at 03:53