Настройка уровня сжатия jpg с помощью ImageIO в Java

Я использую javax.imageio.ImageIO сохранить BufferedImage как файл jpeg. В частности, я создал следующую функцию 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);
        }
}

аналогично любому программному обеспечению для обработки изображений, я хочу изменить уровень сжатия файла jpeg. Тем не менее, я ищу эту опцию, которая, кажется, отсутствует в ImageIO.

могу ли я установить уровень сжатия и как?

2 ответов


вы должны использовать JPEGImageWriteParam а затем сохраните изображение с помощью ImageWriter.write(). Прежде чем писать, установите выход через ImageWriter.setOutput.

установить уровень сжатия следующим образом:

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

здесь 1f номер поплавка который стоит для качества 100%. Значение по умолчанию:около 70% если я не ошиблась.

редактировать

тогда, вы должны сделать следующее, Чтобы получить пример ImageWriter. Есть два пути, короткий и длинный (я так, на всякий случай).

The короткий путь (по предложению Лапо в одном комментарии):

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

или времени

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

более краткий способ-получить ImageWriter непосредственно с 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();

вызов ImageWriteParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT) необходимо для того, чтобы явно установить уровень сжатия (качество).

на ImageWriteParam.setCompressionQuality() 1.0f максимальное качество, минимальное обжатие, пока 0.0f минимальное качество, максимальное обжатие.

ImageWriter.setOutput должен быть передан ImageOutputStream. Хотя метод принимает Object, согласно документации обычно нет поддерживается:

использование общего Object кроме ImageOutputStream предназначено для писателей которые взаимодействуют сразу с прибором вывода или протоколом воображения. Набор юридических классов рекламируется поставщиком услугgetOutputTypes метод; большинство авторов вернут одноэлементный массив, содержащий только ImageOutputStream.class указать, что они принимают только ImageOutputStream.

большинство случаев должны обрабатываться этими двумя классы:

  • FileImageOutputStream - реализация ImageOutputStream который записывает свой вывод непосредственно в File или RandomAccessFile.
  • MemoryCacheImageOutputStream - реализация ImageOutputStream который записывает свой вывод в обычный OutputStream. Обычно используется с ByteArrayOutputStream (спасибо за совет, @lmiguelmh!).