2010-03-09 26 views
37

Mam problem z odczytaniem tego pliku JPEG przy użyciu ImageIO.read (plik pliku) - zgłasza wyjątek z komunikatem "Nieobsługiwany typ obrazu".Nie można odczytać obrazu JPEG przy użyciu ImageIO.read (plik pliku)

Próbowałem innych obrazów JPEG i wydaje się, że działają dobrze.

Jedyną różnicą, jaką udało mi się zauważyć, jest to, że plik ten zawiera miniaturę - czy wiadomo, że powoduje problemy z ImageIO.read()?

Troublesome image

EDIT:

Dodany obraz wynikowy:

Strange colors

+0

Byłoby przydatne, aby zobaczyć stacktrace od wyjątku. – simonlord

+8

Proszę przywrócić obrazy! – math

Odpowiedz

34

Twój obraz "Model kolorów" to CMYK, JPEGImageReader (wewnętrzna klasa, która odczytuje plik) odczytuje tylko Model kolorów RGB.

Jeśli nalegasz na odczytywanie obrazów CMYK, musisz je przekonwertować, spróbuj tego kodu.

UPDATE

Czytaj obrazu CMYK do 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); 

UPDATE - marzec 2015 - Dodawanie obrazów symulacyjnych

Oryginalne obrazy zostały usunięte z Dropbox OP. Dodaję więc nowe obrazy (nie oryginały), które symulują problem, który się z nimi działo.

Pierwsze zdjęcie przedstawia wygląd normalnego obrazu RGB.

Image RGB

Drugi obraz jest ten sam obraz, jak będzie wyglądać w modelu kolorów CMYK.

Nie można zobaczyć, jak wygląda w Internecie, ponieważ zostanie przekonwertowany na hosta przez RGB. Aby zobaczyć dokładnie, jak wygląda, weź obraz RGB i przeprowadź go przez konwerter RGB na CMYK.

Trzeci obraz to sposób, w jaki obraz CMYK będzie wyglądał po przeczytaniu, a następnie zapisany przy użyciu Java ImageIO.

Image CMYK read through Java RGB

Problem, że dzieje się z OP to oni mieli coś takiego obrazu 2, która zgłasza wyjątek podczas próby, aby ją przeczytać.

+0

Doskonale, spróbuję. Czy będzie działać również dla obrazów RGB, czy będę musiał jakoś wykryć typ? – Malakim

+0

Znajdziesz wiele sposobów na wykrycie modelu kolorów, moim preferowanym jest użycie JPEGImageReader, jeśli rzuci wyjątek 'Unsupported Image Type', a następnie najprawdopodobniej CMYK. – medopal

+1

To działa wystarczająco dobrze, jednak kolory się popsują.Zobacz nowy obraz dołączony do pytania. Czy masz jakieś rady dotyczące tego? Dzięki! – Malakim

5

znalazłem https://stackoverflow.com/questions/22409... tutaj jak dobrze, ten ma wielkie konwersji kolorów

I połączeniu zarówno uzyskać to:

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

To była jedyna odpowiedź, którą znalazłem, która rozwiązuje problem z zielonymi odcieniami w plikach JPEG, które mają kilka pytań na temat 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

Z dokumentacji interfejsu API: 'Zwróć uwagę, że klasy w pakiecie com.sun.image.codec.jpeg nie są częścią podstawowych interfejsów API Java. Są częścią dystrybucji JDK i JRE firmy Sun. Chociaż inni licencjobiorcy mogą zdecydować się na dystrybucję tych klas, programiści nie mogą polegać na ich dostępności w implementacjach innych niż Sun. Oczekujemy, że odpowiednia funkcjonalność będzie ostatecznie dostępna w rdzeniu API lub rozszerzeniu standardowym. " – Omertron

18

jestem trochę spóźniony na imprezę. Ale prawdopodobnie nadal warto opublikować odpowiedź, ponieważ żadna z odpowiedzi nie rozwiązuje problemu.

Rozwiązanie wymaga Sanselan (lub Apache Commons Imaging jak to się nazywa teraz) i wymaga rozsądnego profilu kolorów CMYK (plik .icc). Możesz pobrać później z Adobe lub z eci.org.

Podstawowym problemem jest to, że Java - po wyjęciu z pudełka - może tylko czytać pliki JPEG w RGB. Jeśli masz plik CMYK, musisz rozróżnić zwykłe CMYK, Adobe CMYK (z wartościami odwróconymi, tj. 255 dla braku atramentu i 0 dla maksymalnego atramentu) i Adobe CYYK (niektóre wersje również z odwróconymi kolorami).

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

Kod próbuje najpierw odczytać plik przy użyciu zwykłej metody, która działa dla plików RGB. Jeśli się nie powiedzie, odczytuje szczegóły modelu kolorów (profil, znacznik Adobe, wariant Adobe). Następnie odczytuje surowe dane pikseli (rastrowe) i wykonuje całą niezbędną konwersję (YCCK na CMYK, odwrócone kolory, CMYK na RGB).

Nie jestem całkiem zadowolony z mojego rozwiązania. Chociaż kolory są w większości dobre, ciemne obszary są nieco zbyt jasne, w szczególności czerń nie jest całkowicie czarna. Jeśli ktokolwiek wie, co mogę poprawić, byłbym zadowolony, słysząc to.

+0

To jest najlepsza odpowiedź, którą znalazłem na tym, ale czy nie chcesz zamknąć ImageInputStream w bloku finally? – Amalgovinus

+0

Dzięki za fragment kodu, działa dobrze. (ISOcoated_v2_300_eci.icc można znaleźć tutaj: http://www.humburg.de/?page=4) – user2198875

40

Stary post, ale na przyszłość:

Zainspirowany to pytanie i linki znalezione tu pisałem wtyczki JPEGImageReader dla ImageIO który obsługuje modele kolorów CMYK (zarówno z oryginalnego modelu kolorów lub niejawnie konwertowane do RGB przy odczycie). Czytnik wykonuje także odpowiednią konwersję kolorów, używając profilu ICC osadzonego w strumieniu JPEG, w przeciwieństwie do innych rozwiązań tutaj wymienionych.

Jest to zwykła Java i nie wymaga JAI. Kod źródłowy i dystrybucje binarne są dostępne bezpłatnie pod adresem github.com/haraldk/TwelveMonkeys i są objęte licencją typu BSD.

Gdy masz go zainstalowanego, to pozwala na odczyt JPEG CMYK z wykorzystaniem ImageIO.read(...) takiego:

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

tj .: W większości przypadków nie jest to konieczne, aby zmodyfikować kod.

+0

Dzięki! Pragnąłem czegoś takiego. Czy masz plik readme/docs? :) czy powinienem po prostu sprawdzić testy? Jeszcze raz dziękuję –

+4

Niestety, dokumentacja jest w tej chwili skąpa. Jest to jednak wtyczka ImageIO, więc jeśli chcesz tylko odczytać obraz CMYK JPEG, wykonaj następujące czynności: Zbuduj JAR-y używając Mavena, umieszczając w ścieżce klas i ImageIO.read (cmykJPEGFile) powinno po prostu działać. Możesz zapytać, czy jest coś konkretnego, co chcesz zrobić. :-) – haraldK

+1

Fajna, ładna wtyczka, którą tam masz. – medopal

0

Naprawię to przez to. wystarczy dodać tę zależność. mogę odczytać obraz CMYK przez ImageIO. TwelveMonkeys

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