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 deImageOutputStream
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étodogetOutputTypes
del proveedor de servicios delgetOutputTypes
; la mayoría de los escritores devolverá una matriz de un solo elemento que solo contengaImageOutputStream.class
para indicar que solo aceptan unImageOutputStream
.
La mayoría de los casos deben ser manejados por estas dos clases:
-
FileImageOutputStream
: una implementación deImageOutputStream
que escribe su salida directamente en unFile
oRandomAccessFile
. -
MemoryCacheImageOutputStream
: una implementación deImageOutputStream
que escribe su salida en unOutputStream
regular. Usualmente se usa conByteArrayOutputStream
(gracias por la sugerencia, @lmiguelmh !).