Как мога да преоразмеря изображение с помощта на Java?

1. Въведение

В този урок ще научим как да преоразмерявате (мащабирате) изображение с помощта на Java. Ще проучим както основните Java, така и библиотеките на трети страни с отворен код, които предлагат функцията за преоразмеряване на изображението.

Важно е да споменем, че можем да мащабираме изображенията както нагоре, така и надолу. В примерните кодове в този урок ще преоразмерим изображенията до по-малки размери, тъй като на практика това е най-често срещаният сценарий.

2. Преоразмерете изображение с помощта на Core Java

Core Java предлага следните опции за преоразмеряване на изображения:

  • Преоразмерете с помощта на java.awt.Graphics2D
  • Преоразмерете с помощта на Image # getScaledInstance

2.1. java.awt.Graphics2D

Graphics2D е основният клас за изобразяване на двуизмерни фигури, текст и изображения на платформата Java.

Нека започнем с преоразмеряване на изображение с помощта на Graphics2D :

BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) throws IOException { BufferedImage resizedImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB); Graphics2D graphics2D = resizedImage.createGraphics(); graphics2D.drawImage(originalImage, 0, 0, targetWidth, targetHeight, null); graphics2D.dispose(); return resizedImage; }

Нека да видим как изглежда изображението преди и след преоразмеряване:

Параметърът BufferedImage.TYPE_INT_RGB показва цветния модел на изображението. Пълен списък с наличните стойности е наличен в официалната документация на Java BufferedImage .

Graphics2D приема допълнителни параметри, наречени RenderingHints . Използваме RenderingHints, за да повлияем на различни аспекти на обработката на изображения и най-важното качество на изображението и времето за обработка.

Можем да добавим RenderingHint, използвайки метода setRenderingHint :

graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);

Пълен списък с RenderingHints можете да намерите в този урок за Oracle.

2.2. Image.getScaledInstance ()

Този подход при използване на Image е много прост и създава изображения със задоволително качество:

BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) throws IOException { Image resultingImage = originalImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_DEFAULT); BufferedImage outputImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB); outputImage.getGraphics().drawImage(resultingImage, 0, 0, null); return outputImage; }

Нека да видим какво ще се случи със снимка на нещо вкусно:

Също така можем да насочим механизма за мащабиране да използва един от наличните подходи, като предоставим метода getScaledInstance () с флаг, който указва типа алгоритъм, който да се използва за нуждите ни от преизмерване на изображения:

Image resultingImage = originalImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_SMOOTH);

Всички налични флагове са описани в официалната документация за Java Image.

3. Imgscalr

Imgscalr използва Graphic2D във фонов режим. Той има прост API с няколко различни метода за преоразмеряване на изображението.

Imgscalr ни предоставя или най-добре изглеждащия резултат, най-бързия резултат или балансиран резултат в зависимост от избраната от нас опция за мащабиране. Предлагат се и други функции за манипулиране на изображения - като тези за изрязване и завъртане. Нека покажем как работи в един прост пример.

Ще добавим следната зависимост на Maven:

 org.imgscalr imgscalr-lib 4.2 

Проверете Maven Central за най-новата версия.

Най-простият начин за използване на Imgscalr е:

BufferedImage simpleResizeImage(BufferedImage originalImage, int targetWidth) throws Exception { return Scalr.resize(originalImage, targetWidth); }

Where originalImage is the BufferedImage to be resized and targetWidth is the width of a result image. This approach will keep the original image proportions and use default parameters – Method.AUTOMATIC and Mode.AUTOMATIC.

How does it do with a picture of delicious fruit? Let's see:

The library also allows multiple configuration options, and, it handles image transparency in the background.

The most important parameters are:

  • mode – used to define the resizing modes that the algorithm will use. For example, we can define whether we would like to keep proportions of the image (options are AUTOMATIC, FIT_EXACT, FIT_TO_HEIGHT, and FIT_TO_WIDTH)
  • method – instructs the resizing process so that its focus is on speed, quality, or both. Possible values are AUTOMATIC, BALANCED, QUALITY, SPEED, ULTRA_QUALITY

It's also possible to define additional resize properties that will provide us with logging or direct the library to do some color modifications on the image (make it lighter, darker, grayscale, and so on).

Let's use the full resize() method parameterization:

BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) throws Exception { return Scalr.resize(originalImage, Scalr.Method.AUTOMATIC, Scalr.Mode.AUTOMATIC, targetWidth, targetHeight, Scalr.OP_ANTIALIAS); }

And now we get:

Imgscalr works with all files supported by Java Image IO – JPG, BMP, JPEG, WBMP, PNG, and GIF.

4. Thumbnailator

Thumbnailator is an open-source image resizing library for Java that uses progressive bilinear scaling. It supports JPG, BMP, JPEG, WBMP, PNG, and GIF.

We'll include it in our project by adding the following Maven dependency to our pom.xml:

 net.coobird thumbnailator 0.4.11 

Available dependency versions can be found on Maven Central.

It has a very simple API and allows us to set output quality in percentage:

BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) throws Exception { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); Thumbnails.of(originalImage) .size(targetWidth, targetHeight) .outputFormat("JPEG") .outputQuality(1) .toOutputStream(outputStream); byte[] data = outputStream.toByteArray(); ByteArrayInputStream inputStream = new ByteArrayInputStream(data); return ImageIO.read(inputStream); }

Let's see how this smiling photograph looks before and after resizing:

It also has an option for batch processing:

Thumbnails.of(new File("path/to/directory").listFiles()) .size(300, 300) .outputFormat("JPEG") .outputQuality(0.80) .toFiles(Rename.PREFIX_DOT_THUMBNAIL);

As Imgscalr, Thumblinator works with all files supported by Java Image IO – JPG, BMP, JPEG, WBMP, PNG, and GIF.

5. Marvin

Marvin is a handy tool for image manipulation and it offers a lot of useful basic (crop, rotate, skew, flip, scale) and advanced (blur, emboss, texturing) features.

As before, we'll add Maven dependencies needed for Marvin resizing:

 com.github.downgoon marvin 1.5.5 pom   com.github.downgoon MarvinPlugins 1.5.5 

Available Marvin dependency versions can be found on Maven Central, along with the Marvin Plugins versions.

The downside of Marvin is that it doesn't offer an additional scaling configuration. Also, the scale method requires an image and image clone which is a bit cumbersome:

BufferedImage resizeImage(BufferedImage originalImage, int targetWidth, int targetHeight) { MarvinImage image = new MarvinImage(originalImage); Scale scale = new Scale(); scale.load(); scale.setAttribute("newWidth", targetWidth); scale.setAttribute("newHeight", targetHeight); scale.process(image.clone(), image, null, null, false); return image.getBufferedImageNoAlpha(); }

Let's now resize an image of a flower and see how it goes:

6. Best Practice

Image processing is an expensive operation in terms of resources, so picking the highest quality is not necessarily the best option when we don't really need it.

Let's see the performance of all of the approaches. We took one 1920×1920 px image, and scaled it to 200×200 px. The resulting observed times are as follows:

  • java.awt.Graphics2D – 34ms
  • Image.getScaledInstance() – 235ms
  • Imgscalr – 143ms
  • Thumbnailator – 547ms
  • Marvin – 361ms

Също така, докато определяме целевата ширина и височина на изображението, трябва да обърнем внимание на съотношението на изображението. По този начин изображението ще запази първоначалните си пропорции и няма да бъде разтегнато.

7. Заключение

Тази статия илюстрира няколко начина за преоразмеряване на изображение в Java. Също така научихме колко различни фактори могат да повлияят на процеса на преоразмеряване.

Пълни примерни кодове са достъпни в GitHub.