无法使用 PDFtk 生成正确的 PDF 文件

Posted

技术标签:

【中文标题】无法使用 PDFtk 生成正确的 PDF 文件【英文标题】:Can't generate proper PDF files with PDFtk 【发布时间】:2013-07-03 17:54:21 【问题描述】:

我正在使用 Ruby on Rails 3 开发一个 Web 应用程序。该应用程序的功能之一是使用 mysql 数据库中的数据来填写在 Adob​​e LiveCycle Designer 中设计的 PDF 模板表单。

我正在使用使用数据生成 XFDF 文件的技术,并使用它来填充实际的 PDF 文件。我正在使用 PDFtk 执行此操作,如果我从命令提示符(Windows 7 64 位)运行它,它可以正常工作。

我使用 Greg Lappen 在 http://bleep.lapcominc.com/2012/02/07/filling-pdf-forms-with-ruby-and-pdftk/ 的代码在我的 Rails 应用程序中实现了这个过程,但它似乎不起作用

输出的 PDF 无法在 Acrobat 中打开,因为它指出文件已损坏。如果我使用普通文本编辑器打开它,它所包含的只是#<StringIO:0x5958f30>,每次输出后十六进制值都会发生变化。

生成 XML 数据的代码是正确的。我能够将它保存到一个文件中并自己通过命令提示符运行它。

def self.generate_xfdf(fields, filename)
    xml = Builder::XmlMarkup.new
    xml.instruct!
    xml.xfdf("xmlns" => "http://ns.adobe.com/xfdf/", "xml:space" => "preserve") 
      xml.f :href => filename
      xml.fields 
        fields.each do |field, value|
          xml.field(:name => field) 
            if value.is_a? Array
              value.each |item| xml.value(item.to_s) 
            else
              xml.value(value.to_s)
            end
          
        end
      
    
    xml.target!
  end

我怀疑真正的问题出在下面的两个代码 sn-ps 中。我刚开始学习 Ruby on Rails,但无法调试它。我尝试了各种不同的方法,但到目前为止都没有成功。非常感谢任何帮助。

  def self.stamp(input_pdf, fields)
    stdin, stdout, stderr = Open3.popen3("pdftk #input_pdf fill_form - output - flatten")
    stdin << generate_xfdf(fields, File.basename(input_pdf))     
    stdin.close
    yield stdout
    stdout.close
    stderr.close
  end

PdfStamper.stamp('C:/clean-it-template.pdf',  'LastName' => "Test Last Name", 'FirstName' => "Test First Name" ) do |pdf_io|
    pdf_content = StringIO.new
    pdf_content << pdf_io.read
    send_data pdf_content.string, :filename=>'output.pdf', :disposition=>'inline', :type=>'application/pdf'
end

这是我的控制器类中的完整代码

require 'pdf_stamper'

class FormPagesController < ApplicationController
    def pdftest
        PdfStamper.stamp('C:/clean-it-template.pdf',  'LastName' => "Test Last Name", 'FirstName' => "Test First Name" ) do |pdf_io|
            pdf_content = StringIO.new
            pdf_content << pdf_io.read
            send_data pdf_content.string, :filename=>'output.pdf', :disposition=>'inline', :type=>'application/pdf'
        end
    end
end

这是我正在使用的 pdf_stamper 类的完整代码

require 'builder'
require 'open3'

class PdfStamper
  def self.stamp(input_pdf, fields)
    stdin, stdout, stderr = Open3.popen3("pdftk #input_pdf fill_form - output - flatten")
    stdin << generate_xfdf(fields, File.basename(input_pdf))     
    stdin.close
    yield stdout
    stdout.close
    stderr.close
  end

  def self.generate_xfdf(fields, filename)

    xml = Builder::XmlMarkup.new
    xml.instruct!
    xml.xfdf("xmlns" => "http://ns.adobe.com/xfdf/", "xml:space" => "preserve") 
      xml.f :href => filename
      xml.fields 
        fields.each do |field, value|
          xml.field(:name => field) 
            if value.is_a? Array
              value.each |item| xml.value(item.to_s) 
            else
              xml.value(value.to_s)
            end
          
        end
      
    
    xml.target!
    #file = File.new("C:/debug.xml", "w+")
    #file.write(xml_data)
    #file.close
  end

end

更新 #1:

我在 Ubuntu 上运行了 Web 应用程序,但仍然遇到相同的错误。在网上搜索后,我将控制器中的代码更改为:

def pdftest
    PdfStamper.stamp('/home/nikolaos/clean-it-template.pdf',  'LastName' => "Test Last Name", 'FirstName' => "Test First Name" ) do |pdf_io|
        pdf_content = StringIO.new("", 'wb')
        pdf_content << pdf_io.read
        send_data pdf_content.string, :filename=>'output.pdf', :disposition=>'inline', :type=>'application/pdf'
    end
end

我将 StringIO 更改为二进制写入模式,它可以在 Ubuntu 中运行! PDF 正确打开并填写了所有字段。我使用 Acrobat 在 Windows 上打开了相同的文件,没有问题,但是如果我在 Windows 上运行 Web 应用程序,它仍然会生成损坏的 PDF 文件。

有没有人有关于如何在 Windows 中使用它的任何解决方案?我猜这与 Windows 和 Linux 解释换行符或类似的方式有关?

【问题讨论】:

我更新了我的问题。请参阅我帖子末尾的更新 #1。 【参考方案1】:

在通过 Ruby 文档进行更多搜索后,我设法解决了我的问题。现在我的应用程序能够在 Windows 上生成有效的 PDF 文件。这是我为遇到同样问题的人提供的解决方案。

解决方案是在控制器中使用 IO 代替 StringIO。

我的 FormPages 控制器代码

require 'pdf_stamper'

class FormPagesController < ApplicationController
    def pdftest
        PdfStamper.stamp('C:/clean-it-template.pdf',  'LastName' => "Bukas", 'FirstName' => "Nikolaos" ) do |pdf_io|
            pdf_content = IO.new(pdf_io.to_i, "r+b")
            pdf_content.binmode
            send_data pdf_content.read, :filename=>'output.pdf', :disposition=>'inline', :type=>'application/pdf'
        end
    end
end

负责使用 PDFtk 填充和生成 PDF 的 pdf_stamper 类

require 'builder'
require 'open3'

class PdfStamper
  def self.stamp(input_pdf, fields)
    Open3.popen3("pdftk #input_pdf fill_form - output -") do |stdin,  stdout, stderr|
      stdin << generate_xfdf(fields, File.basename(input_pdf))
      stdin.close
      yield stdout
      stdout.close
      stderr.close
    end
  end

  def self.generate_xfdf(fields, filename)

    xml = Builder::XmlMarkup.new
    xml.instruct!
    xml.xfdf("xmlns" => "http://ns.adobe.com/xfdf/", "xml:space" => "preserve") 
      xml.f :href => filename
      xml.fields 
        fields.each do |field, value|
          xml.field(:name => field) 
            if value.is_a? Array
              value.each |item| xml.value(item.to_s) 
            else
              xml.value(value.to_s)
            end
          
        end
      
    
    xml.target!
  end
end

【讨论】:

它会生成mi损坏的文件...:/

以上是关于无法使用 PDFtk 生成正确的 PDF 文件的主要内容,如果未能解决你的问题,请参考以下文章

pdftk

Windows批处理脚本在子文件夹中查找最大的PDF文件并使用Ghostscript和`pdftk`在页脚中打印路径

Rotativa 生成的 PDF 无法正确呈现 - 分页符/元素中断

如何使用 pdfjam 或 pdftk 在 pdf 中添加页脚?

iText 7:此 pdf 文档可能无法正确显示 Firefox

强大的pdf文件操作小工具——PDFtk的小白用法