Skip to content

Commit

Permalink
Filling in the documentation gap. Bounding box may need to be made a …
Browse files Browse the repository at this point in the history
…little clearer
  • Loading branch information
sandal committed May 26, 2008
1 parent 7a2c295 commit a3a9986
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 31 deletions.
30 changes: 19 additions & 11 deletions lib/prawn/document.rb
Expand Up @@ -18,8 +18,8 @@ class Document


attr_accessor :page_size, :page_layout, :y attr_accessor :page_size, :page_layout, :y


# Creates and renders a PDF document. If a filename is given, the output # Creates and renders a PDF document.
# will be rendered to file, otherwise the result will be turned as a string. #
# The explicit receiver argument is necessary only when you need to make # The explicit receiver argument is necessary only when you need to make
# use of a closure. # use of a closure.
# #
Expand All @@ -29,27 +29,30 @@ class Document
# text "Hello World", :at => [200,720], :size => 32 # text "Hello World", :at => [200,720], :size => 32
# end # end
# #
# # Using explicit block form and rendering to a file # # Using explicit block form and rendering to a file
# content = "Hello World"
# Prawn::Document.generate "foo.pdf" do |pdf| # Prawn::Document.generate "foo.pdf" do |pdf|
# pdf.font "Times-Roman" # pdf.font "Times-Roman"
# pdf.text "Hello World", :at => [200,720], :size => 32 # pdf.text content, :at => [200,720], :size => 32
# end # end
# #
# # Using implicit block form and rendering to string def self.generate(filename,options={},&block)
# output = Prawn::Document.generate { stroke_line [100,100], [200,200] } pdf = Prawn::Document.new(options)
#
def self.generate(filename=nil,&block)
pdf = Prawn::Document.new
block.arity < 1 ? pdf.instance_eval(&block) : yield(pdf) block.arity < 1 ? pdf.instance_eval(&block) : yield(pdf)
filename ? pdf.render_file(filename) : pdf.render pdf.render_file(filename)
end end


# Creates a new PDF Document. The following options are available: # Creates a new PDF Document. The following options are available:
# #
# <tt>:page_size</tt>:: One of the Document::PageGeometry::SIZES (default: LETTER) # <tt>:page_size</tt>:: One of the Document::PageGeometry::SIZES (default: LETTER)
# <tt>:page_layout</tt>:: Either <tt>:portrait</tt> or <tt>:landscape</tt> # <tt>:page_layout</tt>:: Either <tt>:portrait</tt> or <tt>:landscape</tt>
# <tt>:on_page_start</tt>:: Optional proc run at each page start # <tt>:on_page_start</tt>:: Optional proc run at each page start
# <tt>:on_page_stop</tt>:: Optional proc run at each page stop # <tt>:on_page_stop</tt>:: Optional proc run at each page stop
# <tt>:left_margin</tt>:: Sets the left margin in points [default: 0.5 inch]
# <tt>:right_margin</tt>:: Sets the right margin in points [default: 0.5 inch]
# <tt>:top_margin</tt>:: Sets the top margin in points [default: 0.5 inch]
# <tt>:bottom_margin</tt>:: Sets the bottom margin in points [default: 0.5 inch]
#
# #
# # New document, US Letter paper, portrait orientation # # New document, US Letter paper, portrait orientation
# pdf = Prawn::Document.new # pdf = Prawn::Document.new
Expand Down Expand Up @@ -143,6 +146,11 @@ def render_file(filename)
File.open(filename,"wb") { |f| f << render } File.open(filename,"wb") { |f| f << render }
end end


# Returns the current BoundingBox object, which is by default
# the box represented by the margin box. When called from within
# a <tt>bounding_box</tt> block, the box defined by that call will
# be used.
#
def bounds def bounds
@bounding_box @bounding_box
end end
Expand Down
101 changes: 84 additions & 17 deletions lib/prawn/document/bounding_box.rb
@@ -1,6 +1,63 @@
module Prawn module Prawn
class Document class Document


# A bounding box serves two important purposes:
# * Provide bounds for flowing text, starting at a given point
# * Translate the origin (0,0) for graphics primitives, for the purposes
# of simplifying coordinate math.
#
# When flowing text, the usage of a bounding box is simple. Text will
# begin at the point specified, flowing the width of the bounding box.
# After the block exits, the text drawing position will be moved to
# the bottom of the bounding box (y - height). Currently, Prawn allows
# text to overflow the bottom border of the bounding box, so it is up to
# the user to ensure the text provided will fit within the height of the
# bounding box.
#
# pdf.bounding_box([100,500], :width => 100, :height => 300) do
# pdf.text "This text will flow in a very narrow box starting" +
# "from [100,500]. The pointer will then be moved to [100,200]" +
# "and return to the margin_box"
# end
#
# When translating coordinates, the idea is to allow the user to draw
# relative to the origin, and then translate their drawing to a specified
# area of the document, rather than adjust all their drawing coordinates
# to match this new region.
#
# Take for example two triangles which share one point, drawn from the
# origin:
#
# pdf.polygon [0,250], [0,0], [150,100]
# pdf.polygon [100,0], [150,100], [200,0]
#
# It would be easy enough to translate these triangles to another point,
# e.g [200,200]
#
# pdf.polygon [200,450], [200,200], [350,300]
# pdf.polygon [300,200], [350,300], [400,200]
#
# However, each time you want to move the drawing, you'd need to alter
# every point in the drawing calls, which as you might imagine, can become
# tedious.
#
# If instead, we think of the drawing as being bounded by a box, we can
# see that the image is 200 points wide by 250 points tall.
#
# To translate it to a new origin, we simply select a point at (x,y+height)
#
# Using the [200,200] example:
#
# pdf.bounding_box([200,450], :width => 200, :height => 250) do
# pdf.polygon [0,250], [0,0], [150,100]
# pdf.polygon [100,0], [150,100], [200,0]
# end
#
# Notice that the drawing is still relative to the origin. If we want to
# move this drawing around the document, we simply need to recalculate the
# top-left corner of the rectangular bounding-box, and all of our graphics
# calls remain unmodified.
#
def bounding_box(*args,&block) def bounding_box(*args,&block)
@bounding_box = BoundingBox.new(*args) @bounding_box = BoundingBox.new(*args)
self.y = @bounding_box.absolute_top self.y = @bounding_box.absolute_top
Expand All @@ -13,43 +70,53 @@ def bounding_box(*args,&block)


class BoundingBox class BoundingBox


def initialize(point,options={}) def initialize(point,options={}) #:nodoc:
@x,@y = point @x,@y = point
@width, @height = options[:width], options[:height] @width, @height = options[:width], options[:height]
end end


# The translated origin (x,y-height) which describes the location
# of the bottom left corner of the bounding box in absolute terms.
def anchor def anchor
[@x, @y - @height] [@x, @y - @height]
end end


# Relative left x-coordinate of the bounding box. (Always 0)
def left def left
0 0
end end


# Relative right x-coordinate of the bounding box. (Equal to the box width)
def right def right
@width @width
end end


# Relative top y-coordinate of the bounding box. (Equal to the box height)
def top def top
@height @height
end end


# Relative bottom y-coordinate of the bounding box (Always 0)
def bottom def bottom
0 0
end end


# Absolute left x-coordinate of the bounding box
def absolute_left def absolute_left
@x @x
end end


# Absolute right x-coordinate of the bounding box
def absolute_right def absolute_right
@x + @width @x + @width
end end


# Absolute top y-coordinate of the bounding box
def absolute_top def absolute_top
@y @y
end end


# Absolute bottom y-coordinate of the bottom box
def absolute_bottom def absolute_bottom
@y - @height @y - @height
end end
Expand Down
14 changes: 12 additions & 2 deletions lib/prawn/document/text.rb
Expand Up @@ -14,10 +14,20 @@ module Text
Times-Roman Times-Bold Times-Italic Times-BoldItalic Times-Roman Times-Bold Times-Italic Times-BoldItalic
Symbol ZapfDingbats ] Symbol ZapfDingbats ]


# Draws text at a specified position on the page. # Draws text on the page. If a point is specified via the <tt>:at</tt>
# option the text will begin exactly at that point, and the string is
# assumed to be pre-formatted to properly fit the page.
#
# When <tt>:at</tt> is not specified, Prawn attempts to wrap the text to
# fit within your current bounding box (or margin box if no bounding box
# is being used ). Text will flow onto the next page when it reaches
# the bottom of the margin_box. Text wrap in Prawn does not re-flow
# linebreaks, so if you want fully automated text wrapping, be sure to
# remove newlines before attempting to draw your string.
# #
# pdf.text "Hello World", :at => [100,100] # pdf.text "Hello World", :at => [100,100]
# pdf.text "Goodbye World", :at => [50,50], :size => 16 # pdf.text "Goodbye World", :at => [50,50], :size => 16
# pdf.text "This will be wrapped when it hits the edge of your bounding box"
# #
def text(text,options={}) def text(text,options={})
return wrapped_text(text,options) unless options[:at] return wrapped_text(text,options) unless options[:at]
Expand Down
2 changes: 1 addition & 1 deletion lib/prawn/font/afm.rb
Expand Up @@ -9,7 +9,7 @@


module Prawn module Prawn
module Font module Font
class AFM class AFM #:nodoc:


ISOLatin1Encoding = %w[ ISOLatin1Encoding = %w[
.notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef .notdef
Expand Down

0 comments on commit a3a9986

Please sign in to comment.