ruby-on-rails - 将JSON渲染为Prawn PDF中的图像

标签 ruby-on-rails json

我在Rails 3.2应用程序中将虾pdf与签名板gem结合使用,但在将JSON数据转换为图像以在pdf中呈现时遇到了麻烦。

我完成签名板后,将JSON数据扔进了表中,看起来像这样。

JSON格式

[{"lx":29,"ly":18,"mx":29,"my":17},{"lx":29,"ly":19,"mx":29,"my":18},{"lx":29,"ly":24,"mx":29,"my":19},{"lx":29,"ly":27,"mx":29,"my":24},{"lx":29,"ly":30,"mx":29,"my":27},{"lx":29,"ly":32,"mx":29,"my":30},{"lx":32,"ly":32,"mx":29,"my":32},{"lx":33,"ly":32,"mx":32,"my":32},{"lx":35,"ly":31,"mx":33,"my":32},{"lx":39,"ly":24,"mx":35,"my":31},{"lx":42,"ly":16,"mx":39,"my":24},{"lx":48,"ly":7,"mx":42,"my":16},{"lx":51,"ly":2,"mx":48,"my":7},{"lx":54,"ly":-3,"mx":51,"my":2},{"lx":58,"ly":2,"mx":58,"my":1},{"lx":59,"ly":9,"mx":58,"my":2},{"lx":60,"ly":18,"mx":59,"my":9},{"lx":60,"ly":27,"mx":60,"my":18},{"lx":60,"ly":38,"mx":60,"my":27},{"lx":55,"ly":45,"mx":60,"my":38},{"lx":49,"ly":51,"mx":55,"my":45},{"lx":45,"ly":54,"mx":49,"my":51},{"lx":39,"ly":57,"mx":45,"my":54},{"lx":35,"ly":51,"mx":35,"my":50},{"lx":43,"ly":45,"mx":35,"my":51},{"lx":54,"ly":39,"mx":43,"my":45},{"lx":70,"ly":32,"mx":54,"my":39},{"lx":81,"ly":28,"mx":70,"my":32},{"lx":96,"ly":25,"mx":81,"my":28},{"lx":111,"ly":23,"mx":96,"my":25},{"lx":119,"ly":23,"mx":111,"my":23},{"lx":126,"ly":23,"mx":119,"my":23},{"lx":129,"ly":23,"mx":126,"my":23},{"lx":130,"ly":23,"mx":129,"my":23},{"lx":128,"ly":24,"mx":130,"my":23},{"lx":117,"ly":25,"mx":128,"my":24},{"lx":105,"ly":27,"mx":117,"my":25},{"lx":96,"ly":29,"mx":105,"my":27},{"lx":89,"ly":30,"mx":96,"my":29},{"lx":85,"ly":30,"mx":89,"my":30},{"lx":84,"ly":31,"mx":85,"my":30},{"lx":87,"ly":32,"mx":84,"my":31},{"lx":101,"ly":36,"mx":87,"my":32},{"lx":118,"ly":39,"mx":101,"my":36},{"lx":136,"ly":42,"mx":118,"my":39},{"lx":151,"ly":43,"mx":136,"my":42},{"lx":165,"ly":43,"mx":151,"my":43},{"lx":171,"ly":40,"mx":165,"my":43},{"lx":175,"ly":37,"mx":171,"my":40},{"lx":177,"ly":34,"mx":175,"my":37},{"lx":178,"ly":32,"mx":177,"my":34},{"lx":178,"ly":31,"mx":178,"my":32}]

我看过this,但是我不确定如何最好地实现它?

Controller
  def show
    @form = Form.find(params[:id])

    respond_to do |format|
      format.html
      format.pdf do
          pdf = FormPdf.new(@form)
          send_data pdf.render, filename: "form - #{@form.title}", type: "application/pdf", disposition: "inline"
      end
    end
  end

大虾PDF
# encoding: utf-8
class FormPdf < Prawn::Document

  def initialize(form)
    super()
    @form = form
    all
  end

  def all
    text "Form text here"
    move_down 20
    signature_data = [[@form.signature, "Signature of person"]]
      table(signature_data, position: :center) do 
      cells.style(:border_width => 0)
    end
  end

最佳答案

请参阅:https://github.com/nqngo/rails-signature-pad-prawns-demo

有问题的签名图片:

SignaturePad Signature

幸运的是,我在工作场所做了类似的事情,所以我将引导您完成整个思考过程。假设我们将数据存储在@sig中,并设置一个签名框dimension:

signature = '[{"lx":29,"ly":18,"mx":29,"my":17},{"lx":29,"ly":19,"mx":29,"my":18},{"lx":29,"ly":24,"mx":29,"my":19},{"lx":29,"ly":27,"mx":29,"my":24},{"lx":29,"ly":30,"mx":29,"my":27},{"lx":29,"ly":32,"mx":29,"my":30},{"lx":32,"ly":32,"mx":29,"my":32},{"lx":33,"ly":32,"mx":32,"my":32},{"lx":35,"ly":31,"mx":33,"my":32},{"lx":39,"ly":24,"mx":35,"my":31},{"lx":42,"ly":16,"mx":39,"my":24},{"lx":48,"ly":7,"mx":42,"my":16},{"lx":51,"ly":2,"mx":48,"my":7},{"lx":54,"ly":-3,"mx":51,"my":2},{"lx":58,"ly":2,"mx":58,"my":1},{"lx":59,"ly":9,"mx":58,"my":2},{"lx":60,"ly":18,"mx":59,"my":9},{"lx":60,"ly":27,"mx":60,"my":18},{"lx":60,"ly":38,"mx":60,"my":27},{"lx":55,"ly":45,"mx":60,"my":38},{"lx":49,"ly":51,"mx":55,"my":45},{"lx":45,"ly":54,"mx":49,"my":51},{"lx":39,"ly":57,"mx":45,"my":54},{"lx":35,"ly":51,"mx":35,"my":50},{"lx":43,"ly":45,"mx":35,"my":51},{"lx":54,"ly":39,"mx":43,"my":45},{"lx":70,"ly":32,"mx":54,"my":39},{"lx":81,"ly":28,"mx":70,"my":32},{"lx":96,"ly":25,"mx":81,"my":28},{"lx":111,"ly":23,"mx":96,"my":25},{"lx":119,"ly":23,"mx":111,"my":23},{"lx":126,"ly":23,"mx":119,"my":23},{"lx":129,"ly":23,"mx":126,"my":23},{"lx":130,"ly":23,"mx":129,"my":23},{"lx":128,"ly":24,"mx":130,"my":23},{"lx":117,"ly":25,"mx":128,"my":24},{"lx":105,"ly":27,"mx":117,"my":25},{"lx":96,"ly":29,"mx":105,"my":27},{"lx":89,"ly":30,"mx":96,"my":29},{"lx":85,"ly":30,"mx":89,"my":30},{"lx":84,"ly":31,"mx":85,"my":30},{"lx":87,"ly":32,"mx":84,"my":31},{"lx":101,"ly":36,"mx":87,"my":32},{"lx":118,"ly":39,"mx":101,"my":36},{"lx":136,"ly":42,"mx":118,"my":39},{"lx":151,"ly":43,"mx":136,"my":42},{"lx":165,"ly":43,"mx":151,"my":43},{"lx":171,"ly":40,"mx":165,"my":43},{"lx":175,"ly":37,"mx":171,"my":40},{"lx":177,"ly":34,"mx":175,"my":37},{"lx":178,"ly":32,"mx":177,"my":34},{"lx":178,"ly":31,"mx":178,"my":32}]'
@sig = JSON.parse signature
sigpad_height = 55
sigpad_width = 198

然后,您在bounding_box点创建一个cursor并从JSON数据中绘制line。我们必须使用bounding_box的原因是为了设置line原点的坐标。否则,line函数将使用页面的左下方作为原点:
bounding_box([0, cursor], width: sigpad_width, height: sigpad_height) do
  stroke_bounds
  @sig.each do |e|
    stroke { line [e["lx"], e["ly"]],
                  [e["mx"], e["my"]] }
  end
end

生成的PDF将是:

PDF 1

注意图像是如何上下颠倒的,这是由于PDFcanvas之间的轴方向点不同。在PDF中,起点是左下角,而在canvas中,起点是左上角。我们需要做的是将坐标从canvas样式转换为PDF样式。一个基本的转换是将其在x轴上翻转,并通过sigpad_height将其转换回去。现在,line代码为:
    stroke { line [e["lx"], sigpad_height - e["ly"]],
                  [e["mx"], sigpad_height - e["my"]] }

最终结果将是:

PDF 2

如果您不希望bounding_box周围的边框删除stroke_bounds。您需要注意以下两点:
  • SignaturePad捕获HTML签名板尺寸之外的数据坐标,因此为什么您看到呈现的PDF签名在其bounding_box之外覆盖了线条。
  • 上面的转换假定边界框的签名高度和HTML填充相同。如果不同,则由于在x轴上翻转,您将需要添加一些偏移量以将签名转换回正确的位置。
  • 取决于您如何在数据库中存储JSON。您可能可以使用:hash来访问坐标。因此e["lx"]将产生nil,您必须改用e[:lx]
  • 关于ruby-on-rails - 将JSON渲染为Prawn PDF中的图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37847686/

    相关文章:

    ruby-on-rails - Rspec 模拟:ActiveRecord::AssociationTypeMismatch

    ruby-on-rails - 如何使用 Rails 验证 MongoDB 中模型的唯一性?

    java - 用于反序列化的 Jackson 构建器模式

    java - 如何使用java代码从这个url获取文件?

    javascript - JS - 如何转换两个字符串并作为一个 JSON 对象传递(而不是 JSON.parse())

    javascript - 序列化元素内的输入(不是表单)

    ruby-on-rails - Ruby on Rails - 复选框未保存到数据库?

    ruby-on-rails - rake Assets 之间的差异 :precompile and rake assets:clobber

    mysql - Ruby on Rails 将 CSV 导入 MySQL

    json - 如何禁用 ListView 中特定项目的单击