使用ImageIO.write存储png格式图片性能较差问题

目前加载一个png格式的图片,做一些绘图工作,发现ImageIO.write存储png性能较差,转为存储jpg格式图片,性能可以提高6,7倍。
代码如下。

package test;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;

import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;

import javax.imageio.ImageIO;

import java.util.Iterator;
import javax.imageio.*;
import javax.imageio.stream.*;

import org.junit.Before;
import org.junit.Test;

/**
* 加载png格式图片,使用不同方式转为png或者jpg格式的性能对比。
* */
public class PngJpgImagePerTest {

private static String PNG = "png";
private static String JPG = "jpg";

private static String SimpleSavePNG = "__SimpleSavePNG.png";
private static String Convert2ArrayAndSavePNG = "__Convert2ArrayAndSavePNG.png";
private static String NewImageSavePNG = "__NewPNG.png";
private static String NewImageSaveJPG = "__NewJPG.jpg";
private static String SaveJPG = "__JPG_quality.jpg";

/**
* 保存文件。
* */
public static void save2File(String filePath, byte[] data) {

BufferedOutputStream bufferOutput = null;

try {
bufferOutput = new BufferedOutputStream(new FileOutputStream(
new File(filePath)), 1024);

bufferOutput.write(data);
bufferOutput.flush();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
if (bufferOutput != null) {
try {
bufferOutput.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}

/**
* load image
* */
public static BufferedImage loadImage(String filePath) {
try {
return ImageIO.read(new File(filePath));
} catch (Exception e) {
throw new RuntimeException(e);
}
}

/**
* simple save use ImageIO.write
*/
public static void saveImage(BufferedImage image, String format,
String filePath) {
try {
ImageIO.write(image, format, new File(filePath));
} catch (Exception e) {
throw new RuntimeException(e);
}
}

/**
* convert to byte array.
* */
public static byte[] convert2bytes(BufferedImage image, String format) {
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
ImageIO.write(image, format, bout);
byte[] data = bout.toByteArray();
return data;
} catch (Exception e) {
throw new RuntimeException(e);
}
}

/**
* create new buffer image and save using png format.
* */
public static void savePngImage(BufferedImage image, String format,
String filePath) {
BufferedImage bufferedImage = new BufferedImage(image.getWidth(), image
.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
bufferedImage.getGraphics().drawImage(image, 0, 0, null);
saveImage(bufferedImage, PNG, filePath);
}

/**
* create new buffer image and save using jpg format.
* */
public static void saveJpgImage(BufferedImage image, String format,
String filePath) {
BufferedImage bufferedImage = new BufferedImage(image.getWidth(), image
.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
bufferedImage.getGraphics().drawImage(image, 0, 0, null);
saveImage(bufferedImage, JPG, filePath);
}

/**
* save jpg with specified quality. 为了图片质量,quality的值不能太低。
* */
public static void saveImageUsingJPGWithQuality(BufferedImage image,
String filePath, float quality) throws Exception {

BufferedImage newBufferedImage = new BufferedImage(image.getWidth(),
image.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
newBufferedImage.getGraphics().drawImage(image, 0, 0, null);

Iterator<ImageWriter> iter = ImageIO
.getImageWritersByFormatName("jpeg");

ImageWriter imageWriter = iter.next();
ImageWriteParam iwp = imageWriter.getDefaultWriteParam();

iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
iwp.setCompressionQuality(quality);

File file = new File(filePath);
FileImageOutputStream fileImageOutput = new FileImageOutputStream(file);
imageWriter.setOutput(fileImageOutput);
IIOImage iio_image = new IIOImage(newBufferedImage, null, null);
imageWriter.write(null, iio_image, iwp);
imageWriter.dispose();
}

public static void drawString(Graphics2D g2, String value, int x, int y) {
Font font = new Font("Arial", Font.BOLD, 16);
g2.setColor(Color.BLACK);
g2.setFont(font);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2.drawString(value, x, y);
}

private String sourceFilePath;
private BufferedImage sourceImage;
private int loop;
private float quality;

@Before
public void setup() {
sourceFilePath = "E:\\allencode\\ImgTest\\stat.png";
sourceImage = loadImage(sourceFilePath);
loop = 10;
quality = 0.8F;
Graphics2D g2 = sourceImage.createGraphics();
draw(g2);
}

private void draw(Graphics2D g2) {
drawString(g2, "Allen Hello world.", 500, 200);
}

/**
* ImageIO.write存储图片时主要的性能消耗在计算上。
* */
@Test
public void test_01() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < loop; i++) {
long start = System.currentTimeMillis();
saveImage(sourceImage, PNG, sourceFilePath + SimpleSavePNG);
long end = System.currentTimeMillis();
sb.append(" saveImage = " + (end - start));

long convertStart = System.currentTimeMillis();
byte[] pngData = convert2bytes(sourceImage, PNG);
long convertEnd = System.currentTimeMillis();
sb.append(" convert = " + (convertEnd - convertStart));

long saveStart = System.currentTimeMillis();
save2File(sourceFilePath + Convert2ArrayAndSavePNG, pngData);
long saveEnd = System.currentTimeMillis();
sb.append(" save = " + (saveEnd - saveStart));

sb.append("\n");
}

System.out.println(sb);
}

/**
* ImageIO.write和新建一个BufferedImage,采用jpg或png保存的比较。
* */
@Test
public void test_02() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < loop; i++) {
long start = System.currentTimeMillis();
saveImage(sourceImage, PNG, sourceFilePath + SimpleSavePNG);
long end = System.currentTimeMillis();
sb.append(" saveImage = " + (end - start));

start = System.currentTimeMillis();
savePngImage(sourceImage, "png", sourceFilePath + NewImageSavePNG);
end = System.currentTimeMillis();
sb.append(" savePngImage = " + (end - start));

start = System.currentTimeMillis();
saveJpgImage(sourceImage, "jpg", sourceFilePath + NewImageSaveJPG);
end = System.currentTimeMillis();
sb.append(" saveJpgImage = " + (end - start));

sb.append("\n");
}

System.out.println(sb);
}

/**
* ImageIO.write存储图片和保存jpg的时间对比。
* */
@Test
public void test_03() throws Exception {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < loop; i++) {
long pngStart = System.currentTimeMillis();
saveImage(sourceImage, PNG, sourceFilePath + SimpleSavePNG);
long pngEnd = System.currentTimeMillis();
sb.append(" saveImage = " + (pngEnd - pngStart));

long jpgStart = System.currentTimeMillis();
saveImageUsingJPGWithQuality(sourceImage, sourceFilePath + SaveJPG,
quality);
long jpgEnd = System.currentTimeMillis();
sb.append(" JPGWithQuality = " + (jpgEnd - jpgStart));

sb.append(" % = " + (pngEnd - pngStart) * 1D / (jpgEnd - jpgStart));
sb.append("\n");
}

System.out.println(sb);
}
}
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值