#!/usr/bin/env ruby
# encoding: US-ASCII
#
# Created by Brent Rowland on 2007-07-13.
# Copyright (c) 2007, 2008 Eidetic Software. All rights reserved.
require 'epdfpw'
require 'epdfo'
require 'epdfk'
require 'epdfafm'
require 'epdftt'
module EideticPDF
class DocumentWriter
def next_seq # :nodoc:
@next_seq += 1
end
attr_reader :pages # :nodoc:
attr_reader :catalog, :file, :resources # :nodoc:
attr_reader :fonts, :images, :encodings, :bullets # :nodoc:
attr_reader :in_page
# Instantiate a new DocumentWriter object. Document is NOT open for writing at this point.
def initialize
@fonts = {}
@images = {}
@encodings = {}
@bullets = {}
end
# Render document to PDF and return as a binary string.
def to_s
@file.to_s
end
# Open the document for writing.
#
# The following document options apply:
# [:+pages_up+] A tuple (array) of the form [+pages_across+, +pages_down+] specifying the layout of virtual pages. Defaults to [1, 1] (no virtual pages).
# [:+pages_up_layout+] When :+across+, virtual pages proceed from left to right before top to bottom. When :+down+, virtual pages proceed from top to bottom before left to right.
#
# In addition, any of the options for +open_page+ may be supplied and will apply to each page, unless explicitly overridden.
def open(options={})
raise Exception.new("Already in document") if @in_doc
@in_doc = true
@options = options
@pages = []
@next_seq = 0
@file = PdfObjects::PdfFile.new
pages = PdfObjects::PdfPages.new(next_seq, 0)
outlines = PdfObjects::PdfOutlines.new(next_seq, 0)
@catalog = PdfObjects::PdfCatalog.new(next_seq, 0, :use_none, pages, outlines)
@file.body << pages << outlines << @catalog
@file.trailer.root = @catalog
define_resources
@pages_across, @pages_down = options[:pages_up] || [1, 1]
@pages_up = @pages_across * @pages_down
end
# Close any open pages, preparing the document for rendering to PDF.
def close
open_page if @pages.empty? # empty document needs at least one page
close_page if @in_page
@pages.each { |page| page.close unless page.closed? }
end
# Open the document for writing and yield to the block given before calling +close+.
def doc(options={}, &block)
open(options)
yield(self)
close
end
# Open a page for writing. Raises Exception if a page is already open.
#
# The following page options apply:
# [:+compress+] Compress page streams using zlib deflate.
# [:+units+] A symbol from EideticPDF::UNIT_CONVERSION hash, specifying ratio of units to points. Defaults to :+pt+. Other choices are :+in+ for inches and :+cm+ for centimeters. Custom units may be added.
# [:+v_text_align+] Initial vertical text alignment for page. See +v_text_align+ method.
# [:+font+] Initial font for page. Defaults to { :name => 'Helvetica', :size => 12 }.
# [:+fill_color+] Initial fill color. Defaults to 0 (black). See +fill_color+ method.
# [:+line_color+] Initial line color. Defaults to 0 (black). See +line_color+ method.
# [:+line_height+] Initial line height. Defaults to 1.7. See +line_height+ method.
# [:+line_width+] Initial line width. Defaults to 1.0. See +line_width+ method.
# [:+margins+] Page margins. Defaults to 0. See +margins+ method.
# [:+unscaled+] If true, virtual pages are not scaled down. Defaults to +false+.
def open_page(options={})
raise Exception.new("Already in page") if @in_page
options.update(:_page => pdf_page(@pages.size), :sub_page => sub_page(@pages.size))
@cur_page = PageWriter.new(self, @options.merge(options))
@pages << @cur_page
@in_page = true
return @cur_page
end
# Close the current open page. Raises Exception if no page is currently open.
def close_page
raise Exception.new("Not in page") unless @in_page
@cur_page.close
@cur_page = nil
@in_page = false
end
# Open a page for writing and yield to the block given before calling +close_page+.
#
# +options+ is passed through to +open_page+.
def page(options={}, &block)
cur_page = open_page(options)
yield(cur_page)
close_page
end
# Close the current page and begin a new page with the specified options.
# [+options+] See +open_page+ method.
def new_page(options={})
close_page
open_page(options)
end
def cur_page # :nodoc:
@cur_page || open_page
end
# Set units measurements are to be specified in. If no units are specified, returns current units setting.
# Valid units include :+pt+ (points), :+in+ (inches) and :+cm+ (centimeters) by default.
#
# Custom units can be specified by updating the EideticPDF::UNIT_CONVERSION hash with a new symbol and conversion ratio.
def units(units=nil)
cur_page.units(units)
end
# Set top, right, bottom and left margins. If 1, 2 or 4 values are not specified, returns current margins as a tuple (array)
# of values in the form [top, right, bottom, left].
# [+margins+] When 4 values are given, [top, right, bottom, left]. When 2 values are given, [top and bottom, right and left]. When 1 value is specified, it is used for all 4 settings.
def margins(*margins)
cur_page.margins(*margins)
end
# Returns top margin as set by +margins+ method.
def margin_top
cur_page.margin_top
end
# Returns right margin as set by +margins+ method.
def margin_right
cur_page.margin_right
end
# Returns bottom margin as set by +margins+ method.
def margin_bottom
cur_page.margin_bottom
end
# Returns left margin as set by +margins+ method.
def margin_left
cur_page.margin_left
end
# +page_height+ excluding top and bottom margins.
def canvas_width
cur_page.canvas_width
end
# +page_width+ excluding left and right margins.
def canvas_height
cur_page.canvas_height
end
# Set horizontal tabs using an array of numbers or a comma-delimited string. If no tabs are specified, returns current tabs.
# Use false to clear current tab stops.
def tabs(tabs=nil)
cur_page.tabs(tabs)
end
# Move right to next horizontal tab. If no more tab stops exist, then moves to first tab stop on the following line.
# If a block is given, the value returned is used instead as the vertical distance to move down.
def tab(&block)
cur_page.tab(&block)
end
# Set vertical tabs using an array of numbers or a comma-delimited string. If no tabs are specified, returns current tabs.
# Use false to clear current tab stops.
def vtabs(tabs=nil)
cur_page.vtabs(tabs)
end
# Move down to next vertical tab. If no more tab stops exist and a block is given, moves up to the first vertical tab stop
# and right the value returned by the block.
def vtab(&block)
cur_page.vtab(&block)
end
# Set horizontal indentation. If no value is specified, returns current indentation setting.
# [+value+] The new indentation.
# [+absolute+] If +true+, the new value is relative only to the left margin. If +false+, value is relative to previous indentation.
# The indent setting is used by the +puts+ and +new_line+ methods.
def indent(value=nil, absolute=false)
cur_page.indent(value, absolute)
end
# Returns page width in current units.
def page_width
cur_page.page_width
end
# Returns page height in current units.
def page_height
cur_page.page_height
end
# Set line height as used by methods like +paragraph+ that display multiple lines of text.
# If no value is specified, returns current +line_height+.
# [+height+] Ratio of +font_size+ to effective line height.
def line_height(height=nil)
cur_page.line_height(height)
end
# Move pen to point (x, y).
def move_to(x, y)
cur_page.move_to(x, y)
end
# Move pen to point (x, y) like +move_to+, returning previous location. If x is not specified, returns current location.
def pen_pos(x=nil, y=nil)
cur_page.pen_pos(x, y)
end
# Move the pen to a new location relative to the current location.
# [+dx+] Horizontal distance to move pen. Positive values move right. Negative values move left.
# [+dy+] Vertical distance to move pen. Positive values move down. Negative values move up.
def move_by(dx, dy)
cur_page.move_by(dx, dy)
end
# Draw a line from the current location to point (x, y).
# If +auto_path+ is off, a new segment is appended to the current path.
def line_to(x, y)
cur_page.line_to(x, y)
end
# Draw a line from point (x, y) to a point +length+ units distant at +angle+ degrees.
def line(x, y, angle, length)
cur_page.line(x, y, angle, length)
end
# Draw a rectangle with the specified +width+ and +height+ and its top, left corner at (x, y).
#
# The following +options+ apply:
# [:+border+] If true or a color, a border is drawn with the current or specified +line_color+, respectively. Defaults to +true+.
# [:+fill+] If true or a color, the area is filled with the current or specified +fill_color+, respectively. Defaults to +false+.
# [:+clip+] If true and a block is given, the shape acts as a clipping boundary for anything drawn within the supplied block.
# [:+reverse+] Draw polygon clockwise. This is useful for drawing hollow shapes.
#
# These current settings also apply: +line_color+, +line_width+, +line_dash_pattern+ and +fill_color+.
def rectangle(x, y, width, height, options={})
cur_page.rectangle(x, y, width, height, options)
end
# Draw a cubic Bezier curve from (x0, y0) to (x3, y3) with control points and (x2, y2).
# If the first point does not coincide with the current position, any current path is stroked and a new path is begun.
# Otherwise, the curve is appended to the current path.
def curve(x0, y0, x1, y1, x2, y2, x3, y3)
cur_page.curve(x0, y0, x1, y1, x2, y2, x3, y3)
end
# Draw a series of cubic Bezier curves. After moving to the first point, a curve to the 4th point is appended to the current path
# with the 2nd and 3rd points acting as control points. A curve is appended to the current path for each additional group
# of 3 points, with the 1st and 2nd point in each group acting as control points.
#
# [+points+] array of +Location+ structs
def curve_points(points)
cur_page.curve_points(points)
end
# Returns array of +Location+ structs for circle, suitable for feeding to +curve_points+ method. See +circle+ method.
def points_for_circle(x, y, r)
cur_page.points_for_circle(x, y, r)
end
# Draw a circle with center x, y and radius +r+.
# Direction is counterclockwise (anticlockwise), unless :+reverse+ option is specified.
#
# The following +options+ apply:
# [:+border+] If true or a color, a border is drawn with the current or specified +line_color+, respectively. Defaults to +true+.
# [:+fill+] If true or a color, the area is filled with the current or specified +fill_color+, respectively. Defaults to +false+.
# [:+clip+] The shape acts as a clipping boundary for anything drawn within the supplied block.
# [:+reverse+] Draw circle clockwise. Useful for drawing hollow shapes.
#
# These current settings also apply: +line_color+, +line_width+, +line_dash_pattern+ and +fill_color+.
def circle(x, y, r, options={}, &block)
cur_page.circle(x, y, r, options, &block)
end
# Returns array of +Location+ structs for ellipse, suitable for feeding to +curve_points+ method. See +ellipse+ method.
def points_for_ellipse(x, y, rx, ry)
cur_page.points_for_ellipse(x, y, rx, ry)
end
# Draw an ellipse with foci (x, y) and (x, y) and radius +r+.
# Direction is counterclockwise (anticlockwise), unless :+reverse+ option is specified.
#
# The following +options+ apply:
# [:+border+] If true or a color, a border is drawn with the current or specified +line_color+, respectively. Defaults to +true+.
# [:+fill+] If true or a color, the area is filled with the current or specified +fill_color+, respectively. Defaults to +false+.
# [:+clip+] The shape acts as a clipping boundary for anything drawn within the supplied block.
# [:+reverse+] Draw ellipse clockwise. Useful for drawing hollow shapes.
#
# These current settings also apply: +line_color+, +line_width+, +line_dash_pattern+ and +fill_color+.
def ellipse(x, y, rx, ry, options={})
cur_page.ellipse(x, y, rx, ry, options)
end
# Returns array of +Location+ structs for arc, suitable for feeding to +curve_points+ method. See +arc+ method.
def points_for_arc(x, y, r, start_angle, end_angle)
cur_page.points_for_arc(x, y, r, start_angle, end_angle)
end
# Draw an arc with origin x, y and radius +r+ from +start_angle+ to +end_angle+ degrees.
# Direction is counterclockwise (anticlockwise), unless +end_angle+ < +start_angle+.
# Angles are allowed to exceed 360 degrees.
#
# By default, arc extends the current path to the point where the arc begins.
# If move_to0 is true (or there is no current path) a move is performed to where the arc begins.
#
# This method returns immediately if start_angle == end_angle.
def arc(x, y, r, start_angle, end_angle, move_to0=false)
cur_page.arc(x, y, r, start_angle, end_angle, move_to0)
end
# Draw a pie-shaped wedge with origin x, y and radius +r+ from +start_angle+ to +end_angle+ degrees.
# [:+border+] If true or a color, a border is drawn with the current or specified +line_color+, respectively. Defaults to +true+.
# [:+fill+] If true or a color, the area is filled with the current or specified +fill_color+, respectively. Defaults to +false+.
# [:+clip+] If true and a block is given, the shape acts as a clipping boundary for anything drawn within the supplied block.
# [:+reverse+] By default, the bounding path is drawn from (x, y) to (r, start_angle) through (r, end_angle) and back to (x, y). This order is reversed if :reverse => true. This is useful for drawing hollow shapes.
#
# These current settings also apply: +line_color+, +line_width+, +line_dash_pattern+ and +fill_color+.
def pie(x, y, r, start_angle, end_angle, options={})
cur_page.pie(x, y, r, start_angle, end_angle, options)
end
# Draw an arch with origin x, y from +start_angle+ to _end_angle_ degrees.
# The result is a bounded area between radii r1 and r2.
#
# The following +options+ apply:
# [:+border+] If true or a color, a border is drawn with the current or specified +line_color+, respectively. Defaults to +true+.
# [:+fill+] If true or a color, the area is filled with the current or specified +fill_color+, respectively. Defaults to +false+.
# [:+clip+] If true and a block is given, the shape acts as a clipping boundary for anything drawn within the supplied block.
# [:+reverse+] By default, the bounding path is drawn from (r1, start_angle) to (r1, end_angle), (r2, end_angle), (r2, start_angle) and back to (r1, start_angle). This order is reversed if reverse => true. This is useful for drawing hollow shapes.
#
# These current settings also apply: +line_color+, +line_width+, +line_dash_pattern+ and +fill_color+.
def arch(x, y, r1, r2, start_angle, end_angle, options={}, &block)
cur_page.arch(x, y, r1, r2, start_angle, end_angle, options, &block)
end
# Returns array of +Location+ structs representing the vertices of a polygon. See +polygon+ method.
def points_for_polygon(x, y, r, sides, options={})
cur_page.points_for_polygon(x, y, r, sides, options)
end
# Draw a polygon with origin (x, y), radius +r+ and the specified number of +sides+.
#
# The following +options+ apply:
# [:+border+] If true or a color, a border is drawn with the current or specified +line_color+, respectively. Defaults to +true+.
# [:+fill+] If true or a color, the area is filled with the current or specified +fill_color+, respectively. Defaults to +false+.
# [:+clip+] If true and a block is given, the shape acts as a clipping boundary for anything drawn within the supplied block.
# [:+reverse+] Draw polygon clockwise. This is useful for drawing hollow shapes.
#
# These current settings also apply: +line_color+, +line_width+, +line_dash_pattern+ and +fill_color+.
def polygon(x, y, r, sides, options={})
cur_page.polygon(x, y, r, sides, options)
end
# Draw a star with origin (x, y), outer radius +r1+, inner radius +r2+ and the specified number of +sides+.
#
# The following +options+ apply:
# [:+border+] If true or a color, a border is drawn with the current or specified +line_color+, respectively. Defaults to +true+.
# [:+fill+] If true or a color, the area is filled with the current or specified +fill_color+, respectively. Defaults to +false+.
# [:+clip+] If true and a block is given, the shape acts as a clipping boundary for anything drawn within the supplied block.
# [:+reverse+] Draw polygon clockwise. This is useful for drawing hollow shapes.
#
# These current settings also apply: +line_color+, +line_width+, +line_dash_pattern+ and +fill_color+.
def star(x, y, r1, r2, points, options={})
cur_page.star(x, y, r1, r2, points, options)
end
# Returns current status of auto_path. Defaults to +true+. False while in a block given to +path+ method.
# When +true+, paths are automatically stroked before a new, non-contiguous segment is appended or a closed shape is drawn.
def auto_path
cur_page.auto_path
end
# Turn off auto_path. If a block is given, yields to it before filling and/or stroking anything drawn within it according to
# the +options+ supplied. The path may be non-contiguous. Shapes may be hollow when inner paths are drawn in the opposite
# direction as outer paths.
#
# The following options apply:
# [:+stroke+] If true or a color, the path will be stroked with the current or specified +line_color+, respectively. Defaults to +false+.
# [:+fill+] If true or a color, the area bounded by the path will be filled with the current or specified +fill_color+, respectively. Defaults to +false+.
def path(options={}, &block)
cur_page.path(options, &block)
end
# Fill current path (begun by +path+ method) and resume +auto_path+. The +line_color+ and +fill_color+ in effect before +path+
# was begun are restored. Raises Exception if no current path exists.
def fill
cur_page.fill
end
# Stroke current path (begun by +path+ method) and resume +auto_path+. The +line_color+ and +fill_color+ in effect before +path+
# was begun are restored. Raises Exception if no current path exists.
def stroke
cur_page.stroke
end
# Fill and stroke current path (begun by +pat+ method) and resume +auto_path+. The +line_color+ and +fill_color+ in effect
# before +path+ was begun are restored. Raises Exception if no current path exists.
def fill_and_stroke
cur_page.fill_and_stroke
end
# Use current path as a clipping boundary for anything drawn within the supplied block.
#
# The following +options+ apply:
# [:+stroke+] If true, the current path is stroked with the current +line_color+. Defaults to +false+.
# [:+fill+] If true, the area bounded by the current path is filled with the current +fill_color+. Defaults to +false+.
def clip(options={}, &block)
cur_page.clip(options, &block)
end
# Set the shape to be used at the ends of lines. If no style is specified, returns current style.
# [+style+] One of the symbols :butt_cap, :round_cap or :projecting_square_cap, or a string 'butt_cap', 'round_cap' or 'projecting_square_cap'.
def line_cap_style(style=nil)
cur_page.line_cap_style(style)
end
# Set the pattern of dashes and gaps used to draw lines. If no pattern is specified, returns current pattern.
# [+pattern+] A string of the form '[dash gap] phase' or one of the symbols :+solid+, :+dotted+ or :+dashed+.
# When a symbol is specified, dash and gap lengths are multiplied by +line_width+ for proportion.
def line_dash_pattern(pattern=nil)
cur_page.line_dash_pattern(pattern)
end
# Set line width used when stroking paths. If no width is specified, returns current +line_width+.
# [+value+] If +value+ is a number, the new +line_width+ setting. If +value+ is a symbol (such as :pt, :cm or :in), the units to return the current +line_width+ in. If +value+ is a string, it may include the units as a suffix, e.g. "5.5in" for 5.5 inches.
# [+units+] Units value is expressed in. Defaults to current units setting.
def line_width(value=nil, units=nil)
cur_page.line_width(value, units)
end
# Returns hash of named colors consisting of (name, color) pairs.
# Initial value comes from EideticPDF::PdfK::NAMED_COLORS, but may be augmented or replaced.
def named_colors
@named_colors ||= PdfK::NAMED_COLORS.dup
end
# Set line color, returning previous line color. If no color is specified, returns current font color.
# [+color+] Tuple (array) containing [red, green, blue] components of new color (where components range from 0..255), string key into +named_colors+ or integer encoded from rgb bytes where blue is in the least-significant byte.
# Return values are always in string or integer form.
def line_color(color=nil)
cur_page.line_color(color)
end
# Set fill color, returning previous fill color. If no color is specified, returns current fill color.
# [+color+] Tuple (array) containing [red, green, blue] components of new color (where components range from 0..255) or integer encoded from rgb bytes where blue is in the least-significant byte.
# Return values are always in integer form.
def fill_color(color=nil)
cur_page.fill_color(color)
end
# Set font color, returning previous font color. If no color is specified, returns current font color.
# [+color+] Tuple (array) containing [red, green, blue] components of new color (where components range from 0..255) or integer encoded from rgb bytes where blue is in the least-significant byte.
# Return values are always in integer form.
def font_color(color=nil)
cur_page.font_color(color)
end
# Set font encoding, returning previous font encoding. If no encoding is specified, returns current font encoding.
def font_encoding(encoding=nil)
cur_page.font_encoding(encoding)
end
# Print text, starting from the current position.
#
# The following options apply:
# [:+align+] When :+left+, left edge of text is aligned to current position. When :+center+, text is centered at current position. When :+right+, right edge of text is aligned to current position. When any alignment is specified, the pen is restored to its original location.
# [:+angle+] Print text at the specified +angle+ in degrees. Defaults to 0.
# [:+scale+] Horizontal scaling of text, specified as ratio to normal width. Defaults to 1.0. Cannot be combined with :+clip+.
# [:+underline+] Override +underline+ setting for this piece of text.
# [:+clip+] If true and a block is given, the edges of the text act as a clipping boundary for anything drawn within the supplied block. Cannot be combined with :+scale+.
# [:+fill+] (Only applicable with :+clip+) Fill text and add to path for clipping.
# [:+stroke+] (Only applicable with :+clip+) Stroke text with current +line_color+ and add to path for clipping.
#
# These current settings also apply: +font+, +font_color+, +line_color+ (when outlines are stroked) and vertical text alignment (+v_text_align+).
def print(text, options={}, &block)
cur_page.print(text, options, &block)
end
# Move to (x, y) and print text. See +print+ method.
def print_xy(x, y, text, options={}, &block)
cur_page.print_xy(x, y, text, options, &block)
end
# Print one or more lines of text before moving to the next line, as specified by +indent+.
def puts(text='', options={}, &block)
cur_page.puts(text, options, &block)
end
# Move to (x, y) and print one or more lines of text indented to +x+. See +puts+ method.
def puts_xy(x, y, text, options={}, &block)
cur_page.puts_xy(x, y, text, options={}, &block)
end
# Move pen down one or more lines and back to current indent.
# [+count+] Number of lines to move down.
def new_line(count=1)
cur_page.new_line(count)
end
# Returns width of a string as rendered using the current font.
def width(text)
cur_page.width(text)
end
# Breaks text into tokens and reassembles into array of strings, each one not exceeding +length+.
# Newlines are respected and all other white space is preserved.
def wrap(text, length)
cur_page.wrap(text, length)
end
# Returns text ascent, based on the current font.
# [+units+] Units the value is returned in.
def text_ascent(units=nil)
cur_page.text_ascent(units)
end
# Returns text height, based on the current font, excluding external leading.
# [+units+] Units the value is returned in.
def text_height(units=nil)
cur_page.text_height(units)
end
# Returns height of a line or array of lines, including external leading as determined by +line_height+.
# [+text+] Line or array of lines to be measured. Height is determined only by current font and number of lines.
# [+units+] Units result should be expressed in. Defaults to current +units+.
def height(text='', units=nil) # may not include external leading?
cur_page.height(text, units)
end
# Wrap +text+ and render with the following +options+.
# [:+width+] Maximum width to wrap text within. Defaults to the canvas width minus the current horizontal position.
# [:+height+] Maximum height allowed. Any text not rendered will be returned by the method call. Defaults to the canvas height minus the current vertical position.
# [:+bullet+] Render paragraph as a bullet, using the named bullet as defined using the +bullet+ method. The bullet width is subtracted from the :+width+ specified.
def paragraph(text, options={})
cur_page.paragraph(text, options)
end
# Move to (x, y) and render paragraph.
def paragraph_xy(x, y, text, options={})
cur_page.paragraph_xy(x, y, text, options)
end
# Set vertical text alignment. This is the part of the text that would coincide with a line if one were drawn at the same
# coordinates as the text.
# [:+above+] At the top of the text, plus an amount equal to the height of descenders.
# [:+top+] At the top of the text--text is rendered below the line.
# [:+middle+] Through the middle of the text, like a strikeout.
# [:+base+] At the base of the text--text is rendered above the line, except for descenders.
# [:+below+] Below the text--text is rendered above the line, including descenders.
# Default is :+top+.
def v_text_align(vta=nil)
cur_page.v_text_align(vta)
end
# Set new underline status, returning previous status. If new status is not specified, returns current underline status.
def underline(underline=nil)
cur_page.underline(underline)
end
# Returns an array of font names, including weight and style, from the (local) fonts directory.
def type1_font_names
if @options[:built_in_fonts]
PdfK::FONT_NAMES
else
AFM::font_names
end
end
def truetype_font_names # :nodoc:
if @options[:built_in_fonts]
PdfTT::FONT_NAMES
else
raise Exception.new("Non-built-in TrueType fonts not supported yet.")
end
end
# Set font, returning previous font. If no font is specified, returns current font.
# [+name+] Base name of a Type1 font with metrics file in fonts directory.
# [+size+] Size of font in points. See also +font_size+ method.
# The following +options+ apply:
# [:+style+] Bold, Italic, Oblique or a combination of weight and style such as BoldItalic or BoldOblique. See +font_style+ method.
# [:+color+] Font color as given to +font_color+ method. Color is unchanged if not specified.
# [:+encoding+] Currently-supported encodings include StandardEncoding, WinAnsiEncoding/CP1250, CP1250, CP1254, ISO-8859-1, ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-7, ISO-8859-9, ISO-8859-10, ISO-8859-13, ISO-8859-14, ISO-8859-15, ISO-8859-16, MacTurkish or Macintosh. Defaults to WinAnsiEncoding.
# [:+sub_type+] Currently only Type1 fonts are supported. Defaults to Type1.
# [:+fill+] Fill text with current +font_color+. Defaults to +true+.
# [:+stroke+] Stroke text with current +line_color+. Defaults to +false+.
def font(name=nil, size=nil, options={})
cur_page.font(name, size, options)
end
# Set font style, returning previous font style. If no style is specified, returns current font style.
# [+style+] Bold (or other weight), Italic, Oblique or combination such as BoldItalic or BoldOblique.
# Exact weights and combinations available depend on the font specification files in the (local) fonts directory.
def font_style(style=nil)
cur_page.font_style(style)
end
# Set font size, returning previous font size. If no size is specified, returns current font size.
# [+size+] Size of font in points.
def font_size(size=nil)
cur_page.font_size(size)
end
# Returns +true+ if image is a buffer beginning with a JPEG signature.
def jpeg?(image)
cur_page.jpeg?(image)
end
# Returns a tuple (array) of image dimensions of the form [width, height, components, bits_per_component].
# Raises ArgumentError if +image+ is not a JPEG.
def jpeg_dimensions(image)
cur_page.jpeg_dimensions(image)
end
def load_image(image_file_name, stream=nil) # :nodoc:
cur_page.load_image(image_file_name, stream)
end
# Load graphic file (currently only JPEG is supported) from disk (or network, if open-uri library is loaded) and display at the specified location.
# [+image_file_name+] Path or URL to image.
# [+x+] Left edge of image is placed at this offset. Defaults to pen_pos.x.
# [+y+] Top edge of image is placed at this offset. Defaults to pen_pos.y.
# [+width+] Width to make image. Defaults to natural image width or a width proportionate to +height+ if +height+ is specified.
# [+height+] Height to make image. Defaults to natural image height or a height proportionate to +width+ if +width+ is specified.
def print_image_file(image_file_name, x=nil, y=nil, width=nil, height=nil)
cur_page.print_image_file(image_file_name, x, y, width, height)
end
# Display graphic (currently only JPEG is supported) from disk (or network, if open-uri library is loaded) and display at the specified location.
# [+data+] Buffer containing image.
# [+x+] Left edge of image is placed at this offset. Defaults to pen_pos.x.
# [+y+] Top edge of image is placed at this offset. Defaults to pen_pos.y.
# [+width+] Width to make image. Defaults to natural image width or a width proportionate to +height+ if +height+ is specified.
# [+height+] Height to make image. Defaults to natural image height or a height proportionate to +width+ if +width+ is specified.
def print_image(data, x=nil, y=nil, width=nil, height=nil)
cur_page.print_image(data, x, y, width, height)
end
def print_link(s, uri) # :nodoc:
cur_page.print_link(s, uri)
end
# Given a block, defines a named bullet. Otherwise the named Bullet struct is returned.
#
# The following +options+ apply:
# [:+units+] The units that :+width+ is expressed in. Defaults to the current units setting.
# [:+width+] The width of the area reserved for the bullet.
#
# If a block is given, the block should expect a +writer+ parameter to be used for printing or drawing the bullet.
# Within the block, all altered settings, other than the location, should be restored.
def bullet(name, options={}, &block)
cur_page.bullet(name, options, &block)
end
# Rotate anything drawn within the supplied block +angle+ degrees around origin (x, y).
def rotate(angle, x, y, &block)
cur_page.rotate(angle, x, y, &block)
end
def scale(x, y, scale_x, scale_y, &block)
cur_page.scale(x, y, scale_x, scale_y, &block)
end
protected
def define_resources # :nodoc:
@resources = PdfObjects::PdfResources.new(next_seq, 0)
@resources.proc_set = PdfObjects::PdfName.ary ['PDF','Text','ImageB','ImageC']
@file.body << @resources
end
def sub_page(page_no) # :nodoc:
if @pages_up == 1
nil
elsif @options[:pages_up_layout] == :down
[(page_no / @pages_down) % @pages_across, @pages_across, page_no % @pages_down, @pages_down]
else
[page_no % @pages_across, @pages_across, (page_no / @pages_across) % @pages_down, @pages_down]
end
end
def pdf_page(page_no) # :nodoc:
if page = @pages[page_no / @pages_up * @pages_up]
page.page
else
nil
end
end
end
end