J'utilise javax.imageio.ImageIO
pour enregistrer un BufferedImage
en tant que fichier jpeg. En particulier, j'ai créé la fonction Java 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);
}
}
Comme pour tout logiciel de manipulation d'images, je souhaite modifier le niveau de compression du fichier jpeg. Cependant, je recherche cette option qui semble manquer dans ImageIO
.
Puis-je définir le niveau de compression et comment?
Vous devez utiliser JPEGImageWriteParam
puis enregistrer l'image avec ImageWriter.write()
. Avant d'écrire, définissez la sortie via ImageWriter.setOutput
.
Définissez le niveau de compression comme suit:
JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null);
jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpegParams.setCompressionQuality(1f);
Où 1f
est un nombre flottant qui signifie 100% de qualité. La valeur par défaut est environ 70% si je ne me souviens pas mal.
[~ # ~] modifier [~ # ~]
Ensuite, vous devez procéder comme suit pour obtenir une instance d'un ImageWriter
. Il y a deux façons, une courte et une longue (je garde les deux, juste au cas où).
Le court chemin (suggéré par lapo dans un commentaire) est:
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);
ou plus long chemin
// 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);
Une manière plus succincte consiste à obtenir le ImageWriter
directement à partir de 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();
L'appel à ImageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT)
est nécessaire afin de définir explicitement le niveau de compression (qualité).
Dans ImageWriteParam.setCompressionQuality()
1.0f
Est la qualité maximale, compression minimale, tandis que 0.0f
Est la qualité minimale, compression maximale.
ImageWriter.setOutput
Doit être passé un ImageOutputStream
. Bien que la méthode accepte Object
, selon la documentation, elle n'est généralement pas prise en charge:
L'utilisation d'un
Object
général autre qu'unImageOutputStream
est destiné aux rédacteurs qui interagissent directement avec un périphérique de sortie ou un protocole d'imagerie. L'ensemble des classes juridiques est annoncé par la méthodegetOutputTypes
du fournisseur de services de l'auteur; la plupart des rédacteurs renverront un tableau à un seul élément contenant uniquementImageOutputStream.class
pour indiquer qu'ils acceptent uniquement unImageOutputStream
.
La plupart des cas doivent être traités par ces deux classes:
FileImageOutputStream
- une implémentation de ImageOutputStream
qui écrit sa sortie directement dans un File
ou RandomAccessFile
.MemoryCacheImageOutputStream
- une implémentation de ImageOutputStream
qui écrit sa sortie dans un OutputStream
normal. Habituellement utilisé avec ByteArrayOutputStream
(merci pour l'astuce, @ lmiguelmh !).Une méthode plus générale sera (de réponse d'Igor ):
static void saveImage(BufferedImage image,File jpegFiletoSave,float quality) throws IOException{
// save jpeg image with specific quality. "1f" corresponds to 100% , "0.7f" corresponds to 70%
ImageWriter jpgWriter = ImageIO.getImageWritersByFormatName("jpg").next();
ImageWriteParam jpgWriteParam = jpgWriter.getDefaultWriteParam();
jpgWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
jpgWriteParam.setCompressionQuality(quality);
jpgWriter.setOutput(ImageIO.createImageOutputStream(jpegFiletoSave));
IIOImage outputImage = new IIOImage(image, null, null);
jpgWriter.write(null, outputImage, jpgWriteParam);
jpgWriter.dispose();
}