Как объединить PDF-файлы в ruby?

Это спросил в 2008. Надеюсь, теперь есть лучший ответ.

Как вы можете объединить PDF-файлы в ruby?

Я использую pdf-stamper gem заполнить форму в формате PDF. Я хотел бы взять n PDF-файлы, заполните форму в каждом из них и сохраните результат как n-страничный документ.

можете ли вы сделать это с родной библиотекой, такой как креветка? Можете ли вы сделать это с помощью rjb и iText? pdf-stamper-это обертка на iText.

Я бы хотел избежать использования двух библиотек (например, pdftk и iText), если это возможно.

8 ответов


С 2013 года вы можете использовать креветки для слияния PDF-файлов. Суть: https://gist.github.com/4512859

class PdfMerger

  def merge(pdf_paths, destination)

    first_pdf_path = pdf_paths.delete_at(0)

    Prawn::Document.generate(destination, :template => first_pdf_path) do |pdf|

      pdf_paths.each do |pdf_path|
        pdf.go_to_page(pdf.page_count)

        template_page_count = count_pdf_pages(pdf_path)
        (1..template_page_count).each do |template_page_number|
          pdf.start_new_page(:template => pdf_path, :template_page => template_page_number)
        end
      end

    end

  end

  private

  def count_pdf_pages(pdf_file_path)
    pdf = Prawn::Document.new(:template => pdf_file_path)
    pdf.page_count
  end

end

после долгого поиска чистого решения Ruby я закончил писать код с нуля, чтобы проанализировать и объединить/объединить PDF-файлы.

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

Я написал онлайн и вы можете найти его в GitHub как хорошо.

вы можно установить его с:

gem install combine_pdf

Это очень простой в использовании (с или без сохранения данных PDF-файл).

например, вот "однострочный":

(CombinePDF.load("file1.pdf") << CombinePDF.load("file2.pdf") << CombinePDF.load("file3.pdf")).save("out.pdf")

Если вы обнаружите какие-либо вопросы, пожалуйста, дайте мне знать, и я буду работать над исправлением.


используйте ghostscript для объединения PDF-файлов:

 options = "-q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite"
 system "gs #{options} -sOutputFile=result.pdf file1.pdf file2.pdf"

Я написал рубиновый камень, чтобы сделать это - PDF:: Merger. Он использует iText. Вот как вы его используете:

pdf = PDF::Merger.new
pdf.add_file "foo.pdf"
pdf.add_file "bar.pdf"
pdf.save_as "combined.pdf"

не видел отличных вариантов в Ruby - я получил лучшие результаты, обстреливая pdftk:

system "pdftk #{file_1} multistamp #{file_2} output #{file_combined}"

мы ближе, чем были в 2008 году, но еще не совсем там.

последняя версия Dev креветки позволяет использовать существующий PDF в качестве шаблона, но не использовать шаблон снова и снова, как вы добавляете больше страниц.


через iText, это будет работать... хотя вы должны сгладить формы перед их объединением, чтобы избежать конфликтов имен полей. Это или переименовать поля по одной странице за раз.

в PDF, поля с тем же именем поделиться стоимостью. Это обычно не желаемое поведение, хотя время от времени оно пригодится.

что-то вроде (в java):

PdfCopy mergedPDF = new PdfCopy( new Document(), new FileOutputStream( outPath );

for (String path : paths ) {
  PdfReader reader = new PdfReader( path );
  ByteArrayOutputStream curFormOut = new ByteArrayOutputStream();
  PdfStamper stamper = new PdfStamper( reader, curFormOut );

  stamper.setField( name, value ); // ad nauseum

  stamper.setFlattening(true); // flattening setting only takes effect during close()
  stamper.close();

  byte curFormBytes = curFormOut.toByteArray();
  PdfReader combineMe = new PdfReader( curFormBytes );

  int pages = combineMe .getNumberOfPages();
  for (int i = 1; i <= pages; ++i) { // "1" is the first page
    mergedForms.addPage( mergedForms.getImportedPage( combineMe, i );
  }
}

mergedForms.close();

Если вы хотите добавить любой шаблон (созданный macOS Pages или Google Docs) с помощью combine_pdf тогда вы можете попробовать с этим:

final_pdf = CombinePDF.new
company_template = CombinePDF.load(template_file.pdf).pages[0]
pdf = CombinePDF.load (content_file.pdf)
pdf.pages.each {|page| final_pdf << (company_template << page)} 
final_pdf.save "final_document.pdf"