lib/prawn/document.rb in prawn-0.12.0 vs lib/prawn/document.rb in prawn-0.13.0
- old
+ new
@@ -5,11 +5,10 @@
# Copyright April 2008, Gregory Brown. All Rights Reserved.
#
# This is free software. Please see the LICENSE and COPYING files for details.
require "stringio"
-require "prawn/document/page_geometry"
require "prawn/document/bounding_box"
require "prawn/document/column_box"
require "prawn/document/internals"
require "prawn/document/span"
require "prawn/document/snapshot"
@@ -50,19 +49,20 @@
#
# See the new and generate methods for further details on the above.
#
class Document
include Prawn::Document::Internals
- include Prawn::Core::Annotations
- include Prawn::Core::Destinations
+ include PDF::Core::Annotations
+ include PDF::Core::Destinations
include Prawn::Document::Snapshot
include Prawn::Document::GraphicsState
include Prawn::Document::Security
include Prawn::Text
include Prawn::Graphics
include Prawn::Images
include Prawn::Stamp
+ include Prawn::SoftMask
# Any module added to this array will be included into instances of
# Prawn::Document at the per-object level. These will also be inherited by
# any subclasses.
#
@@ -134,12 +134,14 @@
# <tt>:bottom_margin</tt>:: Sets the bottom margin in points [0.5 inch]
# <tt>:skip_page_creation</tt>:: Creates a document without starting the first page [false]
# <tt>:compress</tt>:: Compresses content streams before rendering them [false]
# <tt>:optimize_objects</tt>:: Reduce number of PDF objects in output, at expense of render time [false]
# <tt>:background</tt>:: An image path to be used as background on all pages [nil]
+ # <tt>:background_scale</tt>:: Backgound image scale [1] [nil]
# <tt>:info</tt>:: Generic hash allowing for custom metadata properties [nil]
# <tt>:template</tt>:: The path to an existing PDF file to use as a template [nil]
+ # <tt>:text_formatter</tt>: The text formatter to use for <tt>:inline_format</tt>ted text [Prawn::Text::Formatted::Parser]
#
# Setting e.g. the :margin to 100 points and the :left_margin to 50 will result in margins
# of 100 points on every side except for the left, where it will be 50.
#
# The :margin can also be an array much like CSS shorthand:
@@ -164,36 +166,39 @@
#
# # New document, Custom size
# pdf = Prawn::Document.new(:page_size => [200, 300])
#
# # New document, with background
- # pdf = Prawn::Document.new(:background => "#{Prawn::BASEDIR}/data/images/pigs.jpg")
+ # pdf = Prawn::Document.new(:background => "#{Prawn::DATADIR}/images/pigs.jpg")
#
def initialize(options={},&block)
options = options.dup
Prawn.verify_options [:page_size, :page_layout, :margin, :left_margin,
:right_margin, :top_margin, :bottom_margin, :skip_page_creation,
:compress, :skip_encoding, :background, :info,
- :optimize_objects, :template], options
+ :optimize_objects, :template, :text_formatter], options
# need to fix, as the refactoring breaks this
# raise NotImplementedError if options[:skip_page_creation]
self.class.extensions.reverse_each { |e| extend e }
- @internal_state = Prawn::Core::DocumentState.new(options)
+ @internal_state = PDF::Core::DocumentState.new(options)
@internal_state.populate_pages_from_store(self)
min_version(state.store.min_version) if state.store.min_version
@background = options[:background]
+ @background_scale = options[:background_scale] || 1
@font_size = 12
@bounding_box = nil
@margin_box = nil
@page_number = 0
+ @text_formatter = options.delete(:text_formatter) || Text::Formatted::Parser
+
options[:size] = options.delete(:page_size)
options[:layout] = options.delete(:page_layout)
if options[:template]
fresh_content_streams(options)
@@ -215,10 +220,11 @@
attr_accessor :margin_box
attr_reader :margins, :y
attr_writer :font_size
attr_accessor :page_number
+ attr_accessor :text_formatter
def state
@internal_state
end
@@ -239,10 +245,13 @@
# A template for a page can be specified by pointing to the path of and existing pdf.
# One can also specify which page of the template which defaults otherwise to 1.
#
# pdf.start_new_page(:template => multipage_template.pdf, :template_page => 2)
#
+ # Note: templates get indexed by either the object_id of the filename or stream
+ # entered so that if you reuse the same template multiple times be sure to use the
+ # same instance for more efficient use of resources and smaller rendered pdfs.
def start_new_page(options = {})
if last_page = state.page
last_page_size = last_page.size
last_page_layout = last_page.layout
last_page_margins = last_page.margins
@@ -250,18 +259,18 @@
page_options = {:size => options[:size] || last_page_size,
:layout => options[:layout] || last_page_layout,
:margins => last_page_margins}
if last_page
- new_graphic_state = last_page.graphic_state.dup
+ new_graphic_state = last_page.graphic_state.dup if last_page.graphic_state
#erase the color space so that it gets reset on new page for fussy pdf-readers
- new_graphic_state.color_space = {}
+ new_graphic_state.color_space = {} if new_graphic_state
page_options.merge!(:graphic_state => new_graphic_state)
end
merge_template_options(page_options, options) if options[:template]
- state.page = Prawn::Core::Page.new(self, page_options)
+ state.page = PDF::Core::Page.new(self, page_options)
apply_margin_options(options)
generate_margin_box
# Reset the bounding box if the new page has different size or layout
@@ -270,16 +279,17 @@
@bounding_box = @margin_box
end
state.page.new_content_stream if options[:template]
use_graphic_settings(options[:template])
+ forget_text_rendering_mode! if options[:template]
unless options[:orphan]
state.insert_page(state.page, @page_number)
@page_number += 1
- canvas { image(@background, :at => bounds.top_left) } if @background
+ canvas { image(@background, :scale => @background_scale, :at => bounds.top_left) } if @background
@y = @bounding_box.absolute_top
float do
state.on_page_create_action(self)
end
@@ -346,32 +356,36 @@
yield
go_to_page(original_page) unless page_number == original_page
self.y = original_y
end
- # Renders the PDF document to string
+ # Renders the PDF document to string.
+ # Pass an open file descriptor to render to file.
#
- def render
- output = StringIO.new
+ def render(output = StringIO.new)
finalize_all_page_contents
render_header(output)
render_body(output)
render_xref(output)
render_trailer(output)
- str = output.string
- str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
- str
+ if output.instance_of?(StringIO)
+ str = output.string
+ str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
+ return str
+ else
+ return nil
+ end
end
# Renders the PDF document to file.
#
# pdf.render_file "foo.pdf"
#
def render_file(filename)
Kernel.const_defined?("Encoding") ? mode = "wb:ASCII-8BIT" : mode = "wb"
- File.open(filename,mode) { |f| f << render }
+ File.open(filename,mode) { |f| render(f) }
end
# The bounds method returns the current bounding box you are currently in,
# which is by default the box represented by the margin box on the
# document itself. When called from within a created <tt>bounding_box</tt>
@@ -537,30 +551,30 @@
# <total> refers to the total amount of pages in the document. Page numbering should
# occur at the end of your Prawn::Document.generate block because the method iterates
# through existing pages after they are created.
#
# Parameters are:
- #
- # <tt>string</tt>:: Template string for page number wording.
+ #
+ # <tt>string</tt>:: Template string for page number wording.
# Should include '<page>' and, optionally, '<total>'.
# <tt>options</tt>:: A hash for page numbering and text box options.
- # <tt>:page_filter</tt>:: A filter to specify which pages to place page numbers on.
+ # <tt>:page_filter</tt>:: A filter to specify which pages to place page numbers on.
# Refer to the method 'page_match?'
# <tt>:start_count_at</tt>:: The starting count to increment pages from.
# <tt>:total_pages</tt>:: If provided, will replace <total> with the value given.
- # Useful to override the total number of pages when using
+ # Useful to override the total number of pages when using
# the start_count_at option.
# <tt>:color</tt>:: Text fill color.
#
# Please refer to Prawn::Text::text_box for additional options concerning text
# formatting and placement.
#
# Example: Print page numbers on every page except for the first. Start counting from
# five.
#
# Prawn::Document.generate("page_with_numbering.pdf") do
- # number_pages "<page> in a total of <total>",
+ # number_pages "<page> in a total of <total>",
# {:start_count_at => 5,
# :page_filter => lambda{ |pg| pg != 1 },
# :at => [bounds.right - 50, 0],
# :align => :right,
# :size => 14}
@@ -575,46 +589,46 @@
:all
end
total_pages = opts.delete(:total_pages)
txtcolor = opts.delete(:color)
# An explicit height so that we can draw page numbers in the margins
- opts[:height] = 50
-
+ opts[:height] = 50 unless opts.has_key?(:height)
+
start_count = false
pseudopage = 0
(1..page_count).each do |p|
unless start_count
pseudopage = case start_count_at
when 0
1
else
start_count_at.to_i
end
- end
+ end
if page_match?(page_filter, p)
go_to_page(p)
# have to use fill_color here otherwise text reverts back to default fill color
fill_color txtcolor unless txtcolor.nil?
total_pages = total_pages.nil? ? page_count : total_pages
str = string.gsub("<page>","#{pseudopage}").gsub("<total>","#{total_pages}")
text_box str, opts
start_count = true # increment page count as soon as first match found
- end
+ end
pseudopage += 1 if start_count
end
end
# Provides a way to execute a block of code repeatedly based on a
- # page_filter.
+ # page_filter.
#
# Available page filters are:
# :all repeats on every page
# :odd repeats on odd pages
# :even repeats on even pages
# some_array repeats on every page listed in the array
# some_range repeats on every page included in the range
- # some_lambda yields page number and repeats for true return values
+ # some_lambda yields page number and repeats for true return values
def page_match?(page_filter, page_number)
case page_filter
when :all
true
when :odd
@@ -624,11 +638,11 @@
when Range, Array
page_filter.include?(page_number)
when Proc
page_filter.call(page_number)
end
- end
+ end
# Returns true if content streams will be compressed before rendering,
# false otherwise
#
@@ -638,11 +652,11 @@
private
def merge_template_options(page_options, options)
object_id = state.store.import_page(options[:template], options[:template_page] || 1)
- page_options.merge!(:object_id => object_id )
+ page_options.merge!(:object_id => object_id, :page_template => true)
end
# setting override_settings to true ensures that a new graphic state does not end up using
# previous settings especially from imported template streams
def use_graphic_settings(override_settings = false)
@@ -694,8 +708,12 @@
[:left,:right,:top,:bottom].each do |side|
if margin = options[:"#{side}_margin"]
state.page.margins[side] = margin
end
end
+ end
+
+ def font_metric_cache #:nodoc:
+ @font_metric_cache ||= FontMetricCache.new( self )
end
end
end