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

本文通过代码实现展示了加载png格式图片后,分别使用不同方式将其转换为png或jpg格式图片,并对比了存储过程的性能差异。结果显示,转为jpg格式图片时性能提升显著,最高可达6至7倍。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目前加载一个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);
}
}
package com; import java.awt.image.BufferedImage; import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGImageEncoder; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import javax.imageio.ImageIO; /** * 图片压缩 * @author 86183 */ @SuppressWarnings("restriction") public class yasuo { static BufferedImage img = null; public yasuo(String fileName) throws IOException { try { File imageFile = new File(fileName); if (!imageFile.exists()) { System.err.println("文件不存在: " + imageFile.getAbsolutePath()); return; } BufferedImage img = ImageIO.read(imageFile); if (img == null) { System.out.println("不支持的图片格式或文件已损坏"); } } catch (IOException e) { System.err.println("读取文件错误: " + e.getMessage()); } // File file = new File(fileName);// 读入文件 // img = ImageIO.read(file); // 构造Image对象 } /** * 强制压缩/放大图片到固定的大小 * @param w int 新宽度 * @param h int 新高度 */ public void resize(int w, int h, String toPic) throws IOException { // SCALE_SMOOTH 的缩略算法 生成缩略图片的平滑度的 先级比速度高 生成的图片质量比较好 但速度慢 BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); image.getGraphics().drawImage(img, 0, 0, w, h, null); // 绘制缩小后的图 File destFile = new File(toPic); FileOutputStream out = new FileOutputStream(destFile); // 输出到文件流 // 可以正常实现bmp、png、gifjpg JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); encoder.encode(image); // JPEG编码 out.close(); } }请将这个代码中的resize方法中的实现换成用哈夫曼树的算法进行压缩,
最新发布
07-09
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值