2010-03-09 3 views
37

Je rencontre des problèmes lors de la lecture de ce fichier JPEG en utilisant ImageIO.read (Fichier) - il émet une exception avec le message "Type d'image non pris en charge".Impossible de lire l'image JPEG en utilisant ImageIO.read (Fichier)

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

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

Troublesome image

EDIT:

Ajouté la image résultante:

Strange colors

+0

serait utile de voir le stacktrace de l'exception. – simonlord

+8

S'il vous plaît restaurer les images! – math

Répondre

34

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

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

MISE À JOUR

Lire une image CMJN en RVB BufferedImage.

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 ici à 2015 - Ajout d'images de simulation

images originales ont été retirées de la dropbox OP. J'ajoute donc de nouvelles images (pas les originaux) qui simulent le problème qui se produisait avec eux.

Première image ressemble à une image RVB normale.

Image RGB

deuxième image comment la même image ressemblera dans le modèle de couleur CMJN.

Vous ne pouvez pas voir à quoi il ressemble sur le web car il sera converti en RGB par l'hôte. Pour voir exactement à quoi il ressemble, prenez l'image RVB et lancez-la via un convertisseur RVB vers CMJN.

Troisième image est la façon dont l'image CMJN se présentera lorsqu'elle sera lue puis écrite avec Java ImageIO.

Image CMYK read through Java RGB

Le problème qui se passait avec OP est qu'ils avaient quelque chose comme l'image 2, qui jette une exception lorsque vous essayez de le lire.

+0

Excellent, je vais essayer. Cela fonctionnera-t-il également pour les images RVB, ou devrais-je détecter le type en quelque sorte? – Malakim

+0

Vous trouverez de nombreuses façons de détecter le modèle de couleur, mon préféré est d'utiliser JPEGImageReader, si elle renvoie l'exception 'Type d'image non pris en charge', puis son CMJN le plus probable. – medopal

+1

Cela fonctionne assez bien, cependant, les couleurs deviennent tout foiré.Voir la nouvelle image que j'ai attachée à la question. Avez-vous des conseils à ce sujet? Merci! – Malakim

5

Je trouve https://stackoverflow.com/questions/22409... ici aussi bien, celui-ci fait une grande conversion des couleurs

Et combiné à la fois 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; 
} 
+1

C'est la seule réponse que j'ai trouvée qui corrige le problème avec des teintes vertes sur les JPEGs qui ont plusieurs questions sur SO. – Phil

6

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(); 
+4

A partir de la documentation de l'API: 'Notez que les classes du package com.sun.image.codec.jpeg ne font pas partie des API Java principales. Ils font partie des distributions JDK et JRE de Sun. Bien que d'autres licenciés puissent choisir de distribuer ces classes, les développeurs ne peuvent pas dépendre de leur disponibilité dans des implémentations non-Sun. Nous pensons que des fonctionnalités équivalentes seront éventuellement disponibles dans une API principale ou une extension standard. » – Omertron

18

Je suis un peu tard à la fête. Mais il vaut probablement la peine de poster 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 on l'appelle maintenant) et nécessite un profil de couleur CMJN raisonnable (fichier .icc). Vous pouvez obtenir le dernier d'Adobe ou d'eci.org.

Le problème de base est que Java - hors de la boîte - ne peut lire que les fichiers JPEG en RVB. Si vous avez un fichier CMJN, vous devez distinguer le CMJN normal, Adobe CMJN (avec des valeurs inversées, à savoir 255 pour l'absence d'encre et 0 pour l'encre maximum) et Adobe CYYK (certaines variantes avec des couleurs inversées).

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 régulière, qui fonctionne pour les fichiers RVB. En cas d'échec, il lit les détails du modèle de couleur (profil, marqueur Adobe, variante Adobe). Ensuite, il lit les données de pixel brutes (raster) et effectue toutes les conversions nécessaires (YCCK en CMYK, couleurs inversées, CMJN en RVB).

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

+0

Voici la meilleure réponse que j'ai trouvée à ce sujet, mais ne souhaitez-vous pas fermer ImageInputStream dans un bloc finally? – Amalgovinus

+0

Merci pour l'extrait de code, fonctionne très bien. (ISOcoated_v2_300_eci.icc peut être trouvé ici: http://www.humburg.de/?page=4) – user2198875

40

poste Vieux, mais pour référence future:

Inspiré par cette question et les liens trouvés ici, je l'ai écrit un plugin JPEGImageReader pour ImageIO qui prend en charge les modèles de couleurs CMJN (à la fois avec le modèle de couleur d'origine, ou converti implicitement RGB en lecture). Le lecteur effectue également une conversion de couleur appropriée, en utilisant le profil ICC intégré dans le flux JPEG, contrairement aux autres solutions mentionnées ici.

C'est Java simple et ne nécessite pas JAI. Le code source et les distributions binaires sont disponibles gratuitement sous github.com/haraldk/TwelveMonkeys et sont couverts par une licence de style BSD.

Une fois que vous l'avez installé, il vous permet de lire les fichiers JPEG CMJN à l'aide ImageIO.read(...) comme ceci:

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

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

+0

Merci! Je souhaitais quelque chose comme ça. Avez-vous un readme/docs? :) ou devrais-je simplement vérifier les tests? Merci encore –

+4

Désolé, la documentation est clairsemée pour le moment. Cependant, il s'agit d'un plugin ImageIO, donc si vous voulez simplement lire un JPEG CMJN, procédez comme suit: Construisez les fichiers JAR en utilisant Maven, placez-le dans classpath et ImageIO.read (cmykJPEGFile) devrait fonctionner. N'hésitez pas à demander, s'il y a quelque chose de spécifique que vous aimeriez faire. :-) – haraldK

+1

Cool, joli plugin que vous avez là. – medopal

0

Je le corrige par ceci. seulement besoin ajouter cette dépendance. Je peux lire l'image CMJN par ImageIO. TwelveMonkeys

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