2010-03-09 4 views
37

Ho problemi a leggere questo file JPEG utilizzando ImageIO.read (File file) - genera un'eccezione con il messaggio "Tipo di immagine non supportato".Impossibile leggere l'immagine JPEG utilizzando ImageIO.read (File file)

Ho provato altre immagini JPEG e sembrano funzionare correttamente.

L'unica differenza che sono riuscito a individuare è che questo file sembra includere una miniatura: è noto che causa problemi con ImageIO.read()?

Troublesome image

EDIT:

Aggiunto l'immagine risultante:

Strange colors

+0

sarebbe utile per vedere la StackTrace dal l'eccezione. – simonlord

+8

Si prega di ripristinare le immagini! – math

risposta

34

La tua immagine "Modello di colore" è CMYK, JPEGImageReader (classe interna che legge il file) legge solo Modello a colori RGB.

Se si desidera leggere le immagini CMYK, sarà necessario convertirle, provare questo codice.

UPDATE

Leggi un'immagine CMYK in RGB 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); 

AGGIORNAMENTO - marzo 2015 - L'aggiunta di immagini di simulazione

Le immagini originali sono state rimosse dal set di OP. Quindi aggiungo nuove immagini (non quelle originali) che simulano il problema che stava accadendo con loro.

Prima immagine è l'aspetto di un'immagine RGB normale.

Image RGB

seconda immagine è come la stessa immagine sarà simile nel modello di colore CMYK.

In realtà non è possibile vedere come appare sul Web perché sarà convertito in RGB dall'host. Per vedere esattamente come appare, prendere l'immagine RGB ed eseguirla attraverso un convertitore da RGB a CMYK.

Terza immagine è l'aspetto dell'immagine CMYK quando viene letta e scritta utilizzando Java ImageIO.

Image CMYK read through Java RGB

Il problema che stava accadendo con OP è che avevano qualcosa come immagine 2 che genera un'eccezione quando si tenta di leggerlo.

+0

Eccellente, ci provo. Funzionerà anche per le immagini RGB o dovrò rilevare il tipo in qualche modo? – Malakim

+0

Troverai molti modi per rilevare il modello di colore, il mio preferito è usare JPEGImageReader, se lancia l'eccezione "Tipo di immagine non supportato" quindi probabilmente CMYK. – medopal

+1

Funziona abbastanza bene, tuttavia, i colori diventano tutti incasinati.Guarda la nuova immagine che ho allegato alla domanda. Hai qualche consiglio in merito? Grazie! – Malakim

5

ho trovato https://stackoverflow.com/questions/22409... qui come bene, questo fa un grande conversione del colore

e combinati sia per ottenere questo:

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

Questa è stata l'unica risposta che ho trovato che risolve il problema con le tinte verdi su JPEG che hanno diverse domande su 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

Dalla documentazione dell'API: 'Si noti che le classi nel pacchetto com.sun.image.codec.jpeg non fanno parte delle API Java principali. Fanno parte delle distribuzioni JDK e JRE di Sun. Sebbene altri licenziatari possano scegliere di distribuire queste classi, gli sviluppatori non possono dipendere dalla loro disponibilità in implementazioni non Sun. Ci aspettiamo che la funzionalità equivalente alla fine sarà disponibile in un'API principale o un'estensione standard. – Omertron

18

Sono un po 'in ritardo per la festa. Ma probabilmente vale ancora la pena di pubblicare la mia risposta in quanto nessuna delle risposte risolve il problema.

La soluzione richiede Sanselan (o Apache Commons Imaging come viene chiamato ora) e richiede un profilo colore CMYK ragionevole (file .icc). È possibile ottenere il successivo da Adobe o da eci.org.

Il problema di base è che Java - out of the box - può solo leggere file JPEG in RGB. Se si dispone di un file CMYK, è necessario distinguere tra normale CMYK, Adobe CMYK (con valori invertiti, vale a dire 255 per nessun inchiostro e 0 per il massimo dell'inchiostro) e Adobe CYYK (anche alcune varianti con colori invertiti).

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

Il codice tenta innanzitutto di leggere il file utilizzando il metodo normale, che funziona per i file RGB. Se fallisce, legge i dettagli del modello di colore (profilo, marcatore Adobe, variante Adobe). Quindi legge i dati grezzi dei pixel (raster) e fa tutta la conversione necessaria (da YCCK a CMYK, colori invertiti, da CMYK a RGB).

Non sono abbastanza soddisfatto della mia soluzione. Mentre i colori sono per lo più buoni, le aree scure sono leggermente troppo luminose, in particolare il nero non è completamente nero. Se qualcuno sa cosa potrei migliorare, sarei felice di sentirlo.

+0

Questa è la risposta migliore che ho trovato su questo, ma non vuoi chiudere ImageInputStream in un blocco finale? – Amalgovinus

+0

Grazie per lo snippet di codice, funziona perfettamente. (ISOcoated_v2_300_eci.icc può essere trovato qui: http://www.humburg.de/?page=4) – user2198875

40

Vecchio post, ma per riferimento futuro:

Ispirato da questa domanda e collegamenti trovato qui, ho scritto un plugin per JPEGImageReader ImageIO che supporta i modelli di colore CMYK (sia con il modello di colore originale, o implicitamente convertito in RGB on read). Il lettore esegue anche la conversione del colore corretta, utilizzando il profilo ICC incorporato nel flusso JPEG, in contrasto con altre soluzioni menzionate qui.

È semplice Java e non richiede JAI. Il codice sorgente e le distribuzioni binarie sono disponibili gratuitamente allo github.com/haraldk/TwelveMonkeys ed è coperto da una licenza in stile BSD.

volta che lo avete installato, consente di leggere i file JPEG CMYK utilizzando ImageIO.read(...) come questo:

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

cioè .: Nella maggior parte dei casi, non è necessario modificare il codice.

+0

Grazie! Volevo qualcosa di simile. Hai un readme/documenti? :) o dovrei semplicemente controllare i test? Grazie ancora –

+4

Siamo spiacenti, la documentazione è scarsa al momento. Tuttavia, è un plugin ImageIO, quindi se vuoi solo leggere un file CMYK JPEG, procedi come segue: Costruisci i JAR usando Maven, posiziona in classpath e ImageIO.read (cmykJPEGFile) dovrebbe funzionare. Sentiti libero di chiedere, se c'è qualcosa di specifico che ti piacerebbe fare. :-) – haraldK

+1

Cool, bel plugin che hai lì. – medopal

0

l'ho risolto con questo. solo bisogno di aggiungere questa dipendenza. posso leggere l'immagine CMYK di ImageIO. TwelveMonkeys

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