You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

寻找比ImageIO.write更快的BufferedImage转GIF字节方案

问题

我用ImageIO.write时发现它占用硬盘资源较多,了解到jDeli、Apache Commons、JAI这类工具处理速度更快,但jDeli成本太高。我需要把编码后的字节用于自定义远程桌面工具,现有转换代码如下:

public static byte[] imageToJPEGByteArray(Image aImage, int width, int height, int qualityPercent) throws IOException {
 byte[] imageBytes = new byte[0];
 

   float quality = 75 / 100f;

   BufferedImage destImage;
   destImage = SwingFXUtils.fromFXImage(aImage, null);
 
   // Output JPEG byte array
   ByteArrayOutputStream baos = new ByteArrayOutputStream();
 
   if(qualityPercent != -1) {
       // Start to create JPEG with quality option
       ImageWriter writer = null;
       Iterator iter = ImageIO.getImageWritersByFormatName("gif");
       if (iter.hasNext()) {
         writer = (ImageWriter) iter.next();
       }
       ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
       writer.setOutput(ios); 
       ImageWriteParam iwparam = new JPEGImageWriteParam(Locale.getDefault());
       iwparam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
       iwparam.setCompressionQuality(quality);
       writer.write(null, new IIOImage(destImage, null, null), iwparam);
       ios.flush();
       writer.dispose();
       ios.close();
       // Done creating JPEG with quality option
   } else {
       // This one line below created a JPEG file without quality option
       ImageIO.write(destImage, "gif", baos);
   }
 
   baos.flush();
   imageBytes = baos.toByteArray();
   baos.close();
 
   // Done
   return imageBytes; 
}
解决方案

先修复原生ImageIO代码的bug

你的代码里有几个明显问题:

  • 要转JPEG却用了"gif"格式的ImageWriter,格式完全错配
  • quality变量固定写死75%,没用到传入的qualityPercent参数
  • 未处理writer为null的异常情况

修复后的代码:

public static byte[] imageToJPEGByteArray(Image aImage, int width, int height, int qualityPercent) throws IOException {
    // 使用传入的qualityPercent,默认75%
    float quality = qualityPercent != -1 ? qualityPercent / 100f : 0.75f;
    BufferedImage destImage = SwingFXUtils.fromFXImage(aImage, null);

    // 用try-with-resources自动关闭流,避免资源泄漏
    try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
         ImageOutputStream ios = ImageIO.createImageOutputStream(baos)) {

        // 获取JPEG格式的ImageWriter
        ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
        try {
            writer.setOutput(ios);
            JPEGImageWriteParam iwparam = new JPEGImageWriteParam(Locale.getDefault());
            iwparam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            iwparam.setCompressionQuality(quality);
            writer.write(null, new IIOImage(destImage, null, null), iwparam);
            ios.flush();
        } finally {
            writer.dispose();
        }

        return baos.toByteArray();
    }
}

用Apache Commons Imaging替代(免费开源)

Apache Commons Imaging是免费开源库,编码速度比原生ImageIO更快,资源占用更低,适合远程桌面这种对性能敏感的场景。

示例代码:

import org.apache.commons.imaging.Imaging;
import org.apache.commons.imaging.formats.jpeg.JpegConstants;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.HashMap;
import java.util.Map;

public static byte[] imageToJPEGByteArrayWithCommons(Image aImage, int qualityPercent) throws Exception {
    float quality = qualityPercent != -1 ? qualityPercent / 100f : 0.75f;
    BufferedImage destImage = SwingFXUtils.fromFXImage(aImage, null);
    
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    Map<String, Object> params = new HashMap<>();
    params.put(JpegConstants.PARAM_KEY_QUALITY, quality);
    
    Imaging.writeImage(destImage, baos, org.apache.commons.imaging.ImageFormats.JPEG, params);
    return baos.toByteArray();
}

用JAI Image I/O替代(免费开源)

JAI Image I/O是原生ImageIO的扩展,提供更高效的编码实现,同样免费开源。需要先添加对应的依赖包(比如jai-imageio-core)。

示例代码:

import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.IIOImage;
import com.sun.media.imageio.plugins.jpeg.JPEGImageWriteParam;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Iterator;
import java.util.Locale;

public static byte[] imageToJPEGByteArrayWithJAI(Image aImage, int qualityPercent) throws Exception {
    float quality = qualityPercent != -1 ? qualityPercent / 100f : 0.75f;
    BufferedImage destImage = SwingFXUtils.fromFXImage(aImage, null);
    
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpeg");
    ImageWriter writer = writers.next();
    
    try (ImageOutputStream ios = ImageIO.createImageOutputStream(baos)) {
        writer.setOutput(ios);
        JPEGImageWriteParam param = new JPEGImageWriteParam(Locale.getDefault());
        param.setCompressionMode(JPEGImageWriteParam.MODE_EXPLICIT);
        param.setCompressionQuality(quality);
        writer.write(null, new IIOImage(destImage, null, null), param);
        ios.flush();
        return baos.toByteArray();
    } finally {
        writer.dispose();
    }
}

内容的提问来源于stack exchange,提问作者orkim okard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 16:55:25