如何使用 Java 在不将图像加载到内存的情况下裁剪图像

How do I crop an image without loading it into memory using Java

有没有办法在不将整个图像加载到内存中然后裁剪的情况下裁剪图像?

场景是我有一个非常非常大的图像文件,并且我有一个直角坐标列表,我需要从大图像中裁剪出这些直角坐标。图像太大了,我不能直接将它加载到内存中。有没有一种技术可以流式传输图像并找到要裁剪的起点和终点?如果我必须为每组坐标多次执行此步骤,请不要介意。哦,是的,假设图像的格式是 JPG/PNG/TIFF,哪种格式最容易使用。

应该能够 运行 在 Windows 上 Linux 如果对本机库有任何依赖性。

谢谢。

您可以使用 libvips 执行此操作 - 它适用于 Linux、OSX 和 Windows。

为了开始设置,让我们使用 ImageMagick 创建一个大图像 (10,000x10,000),因为它充满了随机噪声而难以压缩:

convert -size 10000x10000 xc:gray +noise random  \
   -fill red  -draw "rectangle 0,0 100,100"      \
   -fill blue -draw "rectangle 9900,9900 10000,10000" BigBoy.tif

缩小尺寸,仔细看是这样的,top-left里面是红色的矩形,bottom-right里面是蓝色的矩形:

重量为 800 MB:

-rw-r--r--@  1 mark  staff  800080278  5 May 12:08 BigBoy.tif

现在让我们使用 libvips(就在 command-line 处)提取 top-left 和 bottom-right 角(很容易识别 - 你看到我做了什么吗在那里?):

vips im_extract_area BigBoy.tif topleft.jpg 0 0 200 200 --vips-leak
memory: high-water mark 118.85 MB

vips im_extract_area BigBoy.tif bottomright.jpg 9800 9800 200 200 --vips-leak
memory: high-water mark 118.85 MB

这两个命令都使用了大约 120MB 的内存。我不相信 libvips 有 Java 绑定,但我认为你可以 fork()exec() 东西或使用类似 C 的 system() 函数。