2

Ruby on Rails 3 を使用して Web アプリを開発しています。このアプリの機能の 1 つは、MySQL データベースのデータを使用して、Adobe LiveCycle Designer で設計された PDF テンプレート フォームに入力することです。

データを含む XFDF ファイルを生成し、それを使用して実際の PDF ファイルに入力する手法を使用しています。これを行うために PDFtk を使用していますが、コマンド プロンプト (Windows 7 64 ビット) から実行すると正常に動作します。

このプロセスを Rails アプリに実装するために、 http: //bleep.lapcominc.com/2012/02/07/filling-pdf-forms-with-ruby-and-pdftk/ の Greg Lappen によるコードを使用しましたが、そうではありません。動作するようです

ファイルが破損していると表示されるため、出力 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

本当の問題は、以下の 2 つのコード スニペットのいずれかにあると思われます。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 ファイルを生成できるようになりました。これは、同じ問題を抱えている人のための私の解決策です。

解決策は、コントローラーで StringIO の代わりに IO を使用することでした。

私の 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
于 2013-07-04T15:36:34.693 に答える