Создавайте множество изображений одновременно в 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)

Он работает отлично, за исключением того, что файл PDF на 20 страниц занимает три минуты. Я ищу лучший способ сделать это. Я подозреваю, что один из этих двух вариантов будет работать:

  1. Скомпонуйте все изображения страницы PDF одновременно, хотя я не понял, как это сделать.
  2. Используйте vips благодаря конвейерной реализации.

Я предпочел бы остаться с imagemagick, но я открыт для любого пути. Я ищу указатели, как достичь того, что я ищу.


person Brandon    schedule 04.10.2018    source источник


Ответы (2)


Я попробовал версию 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]

На этом рабочем столе с этим 58-страничным 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

Таким образом, он создает JPG высотой 50 000 пикселей примерно за 1,1 секунды и требует пикового объема памяти 150 МБ.

Я попробовал умную строку imagemagick от fmw42:

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

так 500 мб памяти и 5.2с. Это делает изображение почти точно такого же размера.

Разница в скорости, конечно, в основном связана с библиотекой рендеринга PDF: IM работает с ghostscript, тогда как ruby-vips напрямую вызывает poppler или PDFium. libvips может выполнять потоковую передачу этой программы, поэтому во время оценки она никогда не имеет одновременно более одной страницы в памяти.

JPG имеет ограничение в 65535 пикселей по любой оси, поэтому вы не сможете получить намного больше, чем это. Для более коротких документов вы можете добавить dpi: 300 к загрузке PDF, чтобы получить более подробную информацию. По умолчанию используется разрешение 72 dpi.

Вы должны получить хорошее качество текста без необходимости рендеринга в высоком разрешении. Например, для приведенного выше PDF-файла, если я запускаю:

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

Чтобы отобразить страницу 12 с разрешением 72 dpi по умолчанию, я получаю:

введите здесь описание изображения

person jcupitt    schedule 05.10.2018
comment
Это работает очень хорошо. Я хотел бы изменить размер моего окончательного изображения, но я не могу понять, как это сделать. Я не могу понять, как использовать #reduceh, и я думаю, что это то, что я должен использовать. Он говорит Vips::Error: reduceh: parameter hshrink not set для моего звонка image = image.reduceh(72 / dpi) # return image to 72dpi. Вы хоть понимаете, что я делаю неправильно? - person Brandon; 05.10.2018
comment
Вы можете просто добавить image = image.resize 0.5 (или любой другой коэффициент изменения размера) непосредственно перед последним write_to_file. Хотя было бы быстрее изменить DPI, с которым вы загружаетесь. Вы должны получить хорошее качество текста без передискретизации. - person jcupitt; 06.10.2018
comment
'reduceh' принимает коэффициент сжатия, поэтому 2 означает уменьшение в два раза. Но не используйте его! Это часть resize, сама по себе она бесполезна. - person jcupitt; 06.10.2018
comment
... Я добавил страницу примера вывода. - person jcupitt; 06.10.2018
comment
Ой ну спасибо. На самом деле я пытаюсь прочитать его с высоким DPI, а затем уменьшить разрешение окончательного изображения после компиляции страниц. Это помогло улучшить качество текста в версии imagemagick, поэтому я предполагаю, что то же самое будет и с VIP-клиентами. Спасибо еще раз! - person Brandon; 08.10.2018
comment
Вам не нужно - просто визуализируйте с нужным вам разрешением, и это должно выглядеть красиво. libvips по умолчанию использует poppler для рендеринга PDF и выполняет высококачественное сглаживание. Попробуйте щелкнуть образец страницы, который я загрузил. - person jcupitt; 08.10.2018

Я не уверен, что это то, что вы хотите, но из вашего описания мне кажется, что вы хотите добавить изображения.

Я создал 3-страничный PDF-файл из 3-х изображений jpg только для тестирования. Затем я добавляю черную рамку (в данном случае 10 пикселей, чтобы было лучше видно) внизу каждой страницы, а затем добавляю все страницы.

Это было сделано с помощью Imagemagick 6.9.10.12 Q16, но я подозреваю, что Python Wand или minimagick имеют аналогичную функциональность.

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


введите здесь описание изображения

При необходимости вы можете обрезать черную строку внизу последней страницы после добавления с помощью -chop 0x10.

person fmw42    schedule 04.10.2018
comment
На самом деле это выглядит очень многообещающе. На самом деле я использую PDF -> JPG, что противоположно тому, что вы сделали, но я думаю, что это все равно будет работать. Я обязательно соглашусь, если это сработает. Спасибо! - person Brandon; 04.10.2018
comment
Я думаю, вы могли неправильно понять. Я создал PDF из 3 изображений только для использования в качестве входных данных для процесса, так как у меня не было удобного PDF. Затем я добавил страницы PDF друг к другу и сохранил в формате JPG. Так что я собирался PDF в JPG. Размеры каждой страницы и окончательный JPG можно изменить, добавив -density XXX перед чтением PDF. convert -density 150 test.pdf -background black -gravity south -splice 0x10 -append test.jpg. Плотность по умолчанию равна 72, если не выбрано. - person fmw42; 05.10.2018
comment
А, это имеет больше смысла. Я действительно задавался вопросом, было ли это то, что вы имели в виду, но, видимо, решил неправильно. - person Brandon; 05.10.2018
comment
Это отлично сработало, так как сократило время на 95%. К сожалению, качество текста из PDF ужасно. Я пытался изменить размер и плотность изображения, и это не помогло. Если у вас есть другие советы, они будут очень признательны! - person Brandon; 05.10.2018
comment
Вы можете улучшить качество, используя большую плотность перед чтением PDF-файла, а затем уменьшая его размер после прочтения PDF-файла. Таким образом, 1_. Плотность по умолчанию 72. Так что 4*72=288. Итак, чтобы вернуться к нормальному размеру, используйте -resize 25%, что составляет 1/4. Попробуй это. Если вам нужны изображения большего размера, измените размер меньше, например, на 50%. Или, если вам нужно более высокое качество, используйте -density 8*72 и измените размер на 1/8. Это замедлит обработку, но даст вам более высокое качество. Торгуйтесь по своему желанию. - person fmw42; 05.10.2018
comment
Это работает очень хорошо, за исключением того, что когда я добавляю изменение размера, белый фон за моим текстом становится черным, даже когда я удаляю -background black. - person Brandon; 05.10.2018