imageio example java jpeg image-compression javax.imageio

imageio - image java example



Estableciendo el nivel de compresiĆ³n jpg con ImageIO en Java (2)

Tienes que usar JPEGImageWriteParam y luego guardar la imagen con ImageWriter.write() . Antes de escribir, configure la salida mediante ImageWriter.setOutput .

Establezca el nivel de compresión de la siguiente manera:

JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null); jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); jpegParams.setCompressionQuality(1f);

Donde 1f es un número flotante que representa el 100% de calidad. El valor predeterminado es alrededor del 70% si no recuerdo mal.

EDITAR

Luego, debe hacer lo siguiente para obtener una instancia de un ImageWriter . Hay dos formas, una corta y una larga (mantengo ambas, por las dudas).

El camino corto (sugerido por lapo en un comentario) es:

final ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next(); // specifies where the jpg image has to be written writer.setOutput(new FileImageOutputStream( new File(folder.toString() + "/" + filename + ".jpg"))); // writes the file with given compression level // from your JPEGImageWriteParam instance writer.write(null, new IIOImage(capture, null, null), jpegParams);

o más largo

// use IIORegistry to get the available services IIORegistry registry = IIORegistry.getDefaultInstance(); // return an iterator for the available ImageWriterSpi for jpeg images Iterator<ImageWriterSpi> services = registry.getServiceProviders(ImageWriterSpi.class, new ServiceRegistry.Filter() { @Override public boolean filter(Object provider) { if (!(provider instanceof ImageWriterSpi)) return false; ImageWriterSpi writerSPI = (ImageWriterSpi) provider; String[] formatNames = writerSPI.getFormatNames(); for (int i = 0; i < formatNames.length; i++) { if (formatNames[i].equalsIgnoreCase("JPEG")) { return true; } } return false; } }, true); //...assuming that servies.hasNext() == true, I get the first available service. ImageWriterSpi writerSpi = services.next(); ImageWriter writer = writerSpi.createWriterInstance(); // specifies where the jpg image has to be written writer.setOutput(new FileImageOutputStream( new File(folder.toString() + "/" + filename + ".jpg"))); // writes the file with given compression level // from your JPEGImageWriteParam instance writer.write(null, new IIOImage(capture, null, null), jpegParams);

Estoy usando javax.imageio.ImageIO para guardar una imagen BufferedImage como un archivo jpeg. En particular, creé la siguiente función de Java:

public static void getScreenShot(BufferedImage capture, Path folder, String filename) { try { ImageIO.write(capture, "jpeg", new File(folder.toString()+"/"+filename+".jpg")); } catch (AWTException | IOException ex) { Logger.getLogger(ScreenShotMaker.class.getName()).log(Level.SEVERE, null, ex); } }

Del mismo modo que cualquier software de manipulación de imágenes, deseo cambiar el nivel de compresión del archivo jpeg. Sin embargo, estoy buscando esta opción que parece estar ausente en ImageIO .

¿Puedo establecer el nivel de compresión y cómo?


Una forma más sucinta es obtener el ImageWriter directamente desde ImageIO :

ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName("jpg").next(); ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam(); jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); jpgWriteParam.setCompressionQuality(0.7f); ImageOutputStream outputStream = createOutputStream(); // For example implementations see below jpgWriter.setOutput(outputStream); IIOImage outputImage = new IIOImage(image, null, null); jpgWriter.write(null, outputImage, jpgWriteParam); jpgWriter.dispose();

La llamada a ImageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT) es necesaria para establecer explícitamente el nivel de compresión (calidad).

En ImageWriteParam.setCompressionQuality() 1.0f es la calidad máxima, la compresión mínima, mientras que 0.0f es la calidad mínima, la compresión máxima.

ImageWriter.setOutput debe pasar un ImageOutputStream . Mientras que el método acepta Object , según la documentación, generalmente no es compatible:

El uso de un Object general distinto de ImageOutputStream está destinado a escritores que interactúan directamente con un dispositivo de salida o un protocolo de imágenes. El conjunto de clases legales se anuncia mediante el método getOutputTypes del proveedor de servicios del getOutputTypes ; la mayoría de los escritores devolverá una matriz de un solo elemento que solo contenga ImageOutputStream.class para indicar que solo aceptan un ImageOutputStream .

La mayoría de los casos deben ser manejados por estas dos clases:

  • FileImageOutputStream : una implementación de ImageOutputStream que escribe su salida directamente en un File o RandomAccessFile .
  • MemoryCacheImageOutputStream : una implementación de ImageOutputStream que escribe su salida en un OutputStream regular. Usualmente se usa con ByteArrayOutputStream (gracias por la sugerencia, @lmiguelmh !).