"This is the fourth day of my participation in 2022's first update challenge. See the activity details: 2022 first update challenge」.
Article introduction
Sometimes, our project needs to generate small thumbnails for business images or transcode the image format. What method will you use?
Directly use object storage and hand over business requirements to a third party? Or use javaScript to manipulate images?
Have you ever tried back-end direct processing?
This article introduces how to use Java to process pictures gracefully; Including: transcoding of mainstream image format, image compression (thumbnail generation), image with watermark, etc. External toolkits mainly used:
- Thumbnailator : old thumbnail generation tool.
- webp-imageio-core : let Java support reading and writing of Webp.
If you want to support more pictures, you can extend the Java picture IO stream, which will be discussed later
Video tutorial
A video is simply recorded. If necessary, you can go to station b:
Image transcoding / thumbnail generation
principle
The thumbnail package used this time is actually encapsulated classes and methods, which are implemented by Java based API interfaces such as Image I/O API and Java 2D API.
So, because based on Java Image I/O API Therefore, the supported image formats are limited, but they have met most situations. Generally supported formats are as follows:
- Read: JPEG 2000, JPG, tiff, bmp, PCX, gif, WBMP, PNG, RAW, JPEG, PNM, tif, TIFF, wbmp, jpeg, jbig2, jpg, JPEG2000, BMP, pcx, GIF, png, raw, JBIG2, pnm, TIF, jpeg2000, jpeg 2000
- Write: JPEG 2000, JPG, tiff, bmp, PCX, gif, WBMP, PNG, RAW, JPEG, PNM, tif, TIFF, wbmp, jpeg, jpg, JPEG2000, BMP, pcx, GIF, png, raw, pnm, TIF, jpeg2000, jpeg 2000
Many article authors introduced this package and even said that they support Apple's HEIC format. This definitely does not support using thumbnail for processing. Unless you can write a transcoder directly. But in this way, I think it's better to call ImageMagick . I'll have a chance to share this with you in the future.
How to install
First, add the lib package. If you are a Maven project or a project managed by Maven, add dependencies:
<dependency> <groupId>net.coobird</groupId> <artifactId>thumbnailator</artifactId> <version>[0.4, 0.5)</version> </dependency> Copy code
The above dependency definition is to get 0.4 The latest available version of thumbnail in the X version range. If you need a specific version of thumbnail, replace [0.4, 0.5) with a specific version number, such as 0.4.13
In addition, if the download is too slow, you can change Maven to a domestic download source (for example: Ali Maven image source)
If you are not a Maven project, you can download the latest version of thumbnail. How to add lib package manually? Download the latest version of thumbnail: github.com/coobird/thu...
How to use
The use of thumbnail is very simple. Originally, you need to use Java's Image I/O API, BufferedImages and Graphics2D to process images. Thumbnail directly encapsulates the above operations. Simple use demonstration:
Thumbnails.of(new File("path/to/directory").listFiles()) .size(640, 480) .outputFormat("jpg") .toFiles(Rename.PREFIX_DOT_THUMBNAIL); Copy code
- Original picture address: path/to/directory
- Output picture size: 640 * 480
- Output picture format: jpg
- IO stream output address (output picture): Rename PREFIX_ DOT_ THUMBNAIL
Picture transcoding
Demo code:
Thumbnails.of(originalImage).scale(scale) .outputFormat("jpg") .outputQuality(compression) .toFile(thumbnailImage); Copy code
Of which:
- scale is the proportional scaling of the picture size, which is of type float.
- outputFormat is the type of output picture. Note: webp is not supported by default. If webp needs to be used, it needs to be installed in advance webp-imageio-core , you can see how to make Java support Webp.
- outputQuality is the quality of the output picture, i.e. definition / resolution.
Generate thumbnails using the original picture
Demo code:
Thumbnails.of(new File("original.jpg")) .size(160, 160) .toFile(new File("thumbnail.jpg")); Copy code
For the original picture file, the String can be used instead of the address:
Thumbnails.of("original.jpg") .size(160, 160) .toFile("thumbnail.jpg"); Copy code
Usually, the thumbnail output volume is very small, but it can still be used Outputquality to reduce picture quality (resolution).
Rotate picture
It's simple; add to. Just rotate. For example:
Thumbnails.of(new File("original.jpg")) .rotate(90) .toFile(new File("image-with-watermark.jpg")); Copy code
Add watermark
Adding watermark is also very simple Watermark:
Thumbnails.of(new File("original.jpg")) .watermark(Positions.BOTTOM_RIGHT, ImageIO.read(new File("watermark.png")), 0.5f) .toFile(new File("image-with-watermark.jpg")); Copy code
Practical demonstration
I used the above package on my website to build an online presentation address: tool.mintimate.cn/processIMG
Function: after the user uploads the picture, the system has the user's choice of output format and transcoding the picture.
Extension Judgment
When the front end transmits pictures to the background, we can judge the file extension:
String thumbnailImageName=originalImage.getName(); //Thumbnail output name String thumbnailImagePath; //Thumbnail output address switch (format){ case "JPG": thumbnailImagePath=System.getProperty("user.dir") + "/file/Output/" + thumbnailImageName.substring(0,thumbnailImageName.lastIndexOf("."))+".jpg"; break; case "PNG": thumbnailImagePath=System.getProperty("user.dir") + "/file/Output/" + thumbnailImageName.substring(0,thumbnailImageName.lastIndexOf("."))+".png"; break; case "WEBP": thumbnailImagePath=System.getProperty("user.dir") + "/file/Output/" + thumbnailImageName.substring(0,thumbnailImageName.lastIndexOf("."))+".webp"; break; case "BMP": thumbnailImagePath=System.getProperty("user.dir") + "/file/Output/" + thumbnailImageName.substring(0,thumbnailImageName.lastIndexOf("."))+".bmp"; break; default: thumbnailImagePath=System.getProperty("user.dir") + "/file/Output/" + thumbnailImageName; break; } Copy code
Create a blank thumbnail file
Although the thumbnail can directly and automatically create the corresponding file object according to the String, in order to facilitate our own control, we create it manually:
File thumbnailImage = new File(thumbnailImagePath); // Judge whether the path exists. If it does not exist, create it if (!thumbnailImage.getParentFile().exists()) { thumbnailImage.getParentFile().mkdirs(); } Copy code
Transcoding picture
try { switch (format){ case "JPG": Thumbnails.of(originalImage).scale(scale) .addFilter(new ThumbnailsImgFilter()) .outputFormat("jpg") .outputQuality(compression) .toFile(thumbnailImage); break; case "PNG": Thumbnails.of(originalImage).scale(scale) .outputFormat("png") .outputQuality(compression) .toFile(thumbnailImage); break; case "WEBP": Thumbnails.of(originalImage).scale(scale) .imageType(ThumbnailParameter.DEFAULT_IMAGE_TYPE) .outputFormat("webp") .outputQuality(compression) .toFile(thumbnailImage); break; case "BMP": Thumbnails.of(originalImage).scale(scale) .addFilter(new ThumbnailsImgFilter()) .outputFormat("bmp") .outputQuality(compression) .toFile(thumbnailImage); break; default: Thumbnails.of(originalImage).scale(scale) .imageType(ThumbnailParameter.DEFAULT_IMAGE_TYPE) .outputQuality(compression) .toFile(thumbnailImage); break; } } catch (IOException e) { e.printStackTrace(); } Copy code
Because I use Springboot to quickly build, I actually created a configuration rule addFilter, which can render the transparent background white when PNG transparent pictures are converted to JPG. (just to look good...). Implementation details:
import net.coobird.thumbnailator.filters.ImageFilter; import java.awt.*; import java.awt.image.BufferedImage; public class ThumbnailsImgFilter implements ImageFilter { @Override public BufferedImage apply(BufferedImage bufferedImage) { int w = bufferedImage.getWidth(); int h = bufferedImage.getHeight(); BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); Graphics2D graphic = newImage.createGraphics(); graphic.setColor(Color.white);//The background is set to white graphic.fillRect(0, 0, w, h); graphic.drawRenderedImage(bufferedImage, null); graphic.dispose(); return newImage; } } Copy code
In this way, the picture can be transcoded successfully (if used properly, the picture can also be compressed) Д`)):
The left is the original image and the right is the transcoded image. When the size remains unchanged, the picture quality becomes 80% of the original; The main file size becomes smaller due to the Webp format. Below we introduce the Java transcoding Webp format.
Java handles Webp format
What is Webp format
According to Wiki Encyclopedia: webp (pronunciation: weppy]) is a picture file format that provides both lossy compression and lossless compression (reversible compression). It is derived from the image coding format. It is considered to be a sister project of WebM multimedia format. It was developed by Google after purchasing On2 Technologies and published under BSD license terms. The advantages of webp are obvious:
- Better image data compression algorithm
- Smaller picture size
- No difference in image quality is recognized by naked eye
- Lossless and lossy compression mode
- Alpha transparency and animation properties
In short, it can preserve lossless image quality and maintain image transparency like PNG format; At the same time, you can compress pictures like JPG. Webp in the same case, the file size is smaller than PNG, even smaller than JPG.
Support Webp format
because Webp In fact, it was developed by Google, so the Webp format was not supported at the beginning of Java IO stream design.
There are many ways to make Java IO Streams Support Webp. Here is a method to accept more methods
Depending on the system, you need to install the corresponding dependent packages:
/natives /linux_32 libxxx[-vvv].so /linux_64 libxxx[-vvv].so /osx_32 libxxx[-vvv].dylib /osx_64 libxxx[-vvv].dylib /osx_arm64 libxxx[-vvv].dylib /windows_32 xxx[-vvv].dll /windows_64 xxx[-vvv].dll /aix_32 libxxx[-vvv].so libxxx[-vvv].a /aix_64 libxxx[-vvv].so libxxx[-vvv].a Copy code
Refer to the following items: github.com/scijava/nat... Of course, you can also directly use the lib package integrated by God, such as: webp-imageio-core ; How to use it is explained in detail below.
Webp imageio core usage
Because webp imageio core is not published to Maven central warehouse, users using Maven skeleton need to add lib dependency. First, download the jar release package of webp imageio core at: github.com/nintha/webp... Then add custom < dependency >:
<dependency> <groupId>com.github.nintha</groupId> <artifactId>webp-imageio-core</artifactId> <version>{version}</version> <scope>system</scope> <systemPath>${pom.basedir}/libs/webp-imageio-core-{version}.jar</systemPath> </dependency> Copy code
For example, for my project, add local lib:
At this time, Java already supports the processing of Webp format images.
Practical use
The simplest way to use... Is to add the thumbnail dependency package mentioned above, and you can use thumbnail to directly process image IO streams. When used alone, we can use the most traditional method: image to WEBP:
public static void main(String args[]){ String srcFile = System.getProperty("user.dir") + "/file/Input/"+"Input.png" //Original address String webpFile = System.getProperty("user.dir") + "/file/Output/"+"Output.png" //Output address encodingToWebp(srcFile, webpFile); } public static void encodingToWebp(String srcFile, String webpFile) { encodingToWebp(new File(srcFile),new File(webpFile) ); } /** * @param: srcFile * @param: webpFile * @description: Encode the file in WEBP format * @author: Mintimate */ public static void encodingToWebp(File srcFile, File webpFile) { try { // Obtain an image to encode from somewhere BufferedImage image = ImageIO.read(srcFile); // Obtain a WebP ImageWriter instance ImageWriter writer = ImageIO.getImageWritersByMIMEType("image/webp").next(); // Configure encoding parameters WebPWriteParam writeParam = new WebPWriteParam(writer.getLocale()); writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); writeParam.setCompressionType(writeParam.getCompressionTypes()[WebPWriteParam.LOSSLESS_COMPRESSION]); // Configure the output on the ImageWriter writer.setOutput(new FileImageOutputStream(webpFile)); // Encode writer.write(null, new IIOImage(image, null, null), writeParam); //Release reader writer.dispose(); //Close file stream fileImageOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } Copy code
last
At this point, images can be handled gracefully using thumbnail.
However, you will find that in some cases, the image processing (jpeg image processing) will be red. The processing method is very simple. You can use BufferedImage to write and read pictures, so that there will be no distortion of red or pink pictures.
Have the opportunity to accept other java image IO expansion packages to enable Java projects to support more image formats.