2

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

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

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

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

生成 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

我怀疑真正的问题出在下面的两个代码片段中。我刚开始学习 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 解释换行符或类似的方式有关?

4

1 回答 1

0

在通过 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

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

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
于 2013-07-04T15:36:34.693 回答