【问题标题】:Efficient way to read an image file using Java使用 Java 读取图像文件的有效方法
【发布时间】:2020-07-11 17:49:53
【问题描述】:

我正在使用javax.imageio.ImageIO.read(),读取大小为 5 mb 且位于 windows 临时位置的图像几乎需要 9 秒,PFB 是 Jprofiler 的屏幕截图。我想要一种更有效的方法,可以将时间减少到至少 2-3 秒。

该文件以 org.springframework.web.multipart.MultipartFile 请求的形式通过 rest 端点发送,然后被复制到 windows 临时位置以进行进一步处理。完整的代码块:

String fileName = StringUtils.cleanPath(multipartFile.getOriginalFilename());
Path destinationPath = Paths.get(System.getProperty("java.io.tmpdir"));
String tempPath = destinationPath.resolve(fileName).toString();
File uploadedImageFile = new File(tempPath);
File originalFileInTempLocation = file.transferTo(uploadedImageFile);
BufferedImage originalImage = ImageIO.read(originalFileInTempLocation);

在谷歌搜索时,我发现了一个声称比javax.imageio.ImageIO 更高效的第三方库,但它是付费的:https://files.idrsolutions.com/maven/site/jdeli/apidocs/com/idrsolutions/image/JDeli.html#read(java.io.File)

谁能推荐一种更好更有效的读取图像文件的方法。

【问题讨论】:

  • 请显示如何您正在加载图像。此外,询问图书馆建议是题外话。
  • 您能否发布一个图片链接,以便我查看在我的机器上加载需要多长时间?
  • @Cascader 我需要使用 java.awt.Graphics2D 调整这些图像的大小。我有一堆 6-7 张图片,每张图片都将调整为 2 种变体。第一个变体是 350*300(用于缩略图),另一个变体是 100*100。然后将两个图像变体存储到 aws s3。我已经准备好了,但唯一担心的是图像处理(尤其是ImageIO.read)需要超过 10 秒,这是我们无法承受的。
  • (1-) 你昨天问了这个问题以及问到哪里 1) 发布你的 minimal reproducible example 来展示问题和 2) 获取图片链接。你重复了同样的问题,没有提供任何额外的信息。您的问题是关于 ImageIO,因此仅使用 ImageIO 创建一个示例。您发布的额外代码与 ImageIO 无关,我猜这才是真正的问题所在。
  • 感谢您提出的所有宝贵建议。我尝试了你们提供的所有解决方案。我没有使用 imageIO,而是使用Image image = new ImageIcon(file.getAbsolutePath()).getImage(); 进行文件读取,并且将时间减少了近一半。

标签: java javax.imageio


【解决方案1】:

您的 9 秒时间看起来很糟糕 - 我想知道您是否包含了所有代码和时间,只是 ImageIO.read(File)

但是我发现ImageIO.read(File) 在非 SSD 驱动器上非常慢(即 500 毫秒到 1 秒)。在我的 PC 4-6MB 上测试 NAS 和 HDD 驱动器时,一些图像读取使用 InputStream.read() 多达 1000 次。我发现如果在调用 ImageIO.read 之前将整个图像读入内存,则加载所用时间会减少:

static BufferedImage load(File f) throws IOException
{
    byte[] bytes = Files.readAllBytes(f.toPath());
    try (InputStream is = new ByteArrayInputStream(bytes))
    {
        return ImageIO.read(is);
    }
}

此解决方案可以稍微减慢 SSD 驱动器的访问时间(这对我来说不是问题,大约 20 毫秒),但在我的 PC 上,NAS/网络驱动器的增益幅度为 50-250 毫秒。

显然,您观察到的时间取决于您的硬件、图像文件大小和类型,但在您的特定情况下可能值得尝试。

如果您需要加载多个图像,您可以将文件 I/O 和 ImageIO 调用拆分到单独的线程中以获得少量额外收益,但代价是额外的复杂性和内存占用。

【讨论】:

    【解决方案2】:

    首先,我不得不说,对于现代硬件来说,5Mb 图像的 9 秒似乎太多了。当然,复杂的图像或复杂的格式(即多页 tiff)可能需要更长的时间,但我的低端 PC 需要 1.3 秒才能生成 5mb JPG。我肯定会尝试找出硬件和/或操作系统级别的问题。

    话虽如此,这是我提出的更快图像加载的解决方案,因为用例是生成缩略图。这里的关键是我们可以指示图像阅读器只从磁盘读取图像的部分,因为我们需要更少的图像数据来生成缩略图。对于 JPG,这种技术(下采样)可以实现为:

    Iterator<ImageReader> imageReadersByFormatName = ImageIO.getImageReadersByFormatName("jpg");
    ImageReader ir = imageReadersByFormatName.next(); //There should be at least the default com.sun.imageio.plugins.jpeg.JPEGImageReader installed
    ImageReadParam defaultReadParam = ir.getDefaultReadParam();
    defaultReadParam.setSourceSubsampling(8, 8, 0, 0); //Configure the reader to read every 8th row / 8th column of the image
    ir.setInput(ImageIO.createImageInputStream(new FileInputStream(IMAGE_PATH)), true);
    BufferedImage image = ir.read(0, defaultReadParam);
    

    您必须确定 X 轴和 Y 轴子采样的最佳值(setSourceSubsampling() 的前两个参数)。这将是速度/图像质量的权衡。

    ImageReadParam 有更多配置选项。

    奖励材料:由于您使用的是 AWS,您可以考虑使用 this approach 将此任务委托给 lambda 函数(即,如果此任务可以异步完成)。

    【讨论】:

      【解决方案3】:

      我建议尝试使用 javax.imageio.stream 包中的类:

      • 如果您想将解决方案保留在临时文件中
      FileInputStream fileInputStream = new FileInputStream(uploadedImageFile);
      FileCacheImageInputStream fileCache = new FileCacheImageInputStream​(fileInputStream, new File(tempPath));
      BufferedImage bufferedImage =  ImageIO.read(fileCache);
      
      • 如果您有足够的内存,您可以使用内存缓存解决方案
      FileInputStream fileInputStream = new FileInputStream(uploadedImageFile);
      MemoryCacheImageInputStream memoryCache = new MemoryCacheImageInputStream(fileInputStream);
      BufferedImage bufferedImage =  ImageIO.read(memoryCache);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-06-16
        • 2012-01-19
        • 2020-09-10
        • 1970-01-01
        • 2017-07-01
        • 2012-12-17
        相关资源
        最近更新 更多