openplanning

Java Sejda WebP ImageIO chuyển đổi các định dạng ảnh sang WEBP

  1. Thư viện
  2. Ví dụ
WebP là định dạng hình ảnh thế hệ mới được Google phát triển dành riêng cho Web. Nó hỗ trợ nén mà không làm mất mát chất lượng hình ảnh (lossless compression) và có mất mát chất lượng hình ảnh (lossy compression).
So với với định dạng thường được sử dụng như JPEG, WebP có kích thước tệp nhỏ hơn 25%-34% với cùng chất lượng. WebP cung cấp khả năng nén tốt hơn và giảm kích thước tệp, điều này rất quan trọng đối với web vì mỗi byte dữ liệu được tiết kiệm đều quan trọng.
  • Định dạng hình ảnh WEBP
  • lossless compression vs lossy compression
Trong bài viết này tôi hướng dẫn bạn cách sử dụng thư viện Java Sejda WebP ImageIO để chuyển đổi các định dạng ảnh khác sang WebP.

1. Thư viện

Các phụ thuộc:
porm.xml
<!-- Java Lib for Image WebP -->
<!-- https://mvnrepository.com/artifact/org.sejda.webp-imageio/webp-imageio-sejda -->
<dependency>
    <groupId>org.sejda.webp-imageio</groupId>
    <artifactId>webp-imageio-sejda</artifactId>
    <version>0.1.0</version> 
</dependency>

<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
	<groupId>commons-io</groupId>
	<artifactId>commons-io</artifactId>
	<version>2.11.0</version>
</dependency>

2. Ví dụ

Để đơn giản, chúng ta viết một lớp với các phương thức tiện ích giúp chuyển đổi các định dạng ảnh sang WebP:
WebpUtils.java
package org.o7planning.java_14179_webp;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.ImageOutputStream;

import com.luciad.imageio.webp.WebPWriteParam;

public class WebpUtils {

	public static byte[] imageBytesToWebpBytes(byte[] imageBytes) throws IOException {
		InputStream is = new ByteArrayInputStream(imageBytes);
		BufferedImage image = ImageIO.read(is);
		//
		// 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]);

		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		ImageOutputStream ios = ImageIO.createImageOutputStream(baos);

		// Configure the output on the ImageWriter
		writer.setOutput(ios);
		writer.write(null, new IIOImage(image, null, null), writeParam);
		ios.flush();

		return baos.toByteArray();
	}

	public static void imageFileToWebpImageFile(File inputFile, File webpOutputFile) throws IOException {
		FileInputStream fis = new FileInputStream(inputFile);
		BufferedImage image = ImageIO.read(fis);

		ImageWriter writer = ImageIO.getImageWritersByMIMEType("image/webp").next();

		WebPWriteParam writeParam = new WebPWriteParam(writer.getLocale());
		// Notify encoder to consider WebPWriteParams
		writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
		// Set lossless compression
		writeParam.setCompressionType(writeParam.getCompressionTypes()[WebPWriteParam.LOSSLESS_COMPRESSION]);

		// Save the image
		writer.setOutput(new FileImageOutputStream(webpOutputFile));
		writer.write(null, new IIOImage(image, null, null), writeParam);
	}
}
Trong đoạn mã trên, bạn cần lưu ý tới tham số tuỳ chọn:
  • WebPWriteParam.LOSSLESS_COMPRESSION
  • WebPWriteParam.LOSSY_COMPRESSION
WebPWriteParam
Description
LOSSLESS_COMPRESSION
Chuyển đổi ảnh sang định dạng WEBP mà không làm mất chất lượng của hình ảnh. Tuỳ chọn này sẽ nén hình ảnh để tạo ra một file ảnh mới với kích thước nhỏ hơn, và khi giải nén tất cả các dữ liệu ban đầu sẽ được khôi phục.
LOSSY_COMPRESSION
Chuyển đổi ảnh sang định dạng WEBP với chất lượng hình ảnh có thể giảm đi một chút. Nói Nói cách khác, Tuỳ chọn này sẽ nén hình ảnh để tạo ra một file ảnh mới với kích thước nhỏ hơn đồng thời loại bỏ đi một vài dữ liệu không cần thiết. Khi giải nén dữ liệu ban đầu sẽ không được khôi phục.
Sự mất dữ liệu này thường không đáng chú ý. Tuy nhiên, tệp càng được nén nhiều thì sự xuống cấp càng xảy ra nhiều hơn và cuối cùng sự mất mát sẽ lộ rõ.
LOSSY_COMPRESSION
Trong trường hợp bạn nén hình ảnh với tham số LOSSY_COMPRESSION, bạn có thể chỉ định chất lượng hình ảnh mà bạn mong đợi thông qua phương thức setCompressionQuality:
//
// Set lossy compression
//
writeParam.setCompressionType(writeParam.getCompressionTypes()[WebPWriteParam.LOSSY_COMPRESSION]);
//
// Compression Quality: 50%.
//
writeParam.setCompressionQuality(0.5f);
Cuối cùng, chúng ta sử dụng các phương thức tiện ích ở trên để chuyển đổi một file ảnh PNG thành một file ảnh WEBP:
MainTest1.java
package org.o7planning.java_14179_webp;

import java.io.File;
import java.io.IOException;

public class MainTest1 { 

	public static void main(String[] args) throws IOException {
		File inputFile = new File("/Volumes/New/Test/pngFile.png");

		File webpOutputFile = new File("/Volumes/New/Test/output/webpFile1.webp");
		webpOutputFile.getParentFile().mkdirs();

		WebpUtils.imageFileToWebpImageFile(inputFile, webpOutputFile);
		System.out.println("Done!");
	} 
}
MainTest2.java
package org.o7planning.java_14179_webp;

import java.io.File;
import java.io.IOException;

import org.apache.commons.io.FileUtils;

public class MainTest2 {

	public static void main(String[] args) throws IOException {
		File inputFile = new File("/Volumes/New/Test/pngFile.png");
		// Common IO.
		byte[] imageBytes = FileUtils.readFileToByteArray(inputFile);

		// Webp byte array:
		byte[] webpImageBytes = WebpUtils.imageBytesToWebpBytes(imageBytes);

		File webpOutputFile = new File("/Volumes/New/Test/output/webpFile2.webp");

		FileUtils.writeByteArrayToFile(webpOutputFile, webpImageBytes);
		System.out.println("Done!");
	} 
}