Статьи

Сжатие изображений JPG с помощью Groovy

Недавно мне пришлось уменьшить размер большого количества изображений JPG. Я не хотел делать это по одному в инструменте манипулирования графикой, поэтому сценарии казались очевидным выбором. В настоящее время Groovy — мой любимый инструмент для написания сценариев. Я отметил, что Эрик Венделин разместил изображения Crush в командной строке с Groovy, который демонстрирует использование Groovy в сочетании с ImageMagick для «[сжатия] изображений способом Groovy». Это выглядит как простой и привлекательный способ сделать это, но требует ImageMagick и, если на Windows, Cygwin . Я решил написать аналогичный скрипт, используя прямую Java и Groovy, чтобы посмотреть, смогу ли я уменьшить требуемые зависимости. Обратите внимание, что этот сценарий был бы более кратким, если бы я использовалJava Advanced Imaging API , но это означало бы еще одну отдельную зависимость .

rescaleJpgImage.groovy

import java.awt.Image
import java.awt.image.BufferedImage
import java.awt.image.RenderedImage
import javax.imageio.IIOImage
import javax.imageio.ImageIO
import javax.imageio.ImageWriteParam
import javax.imageio.ImageWriter
import javax.imageio.stream.FileImageOutputStream

if (args.length < 2)
{
   println "USAGE: groovy rescaleImage.groovy <sourceDirectory> <scalingFactor>\n"
   println "\twhere <sourceDirectory> is directory from which image files come"
   println "\t      <scalingFactor> is scaling factor for reduced image (0 to 1)"
   System.exit(-1)
}

def directoryPath = args[0]
def directory = new File(directoryPath)
if (!directory.isDirectory())
{
   println "${directoryPath} is NOT an existing directory!"
   System.exit(-1)
}

def scaleFactor = args[1] as float
def iter = ImageIO.getImageWritersByFormatName("jpeg")
def writer = (ImageWriter)iter.next()
def imageWriteParameters = writer.getDefaultWriteParam()
imageWriteParameters.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
imageWriteParameters.setCompressionQuality(scaleFactor);

def backupDirName = "backup_" + System.currentTimeMillis()
def targetDirectory = new File(backupDirName)
targetDirectory.mkdir()
def targetDirectoryPath = targetDirectory.canonicalPath
directory.eachFile
{ file ->
   def fullFileName = file.canonicalPath
   def fileName = file.name
   def sourceImage = ImageIO.read(new File(fullFileName))
   def targetName = targetDirectoryPath + File.separator + fileName
   println "Copying ${fullFileName} to ${targetName} with scale factor of ${scaleFactor} ..."
   def targetFile = new File(targetName);
   def output = new FileImageOutputStream(targetFile);
   writer.setOutput(output);
   def image = new IIOImage(sourceImage, null, null);
   writer.write(null, image, imageWriteParameters);
}
writer.dispose();

Приведенный выше скрипт Groovy не изменяет входные файлы изображений, а перезаписывает их с тем же именем в новый каталог. Новый каталог именуется путем объединения миллисекунд со времени эпохи после «backup_». Файлы записываются в формате JPG и масштабируются с учетом предоставленного коэффициента масштабирования.

Этот сценарий был достаточен для моих нужд, но есть много способов его улучшить. Groovy встроенных в CLI на основе поддержки командной строки можно использовать для более хорошей обработки параметров командной строки. Можно было бы лучше проверить, чтобы убедиться, что предоставленный коэффициент масштабирования является цифрой от 0 до 1. Этот сценарий также предполагает, что все изображения, которые должны быть сжаты, уже имеют формат JPEG. Использование таких библиотек, как Java Advanced Imaging API , ImageMagick или imgscalr, могло бы сделать сценарий еще более лаконичным.

Результаты сжатия

ОБНОВЛЕНИЕ: Этот раздел добавлен к исходному сообщению на основе отзывов Эрика Венделина (см. Ниже). Следующий снимок экрана пытается показать результаты сжатия с точки зрения размеров файла изображения. Самые левые файлы — это исходные файлы. Средний набор файлов был сгенерирован путем запуска вышеуказанного сценария для исходных файлов с коэффициентом масштабирования 0,5. Самый правый набор файлов является результатом запуска сценария для исходных файлов с коэффициентом масштабирования 0,25.

В качестве заключительной части сравнения результатов сжатия я включаю изображение, сделанное в течение недели в Сан-Франциско для JavaOne 2011, во все три формы ниже. Первое — это исходное изображение (3,62 МБ), второе — изображение, созданное с масштабным коэффициентом 0,5 (482 КБ), а третье — изображение, созданное с масштабным коэффициентом 0,25 (326 КБ).

Все три версии изображения Fisherman’s Wharf, включая оригинал, представлены в формате JPEG. Одним из недостатков приведенного выше сценария является то, что этот формат предполагается. Следующие два снимка экрана показывают, что происходит, когда более раннее изображение PNG, сравнивающее размеры файла, запускается через этот скрипт.

Добавление возможности обрабатывать другие форматы изображений в качестве входных файлов — вот где отдельная библиотека для работы с изображениями, такая как ImageMagick, может быть особенно полезна.

Вывод

Это еще один пример того, как Groovy сочетает в себе лучшие скрипты с многофункциональными библиотеками Java. Вышеприведенный скрипт мог быть написан на Java, но Groovy кажется более подходящим для таких скриптов, как этот.

 

От http://marxsoftware.blogspot.com/2011/11/compressing-jpg-images-with-groovy.html