prawn-core 0.5.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +340 -0
- data/LICENSE +56 -0
- data/README +121 -0
- data/Rakefile +74 -0
- data/data/encodings/win_ansi.txt +29 -0
- data/data/fonts/Action Man.dfont +0 -0
- data/data/fonts/Activa.ttf +0 -0
- data/data/fonts/Chalkboard.ttf +0 -0
- data/data/fonts/Courier-Bold.afm +342 -0
- data/data/fonts/Courier-BoldOblique.afm +342 -0
- data/data/fonts/Courier-Oblique.afm +342 -0
- data/data/fonts/Courier.afm +342 -0
- data/data/fonts/DejaVuSans.ttf +0 -0
- data/data/fonts/Dustismo_Roman.ttf +0 -0
- data/data/fonts/Helvetica-Bold.afm +2827 -0
- data/data/fonts/Helvetica-BoldOblique.afm +2827 -0
- data/data/fonts/Helvetica-Oblique.afm +3051 -0
- data/data/fonts/Helvetica.afm +3051 -0
- data/data/fonts/MustRead.html +19 -0
- data/data/fonts/Symbol.afm +213 -0
- data/data/fonts/Times-Bold.afm +2588 -0
- data/data/fonts/Times-BoldItalic.afm +2384 -0
- data/data/fonts/Times-Italic.afm +2667 -0
- data/data/fonts/Times-Roman.afm +2419 -0
- data/data/fonts/ZapfDingbats.afm +225 -0
- data/data/fonts/comicsans.ttf +0 -0
- data/data/fonts/gkai00mp.ttf +0 -0
- data/data/images/16bit.alpha +0 -0
- data/data/images/16bit.dat +0 -0
- data/data/images/16bit.png +0 -0
- data/data/images/arrow.png +0 -0
- data/data/images/arrow2.png +0 -0
- data/data/images/barcode_issue.png +0 -0
- data/data/images/dice.alpha +0 -0
- data/data/images/dice.dat +0 -0
- data/data/images/dice.png +0 -0
- data/data/images/dice_interlaced.png +0 -0
- data/data/images/fractal.jpg +0 -0
- data/data/images/letterhead.jpg +0 -0
- data/data/images/page_white_text.alpha +0 -0
- data/data/images/page_white_text.dat +0 -0
- data/data/images/page_white_text.png +0 -0
- data/data/images/pigs.jpg +0 -0
- data/data/images/rails.dat +0 -0
- data/data/images/rails.png +0 -0
- data/data/images/ruport.png +0 -0
- data/data/images/ruport_data.dat +0 -0
- data/data/images/ruport_transparent.png +0 -0
- data/data/images/ruport_type0.png +0 -0
- data/data/images/stef.jpg +0 -0
- data/data/images/tru256.bmp +0 -0
- data/data/images/web-links.dat +1 -0
- data/data/images/web-links.png +0 -0
- data/data/shift_jis_text.txt +1 -0
- data/examples/bounding_box/bounding_boxes.rb +44 -0
- data/examples/bounding_box/russian_boxes.rb +37 -0
- data/examples/column_box/column_box_example.rb +44 -0
- data/examples/general/background.rb +20 -0
- data/examples/general/canvas.rb +16 -0
- data/examples/general/measurement_units.rb +52 -0
- data/examples/general/metadata-info.rb +17 -0
- data/examples/general/multi_page_layout.rb +17 -0
- data/examples/general/page_geometry.rb +32 -0
- data/examples/graphics/basic_images.rb +24 -0
- data/examples/graphics/cmyk.rb +13 -0
- data/examples/graphics/curves.rb +12 -0
- data/examples/graphics/hexagon.rb +14 -0
- data/examples/graphics/image_fit.rb +16 -0
- data/examples/graphics/image_flow.rb +38 -0
- data/examples/graphics/image_position.rb +18 -0
- data/examples/graphics/line.rb +33 -0
- data/examples/graphics/png_types.rb +23 -0
- data/examples/graphics/polygons.rb +17 -0
- data/examples/graphics/remote_images.rb +12 -0
- data/examples/graphics/ruport_style_helpers.rb +20 -0
- data/examples/graphics/stroke_bounds.rb +21 -0
- data/examples/m17n/chinese_text_wrapping.rb +20 -0
- data/examples/m17n/euro.rb +16 -0
- data/examples/m17n/sjis.rb +29 -0
- data/examples/m17n/utf8.rb +14 -0
- data/examples/m17n/win_ansi_charset.rb +55 -0
- data/examples/text/alignment.rb +19 -0
- data/examples/text/dfont.rb +49 -0
- data/examples/text/family_based_styling.rb +25 -0
- data/examples/text/font_calculations.rb +92 -0
- data/examples/text/font_size.rb +34 -0
- data/examples/text/kerning.rb +31 -0
- data/examples/text/simple_text.rb +18 -0
- data/examples/text/simple_text_ttf.rb +18 -0
- data/examples/text/span.rb +30 -0
- data/examples/text/text_box.rb +26 -0
- data/examples/text/text_flow.rb +68 -0
- data/lib/prawn/compatibility.rb +38 -0
- data/lib/prawn/core.rb +79 -0
- data/lib/prawn/document.rb +399 -0
- data/lib/prawn/document/annotations.rb +63 -0
- data/lib/prawn/document/bounding_box.rb +377 -0
- data/lib/prawn/document/column_box.rb +89 -0
- data/lib/prawn/document/destinations.rb +81 -0
- data/lib/prawn/document/internals.rb +133 -0
- data/lib/prawn/document/page_geometry.rb +149 -0
- data/lib/prawn/document/span.rb +55 -0
- data/lib/prawn/document/text.rb +186 -0
- data/lib/prawn/document/text/box.rb +83 -0
- data/lib/prawn/document/text/wrapping.rb +59 -0
- data/lib/prawn/encoding.rb +121 -0
- data/lib/prawn/errors.rb +49 -0
- data/lib/prawn/font.rb +292 -0
- data/lib/prawn/font/afm.rb +202 -0
- data/lib/prawn/font/dfont.rb +31 -0
- data/lib/prawn/font/ttf.rb +327 -0
- data/lib/prawn/graphics.rb +257 -0
- data/lib/prawn/graphics/color.rb +141 -0
- data/lib/prawn/images.rb +339 -0
- data/lib/prawn/images/jpg.rb +45 -0
- data/lib/prawn/images/png.rb +217 -0
- data/lib/prawn/literal_string.rb +14 -0
- data/lib/prawn/measurement_extensions.rb +46 -0
- data/lib/prawn/measurements.rb +71 -0
- data/lib/prawn/name_tree.rb +165 -0
- data/lib/prawn/pdf_object.rb +77 -0
- data/lib/prawn/reference.rb +59 -0
- data/spec/annotations_spec.rb +90 -0
- data/spec/bounding_box_spec.rb +141 -0
- data/spec/destinations_spec.rb +15 -0
- data/spec/document_spec.rb +178 -0
- data/spec/font_spec.rb +274 -0
- data/spec/graphics_spec.rb +209 -0
- data/spec/images_spec.rb +79 -0
- data/spec/jpg_spec.rb +25 -0
- data/spec/measurement_units_spec.rb +23 -0
- data/spec/name_tree_spec.rb +103 -0
- data/spec/pdf_object_spec.rb +117 -0
- data/spec/png_spec.rb +236 -0
- data/spec/reference_spec.rb +42 -0
- data/spec/span_spec.rb +45 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/text_box_spec.rb +83 -0
- data/spec/text_spec.rb +178 -0
- data/vendor/pdf-inspector/README +18 -0
- data/vendor/pdf-inspector/lib/pdf/inspector.rb +25 -0
- data/vendor/pdf-inspector/lib/pdf/inspector/graphics.rb +80 -0
- data/vendor/pdf-inspector/lib/pdf/inspector/page.rb +16 -0
- data/vendor/pdf-inspector/lib/pdf/inspector/text.rb +31 -0
- data/vendor/pdf-inspector/lib/pdf/inspector/xobject.rb +19 -0
- data/vendor/ttfunk/data/fonts/DejaVuSans.ttf +0 -0
- data/vendor/ttfunk/data/fonts/comicsans.ttf +0 -0
- data/vendor/ttfunk/example.rb +45 -0
- data/vendor/ttfunk/lib/ttfunk.rb +102 -0
- data/vendor/ttfunk/lib/ttfunk/directory.rb +17 -0
- data/vendor/ttfunk/lib/ttfunk/encoding/mac_roman.rb +88 -0
- data/vendor/ttfunk/lib/ttfunk/encoding/windows_1252.rb +69 -0
- data/vendor/ttfunk/lib/ttfunk/reader.rb +44 -0
- data/vendor/ttfunk/lib/ttfunk/resource_file.rb +78 -0
- data/vendor/ttfunk/lib/ttfunk/subset.rb +18 -0
- data/vendor/ttfunk/lib/ttfunk/subset/base.rb +141 -0
- data/vendor/ttfunk/lib/ttfunk/subset/mac_roman.rb +46 -0
- data/vendor/ttfunk/lib/ttfunk/subset/unicode.rb +48 -0
- data/vendor/ttfunk/lib/ttfunk/subset/unicode_8bit.rb +63 -0
- data/vendor/ttfunk/lib/ttfunk/subset/windows_1252.rb +51 -0
- data/vendor/ttfunk/lib/ttfunk/subset_collection.rb +72 -0
- data/vendor/ttfunk/lib/ttfunk/table.rb +46 -0
- data/vendor/ttfunk/lib/ttfunk/table/cmap.rb +34 -0
- data/vendor/ttfunk/lib/ttfunk/table/cmap/format00.rb +54 -0
- data/vendor/ttfunk/lib/ttfunk/table/cmap/format04.rb +126 -0
- data/vendor/ttfunk/lib/ttfunk/table/cmap/subtable.rb +79 -0
- data/vendor/ttfunk/lib/ttfunk/table/glyf.rb +64 -0
- data/vendor/ttfunk/lib/ttfunk/table/glyf/compound.rb +81 -0
- data/vendor/ttfunk/lib/ttfunk/table/glyf/simple.rb +37 -0
- data/vendor/ttfunk/lib/ttfunk/table/head.rb +44 -0
- data/vendor/ttfunk/lib/ttfunk/table/hhea.rb +41 -0
- data/vendor/ttfunk/lib/ttfunk/table/hmtx.rb +47 -0
- data/vendor/ttfunk/lib/ttfunk/table/kern.rb +79 -0
- data/vendor/ttfunk/lib/ttfunk/table/kern/format0.rb +62 -0
- data/vendor/ttfunk/lib/ttfunk/table/loca.rb +43 -0
- data/vendor/ttfunk/lib/ttfunk/table/maxp.rb +40 -0
- data/vendor/ttfunk/lib/ttfunk/table/name.rb +119 -0
- data/vendor/ttfunk/lib/ttfunk/table/os2.rb +78 -0
- data/vendor/ttfunk/lib/ttfunk/table/post.rb +91 -0
- data/vendor/ttfunk/lib/ttfunk/table/post/format10.rb +43 -0
- data/vendor/ttfunk/lib/ttfunk/table/post/format20.rb +35 -0
- data/vendor/ttfunk/lib/ttfunk/table/post/format25.rb +23 -0
- data/vendor/ttfunk/lib/ttfunk/table/post/format30.rb +17 -0
- data/vendor/ttfunk/lib/ttfunk/table/post/format40.rb +17 -0
- data/vendor/ttfunk/lib/ttfunk/table/simple.rb +14 -0
- metadata +245 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
# annotations.rb : Implements destination support for PDF
|
|
4
|
+
#
|
|
5
|
+
# Copyright November 2008, Jamis Buck. All Rights Reserved.
|
|
6
|
+
#
|
|
7
|
+
# This is free software. Please see the LICENSE and COPYING files for details.
|
|
8
|
+
#
|
|
9
|
+
require 'prawn/name_tree'
|
|
10
|
+
|
|
11
|
+
module Prawn
|
|
12
|
+
class Document
|
|
13
|
+
module Destinations
|
|
14
|
+
# The maximum number of children to fit into a single node in the Dests tree.
|
|
15
|
+
NAME_TREE_CHILDREN_LIMIT = 20 #:nodoc:
|
|
16
|
+
|
|
17
|
+
# The Dests name tree in the Name dictionary (see Prawn::Document::Internal#names).
|
|
18
|
+
# This name tree is used to store named destinations (PDF spec 8.2.1).
|
|
19
|
+
# (For more on name trees, see section 3.8.4 in the PDF spec.)
|
|
20
|
+
def dests
|
|
21
|
+
names.data[:Dests] ||= ref(Prawn::NameTree::Node.new(self, NAME_TREE_CHILDREN_LIMIT))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Adds a new destination to the dests name tree (see #dests). The
|
|
25
|
+
# +reference+ parameter will be converted into a Prawn::Reference if
|
|
26
|
+
# it is not already one.
|
|
27
|
+
def add_dest(name, reference)
|
|
28
|
+
reference = ref(reference) unless reference.is_a?(Prawn::Reference)
|
|
29
|
+
dests.data.add(name, reference)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Return a Dest specification for a specific location (and optional zoom
|
|
33
|
+
# level).
|
|
34
|
+
def dest_xyz(left, top, zoom=nil, page=@current_page)
|
|
35
|
+
[page, :XYZ, left, top, zoom]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Return a Dest specification that will fit the given page into the
|
|
39
|
+
# viewport.
|
|
40
|
+
def dest_fit(page=@current_page)
|
|
41
|
+
[page, :Fit]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Return a Dest specification that will fit the given page horizontally
|
|
45
|
+
# into the viewport, aligned vertically at the given top coordinate.
|
|
46
|
+
def dest_fit_horizontally(top, page=@current_page)
|
|
47
|
+
[page, :FitH, top]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Return a Dest specification that will fit the given page vertically
|
|
51
|
+
# into the viewport, aligned horizontally at the given left coordinate.
|
|
52
|
+
def dest_fit_vertically(left, page=@current_page)
|
|
53
|
+
[page, :FitV, left]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Return a Dest specification that will fit the given rectangle into the
|
|
57
|
+
# viewport, for the given page.
|
|
58
|
+
def dest_fit_rect(left, bottom, right, top, page=@current_page)
|
|
59
|
+
[page, :FitR, left, bottom, right, top]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Return a Dest specfication that will fit the given page's bounding box
|
|
63
|
+
# into the viewport.
|
|
64
|
+
def dest_fit_bounds(page=@current_page)
|
|
65
|
+
[page, :FitB]
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Same as #dest_fit_horizontally, but works on the page's bounding box
|
|
69
|
+
# instead of the entire page.
|
|
70
|
+
def dest_fit_bounds_horizontally(top, page=@current_page)
|
|
71
|
+
[page, :FitBH, top]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Same as #dest_fit_vertically, but works on the page's bounding box
|
|
75
|
+
# instead of the entire page.
|
|
76
|
+
def dest_fit_bounds_vertically(left, page=@current_page)
|
|
77
|
+
[page, :FitBV, left]
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
# internals.rb : Implements document internals for Prawn
|
|
4
|
+
#
|
|
5
|
+
# Copyright August 2008, Gregory Brown. All Rights Reserved.
|
|
6
|
+
#
|
|
7
|
+
# This is free software. Please see the LICENSE and COPYING files for details.
|
|
8
|
+
|
|
9
|
+
module Prawn
|
|
10
|
+
class Document
|
|
11
|
+
|
|
12
|
+
# This module exposes a few low-level PDF features for those who want
|
|
13
|
+
# to extend Prawn's core functionality. If you are not comfortable with
|
|
14
|
+
# low level PDF functionality as defined by Adobe's specification, chances
|
|
15
|
+
# are you won't need anything you find here.
|
|
16
|
+
#
|
|
17
|
+
module Internals
|
|
18
|
+
# Creates a new Prawn::Reference and adds it to the Document's object
|
|
19
|
+
# list. The +data+ argument is anything that Prawn::PdfObject() can convert.
|
|
20
|
+
#
|
|
21
|
+
# If a block is given, it will be invoked just before the object is written
|
|
22
|
+
# out to the PDF document stream. This allows you to do deferred processing
|
|
23
|
+
# on some references (such as fonts, which you might know all the details
|
|
24
|
+
# about until the last page of the document is finished).
|
|
25
|
+
def ref(data, &block)
|
|
26
|
+
@objects.push(Prawn::Reference.new(@objects.size + 1, data, &block)).last
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Appends a raw string to the current page content.
|
|
30
|
+
#
|
|
31
|
+
# # Raw line drawing example:
|
|
32
|
+
# x1,y1,x2,y2 = 100,500,300,550
|
|
33
|
+
# pdf.add_content("%.3f %.3f m" % [ x1, y1 ]) # move
|
|
34
|
+
# pdf.add_content("%.3f %.3f l" % [ x2, y2 ]) # draw path
|
|
35
|
+
# pdf.add_content("S") # stroke
|
|
36
|
+
#
|
|
37
|
+
def add_content(str)
|
|
38
|
+
@page_content << str << "\n"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Add a new type to the current pages ProcSet
|
|
42
|
+
#
|
|
43
|
+
def proc_set(*types)
|
|
44
|
+
@current_page.data[:ProcSet] ||= ref([])
|
|
45
|
+
@current_page.data[:ProcSet].data |= types
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# The Resources dictionary for the current page
|
|
49
|
+
#
|
|
50
|
+
def page_resources
|
|
51
|
+
@current_page.data[:Resources] ||= {}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# The Font dictionary for the current page
|
|
55
|
+
#
|
|
56
|
+
def page_fonts
|
|
57
|
+
page_resources[:Font] ||= {}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# The XObject dictionary for the current page
|
|
61
|
+
def page_xobjects
|
|
62
|
+
page_resources[:XObject] ||= {}
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# The Name dictionary (PDF spec 3.6.3) for this document. It is
|
|
66
|
+
# lazily initialized, so that documents that do not need a name
|
|
67
|
+
# dictionary do not incur the additional overhead.
|
|
68
|
+
def names
|
|
69
|
+
@root.data[:Names] ||= ref(:Type => :Names)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
def finish_page_content
|
|
75
|
+
@header.draw if @header
|
|
76
|
+
@footer.draw if @footer
|
|
77
|
+
add_content "Q"
|
|
78
|
+
@page_content.compress_stream if compression_enabled?
|
|
79
|
+
@page_content.data[:Length] = @page_content.stream.size
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# raise the PDF version of the file we're going to generate.
|
|
83
|
+
# A private method, designed for internal use when the user adds a feature
|
|
84
|
+
# to their document that requires a particular version.
|
|
85
|
+
def min_version(min)
|
|
86
|
+
@version = min if min > @version
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Write out the PDF Header, as per spec 3.4.1
|
|
90
|
+
def render_header(output)
|
|
91
|
+
# pdf version
|
|
92
|
+
output << "%PDF-#{@version}\n"
|
|
93
|
+
|
|
94
|
+
# 4 binary chars, as recommended by the spec
|
|
95
|
+
output << "\xFF\xFF\xFF\xFF\n"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Write out the PDF Body, as per spec 3.4.2
|
|
99
|
+
def render_body(output)
|
|
100
|
+
@objects.each do |ref|
|
|
101
|
+
ref.offset = output.size
|
|
102
|
+
output << ref.object
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Write out the PDF Cross Reference Table, as per spec 3.4.3
|
|
107
|
+
def render_xref(output)
|
|
108
|
+
@xref_offset = output.size
|
|
109
|
+
output << "xref\n"
|
|
110
|
+
output << "0 #{@objects.size + 1}\n"
|
|
111
|
+
output << "0000000000 65535 f \n"
|
|
112
|
+
@objects.each do |ref|
|
|
113
|
+
output.printf("%010d", ref.offset)
|
|
114
|
+
output << " 00000 n \n"
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Write out the PDF Trailer, as per spec 3.4.4
|
|
119
|
+
def render_trailer(output)
|
|
120
|
+
trailer_hash = {:Size => @objects.size + 1,
|
|
121
|
+
:Root => @root,
|
|
122
|
+
:Info => @info}
|
|
123
|
+
|
|
124
|
+
output << "trailer\n"
|
|
125
|
+
output << Prawn::PdfObject(trailer_hash) << "\n"
|
|
126
|
+
output << "startxref\n"
|
|
127
|
+
output << @xref_offset << "\n"
|
|
128
|
+
output << "%%EOF" << "\n"
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
# page_geometry.rb : Describes PDF page geometries
|
|
4
|
+
#
|
|
5
|
+
# Copyright April 2008, Gregory Brown. All Rights Reserved.
|
|
6
|
+
#
|
|
7
|
+
# This is free software. Please see the LICENSE and COPYING files for details.
|
|
8
|
+
|
|
9
|
+
module Prawn
|
|
10
|
+
class Document
|
|
11
|
+
|
|
12
|
+
# Dimensions pulled from PDF::Writer, rubyforge.org/projects/ruby-pdf
|
|
13
|
+
#
|
|
14
|
+
# All of these dimensions are in PDF Points, see Prawn::Measurements for
|
|
15
|
+
# conversion utilities.
|
|
16
|
+
#
|
|
17
|
+
# Additionally, if the size you are after is not listed below, you can always
|
|
18
|
+
# specify your size by passing an array of width and height to Prawn::Document.new
|
|
19
|
+
# like:
|
|
20
|
+
#
|
|
21
|
+
# Prawn::Document.new(:page_size => [1000, 20000])
|
|
22
|
+
#
|
|
23
|
+
# The sizes below can be used by passing the appropriate string to :size:
|
|
24
|
+
#
|
|
25
|
+
# Prawn::Document.new(:page_size => '2A0')
|
|
26
|
+
#
|
|
27
|
+
# ===Inbuilt Sizes:
|
|
28
|
+
#
|
|
29
|
+
#
|
|
30
|
+
# 4A0:: => 4767.87 x 6740.79
|
|
31
|
+
# 2A0:: => 3370.39 x 4767.87
|
|
32
|
+
# A0:: => 2383.94 x 3370.39
|
|
33
|
+
# A1:: => 1683.78 x 2383.94
|
|
34
|
+
# A2:: => 1190.55 x 1683.78
|
|
35
|
+
# A3:: => 841.89 x 1190.55
|
|
36
|
+
# A4:: => 595.28 x 841.89
|
|
37
|
+
# A5:: => 419.53 x 595.28
|
|
38
|
+
# A6:: => 297.64 x 419.53
|
|
39
|
+
# A7:: => 209.76 x 297.64
|
|
40
|
+
# A8:: => 147.40 x 209.76
|
|
41
|
+
# A9:: => 104.88 x 147.40
|
|
42
|
+
# A10:: => 73.70 x 104.88
|
|
43
|
+
# B0:: => 2834.65 x 4008.19
|
|
44
|
+
# B1:: => 2004.09 x 2834.65
|
|
45
|
+
# B2:: => 1417.32 x 2004.09
|
|
46
|
+
# B3:: => 1000.63 x 1417.32
|
|
47
|
+
# B4:: => 708.66 x 1000.63
|
|
48
|
+
# B5:: => 498.90 x 708.66
|
|
49
|
+
# B6:: => 354.33 x 498.90
|
|
50
|
+
# B7:: => 249.45 x 354.33
|
|
51
|
+
# B8:: => 175.75 x 249.45
|
|
52
|
+
# B9:: => 124.72 x 175.75
|
|
53
|
+
# B10:: => 87.87 x 124.72
|
|
54
|
+
# C0:: => 2599.37 x 3676.54
|
|
55
|
+
# C1:: => 1836.85 x 2599.37
|
|
56
|
+
# C2:: => 1298.27 x 1836.85
|
|
57
|
+
# C3:: => 918.43 x 1298.27
|
|
58
|
+
# C4:: => 649.13 x 918.43
|
|
59
|
+
# C5:: => 459.21 x 649.13
|
|
60
|
+
# C6:: => 323.15 x 459.21
|
|
61
|
+
# C7:: => 229.61 x 323.15
|
|
62
|
+
# C8:: => 161.57 x 229.61
|
|
63
|
+
# C9:: => 113.39 x 161.57
|
|
64
|
+
# C10:: => 79.37 x 113.39
|
|
65
|
+
# RA0:: => 2437.80 x 3458.27
|
|
66
|
+
# RA1:: => 1729.13 x 2437.80
|
|
67
|
+
# RA2:: => 1218.90 x 1729.13
|
|
68
|
+
# RA3:: => 864.57 x 1218.90
|
|
69
|
+
# RA4:: => 609.45 x 864.57
|
|
70
|
+
# SRA0:: => 2551.18 x 3628.35
|
|
71
|
+
# SRA1:: => 1814.17 x 2551.18
|
|
72
|
+
# SRA2:: => 1275.59 x 1814.17
|
|
73
|
+
# SRA3:: => 907.09 x 1275.59
|
|
74
|
+
# SRA4:: => 637.80 x 907.09
|
|
75
|
+
# EXECUTIVE:: => 521.86 x 756.00
|
|
76
|
+
# FOLIO:: => 612.00 x 936.00
|
|
77
|
+
# LEGAL:: => 612.00 x 1008.00
|
|
78
|
+
# LETTER:: => 612.00 x 792.00
|
|
79
|
+
# TABLOID:: => 792.00 x 1224.00
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
module PageGeometry
|
|
83
|
+
|
|
84
|
+
SIZES = { "4A0" => [4767.87, 6740.79],
|
|
85
|
+
"2A0" => [3370.39, 4767.87],
|
|
86
|
+
"A0" => [2383.94, 3370.39],
|
|
87
|
+
"A1" => [1683.78, 2383.94],
|
|
88
|
+
"A2" => [1190.55, 1683.78],
|
|
89
|
+
"A3" => [841.89, 1190.55],
|
|
90
|
+
"A4" => [595.28, 841.89],
|
|
91
|
+
"A5" => [419.53, 595.28],
|
|
92
|
+
"A6" => [297.64, 419.53],
|
|
93
|
+
"A7" => [209.76, 297.64],
|
|
94
|
+
"A8" => [147.40, 209.76],
|
|
95
|
+
"A9" => [104.88, 147.40],
|
|
96
|
+
"A10" => [73.70, 104.88],
|
|
97
|
+
"B0" => [2834.65, 4008.19],
|
|
98
|
+
"B1" => [2004.09, 2834.65],
|
|
99
|
+
"B2" => [1417.32, 2004.09],
|
|
100
|
+
"B3" => [1000.63, 1417.32],
|
|
101
|
+
"B4" => [708.66, 1000.63],
|
|
102
|
+
"B5" => [498.90, 708.66],
|
|
103
|
+
"B6" => [354.33, 498.90],
|
|
104
|
+
"B7" => [249.45, 354.33],
|
|
105
|
+
"B8" => [175.75, 249.45],
|
|
106
|
+
"B9" => [124.72, 175.75],
|
|
107
|
+
"B10" => [87.87, 124.72],
|
|
108
|
+
"C0" => [2599.37, 3676.54],
|
|
109
|
+
"C1" => [1836.85, 2599.37],
|
|
110
|
+
"C2" => [1298.27, 1836.85],
|
|
111
|
+
"C3" => [918.43, 1298.27],
|
|
112
|
+
"C4" => [649.13, 918.43],
|
|
113
|
+
"C5" => [459.21, 649.13],
|
|
114
|
+
"C6" => [323.15, 459.21],
|
|
115
|
+
"C7" => [229.61, 323.15],
|
|
116
|
+
"C8" => [161.57, 229.61],
|
|
117
|
+
"C9" => [113.39, 161.57],
|
|
118
|
+
"C10" => [79.37, 113.39],
|
|
119
|
+
"RA0" => [2437.80, 3458.27],
|
|
120
|
+
"RA1" => [1729.13, 2437.80],
|
|
121
|
+
"RA2" => [1218.90, 1729.13],
|
|
122
|
+
"RA3" => [864.57, 1218.90],
|
|
123
|
+
"RA4" => [609.45, 864.57],
|
|
124
|
+
"SRA0" => [2551.18, 3628.35],
|
|
125
|
+
"SRA1" => [1814.17, 2551.18],
|
|
126
|
+
"SRA2" => [1275.59, 1814.17],
|
|
127
|
+
"SRA3" => [907.09, 1275.59],
|
|
128
|
+
"SRA4" => [637.80, 907.09],
|
|
129
|
+
"EXECUTIVE" => [521.86, 756.00],
|
|
130
|
+
"FOLIO" => [612.00, 936.00],
|
|
131
|
+
"LEGAL" => [612.00, 1008.00],
|
|
132
|
+
"LETTER" => [612.00, 792.00],
|
|
133
|
+
"TABLOID" => [792.00, 1224.00] }
|
|
134
|
+
|
|
135
|
+
def page_dimensions #:nodoc:
|
|
136
|
+
coords = SIZES[page_size] || page_size
|
|
137
|
+
[0,0] + case(page_layout)
|
|
138
|
+
when :portrait
|
|
139
|
+
coords
|
|
140
|
+
when :landscape
|
|
141
|
+
coords.reverse
|
|
142
|
+
else
|
|
143
|
+
raise Prawn::Errors::InvalidPageLayout,
|
|
144
|
+
"Layout must be either :portrait or :landscape"
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
# span.rb : Implements text columns
|
|
4
|
+
#
|
|
5
|
+
# Copyright September 2008, Gregory Brown. All Rights Reserved.
|
|
6
|
+
#
|
|
7
|
+
# This is free software. Please see the LICENSE and COPYING files for details.
|
|
8
|
+
|
|
9
|
+
module Prawn
|
|
10
|
+
class Document
|
|
11
|
+
# A span is a special purpose bounding box that allows a column of
|
|
12
|
+
# elements to be positioned relative to the margin_box.
|
|
13
|
+
#
|
|
14
|
+
# Arguments:
|
|
15
|
+
# +width+:: The width of the column in PDF points
|
|
16
|
+
#
|
|
17
|
+
# Options:
|
|
18
|
+
# <tt>:position</tt>:: One of :left, :center, :right or an x offset
|
|
19
|
+
#
|
|
20
|
+
# This method is typically used for flowing a column of text from one
|
|
21
|
+
# page to the next.
|
|
22
|
+
#
|
|
23
|
+
# span(350, :position => :center) do
|
|
24
|
+
# text "Here's some centered text in a 350 point column. " * 100
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
def span(width, options={})
|
|
28
|
+
Prawn.verify_options [:position], options
|
|
29
|
+
original_position = self.y
|
|
30
|
+
|
|
31
|
+
# FIXME: How many effing times do I want to write this same code?
|
|
32
|
+
left_boundary = case(options[:position] || :left)
|
|
33
|
+
when :left
|
|
34
|
+
margin_box.absolute_left
|
|
35
|
+
when :center
|
|
36
|
+
margin_box.absolute_left + margin_box.width / 2.0 - width /2.0
|
|
37
|
+
when :right
|
|
38
|
+
margin_box.absolute_right - width
|
|
39
|
+
when Numeric
|
|
40
|
+
margin_box.absolute_left + options[:position]
|
|
41
|
+
else
|
|
42
|
+
raise ArgumentError, "Invalid option for :position"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# we need to bust out of whatever nested bounding boxes we're in.
|
|
46
|
+
canvas do
|
|
47
|
+
bounding_box([left_boundary,
|
|
48
|
+
margin_box.absolute_top], :width => width) do
|
|
49
|
+
self.y = original_position
|
|
50
|
+
yield
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
# text.rb : Implements PDF text primitives
|
|
4
|
+
#
|
|
5
|
+
# Copyright May 2008, Gregory Brown. All Rights Reserved.
|
|
6
|
+
#
|
|
7
|
+
# This is free software. Please see the LICENSE and COPYING files for details.
|
|
8
|
+
require "zlib"
|
|
9
|
+
require "prawn/document/text/box"
|
|
10
|
+
require "prawn/document/text/wrapping"
|
|
11
|
+
|
|
12
|
+
module Prawn
|
|
13
|
+
class Document
|
|
14
|
+
module Text
|
|
15
|
+
include Wrapping
|
|
16
|
+
|
|
17
|
+
# Draws text on the page. If a point is specified via the +:at+
|
|
18
|
+
# option the text will begin exactly at that point, and the string is
|
|
19
|
+
# assumed to be pre-formatted to properly fit the page.
|
|
20
|
+
#
|
|
21
|
+
# pdf.text "Hello World", :at => [100,100]
|
|
22
|
+
# pdf.text "Goodbye World", :at => [50,50], :size => 16
|
|
23
|
+
#
|
|
24
|
+
# When +:at+ is not specified, Prawn attempts to wrap the text to
|
|
25
|
+
# fit within your current bounding box (or margin_box if no bounding box
|
|
26
|
+
# is being used ). Text will flow onto the next page when it reaches
|
|
27
|
+
# the bottom of the bounding box. Text wrap in Prawn does not re-flow
|
|
28
|
+
# linebreaks, so if you want fully automated text wrapping, be sure to
|
|
29
|
+
# remove newlines before attempting to draw your string.
|
|
30
|
+
#
|
|
31
|
+
# pdf.text "Will be wrapped when it hits the edge of your bounding box"
|
|
32
|
+
# pdf.text "This will be centered", :align => :center
|
|
33
|
+
# pdf.text "This will be right aligned", :align => :right
|
|
34
|
+
#
|
|
35
|
+
# Wrapping is done by splitting words by spaces by default. If your text
|
|
36
|
+
# does not contain spaces, you can wrap based on characters instead:
|
|
37
|
+
#
|
|
38
|
+
# pdf.text "This will be wrapped by character", :wrap => :character
|
|
39
|
+
#
|
|
40
|
+
# If your font contains kerning pairs data that Prawn can parse, the
|
|
41
|
+
# text will be kerned by default. You can disable this feature by passing
|
|
42
|
+
# <tt>:kerning => false</tt>.
|
|
43
|
+
#
|
|
44
|
+
# === Text Positioning Details:
|
|
45
|
+
#
|
|
46
|
+
# When using the :at parameter, Prawn will position your text by its
|
|
47
|
+
# baseline, and flow along a single line.
|
|
48
|
+
#
|
|
49
|
+
# Otherwise, the text is positioned at font.ascender below the baseline,
|
|
50
|
+
# making it easy to use this method within bounding boxes and spans.
|
|
51
|
+
#
|
|
52
|
+
# == Rotation
|
|
53
|
+
#
|
|
54
|
+
# Text can be rotated before it is placed on the canvas by specifying the
|
|
55
|
+
# :rotate option. Rotation occurs counter-clockwise.
|
|
56
|
+
#
|
|
57
|
+
# == Encoding
|
|
58
|
+
#
|
|
59
|
+
# Note that strings passed to this function should be encoded as UTF-8.
|
|
60
|
+
# If you get unexpected characters appearing in your rendered document,
|
|
61
|
+
# check this.
|
|
62
|
+
#
|
|
63
|
+
# If the current font is a built-in one, although the string must be
|
|
64
|
+
# encoded as UTF-8, only characters that are available in WinAnsi
|
|
65
|
+
# are allowed.
|
|
66
|
+
#
|
|
67
|
+
# If an empty box is rendered to your PDF instead of the character you
|
|
68
|
+
# wanted it usually means the current font doesn't include that character.
|
|
69
|
+
#
|
|
70
|
+
def text(text,options={})
|
|
71
|
+
# we'll be messing with the strings encoding, don't change the users
|
|
72
|
+
# original string
|
|
73
|
+
text = text.to_s.dup
|
|
74
|
+
|
|
75
|
+
save_font do
|
|
76
|
+
options = text_options.merge(options)
|
|
77
|
+
process_text_options(options)
|
|
78
|
+
|
|
79
|
+
font.normalize_encoding!(text) unless @skip_encoding
|
|
80
|
+
|
|
81
|
+
if options[:at]
|
|
82
|
+
x,y = translate(options[:at])
|
|
83
|
+
font_size(options[:size]) { add_text_content(text,x,y,options) }
|
|
84
|
+
else
|
|
85
|
+
if options[:rotate]
|
|
86
|
+
raise ArgumentError, "Rotated text may only be used with :at"
|
|
87
|
+
end
|
|
88
|
+
wrapped_text(text,options)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# A hash of configuration options, to be used globally by text().
|
|
94
|
+
#
|
|
95
|
+
# pdf.text_options.update(:size => 16, :align => :right)
|
|
96
|
+
# pdf.text "Hello World" #=> Size 16 w. right alignment
|
|
97
|
+
#
|
|
98
|
+
def text_options
|
|
99
|
+
@text_options ||= {}
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
def process_text_options(options)
|
|
105
|
+
Prawn.verify_options [:style, :kerning, :size, :at, :wrap,
|
|
106
|
+
:spacing, :align, :rotate, :final_gap ], options
|
|
107
|
+
|
|
108
|
+
if options[:style]
|
|
109
|
+
raise "Bad font family" unless font.family
|
|
110
|
+
font(font.family,:style => options[:style])
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
unless options.key?(:kerning)
|
|
114
|
+
options[:kerning] = font.has_kerning_data?
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
options[:size] ||= font_size
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def move_text_position(dy)
|
|
121
|
+
bottom = @bounding_box.stretchy? ? @margin_box.absolute_bottom :
|
|
122
|
+
@bounding_box.absolute_bottom
|
|
123
|
+
|
|
124
|
+
@bounding_box.move_past_bottom if (y - dy) < bottom
|
|
125
|
+
|
|
126
|
+
self.y -= dy
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def wrapped_text(text,options)
|
|
130
|
+
options[:align] ||= :left
|
|
131
|
+
|
|
132
|
+
font_size(options[:size]) do
|
|
133
|
+
text = naive_wrap(text, bounds.width, font_size,
|
|
134
|
+
:kerning => options[:kerning], :mode => options[:wrap])
|
|
135
|
+
|
|
136
|
+
lines = text.lines.to_a
|
|
137
|
+
last_gap_before = options.fetch(:final_gap, true) ? lines.length : lines.length-1
|
|
138
|
+
|
|
139
|
+
lines.each_with_index do |e,i|
|
|
140
|
+
move_text_position(font.ascender)
|
|
141
|
+
|
|
142
|
+
line_width = width_of(e, :kerning => options[:kerning])
|
|
143
|
+
case(options[:align])
|
|
144
|
+
when :left
|
|
145
|
+
x = @bounding_box.left_side
|
|
146
|
+
when :center
|
|
147
|
+
x = @bounding_box.left_side +
|
|
148
|
+
(@bounding_box.width - line_width) / 2.0
|
|
149
|
+
when :right
|
|
150
|
+
x = @bounding_box.right_side - line_width
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
add_text_content(e,x,y,options)
|
|
154
|
+
|
|
155
|
+
if i < last_gap_before
|
|
156
|
+
move_text_position(font.line_gap - font.descender)
|
|
157
|
+
move_text_position(options[:spacing]) if options[:spacing]
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def add_text_content(text, x, y, options)
|
|
164
|
+
chunks = font.encode_text(text,options)
|
|
165
|
+
|
|
166
|
+
add_content "\nBT"
|
|
167
|
+
if options[:rotate]
|
|
168
|
+
rad = options[:rotate].to_i * Math::PI / 180
|
|
169
|
+
arr = [ Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad), x, y ]
|
|
170
|
+
add_content "%.3f %.3f %.3f %.3f %.3f %.3f Tm" % arr
|
|
171
|
+
else
|
|
172
|
+
add_content "#{x} #{y} Td"
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
chunks.each do |(subset, string)|
|
|
176
|
+
font.add_to_current_page(subset)
|
|
177
|
+
add_content "/#{font.identifier_for(subset)} #{font_size} Tf"
|
|
178
|
+
|
|
179
|
+
operation = options[:kerning] && string.is_a?(Array) ? "TJ" : "Tj"
|
|
180
|
+
add_content Prawn::PdfObject(string, true) << " " << operation
|
|
181
|
+
end
|
|
182
|
+
add_content "ET\n"
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|