Prawn PDF 中的页眉和页脚

问题描述 投票:0回答:8

我已经阅读了 Prawn 上的所有相关帖子,但没有发现(即使在 Prawn 自己的文档中)提到页眉和页脚。

不过,我确实在Prawnto自己的网站上看到了一个关于页眉和页脚的演示。我复制了该演示的整个源代码只是为了看看它是否有效,但有人抱怨未定义方法“标头”的错误。我是否可以理解,Prawn 最近在 gem 中取出了页眉和页脚,或者我需要先做些什么才能使用页眉和页脚?

演示页面: http://cracklabs.com/prawnto/code/prawn_demos/source/text/flowing_text_with_header_and_footer

关注代码部分:

Prawn::Document.generate("flow_with_headers_and_footers.pdf")  do

  header margin_box.top_left do 
      text "Here's My Fancy Header", :size => 25, :align => :center   
  end   

  text "hello world!"
end

为了以防万一,我所说的标题是指通常出现在文档每页角落的单词片段。就像您的账单页面中的帐号一样。

谢谢!

ruby-on-rails prawn prawnto
8个回答
37
投票

您所引用的示例来自 prawnto 插件,使用的是旧版本的 prawn。

因为我还需要页眉和页脚,所以我对此进行了更多研究。那个版本的虾似乎有页眉和页脚方法,它们是使用惰性边界框实现的。 (查看github上的代码找到的)

在新的虾版本中你可以使用中继器做同样的事情。

这是使用新版本重写的完整示例:

require "#{File.dirname(__FILE__)}/../example_helper.rb"

Prawn::Document.generate("test.pdf")  do

   repeat :all do
    # header
    bounding_box [bounds.left, bounds.top], :width  => bounds.width do
        font "Helvetica"
        text "Here's My Fancy Header", :align => :center, :size => 25
        stroke_horizontal_rule
    end

    # footer
    bounding_box [bounds.left, bounds.bottom + 25], :width  => bounds.width do
        font "Helvetica"
        stroke_horizontal_rule
        move_down(5)
        text "And here's a sexy footer", :size => 16
    end
  end

  bounding_box([bounds.left, bounds.top - 50], :width  => bounds.width, :height => bounds.height - 100) do                 
   text "this is some flowing text " * 200    

   move_down(20)

   font "#{Prawn::BASEDIR}/data/fonts/DejaVuSans.ttf"
   table [["ὕαλον ϕαγεῖν",    "baaar",             "1" ],
          ["This is","a sample",          "2" ],
          ["Table",  "dont\ncha\nknow?",  "3" ],
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules\nwith an iron fist", "x" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],   
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ],  
          [ "It",    "Rules",             "4" ],     
          [ "It",    "Rules",             "4" ]],     

     :font_size          => 24, 
     :horizontal_padding => 10,
     :vertical_padding   => 3,
     :border_width       => 2,
     :position           => :center,
     :headers            => ["Column A","Column B","#"]

  end
end

您可以查看 Repeat 的文档页面以了解其他选项,这些选项允许您准确指定中继器的位置。


23
投票

@GrantSayer 谢谢这个例子,但这只会让你显示当前页码,而不是总页数。

您还可以使用页脚的 number_pages 函数:

Prawn::Document.generate("page_with_numbering.pdf") do
  text "Hai"
  start_new_page
  text "bai"
  start_new_page
  text "-- Hai again"
  number_pages "<page> in a total of <total>", [bounds.right - 50, 0]
end

但是,就我而言,我还需要格式化/样式并右对齐页码以匹配公司样式指南。我使用 go_to_page(k) 创建自己的页眉和页脚函数,在创建所有页面后将页眉和页脚添加到每个页面。这为我提供了样式选项和总页数:

Prawn::Document.generate("footer_example.pdf", :skip_page_creation => true) do 10.times do start_new_page text "Some filler text for the page" end # footer page_count.times do |i| go_to_page(i+1) lazy_bounding_box([bounds.right-50, bounds.bottom + 25], :width => 50) { text "#{i+1} / #{page_count}" }.draw end end
    

18
投票
与最新版本的 Prawn 有点不同,你必须传递一个哈希值

Prawn::Document.generate("page_with_numbering.pdf") do text "Hai" start_new_page text "bai" start_new_page text "-- Hai again" number_pages "<page> in a total of <total>", { :start_count_at => 0, :page_filter => :all, :at => [bounds.right - 50, 0], :align => :right, :size => 14 } end
    

10
投票
如果您想要页脚不会在文本上写东西,则必须使用

bounding_box

 在文档边距下方创建 
bounds.bottom

require 'prawn' file_name = 'hello.pdf' random_table = (0..50).map{|i|[*('a'..'z')]} # generate a 2D array for example (~2 pages) Prawn::Document::generate(file_name) do |pdf| pdf.table random_table pdf.page_count.times do |i| pdf.bounding_box([pdf.bounds.left, pdf.bounds.bottom], :width => pdf.bounds.width, :height => 30) { # for each page, count the page number and write it pdf.go_to_page i+1 pdf.move_down 5 # move below the document margin pdf.text "#{i+1}/#{pdf.page_count}", :align => :center # write the page number and the total page count } end end

它应该是这样的,您可以看到页脚位于边距底部之外:

example result

希望对某人有帮助


8
投票

开始编辑

这适用于> = 0.12 的虾

结束编辑

这是我使用重复、画布和单元格的解决方案。本质上,我是在每个页面的绝对顶部和底部绘制边界框。我使用单元格来更好地控制它的样式。希望这会对某人有所帮助。 (我使用了稍微烦人的颜色来更好地说明如何控制页眉和页脚的样式)

Prawn::Document.generate("headers_and_footers_with_background.pdf") do repeat :all do # header canvas do bounding_box([bounds.left, bounds.top], :width => bounds.width) do cell :content => 'Header', :background_color => 'EEEEEE', :width => bounds.width, :height => 50, :align => :center, :text_color => "001B76", :borders => [:bottom], :border_width => 2, :border_color => '00FF00', :padding => 12 end end # footer canvas do bounding_box [bounds.left, bounds.bottom + 50], :width => bounds.width do cell :content => 'Footer', :background_color => '333333', :width => bounds.width, :height => 50, :align => :center, :text_color => "FFFFFF", :borders => [:top], :border_width => 2, :border_color => 'FF0000', :padding => 12 end end end # body bounding_box([bounds.left, bounds.top - 25], :width => bounds.width, :height => bounds.height - 50) do 100.times do text "Some filler text for the page" end end end
    

3
投票
这是使用

bounding_box

 创建自定义页脚内容时的问题...它仍然在边距范围内呈现。

我一直在寻找可以将内容

number_pages一起写在边距区域

中的东西。(因为页脚通常设置在底部边距区域)...但似乎没有。

所以,我使用

text_box

 并将坐标放置在我的主边界框之外,如下所示:

repeat :all do text_box "My custom footer", size: 7, align: :center, :at => [bounds.left, bounds.bottom], :height => 100, :width => bounds.width end

请注意

repeat :all

 会将此页脚文本呈现到每个页面。


1
投票
我发现在页面上获取重复项目的唯一方法是使用

Prawn::Document::LazyBoundingBox

 方法。基本上,这允许您定义一个边界框,该边界框仅在您调用它时才会呈现。所以通常的
pseudo-code
步骤是

    定义惰性边界框元素分配给 somevar
  1. 在每个新页面上调用该元素。
源代码中的示例展示了如何实现

file = "lazy_bounding_boxes.pdf" Prawn::Document.generate(file, :skip_page_creation => true) do point = [bounds.right-50, bounds.bottom + 25] page_counter = lazy_bounding_box(point, :width => 50) do text "Page: #{page_count}" end 10.times do start_new_page text "Some filler text for the page" page_counter.draw end end
这将为您在每个新页面上提供页数文本输出。理想的情况是,如果这可以应用于页面模板的设置中,并且无需手动调用来渲染元素,即可重复使用该页面模板。与文本流相结合,这将提供页眉和页脚的传统解决方案。


0
投票
我的做法略有不同,但深受@konung 的影响。我有一个 PdfGenerator 服务模块,我的基类有一系列共享元素,例如页脚/页眉:

module PdfGenerator class Base HEADER_HEIGHT = 30 FOOTER_HEIGHT = 30 MARGIN_FACTOR = 1.2 def initialize(_ = nil) @pdf = Prawn::Document.new end def apply_header(header = "Custom Builder Select") @pdf.page_count.times do |i| next if i == 0 @pdf.go_to_page(i + 1) @pdf.bounding_box([@pdf.bounds.left, @pdf.bounds.top], width: @pdf.bounds.width, height: HEADER_HEIGHT) do @pdf.fill_color "44403c" @pdf.fill_rectangle [0, @pdf.bounds.top], @pdf.bounds.width, HEADER_HEIGHT @pdf.fill_color "FFFFFF" @pdf.move_down HEADER_HEIGHT / 2 - 6 @pdf.text header, align: :center, size: 12 end end end def apply_footer @pdf.page_count.times do |i| next if i == 0 @pdf.go_to_page(i + 1) @pdf.bounding_box([@pdf.bounds.left, @pdf.bounds.bottom + FOOTER_HEIGHT], width: @pdf.bounds.width, height: FOOTER_HEIGHT) do @pdf.fill_color "44403c" @pdf.fill_rectangle [0, @pdf.bounds.top], @pdf.bounds.width, FOOTER_HEIGHT @pdf.fill_color "FFFFFF" @pdf.move_down FOOTER_HEIGHT / 2 - 5 @pdf.text "#{i + 1} / #{@pdf.page_count}", align: :center, size: 10 end end end def apply_body @pdf.bounding_box( [@pdf.bounds.left, @pdf.bounds.top - HEADER_HEIGHT * MARGIN_FACTOR], width: @pdf.bounds.width, height: @pdf.bounds.height - (HEADER_HEIGHT + FOOTER_HEIGHT) * MARGIN_FACTOR ) do yield if block_given? end end def render @pdf.render end end end
然后,当我想在特定类型的 PDF 生成器中使用它时,我会这样做:

module PdfGenerator class YourPdfClass < Base def initialize(thing) super @thing = thing end def render cover_page # A method for your cover page apply_body do things_pages # A method where you build the content of this things pages end apply_header(@thing.name) apply_footer @pdf.render end end end
这里的主要区别是,我存储了页眉和页脚的尺寸,以便我可以一致地间隔这些尺寸,然后页面的主体位于由这些尺寸定义的框中。如果出于某种原因我想要一个更高的标题,我可以更改该常量,它将调整我的标题、正文开始的点以及正文结束/页脚开始的点。

边距因素是在我的身体和页眉/页脚之间留下一点填充。如果您愿意,您还可以将字体大小设置为常数来计算文本的垂直居中。

© www.soinside.com 2019 - 2024. All rights reserved.