Как и в любом программном обеспечении для обработки изображений, я хочу изменить уровень сжатия файла jpeg. Однако я ищу эту опцию, которая, похоже, отсутствует в ImageIO.
Могу ли я установить уровень сжатия и как?
Переведено автоматически
Ответ 1
Более лаконичный способ - получить ImageWriter непосредственно из ImageIO:
ImageOutputStreamoutputStream= createOutputStream(); // For example implementations see below jpgWriter.setOutput(outputStream); IIOImageoutputImage=newIIOImage(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 методом поставщика услуг writer; большинство writer возвращают одноэлементный массив, содержащий только ImageOutputStream.class, чтобы указать, что они принимают только an ImageOutputStream.
В большинстве случаев эти два класса должны обрабатываться:
FileImageOutputStream - реализация ImageOutputStream, которая записывает свои выходные данные непосредственно в File или RandomAccessFile.
MemoryCacheImageOutputStream - реализация ImageOutputStream, которая записывает свои выходные данные в обычный OutputStream формат. Обычно используется с ByteArrayOutputStream (спасибо за совет, @lmiguelmh!).
Где 1f - число с плавающей точкой, обозначающее 100% качество. Значение по умолчанию - около 70%, если я не ошибаюсь.
Редактировать
Затем вам нужно сделать следующее, чтобы получить экземпляр an ImageWriter. Есть два способа, короткий и длинный (я сохраняю оба, на всякий случай).
Короткий способ (предложенный лапо в одном комментарии) заключается в следующем:
finalImageWriterwriter= ImageIO.getImageWritersByFormatName("jpg").next(); // specifies where the jpg image has to be written writer.setOutput(newFileImageOutputStream( newFile(folder.toString() + "/" + filename + ".jpg")));
// writes the file with given compression level // from your JPEGImageWriteParam instance writer.write(null, newIIOImage(capture, null, null), jpegParams);
или более длинный способ
// use IIORegistry to get the available services IIORegistryregistry= IIORegistry.getDefaultInstance(); // return an iterator for the available ImageWriterSpi for jpeg images Iterator<ImageWriterSpi> services = registry.getServiceProviders(ImageWriterSpi.class, newServiceRegistry.Filter() { @Override publicbooleanfilter(Object provider) { if (!(provider instanceof ImageWriterSpi)) returnfalse;
ImageWriterSpiwriterSPI= (ImageWriterSpi) provider; String[] formatNames = writerSPI.getFormatNames(); for (inti=0; i < formatNames.length; i++) { if (formatNames[i].equalsIgnoreCase("JPEG")) { returntrue; } }
returnfalse; } }, true); //...assuming that servies.hasNext() == true, I get the first available service. ImageWriterSpiwriterSpi= services.next(); ImageWriterwriter= writerSpi.createWriterInstance();
// specifies where the jpg image has to be written writer.setOutput(newFileImageOutputStream( newFile(folder.toString() + "/" + filename + ".jpg")));
// writes the file with given compression level // from your JPEGImageWriteParam instance writer.write(null, newIIOImage(capture, null, null), jpegParams);
staticvoidsaveImage(BufferedImage image,File jpegFiletoSave,float quality)throws IOException{ // save jpeg image with specific quality. "1f" corresponds to 100% , "0.7f" corresponds to 70%
/** * Work method. * Reads the jpeg image in rendImage, compresses the image, and writes it back out to outfile. * JPEGQuality ranges between 0.0F and 1.0F, 0-lowest, 1-highest. ios is closed internally * * @param rendImage [@link RenderedImage} instance with an Rendered Image * @param ios {@link ImageOutputStream} instance, * note that it is disposed in this method * @param JPEGQuality float value for the JPEG compression quality (0..1(max)) * @return {@code true} if image was successfully compressed * else {@code false} on any error, e.g. bad (null) parameters */ publicstaticbooleancompressJpegFile( RenderedImage rendImage, ImageOutputStream ios, float JPEGQuality ) { if ( rendImage == null ) returnfalse; if ( ios == null ) returnfalse; if ( ( JPEGQuality <= 0.0F ) || ( JPEGQuality > 1.0F ) ) returnfalse; ImageWriterwriter=null; try {
// Find a jpeg writer Iteratoriter= ImageIO.getImageWritersByFormatName( "jpg" ); if ( iter.hasNext() ) writer = (ImageWriter) iter.next();
if ( writer == null ) thrownewIllegalArgumentException( "jpg writer not found by call to ImageIO.getImageWritersByFormatName( \"jpg\" )" ); writer.setOutput( ios );
// Set the compression quality ImageWriteParamiwparam=newMyImageWriteParam(); iwparam.setCompressionMode( ImageWriteParam.MODE_EXPLICIT ); iwparam.setCompressionQuality( JPEGQuality ); // float res = iwparam.getCompressionQuality();