web-dev-qa-db-fra.com

Impossible de lire une image JPEG avec ImageIO.read (fichier fichier)

Je ne parviens pas à lire ce fichier JPEG avec ImageIO.read (fichier) - une exception est générée avec le message "Type d'image non prise en charge".

J'ai essayé d'autres images JPEG et elles semblent bien fonctionner.

La seule différence que j'ai pu remarquer, c'est que ce fichier semble inclure une vignette. Est-ce connu pour causer des problèmes avec ImageIO.read ()?

Troublesome image

MODIFIER:

Ajout de l'image résultante:

Strange colors

40
Malakim

Votre image "Modèle de couleur" est CMYK, JPEGImageReader (la classe interne qui lit votre fichier) lit uniquement le modèle de couleur RVB.

Si vous insistez pour lire les images CMJN, vous devrez alors les convertir. Essayez ce code.

METTRE À JOUR

Lire une image CMJN dans l’image tamponnée RVB.

    File f = new File("/path/imagefile.jpg");

    //Find a suitable ImageReader
    Iterator readers = ImageIO.getImageReadersByFormatName("JPEG");
    ImageReader reader = null;
    while(readers.hasNext()) {
        reader = (ImageReader)readers.next();
        if(reader.canReadRaster()) {
            break;
        }
    }

    //Stream the image file (the original CMYK image)
    ImageInputStream input =   ImageIO.createImageInputStream(f); 
    reader.setInput(input); 

    //Read the image raster
    Raster raster = reader.readRaster(0, null); 

    //Create a new RGB image
    BufferedImage bi = new BufferedImage(raster.getWidth(), raster.getHeight(), 
    BufferedImage.TYPE_4BYTE_ABGR); 

    //Fill the new image with the old raster
    bi.getRaster().setRect(raster);

MISE À JOUR - Mars 2015 - Ajout d'images de simulation

Les images originales ont été supprimées de la liste déroulante d'OP. J'ajoute donc de nouvelles images (pas les images originales) qui simulent le problème qui se posait avec elles.

Première image est l'image d'une image RVB normale.

Image RGB

Seconde image est l’affichage de la même image dans le modèle couleur CMYK.

Vous ne pouvez pas réellement voir à quoi ça ressemble sur le Web car il sera converti en RVB par l'hôte. Pour voir exactement à quoi elle ressemble, prenez l’image RVB et exécutez-la avec un convertisseur RVB en CMJN.

La troisième image correspond à l’image CMJN lorsqu’elle est lue puis écrite à l’aide de Java ImageIO.

Image CMYK read through Java RGB

Le problème qui se posait avec OP est qu’ils avaient quelque chose comme l’image 2 qui lève une exception lorsque vous essayez de le lire.

36
medopal

Ancien post, mais pour référence future:

Inspiré par cette question et les liens trouvés ici, j'ai écrit un plugin JPEGImageReader pour ImageIO qui prend en charge les modèles de couleur CMYK (les deux avec le modèle de couleur original ou convertis implicitement en RVB à la lecture). Le lecteur effectue également une conversion de couleur appropriée, en utilisant le profil ICC incorporé dans le flux JPEG, contrairement aux autres solutions mentionnées ici.

C'est simple Java et ne nécessite pas de JAI. Les distributions du code source et binaire sont disponibles gratuitement sur github.com/haraldk/TwelveMonkeys et sont couvertes par une licence de type BSD.

Une fois que vous l’avez installé, il vous permet de lire les JPEG CMJN en utilisant ImageIO.read(...) comme ceci:

File cmykJPEGFile = new File(/*path*/);
BufferedImage image = ImageIO.read(cmykJPEGFile);

I.e .: Dans la plupart des cas, il n'est pas nécessaire de modifier votre code.

45
haraldK

Je suis un peu en retard à la fête. Mais cela vaut probablement la peine que je poste ma réponse car aucune des réponses ne résout vraiment le problème.

La solution nécessite Sanselan (ou Apache Commons Imaging, comme elle s'appelle maintenant) et requiert un profil de couleur CMJN raisonnable (fichier .icc). Vous pouvez vous procurer le dernier auprès d’Adobe ou d’eci.org.

Le problème de base est que Java - prêt à l'emploi - ne peut lire que les fichiers JPEG au format RVB. Si vous avez un fichier CMJN, vous devez faire la distinction entre CMJN normal, Adobe CMJN (avec des valeurs inversées, à savoir 255 pour pas d’encre et 0 pour maximum d’encre) et Adobe CYYK (certaines variantes avec des couleurs inversées également).

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

Le code essaie d'abord de lire le fichier en utilisant la méthode habituelle, qui fonctionne pour les fichiers RVB. S'il échoue, il lit les détails du modèle de couleur (profil, marqueur Adobe, variante Adobe). Ensuite, il lit les données de pixels brutes (raster) et effectue toutes les conversions nécessaires (YCCK vers CMJN, couleurs inversées, CMJN vers RGB).

Je ne suis pas tout à fait satisfait de ma solution. Bien que les couleurs soient généralement bonnes, les zones sombres sont légèrement trop claires, en particulier le noir n’est pas tout à fait noir. Si quelqu'un sait ce que je pourrais améliorer, je serais heureux de l'entendre.

18
Codo

ImageIO.read() -> 

File filePath = new File("C:\\Users\\chang\\Desktop\\05036877.jpg");
com.Sun.image.codec.jpeg.JPEGImageDecoder jpegDecoder =  JPEGCodec.createJPEGDecoder (new FileInputStream(filePath));

BufferedImage image = jpegDecoder.decodeAsBufferedImage();
6
Peter

J'ai trouvé https: //stackoverflow.com/questions/22409 ... ici aussi, celui-ci effectue une excellente conversion de couleur

Et combiné les deux pour obtenir ceci:

private BufferedImage convertCMYK2RGB(BufferedImage image) throws IOException{
    log.info("Converting a CYMK image to RGB");
    //Create a new RGB image
    BufferedImage rgbImage = new BufferedImage(image.getWidth(), image.getHeight(),
    BufferedImage.TYPE_3BYTE_BGR);
    // then do a funky color convert
    ColorConvertOp op = new ColorConvertOp(null);
    op.filter(image, rgbImage);
    return rgbImage;
}
5
enkor

je le répare par ceci . seulement besoin d'ajouter cette dépendance. Je peux lire une image CMJN par ImageIO . TwelveMonkeys

ImageIO.read(new URL("http://img3.tianyancha.com/api/9b80a61183787909e719c77fd0f78103.png"))
0
yaoning