Как я могу объединить все PDF в один файл с wickedpdf? - PullRequest
0 голосов
/ 11 марта 2019

Сейчас я работаю так: я генерирую несколько файлов pdf и отправляю их по одному для загрузки пользователем, но проблема в том, что иногда они заканчиваются слишком большим количеством файлов.

Как я могу объединить все PDF-файлы в один файл перед отправкой их пользователю?

Ответы [ 3 ]

1 голос
/ 11 марта 2019

Попробуйте PDFtk . На мой взгляд, это лучшая библиотека для редактирования PDF-файлов, и есть некоторые гемы, которые обертывают ее для доступа из Ruby.

0 голосов
/ 12 марта 2019

Если вы хотите использовать какой-либо инструмент, например PDFTk или CombinePDF, все, что вам нужно сделать, это предварительно отредактировать ваши отдельные PDF-файлы, используя что-то вроде:

pdf1 = render_to_string(pdf: 'pdf1', template: 'pdf1')
pdf2 = render_to_string(pdf: 'pdf2', template: 'pdf2')

или

pdf1 = WickedPdf.new.pdf_from_string(some_html_string)
pdf2 = WickedPdf.new.pdf_from_string(another_html_string)

Если эти инструменты не воспринимают PDF как строку, вам может понадобиться сначала записать их в временные файлы.

Если вы не хотите вводить другую зависимость для слияния, wkhtmltopdf может взять несколько файлов pdf (или URL) и отобразить их все как один pdf с помощью команды, подобной этой:

wkhtmltopdf tmp/tempfile1.html tmp/tempfile2.html tmp/output.pdf

Зная это, вы можете предварительно преобразовать ваши шаблоны с макетами и всем прочим в строки HTML, а затем передать их в wkhtmltopdf примерно так:

# app/models/concerns/multipage_pdf_renderer.rb
require 'open3'
class MultipagePdfRenderer
  def self.combine(documents)
    outfile = WickedPdfTempfile.new('multipage_pdf_renderer.pdf')

    tempfiles = documents.each_with_index.map do |doc, index|
      file = WickedPdfTempfile.new("multipage_pdf_doc_#{index}.html")
      file.binmode
      file.write(doc)
      file.rewind
      file
    end

    filepaths = tempfiles.map{ |tf| tf.path.to_s }

    binary = WickedPdf.new.send(:find_wkhtmltopdf_binary_path)

    command = [binary, '-q']
    filepaths.each { |fp| command << fp }
    command << outfile.path.to_s
    err = Open3.popen3(*command) do |stdin, stdout, stderr|
      stderr.read
    end

    raise "Problem generating multipage pdf: #{err}" if err.present?
    return outfile.read
  ensure
    tempfiles.each(&:close!)
  end
end

И вызовите в свой контроллер что-то вроде этого:

def fancy_report
  respond_to do |format|
    format.pdf do
      doc1 = render_to_string(template: 'pages/_page1')
      doc2 = render_to_string(template: 'pages/_page2')
      pdf_file = MultipagePdfRenderer.combine([doc1, doc2])
      send_data pdf_file, type: 'application/pdf', disposition: 'inline'
    end
  end
end

Однако это распространяется только на самые простые случаи, вам придется выполнять работу по отрисовке верхних и нижних колонтитулов, если они вам нужны, анализируя (или добавляя) любые параметры, которые вам могут понадобиться.

Это решение изначально пришло от https://github.com/mileszs/wicked_pdf/issues/339, поэтому может быть полезно найти более подробную информацию об этой стратегии.

0 голосов
/ 11 марта 2019

Я использую combine_pdf gem.

Для объединения файлов PDF:

pdf = CombinePDF.new
pdf << CombinePDF.load("file1.pdf") # one way to combine, very fast.
pdf << CombinePDF.load("file2.pdf")
pdf.save "combined.pdf"

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

pdf_data = prawn_pdf_document.render # Import PDF data from Prawn
pdf = CombinePDF.parse(pdf_data)
...