在 imagemagick 中一次合成大量图像 Ruby
Compose lots of images at once in imagemagick Ruby
我有以下代码,它获取一个 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 文件需要三分钟之外,它工作得很好。我正在寻找一种更好的方法来做到这一点。我怀疑这两个选项之一会起作用:
- 一次合成所有 PDF 页面图像,虽然我还不知道该怎么做。
- 使用 vips,这要归功于它的管道实现。
我宁愿留在 imagemagick,但我对任何一种方式都持开放态度。我正在寻找如何实现我正在寻找的东西的指示。
我不确定这是否是您想要的,但从您的描述看来,您想要附加图像。
我从 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
如有必要,您可以使用-chop 0x10 将最后一页底部的黑线切掉。
我尝试了 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
所以制作一个50,000像素高的jpg大约需要1.1秒,需要150mb的内存峰值。
我尝试了 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 秒。它使图像大小几乎完全相同。
速度差异主要是 PDF 渲染库,当然:IM shell out to 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 页,我得到:
我有以下代码,它获取一个 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 文件需要三分钟之外,它工作得很好。我正在寻找一种更好的方法来做到这一点。我怀疑这两个选项之一会起作用:
- 一次合成所有 PDF 页面图像,虽然我还不知道该怎么做。
- 使用 vips,这要归功于它的管道实现。
我宁愿留在 imagemagick,但我对任何一种方式都持开放态度。我正在寻找如何实现我正在寻找的东西的指示。
我不确定这是否是您想要的,但从您的描述看来,您想要附加图像。
我从 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
如有必要,您可以使用-chop 0x10 将最后一页底部的黑线切掉。
我尝试了 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
所以制作一个50,000像素高的jpg大约需要1.1秒,需要150mb的内存峰值。
我尝试了 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 秒。它使图像大小几乎完全相同。
速度差异主要是 PDF 渲染库,当然:IM shell out to 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 页,我得到: