【问题标题】:Cropping a JPG without loading all of it in memory裁剪 JPG 而不将其全部加载到内存中
【发布时间】:2015-09-11 12:52:46
【问题描述】:

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

【问题讨论】:

  • 您尝试了什么,向我们展示您的问题,尝试使用文件流?然后你从磁盘而不是内存中流式传输它,它会比将它推送到内存并在那里处理它要慢得多。内存中的大小应该大致为宽度*高度*4通道*8位=位图在内存中的总位数。一个 41mp 的图像(lumia 1020)应该在内存中大约 150MB,这是完全可以接受的,让我认为这是你尝试的裁剪代码占用了内存。
  • 这适用于 Windows 8 手机应用程序吗?图片大小估计是多少?

标签: c# image crop imagemagick-convert


【解决方案1】:

有几种可能性。您可以使用 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 字节/像素时为 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

然后您可以使用 convertextract.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

【讨论】:

  • 是否有 ImageMagic 或 Vips 的 .Net/C# 端口?
  • 有一个 .Net 实现,由@dlemstra 在 SO 上维护,他可能会提供进一步的建议...magick.codeplex.com
  • 或者,我认为 C# 必须有类似 system() 的函数来生成命令行程序...
  • .Net 框架允许您运行命令,但不适用于 Windows 手机应用程序等孤立的应用程序。 .Net 实现可以工作
  • 对于贵宾,请尝试vips extract area ....,您应该会看到内存使用量大幅下降。 im_ 前缀用于旧的 vips7 API,新的 vips8 API 执行自动图像流。我明白了:$ vips im_extract_area big.jpg x.jpg 8000 50 1000 1000 --vips-leak memory: high-water mark 235.11 MB $ vips extract_area big.jpg x.jpg 8000 50 1000 1000 --vips-leak memory: high-water mark 22.64 MB
【解决方案2】:

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

如果您决定不加载到内存中,那么您将进行大量文件搜索,这会使您的解码器占用更少的内存,但会占用更多的 I/O。

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

【讨论】:

  • vips jpeg 解码器将按需解压缩,因此如果您只需要文件顶部的一个块,它只会解码文件顶部。如果你在底部请求一个块,它会解压缩整个东西,但只会将底部部分保存到内存中,它会丢弃不需要的部分。
【解决方案3】:

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

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

jpegtran -crop WxH+X+Y input_file output_file

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-08
    • 1970-01-01
    • 1970-01-01
    • 2015-05-14
    • 2023-03-21
    • 2011-08-17
    相关资源
    最近更新 更多