java - No se puede leer la imagen JPEG con ImageIO.read(Archivo)
javax.imageio (6)
Tengo problemas para leer este archivo JPEG utilizando ImageIO.read (Archivo): arroja una excepción con el mensaje "Tipo de imagen no admitida".
He probado otras imágenes JPEG, y parecen funcionar bien.
La única diferencia que he podido detectar es que este archivo parece incluir una miniatura: ¿se sabe que causa problemas con ImageIO.read ()?
EDITAR:
Se agregó la imagen resultante:
Encontré https://.com/questions/22409... aquí también, esta tiene una gran conversión de color
Y combinados ambos para obtener esto:
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;
}
Llego un poco tarde a la fiesta. Pero probablemente valga la pena que publique mi respuesta ya que ninguna de las respuestas realmente resuelve el problema.
La solución requiere Sanselan (o Apache Commons Imaging como se llama ahora) y requiere un perfil de color CMYK razonable (archivo .icc). Puede obtener el último de Adobe o de eci.org.
El problema básico es que Java, de fábrica, solo puede leer archivos JPEG en RGB. Si tiene un archivo CMYK, necesita distinguir entre CMYK normal, Adobe CMYK (con valores invertidos, es decir, 255 para sin tinta y 0 para tinta máxima) y Adobe CYYK (también una variante con colores invertidos).
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;
}
}
El código primero intenta leer el archivo usando el método regular, que funciona para archivos RGB. Si falla, lee los detalles del modelo de color (perfil, marcador de Adobe, variante de Adobe). Luego lee los datos brutos de píxel (ráster) y realiza toda la conversión necesaria (YCCK a CMYK, colores invertidos, CMYK a RGB).
No estoy del todo satisfecho con mi solución. Mientras que los colores son en su mayoría buenos, las áreas oscuras son un poco demasiado brillantes, en particular, el negro no es completamente negro. Si alguien sabe lo que podría mejorar, me gustaría escucharlo.
Lo arreglo por esto. solo es necesario agregar esta dependencia. Puedo leer una imagen CMYK con ImageIO. github.com/haraldk/TwelveMonkeys
ImageIO.read(new URL("http://img3.tianyancha.com/api/9b80a61183787909e719c77fd0f78103.png"))
Publicación anterior, pero para futuras referencias:
Inspirado por esta pregunta y los enlaces que se encuentran aquí, he escrito un plugin JPEGImageReader para ImageIO que admite modelos de color CMYK (ambos con el modelo de color original, o convertido implícitamente a RGB en lectura). El lector también realiza una conversión de color adecuada, utilizando el perfil ICC integrado en la secuencia JPEG, en contraste con otras soluciones mencionadas aquí.
Es Java simple y no requiere JAI. El código fuente y las distribuciones binarias están disponibles de forma gratuita en github.com/haraldk/TwelveMonkeys , y están cubiertos por una licencia de estilo BSD.
Una vez que lo tiene instalado, le permite leer ImageIO.read(...)
JPEG CMYK usando ImageIO.read(...)
esta manera:
File cmykJPEGFile = new File(/*path*/);
BufferedImage image = ImageIO.read(cmykJPEGFile);
Es decir: en la mayoría de los casos, no es necesario modificar su código.
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();
Su imagen "Color Model" es CMYK, JPEGImageReader
(la clase interna que lee su archivo) solo lee RGB Color Model.
Si insistes en leer imágenes CMYK, entonces necesitarás convertirlas, prueba este código.
ACTUALIZAR
Lea una imagen CMYK en 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);
ACTUALIZACIÓN - Marzo de 2015 - Agregar imágenes de simulación
Las imágenes originales se eliminaron de Dropbox de OP. Así que estoy agregando nuevas imágenes (no los originales) que simulan el problema que estaba sucediendo con ellos.
La primera imagen es cómo se ve una imagen RGB normal.
La segunda imagen es cómo se verá la misma imagen en el modelo de color CMYK.
Realmente no se puede ver cómo se ve en la web porque el host lo convertirá en RGB. Para ver exactamente cómo se ve, tome la imagen RGB y ejecútela a través de un convertidor RGB a CMYK.
La tercera imagen es cómo se verá la imagen CMYK cuando se lea y luego se escriba usando Java ImageIO.
El problema que estaba pasando con OP es que tenían algo así como la imagen 2, que arroja una excepción cuando intentas leerla.