Rails 2.3.8 将 html 渲染为 pdf

发布于 2024-11-18 20:38:52 字数 85 浏览 2 评论 0原文

我正在使用 Prawn pdf 库,但是我正在做一个复杂的设计,所以我需要一个快速的解决方案来将 html 转换为 pdf 文件。

提前致谢

I am using Prawn pdf library however i am doing a complex design, So I need a quick solution as to convert a html to pdf file.

Thanks in advance

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

空城仅有旧梦在 2024-11-25 20:38:52

我会使用 wkhtmltopdf shell 工具
wicked_pdf ruby​​ gem 一起使用,它是免费的,并使用 qtwebkit 来渲染您的html 到 pdf。还执行 javascript,例如图表。您可以找到有关安装的更多信息:https://github.com/mileszs/wicked_pdf

I would use wkhtmltopdf shell tool
together with the wicked_pdf ruby gem, its free, and uses qtwebkit to render your html to pdf. Also executes javascript as well, for charts for example. You can find more info about installation: https://github.com/mileszs/wicked_pdf

挽袖吟 2024-11-25 20:38:52

我有一个 Rails 应用程序,多年来一直在生产中使用 PrinceXML 。它价格昂贵 - 大约 4K 美元的服务器许可证 - 但在 PDF 文件中渲染 HTML+CSS 方面做得非常好。我还没有研究过更新的解决方案,因为这个解决方案是付费的并且工作得很好。

无论如何,这里有一些我改编自 Subimage Interactive 的代码,以使转换变得简单:

lib/prince .rb

# Prince XML Ruby interface. 
# http://www.princexml.com
#
# Library by Subimage Interactive - http://www.subimage.com
#
#
# USAGE
# -----------------------------------------------------------------------------
#   prince = Prince.new()
#   html_string = render_to_string(:template => 'some_document')
#   send_data(
#     prince.pdf_from_string(html_string),
#     :filename => 'some_document.pdf'
#     :type => 'application/pdf'
#   )
#

class Prince

  attr_accessor :exe_path, :style_sheets, :log_file

  # Initialize method
  #
  def initialize()
    # Finds where the application lives, so we can call it.
    @exe_path = '/usr/local/bin/prince'
    case Rails.env
    when 'production', 'staging'
      # use default hard-coded path
    else
      if File.exist?(@exe_path)
        # use default hard-coded path
      else
        @exe_path = `which prince`.chomp
      end
    end
    @style_sheets = ''
    @log_file = "#{::Rails.root}/log/prince.log"
  end

  # Sets stylesheets...
  # Can pass in multiple paths for css files.
  #
  def add_style_sheets(*sheets)
    for sheet in sheets do
      @style_sheets << " -s #{sheet} "
    end
  end

  # Returns fully formed executable path with any command line switches
  # we've set based on our variables.
  #
  def exe_path
    # Add any standard cmd line arguments we need to pass
    @exe_path << " --input=html --server --log=#{@log_file} "
    @exe_path << @style_sheets
    return @exe_path
  end

  # Makes a pdf from a passed in string.
  #
  # Returns PDF as a stream, so we can use send_data to shoot
  # it down the pipe using Rails.
  #
  def pdf_from_string(string)
    path = self.exe_path()
    # Don't spew errors to the standard out...and set up to take IO 
    # as input and output
    path << ' --silent - -o -'

    # Show the command used...
    #logger.info "\n\nPRINCE XML PDF COMMAND"
    #logger.info path
    #logger.info ''

    # Actually call the prince command, and pass the entire data stream back.
    pdf = IO.popen(path, "w+")
    pdf.puts(string)
    pdf.close_write
    output = pdf.gets(nil)
    pdf.close_read
    return output
  end
end

lib/pdf_helper.rb

module PdfHelper
  require 'prince'

  private
    def make_pdf(template_path, pdf_name, stylesheets = [], skip_base_pdf_stylesheet = false)
      # application notices should never be included in PDFs, pull them from session here
      notices = nil
      if !flash.now[:notice].nil?
        notices = flash.now[:notice]
        flash.now[:notice] = nil
      end
      if !flash[:notice].nil?
        notices = '' if notices.nil?
        notices << flash[:notice]
        flash[:notice] = nil
      end

      prince = Prince.new()
      # Sets style sheets on PDF renderer.
      stylesheet_base = "#{::Rails.root}/public/stylesheets"
      prince.add_style_sheets(
        "#{stylesheet_base}/application.css",
        "#{stylesheet_base}/print.css"
      )
      prince.add_style_sheets("#{stylesheet_base}/pdf.css") unless skip_base_pdf_stylesheet
      if 0 < stylesheets.size
        stylesheets.each { |s| prince.add_style_sheets("#{stylesheet_base}/#{s}.css") }
      end

      # Set RAILS_ASSET_ID to blank string or rails appends some time after
      # to prevent file caching, messing up local - disk requests.
      ENV['RAILS_ASSET_ID'] = ''
      html_string = render_to_string(:template => template_path, :layout => 'application')
      # Make all paths relative, on disk paths...
      html_string.gsub!("src=\"", "src=\"#{::Rails.root}/public")
      html_string.gsub!("src=\"#{::Rails.root}/public#{::Rails.root}", "src=\"#{::Rails.root}")

      # re-insert any application notices into the session
      if !notices.nil?
        flash[:notice] = notices
      end

      return prince.pdf_from_string(html_string)
    end

    def make_and_send_pdf(template_path, pdf_name, stylesheets = [], skip_base_pdf_stylesheet = false)
      send_data(
        make_pdf(template_path, pdf_name, stylesheets, skip_base_pdf_stylesheet),
        :filename => pdf_name,
        :type => 'application/pdf'
      )
    end
end

示例控制器操作

include PdfHelper
def pdf
  index
  make_and_send_pdf '/ads/index', "#{filename}.pdf"
end

I have one Rails app that's been using PrinceXML in production for a few years. It is pricey - around $4K for a server license - but does a very good job of rendering HTML+CSS in PDF files. I haven't looked at newer solutions since this one is paid for and working quite well.

For what it's worth, here's some code I adapted from Subimage Interactive to make the conversion simple:

lib/prince.rb

# Prince XML Ruby interface. 
# http://www.princexml.com
#
# Library by Subimage Interactive - http://www.subimage.com
#
#
# USAGE
# -----------------------------------------------------------------------------
#   prince = Prince.new()
#   html_string = render_to_string(:template => 'some_document')
#   send_data(
#     prince.pdf_from_string(html_string),
#     :filename => 'some_document.pdf'
#     :type => 'application/pdf'
#   )
#

class Prince

  attr_accessor :exe_path, :style_sheets, :log_file

  # Initialize method
  #
  def initialize()
    # Finds where the application lives, so we can call it.
    @exe_path = '/usr/local/bin/prince'
    case Rails.env
    when 'production', 'staging'
      # use default hard-coded path
    else
      if File.exist?(@exe_path)
        # use default hard-coded path
      else
        @exe_path = `which prince`.chomp
      end
    end
    @style_sheets = ''
    @log_file = "#{::Rails.root}/log/prince.log"
  end

  # Sets stylesheets...
  # Can pass in multiple paths for css files.
  #
  def add_style_sheets(*sheets)
    for sheet in sheets do
      @style_sheets << " -s #{sheet} "
    end
  end

  # Returns fully formed executable path with any command line switches
  # we've set based on our variables.
  #
  def exe_path
    # Add any standard cmd line arguments we need to pass
    @exe_path << " --input=html --server --log=#{@log_file} "
    @exe_path << @style_sheets
    return @exe_path
  end

  # Makes a pdf from a passed in string.
  #
  # Returns PDF as a stream, so we can use send_data to shoot
  # it down the pipe using Rails.
  #
  def pdf_from_string(string)
    path = self.exe_path()
    # Don't spew errors to the standard out...and set up to take IO 
    # as input and output
    path << ' --silent - -o -'

    # Show the command used...
    #logger.info "\n\nPRINCE XML PDF COMMAND"
    #logger.info path
    #logger.info ''

    # Actually call the prince command, and pass the entire data stream back.
    pdf = IO.popen(path, "w+")
    pdf.puts(string)
    pdf.close_write
    output = pdf.gets(nil)
    pdf.close_read
    return output
  end
end

lib/pdf_helper.rb

module PdfHelper
  require 'prince'

  private
    def make_pdf(template_path, pdf_name, stylesheets = [], skip_base_pdf_stylesheet = false)
      # application notices should never be included in PDFs, pull them from session here
      notices = nil
      if !flash.now[:notice].nil?
        notices = flash.now[:notice]
        flash.now[:notice] = nil
      end
      if !flash[:notice].nil?
        notices = '' if notices.nil?
        notices << flash[:notice]
        flash[:notice] = nil
      end

      prince = Prince.new()
      # Sets style sheets on PDF renderer.
      stylesheet_base = "#{::Rails.root}/public/stylesheets"
      prince.add_style_sheets(
        "#{stylesheet_base}/application.css",
        "#{stylesheet_base}/print.css"
      )
      prince.add_style_sheets("#{stylesheet_base}/pdf.css") unless skip_base_pdf_stylesheet
      if 0 < stylesheets.size
        stylesheets.each { |s| prince.add_style_sheets("#{stylesheet_base}/#{s}.css") }
      end

      # Set RAILS_ASSET_ID to blank string or rails appends some time after
      # to prevent file caching, messing up local - disk requests.
      ENV['RAILS_ASSET_ID'] = ''
      html_string = render_to_string(:template => template_path, :layout => 'application')
      # Make all paths relative, on disk paths...
      html_string.gsub!("src=\"", "src=\"#{::Rails.root}/public")
      html_string.gsub!("src=\"#{::Rails.root}/public#{::Rails.root}", "src=\"#{::Rails.root}")

      # re-insert any application notices into the session
      if !notices.nil?
        flash[:notice] = notices
      end

      return prince.pdf_from_string(html_string)
    end

    def make_and_send_pdf(template_path, pdf_name, stylesheets = [], skip_base_pdf_stylesheet = false)
      send_data(
        make_pdf(template_path, pdf_name, stylesheets, skip_base_pdf_stylesheet),
        :filename => pdf_name,
        :type => 'application/pdf'
      )
    end
end

sample controller action

include PdfHelper
def pdf
  index
  make_and_send_pdf '/ads/index', "#{filename}.pdf"
end
分分钟 2024-11-25 20:38:52

您可以使用 acts_as_flying_saucer 库直接将现有 HTML 转换为 PDF。对于页眉和页脚,您可以参考
https://github.com/amardaxini/acts_as_flying_saucer/wiki/PDF-Header-Footer

You can directly convert your existing HTML to PDF using acts_as_flying_saucer library.For header and footer you can refer
https://github.com/amardaxini/acts_as_flying_saucer/wiki/PDF-Header-Footer

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文