与其他语言相比,Java BufferedImage到字节数组的转换速度太慢

时间:2017-10-11 12:50:58

标签: java bufferedimage javax.imageio

我正在尝试将图像转换为字节数组,以便我可以通过网络传输它以进行进一步处理。

现在在C#中,代码可以在大约3或2毫秒内完成工作。

Image image = Image.FromFile("D:/tst.jpg");
DateTime pre = DateTime.Now;
int sz;
using (MemoryStream sourceImageStream = new MemoryStream())
{
     image.Save(sourceImageStream, System.Drawing.Imaging.ImageFormat.Jpeg);
     byte[] sourceImageData = sourceImageStream.ToArray();
     sz = sourceImageData.Count();
}
MessageBox.Show("Size " + sz + " time : " + (DateTime.Now - pre).TotalMilliseconds);

规模268152时间:3.0118

但是在Java中做同样的事情会占用太多时间。

BuffredImage image = ImageIO.read(new File("D:/tst.jpg"));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Instant pre = Instant.now();
ImageIO.write( image, "jpeg", baos );
baos.flush();
Instant now = Instant.now();
System.out.println("Size " + baos.size() + " time : " + ChronoUnit.MILLIS.between(pre, now));

规模268167时间:91.0

注意源图片是jpg图片。在C#中使用png压缩时。时间大约是90ms。所以我的猜测是java花费时间以某种方式仍然压缩相同的jpg图像。图像尺寸为2048 * 1536

Java在这里令人沮丧。如何在java中解决此问题?

先谢谢。

编辑:

考虑这个image

C#:

大小1987059时间:11.0129

Java:

大小845093时间:155.0

源图像为1987059 Bytes(与C#编码的字节数组相同)。但在java中,它会被压缩为845093 Bytes。我尝试将压缩质量设置为1f,如this,但它没有帮助减少时间。

1 个答案:

答案 0 :(得分:2)

第一条评论指出了这种测试的主要问题:这是一个微观基准。如果您只在Java中运行该代码一次,那么您将主要测量初始化运行时,类加载和初始化的时间。

以下是您的代码的略微修改版本(我最初将此作为您后续问题的答案,现在作为副本关闭,但同样的概念适用),至少包括预热时间。而且你会发现测量结果存在很大差异。在我的2014 MacBook Pro上,输出是:

Initial load time 415 ms (5)
Average warm up load time 73 ms (5)
Normal load time 65 ms (5)

如您所见,加载图像的“正常”时间远远少于初始时间,其中包括大量开销。

代码:

public class TestJPEGSpeed {
    public static void main(String[] args) throws IOException {
        File input = new File(args[0]);

        test(input, 1, "Initial");
        test(input, 100, "Average warm up");
        test(input, 1, "Normal");
    }

    private static void test(File input, int runs, final String type) throws IOException {
        BufferedImage image = null;

        long start = System.currentTimeMillis();
        for (int i = 0; i < runs; i++) {
            image = ImageIO.read(input);
        }
        long stop = System.currentTimeMillis();

        System.out.println(type + " load time " + ((stop - start) / runs) + " ms (type=" + image.getType() + ")");
    }
}

(我还写了一个不同的版本,它采用了第二个参数,并在“正常”情况下加载了一个不同的文件,但测量结果相似,所以我把它留了出来。)

很可能这个基准测试仍有问题,例如测量I / O时间,而不是解码时间,但至少它更公平。

PS:一些奖金背景信息。如果至少使用Oracle JRE,则ImageIO的捆绑JPEG插件使用JNI,以及IJG的libjpeg(用C编写)的本机编译版本。这用于读取和写入JPEG。如果您使用libjpegTurbo的本机绑定,您可能会看到更好的性能。但由于这是所有本机代码,因此平台之间的性能差异不大。