我正在使用Ruby on Rails 3开发一个Web应用程序。该应用程序的一个功能是使用来自MySQL数据库的数据来填充在Adobe 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应用程序中实现此过程,但它似乎不起作用
无法在Acrobat中打开输出PDF,因为它表明文件已损坏。如果我使用普通文本编辑器打开它,它包含#<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上运行了网络应用程序但仍然遇到了同样的错误。在网上挖掘后,我将控制器中的代码更改为:
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解释换行符的方式有什么关系?
答案 0 :(得分: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