使用无记忆调整巨大的jpeg(Resize huge jpeg using no memory)

2019-10-23 01:39发布

我需要调整巨大的(高达30000x30000)不使用RAM JPEG文件,速度无所谓,有没有办法这样做呢? 我尝试了不同的库(nativejpg等),但他们使用所有可用的RAM,并和崩溃中包含“内存不足”或错误“没有足够的存储是可用来处理此命令”。 我甚至尝试命令行实用程序ImageMagick的,但它也采用GB的内存。

Answer 1:

我建议你看看vips 。 据记载这里 。

我可以创建噪声的10000x10000像这样与ImageMagick的

convert -size 10000x10000! xc:gray50 +noise poisson image.jpg

并检查它是正确的大小是这样的:

identify image.jpg
image.jpg JPEG 10000x10000 10000x10000+0+0 8-bit sRGB 154.9MB 0.000u 

我现在可以使用vips向下调整10000x10000图像2500x2500这样的

time vipsthumbnail image.jpg -s 2500 -o small.jpg --vips-leak
memory: high-water mark 20.48 MB

real    0m1.974s
user    0m2.158s
sys     0m0.096s

注意内存使用量达到峰值,仅20MB

请像这样与ImageMagick的结果

identify result.jpg
result.jpg JPEG 2500x2500 2500x2500+0+0 8-bit sRGB 1.33MB 0.000u 0:00.000

看一看技术说明过,关于性能和内存使用- 在这里 。

您还可以调用它C以及命令行。



Answer 2:

如果打开的libjpeg收缩载你可以用ImageMagick的做到这一点。 尝试:

$ identify big.jpg 
big.jpg JPEG 30000x30000 30000x30000+0+0 8-bit sRGB 128MB 0.000u 0:00.000
$ time convert -define jpeg:size=2500x2500 big.jpg -resize 2500x2500 small.jpg
real    0m3.169s
user    0m2.999s
sys 0m0.159s
peak mem: 170MB

这是如何工作:libjpeg的有很大的收缩载功能。 当你打开一个图像,你可以要求该库由X2,X4或x8在加载过程中下采样 - 库然后只解码每个DCT块的一部分。

但是,此功能必须在图像打开时被启用,以后不能设置。 所以convert需要一个暗示,当它打开big.jpg ,只需要得到至少尺寸2500x2500(目标大小)的图像。 现在,所有的-resize做的是一个缩水像素3800x3800的图像到2500x2500,一个操作非常简单。 您只需要在CPU和内存的1/64。

作为@标记瑟特查上面说的, vipsthumbnail还要快:

$ time vipsthumbnail big.jpg -s 2500 -o small.jpg --vips-leak
memory: high-water mark 29.93 MB
real    0m2.362s
user    0m2.873s
sys 0m0.082s

虽然加速不是很显着的,因为这两个系统其实只是调整3800 - > 2500。

如果您尝试TIF相反,你看到一个大的差异,因为没有可以使用收缩载窍门:

$ identify 360mp.tif 
360mp.tif TIFF 18000x18000 18000x18000+0+0 8-bit sRGB 972MB 0.000u 0:00.000
$ time convert 360mp.tif -resize 2500 x.tif
peak mem: 2.8 GB
real    0m8.397s
user    0m25.508s
sys 0m1.648s
$ time vipsthumbnail 360mp.tif -o x.tif -s 2500 --vips-leak
memory: high-water mark 122.08 MB
real    0m2.583s
user    0m9.012s
sys 0m0.308s

现在vipsthumbnail约4倍速度更快,只需要记忆的1/20。



Answer 3:

借助内置的德尔福支持JPEG,你可以加载重采样为更小的尺寸,而无需装载的内存过量使用大JPEG图像。

JPEG图像缩放属性可以有以下值jsFullSizejsHalfjsQuarterjsEighth

procedure ScaleJpg(const Source, Dest: string);
var
  SourceImg, DestImg: TJPEGImage;
  Bmp: TBitmap;
begin
  Bmp := TBitmap.Create;
  try
    SourceImg := TJPEGImage.Create;
    try
      SourceImg.Scale := jsEighth;
      SourceImg.LoadFromFile(Source);
      Bmp.Width := SourceImg.Width;
      Bmp.Height := SourceImg.Height;
      Bmp.Canvas.Draw(0, 0, SourceImg);
    finally
      SourceImg.Free;
    end;
    DestImg := TJPEGImage.Create;
    try
      DestImg := TJPEGImage.Create;
      DestImg.Assign(Bmp);
      DestImg.SaveToFile(Dest);
    finally
      DestImg.Free;
    end;
  finally
    Bmp.Free;
  end;
end;

一旦你已经大致重新缩放图像到可以在内存中处理舒适的尺寸就可以申请普通的缩放算法,以获得您想要的实际图像大小。



文章来源: Resize huge jpeg using no memory