在imagemagick Ruby中一次合成很多图像

时间:2018-10-04 19:11:12

标签: imagemagick minimagick vips

我有以下代码,它获取一个PDF文件并将其组合成一个jpg图像,在每个PDF页面图像之间都有一条水平的黑线,将PDF页面堆叠在一起。

image = MiniMagick::Image.open(pdf_file)

# create a new blank file which we will use to build a composite image
# containing all of our pages
MiniMagick::Tool::Convert.new do |i|
  i.size "#{image.width}x#{image.layers.size * image.height}"
  i.stroke "black"

  image.layers.count.times.each do |ilc|
    next if ilc.zero?

    top = ilc * (image.height + 1)
    i.draw "line 0,#{top}, #{image.width},#{top}"
  end

  i.xc "white"
  i << image_file_name
end

composite_image = MiniMagick::Image.open(image_file_name)

# For each pdf page, add it to our composite image. We add one so that we
# don't put the image over the 1px black line that was added to separate
# pages.
image.layers.count.times do |i|
  composite_image = composite_image.composite(image.layers[i]) do |c|
    c.compose "Over" # OverCompositeOp
    c.geometry "+0+#{i * (image.height + 1)}"
  end
end

composite_image.format(format)
composite_image.quality(85)
composite_image.write(image_file_name)

它工作正常,除了20页的PDF文件需要三分钟。我正在寻找一种更好的方法来做到这一点。我怀疑这两个选项之一会起作用:

  1. 一次合成所有PDF页面图像,尽管我还不知道该怎么做。
  2. 使用VIP,这要归功于其管道实施。

我宁愿使用imagemagick,但我对这两种方式都持开放态度。我在寻找如何实现自己想要的东西的指针。

2 个答案:

答案 0 :(得分:3)

我在ruby-vips版本上遇到了一次攻击:

require 'vips'

# n: is the number of pages to load, -1 means all pages in tall, thin image
image = Vips::Image.pdfload ARGV[0], n: -1

# we can get the number of pages and the height of each page from the metadata
n_pages = image.get 'pdf-n_pages'
page_height = image.get 'page-height'

# loop down the image cutting it into an array of separate pages
pages = (0 ... n_pages).map do |page_number|
  image.crop(0, page_number * page_height, image.width, page_height)
end 

# make a 50-pixel-high black strip to separate each page
strip = Vips::Image.black image.width, 50

# and join the pages again
image = pages.inject do |acc, page|
  acc.join(strip, 'vertical').join(page, 'vertical')
end 

image.write_to_file ARGV[1]

在带有this 58 page PDF的桌面上,我看到:

$ /usr/bin/time -f %M:%e ruby ./pages.rb nipguide.pdf x.jpg
152984:1.08
$ vipsheader x.jpg
x.jpg: 595x50737 uchar, 3 bands, srgb, jpegload

因此,它可以在约1.1秒内生成50,000像素高的jpg,并且需要150 mb的内存峰值。

我尝试了fmw42的聪明的imagemagick线:

$ /usr/bin/time -f %M:%e convert nipguide.pdf -background black -gravity south -splice 0x50 -append x.jpg
492244:5.16

那么500 mb的内存和5.2 s。它使图像几乎完全相同。

速度上的差异主要是PDF渲染库,当然:IM会封装为ghostscript,而ruby-vips直接调用poppler或PDFium。 libvips能够流式传输该程序,因此在评估过程中,它一次存储在内存中永远不会超过一页。

JPG在任何轴上的限制都是65535像素,因此您将无法获得更大的像素。对于较短的文档,可以将dpi: 300添加到PDF加载中以获取更多详细信息。默认值为72 dpi。

您应该获得良好的文本质量,而不必以高分辨率进行渲染。例如,对于上面链接的PDF,如果我运行:

$ vips pdfload nipguide.pdf x.png --page 12

要以默认的72 dpi渲染第12页,我得到:

enter image description here

答案 1 :(得分:2)

我不确定这是您想要的,但是从您的描述看来,您想要附加图像。

我仅用3张jpg图像创建了一个3页的PDF,仅供测试。然后,在每页底部添加黑色边框(在本例中为10像素,以便更好地显示),然后附加所有页面。

这是通过Imagemagick 6.9.10.12 Q16完成的,但是我怀疑Python Wand或minimagick具有类似的功能。

convert test.pdf -background black -gravity south -splice 0x10 -append test.jpg


enter image description here

如有必要,您可以使用-chop 0x10在添加后将最后一页底部的黑线切掉。