裁剪 JPG 而不将其全部加载到内存中

Cropping a JPG without loading all of it in memory

如何裁剪大的 JPG 并提取其中的一小部分? 问题是主要的 JPG 文件太大,我无法将它们全部加载到内存中。 我使用了 ImageMagick 的 convert.exe,但它不能在所有版本的 windows 上正常工作,我更喜欢一些 C# 方法而不是独立的 exe。

我见过的所有Jpeg解码器都是先将Jpeg转存到内存中,然后再开始解码。这是因为 Jpeg 格式的性质与位图不同,您无法计算像素的文件位置。

如果您决定不加载到内存中,那么您会进行多次文件查找,这会使您的解码器占用更少的内存,但会增加 I/O 密集度。

NanoJpeg 项目是一个好的开始 https://github.com/Deathspike/NanoJPEG.NET/blob/master/NanoJPEG.cs

有两种可能性。您可以使用 stream,它是 ImageMagick 的一部分,或者 vips。让我们先做stream

我可以像这样制作大 (10,000x5,000) JPEG:

convert -size 10000x5000 xc:blue BigBoy.jpg

然后像这样使用 stream 从偏移量 8,000+50

中提取一个 1,000x1,000 的块
stream -extract 1000x1000+8000+50 BigBoy.jpg extract.rgb

并且 extraact.rgb 文件的大小为 3000000 字节,即 3 bytes/pixel.

处的 1,000x1,000

如果我用 time -l 这样做,你可以看到尽管图像很大,但驻留集很小

/usr/bin/time -l stream -extract 1000x1000+8000+50 BigBoy.jpg extract.rgb
        0.81 real         0.79 user         0.01 sys
   2924544  maximum resident set size       <----- 2MB RAM ****
         0  average shared memory size
         0  average unshared data size
         0  average unshared stack size
       796  page reclaims

然后您可以使用 convert

extract.rgb 转换为 JPEG
convert -size 1000x1000 -depth 8 extract.rgb chunk.jpg

我不是 vips 方面的专家,但您可能会使用此命令取得一些成功,该命令还通过末尾的 --vips-leak 标志显示峰值内存使用量

vips extract_area BigBoy.jpg SmallBoy.jpg 8000 50 1000 1000 --vips-leak
memory: high-water mark 8.72 MB

我找到了一个不依赖于外部库的命令行解决方案,jpegtran

您可以在主 exe 旁边添加 jpegtran.exe 并使用这些参数调用它:

jpegtran -crop WxH+X+Y input_file output_file

从这里下载 jpegtranhttp://jpegclub.org/jpegtran/