Paramétrage du niveau de compression jpg avec ImageIO en Java

j'utilise javax.imageio.ImageIO pour enregistrer un BufferedImage comme fichier jpeg. En particulier, j'ai créé la fonction Java suivante:

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

de même que tout logiciel de manipulation d'image, je souhaite changer le niveau de compression du fichier jpeg. Cependant, je cherche cette option qui semble manquer dans ImageIO .

puis-je régler le niveau de compression et comment?

33
demandé sur mat_boy 2013-06-14 16:12:42

2 réponses

vous devez utiliser JPEGImageWriteParam et ensuite enregistrer l'image avec ImageWriter.write() . Avant d'écrire, définissez la sortie via ImageWriter.setOutput .

régler le niveau de compression comme suit:

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

1f est un nombre de flotteurs qui représente 100% de qualité. La valeur par défaut est autour de 70% si Je ne me souviens pas mal.

MODIFIER

Ensuite, vous devez procédez 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 short way (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 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);
37
répondu JeanValjean 2018-08-23 08:39:31

une façon plus succincte est d'obtenir le ImageWriter directement 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 à La ImageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT) est nécessaire afin de définir explicitement la compression (qualité).

Dans ImageWriteParam.setCompressionQuality() 1.0f est une qualité maximale, minimale de compression, tandis que 0.0f est de qualité minimum, le maximum de la compression.

ImageWriter.setOutput doit être passé un ImageOutputStream . Alors que la méthode accepte Object , selon la documentation, elle n'est généralement pas supportée:

utilisation d'un Object général autre qu'un ImageOutputStream 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éthode getOutputTypes du fournisseur de services du rédacteur; la plupart des rédacteurs retourneront un tableau à un seul élément contenant seulement ImageOutputStream.class pour indiquer que ils n'acceptent qu'un ImageOutputStream .

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 mise en œuvre de ImageOutputStream qui écrit sa sortie à une régulière OutputStream . Généralement utilisé avec ByteArrayOutputStream (merci pour le tuyau, @lmiguelmh !).
47
répondu Igor Klimer 2017-05-23 10:31:13