prawn 2.0.2 → 2.3.0
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.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/GPLv2 +20 -21
- data/Gemfile +3 -9
- data/Rakefile +20 -23
- data/lib/prawn.rb +37 -49
- data/lib/prawn/document.rb +181 -133
- data/lib/prawn/document/bounding_box.rb +41 -29
- data/lib/prawn/document/column_box.rb +7 -7
- data/lib/prawn/document/internals.rb +18 -8
- data/lib/prawn/document/span.rb +21 -16
- data/lib/prawn/encoding.rb +69 -68
- data/lib/prawn/errors.rb +12 -7
- data/lib/prawn/font.rb +115 -69
- data/lib/prawn/font_metric_cache.rb +14 -8
- data/lib/prawn/{font → fonts}/afm.rb +102 -68
- data/lib/prawn/{font → fonts}/dfont.rb +5 -11
- data/lib/prawn/fonts/otf.rb +11 -0
- data/lib/prawn/fonts/ttc.rb +36 -0
- data/lib/prawn/{font → fonts}/ttf.rb +87 -68
- data/lib/prawn/graphics.rb +120 -80
- data/lib/prawn/graphics/blend_mode.rb +65 -0
- data/lib/prawn/graphics/cap_style.rb +3 -3
- data/lib/prawn/graphics/color.rb +27 -25
- data/lib/prawn/graphics/dash.rb +23 -11
- data/lib/prawn/graphics/join_style.rb +9 -3
- data/lib/prawn/graphics/patterns.rb +197 -67
- data/lib/prawn/graphics/transformation.rb +17 -8
- data/lib/prawn/graphics/transparency.rb +17 -13
- data/lib/prawn/grid.rb +48 -47
- data/lib/prawn/image_handler.rb +5 -5
- data/lib/prawn/images.rb +39 -30
- data/lib/prawn/images/image.rb +2 -1
- data/lib/prawn/images/jpg.rb +28 -22
- data/lib/prawn/images/png.rb +107 -66
- data/lib/prawn/measurement_extensions.rb +10 -9
- data/lib/prawn/measurements.rb +19 -15
- data/lib/prawn/outline.rb +97 -77
- data/lib/prawn/repeater.rb +14 -10
- data/lib/prawn/security.rb +81 -61
- data/lib/prawn/security/arcfour.rb +2 -2
- data/lib/prawn/soft_mask.rb +26 -26
- data/lib/prawn/stamp.rb +20 -13
- data/lib/prawn/text.rb +68 -52
- data/lib/prawn/text/box.rb +11 -8
- data/lib/prawn/text/formatted.rb +5 -5
- data/lib/prawn/text/formatted/arranger.rb +78 -49
- data/lib/prawn/text/formatted/box.rb +134 -100
- data/lib/prawn/text/formatted/fragment.rb +11 -14
- data/lib/prawn/text/formatted/line_wrap.rb +121 -63
- data/lib/prawn/text/formatted/parser.rb +139 -117
- data/lib/prawn/text/formatted/wrap.rb +43 -31
- data/lib/prawn/transformation_stack.rb +44 -0
- data/lib/prawn/utilities.rb +7 -22
- data/lib/prawn/version.rb +2 -2
- data/lib/prawn/view.rb +17 -7
- data/manual/basic_concepts/adding_pages.rb +6 -7
- data/manual/basic_concepts/basic_concepts.rb +31 -22
- data/manual/basic_concepts/creation.rb +10 -11
- data/manual/basic_concepts/cursor.rb +4 -5
- data/manual/basic_concepts/measurement.rb +6 -7
- data/manual/basic_concepts/origin.rb +5 -6
- data/manual/basic_concepts/other_cursor_helpers.rb +11 -12
- data/manual/basic_concepts/view.rb +22 -16
- data/manual/bounding_box/bounding_box.rb +29 -24
- data/manual/bounding_box/bounds.rb +11 -12
- data/manual/bounding_box/canvas.rb +4 -5
- data/manual/bounding_box/creation.rb +6 -7
- data/manual/bounding_box/indentation.rb +14 -15
- data/manual/bounding_box/nesting.rb +24 -17
- data/manual/bounding_box/russian_boxes.rb +14 -13
- data/manual/bounding_box/stretchy.rb +12 -13
- data/manual/contents.rb +28 -22
- data/manual/cover.rb +33 -28
- data/manual/document_and_page_options/background.rb +11 -13
- data/manual/document_and_page_options/document_and_page_options.rb +25 -20
- data/manual/document_and_page_options/metadata.rb +18 -16
- data/manual/document_and_page_options/page_margins.rb +18 -20
- data/manual/document_and_page_options/page_size.rb +13 -12
- data/manual/document_and_page_options/print_scaling.rb +17 -15
- data/manual/example_helper.rb +5 -4
- data/manual/graphics/blend_mode.rb +52 -0
- data/manual/graphics/circle_and_ellipse.rb +4 -5
- data/manual/graphics/color.rb +7 -9
- data/manual/graphics/common_lines.rb +7 -8
- data/manual/graphics/fill_and_stroke.rb +4 -5
- data/manual/graphics/fill_rules.rb +9 -10
- data/manual/graphics/gradients.rb +27 -21
- data/manual/graphics/graphics.rb +48 -39
- data/manual/graphics/helper.rb +12 -9
- data/manual/graphics/line_width.rb +8 -7
- data/manual/graphics/lines_and_curves.rb +7 -8
- data/manual/graphics/polygon.rb +6 -8
- data/manual/graphics/rectangle.rb +4 -5
- data/manual/graphics/rotate.rb +6 -7
- data/manual/graphics/scale.rb +14 -15
- data/manual/graphics/soft_masks.rb +4 -5
- data/manual/graphics/stroke_cap.rb +6 -7
- data/manual/graphics/stroke_dash.rb +11 -12
- data/manual/graphics/stroke_join.rb +5 -6
- data/manual/graphics/translate.rb +9 -10
- data/manual/graphics/transparency.rb +7 -8
- data/manual/how_to_read_this_manual.rb +6 -6
- data/manual/images/absolute_position.rb +6 -7
- data/manual/images/fit.rb +7 -8
- data/manual/images/horizontal.rb +9 -10
- data/manual/images/images.rb +28 -24
- data/manual/images/plain_image.rb +5 -6
- data/manual/images/scale.rb +9 -10
- data/manual/images/vertical.rb +13 -14
- data/manual/images/width_and_height.rb +10 -11
- data/manual/layout/boxes.rb +5 -6
- data/manual/layout/content.rb +7 -8
- data/manual/layout/layout.rb +18 -16
- data/manual/layout/simple_grid.rb +6 -7
- data/manual/outline/add_subsection_to.rb +20 -21
- data/manual/outline/insert_section_after.rb +15 -16
- data/manual/outline/outline.rb +21 -17
- data/manual/outline/sections_and_pages.rb +17 -18
- data/manual/repeatable_content/alternate_page_numbering.rb +21 -17
- data/manual/repeatable_content/page_numbering.rb +17 -16
- data/manual/repeatable_content/repeatable_content.rb +25 -19
- data/manual/repeatable_content/repeater.rb +14 -15
- data/manual/repeatable_content/stamp.rb +14 -15
- data/manual/security/encryption.rb +9 -10
- data/manual/security/permissions.rb +19 -14
- data/manual/security/security.rb +19 -16
- data/manual/table.rb +3 -3
- data/manual/text/alignment.rb +16 -17
- data/manual/text/color.rb +12 -11
- data/manual/text/column_box.rb +9 -10
- data/manual/text/fallback_fonts.rb +25 -21
- data/manual/text/font.rb +11 -12
- data/manual/text/font_size.rb +13 -14
- data/manual/text/font_style.rb +7 -8
- data/manual/text/formatted_callbacks.rb +25 -21
- data/manual/text/formatted_text.rb +33 -25
- data/manual/text/free_flowing_text.rb +20 -21
- data/manual/text/inline.rb +18 -19
- data/manual/text/kerning_and_character_spacing.rb +14 -15
- data/manual/text/leading.rb +7 -8
- data/manual/text/line_wrapping.rb +37 -18
- data/manual/text/paragraph_indentation.rb +13 -14
- data/manual/text/positioned_text.rb +15 -16
- data/manual/text/registering_families.rb +20 -21
- data/manual/text/rendering_and_color.rb +9 -10
- data/manual/text/right_to_left_text.rb +26 -19
- data/manual/text/rotation.rb +28 -23
- data/manual/text/single_usage.rb +8 -9
- data/manual/text/text.rb +57 -52
- data/manual/text/text_box_excess.rb +20 -17
- data/manual/text/text_box_extensions.rb +18 -15
- data/manual/text/text_box_overflow.rb +18 -19
- data/manual/text/utf8.rb +11 -12
- data/manual/text/win_ansi_charset.rb +21 -19
- data/prawn.gemspec +45 -33
- data/spec/extensions/encoding_helpers.rb +3 -3
- data/spec/prawn/document/bounding_box_spec.rb +546 -0
- data/spec/prawn/document/column_box_spec.rb +75 -0
- data/spec/prawn/document/security_spec.rb +176 -0
- data/spec/prawn/document_annotations_spec.rb +76 -0
- data/spec/prawn/document_destinations_spec.rb +15 -0
- data/spec/prawn/document_grid_spec.rb +99 -0
- data/spec/prawn/document_reference_spec.rb +27 -0
- data/spec/prawn/document_span_spec.rb +36 -0
- data/spec/prawn/document_spec.rb +802 -0
- data/spec/prawn/font_metric_cache_spec.rb +54 -0
- data/spec/prawn/font_spec.rb +542 -0
- data/spec/prawn/graphics/blend_mode_spec.rb +63 -0
- data/spec/prawn/graphics/transparency_spec.rb +81 -0
- data/spec/prawn/graphics_spec.rb +837 -0
- data/spec/prawn/graphics_stroke_styles_spec.rb +229 -0
- data/spec/prawn/image_handler_spec.rb +53 -0
- data/spec/prawn/images/jpg_spec.rb +20 -0
- data/spec/prawn/images/png_spec.rb +283 -0
- data/spec/prawn/images_spec.rb +224 -0
- data/spec/prawn/measurements_extensions_spec.rb +24 -0
- data/spec/prawn/outline_spec.rb +412 -0
- data/spec/prawn/repeater_spec.rb +165 -0
- data/spec/prawn/soft_mask_spec.rb +74 -0
- data/spec/prawn/stamp_spec.rb +172 -0
- data/spec/prawn/text/box_spec.rb +1112 -0
- data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
- data/spec/prawn/text/formatted/box_spec.rb +846 -0
- data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
- data/spec/prawn/text/formatted/line_wrap_spec.rb +494 -0
- data/spec/prawn/text/formatted/parser_spec.rb +697 -0
- data/spec/prawn/text_draw_text_spec.rb +149 -0
- data/spec/prawn/text_rendering_mode_spec.rb +48 -0
- data/spec/prawn/text_spacing_spec.rb +95 -0
- data/spec/prawn/text_spec.rb +603 -0
- data/spec/prawn/text_with_inline_formatting_spec.rb +35 -0
- data/spec/prawn/transformation_stack_spec.rb +66 -0
- data/spec/prawn/view_spec.rb +63 -0
- data/spec/prawn_manual_spec.rb +35 -0
- data/spec/spec_helper.rb +19 -23
- metadata +145 -185
- metadata.gz.sig +4 -0
- data/data/images/16bit.alpha +0 -0
- data/data/images/16bit.color +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/dice.alpha +0 -0
- data/data/images/dice.color +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/indexed_color.dat +0 -0
- data/data/images/indexed_color.png +0 -0
- data/data/images/letterhead.jpg +0 -0
- data/data/images/license.md +0 -8
- data/data/images/page_white_text.alpha +0 -0
- data/data/images/page_white_text.color +0 -0
- data/data/images/page_white_text.png +0 -0
- data/data/images/pal_bk.png +0 -0
- data/data/images/pigs.jpg +0 -0
- data/data/images/prawn.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 +0 -1
- data/data/images/web-links.png +0 -0
- data/data/pdfs/complex_template.pdf +0 -0
- data/data/pdfs/contains_ttf_font.pdf +0 -0
- data/data/pdfs/encrypted.pdf +0 -0
- data/data/pdfs/form.pdf +1 -819
- data/data/pdfs/hexagon.pdf +0 -61
- data/data/pdfs/indirect_reference.pdf +0 -86
- data/data/pdfs/multipage_template.pdf +0 -127
- data/data/pdfs/nested_pages.pdf +0 -118
- data/data/pdfs/page_without_mediabox.pdf +0 -193
- data/data/pdfs/resources_as_indirect_object.pdf +0 -83
- data/data/pdfs/two_hexagons.pdf +0 -90
- data/data/pdfs/version_1_6.pdf +0 -61
- data/data/shift_jis_text.txt +0 -1
- data/spec/acceptance/png.rb +0 -24
- data/spec/annotations_spec.rb +0 -67
- data/spec/bounding_box_spec.rb +0 -501
- data/spec/column_box_spec.rb +0 -59
- data/spec/destinations_spec.rb +0 -13
- data/spec/document_spec.rb +0 -742
- data/spec/extensions/mocha.rb +0 -45
- data/spec/font_metric_cache_spec.rb +0 -52
- data/spec/font_spec.rb +0 -475
- data/spec/formatted_text_arranger_spec.rb +0 -423
- data/spec/formatted_text_box_spec.rb +0 -716
- data/spec/formatted_text_fragment_spec.rb +0 -299
- data/spec/graphics_spec.rb +0 -666
- data/spec/grid_spec.rb +0 -95
- data/spec/image_handler_spec.rb +0 -53
- data/spec/images_spec.rb +0 -167
- data/spec/inline_formatted_text_parser_spec.rb +0 -568
- data/spec/jpg_spec.rb +0 -23
- data/spec/line_wrap_spec.rb +0 -366
- data/spec/measurement_units_spec.rb +0 -22
- data/spec/outline_spec.rb +0 -409
- data/spec/png_spec.rb +0 -235
- data/spec/reference_spec.rb +0 -25
- data/spec/repeater_spec.rb +0 -154
- data/spec/security_spec.rb +0 -151
- data/spec/soft_mask_spec.rb +0 -78
- data/spec/span_spec.rb +0 -43
- data/spec/stamp_spec.rb +0 -179
- data/spec/stroke_styles_spec.rb +0 -208
- data/spec/text_at_spec.rb +0 -142
- data/spec/text_box_spec.rb +0 -1038
- data/spec/text_rendering_mode_spec.rb +0 -45
- data/spec/text_spacing_spec.rb +0 -93
- data/spec/text_spec.rb +0 -549
- data/spec/text_with_inline_formatting_spec.rb +0 -35
- data/spec/transparency_spec.rb +0 -91
- data/spec/view_spec.rb +0 -42
@@ -1,15 +1,9 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
# font.rb : The Prawn font class
|
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
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
9
3
|
require_relative 'ttf'
|
10
4
|
|
11
5
|
module Prawn
|
12
|
-
|
6
|
+
module Fonts
|
13
7
|
# @private
|
14
8
|
class DFont < TTF
|
15
9
|
# Returns a list of the names of all named fonts in the given dfont file.
|
@@ -20,7 +14,7 @@ module Prawn
|
|
20
14
|
#
|
21
15
|
def self.named_fonts(file)
|
22
16
|
TTFunk::ResourceFile.open(file) do |f|
|
23
|
-
return f.resources_for(
|
17
|
+
return f.resources_for('sfnt')
|
24
18
|
end
|
25
19
|
end
|
26
20
|
|
@@ -28,7 +22,7 @@ module Prawn
|
|
28
22
|
#
|
29
23
|
def self.font_count(file)
|
30
24
|
TTFunk::ResourceFile.open(file) do |f|
|
31
|
-
return f.map[
|
25
|
+
return f.map['sfnt'][:list].length
|
32
26
|
end
|
33
27
|
end
|
34
28
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'ttf'
|
4
|
+
|
5
|
+
module Prawn
|
6
|
+
module Fonts
|
7
|
+
# @private
|
8
|
+
class TTC < TTF
|
9
|
+
# Returns a list of the names of all named fonts in the given ttc file.
|
10
|
+
# They are returned in order of their appearance in the file.
|
11
|
+
#
|
12
|
+
def self.font_names(file)
|
13
|
+
TTFunk::Collection.open(file) do |ttc|
|
14
|
+
ttc.map { |font| font.name.font_name.first }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def read_ttf_file
|
21
|
+
TTFunk::File.from_ttc(
|
22
|
+
@name,
|
23
|
+
font_option_to_index(@name, @options[:font])
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def font_option_to_index(file, option)
|
28
|
+
if option.is_a?(Numeric)
|
29
|
+
option
|
30
|
+
else
|
31
|
+
self.class.font_names(file).index { |n| n == option } || 0
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# prawn/font/ttf.rb : Implements AFM font support for Prawn
|
4
4
|
#
|
@@ -11,7 +11,7 @@ require 'ttfunk'
|
|
11
11
|
require 'ttfunk/subset_collection'
|
12
12
|
|
13
13
|
module Prawn
|
14
|
-
|
14
|
+
module Fonts
|
15
15
|
# @private
|
16
16
|
class TTF < Font
|
17
17
|
attr_reader :ttf, :subsets
|
@@ -23,17 +23,18 @@ module Prawn
|
|
23
23
|
def initialize(document, name, options = {})
|
24
24
|
super
|
25
25
|
|
26
|
-
@ttf
|
27
|
-
@subsets
|
26
|
+
@ttf = read_ttf_file
|
27
|
+
@subsets = TTFunk::SubsetCollection.new(@ttf)
|
28
|
+
@italic_angle = nil
|
28
29
|
|
29
|
-
@attributes
|
30
|
-
@bounding_boxes
|
31
|
-
@char_widths
|
30
|
+
@attributes = {}
|
31
|
+
@bounding_boxes = {}
|
32
|
+
@char_widths = {}
|
32
33
|
@has_kerning_data = @ttf.kerning.exists? && @ttf.kerning.tables.any?
|
33
34
|
|
34
|
-
@ascender
|
35
|
-
@descender
|
36
|
-
@line_gap
|
35
|
+
@ascender = Integer(@ttf.ascent * scale_factor)
|
36
|
+
@descender = Integer(@ttf.descent * scale_factor)
|
37
|
+
@line_gap = Integer(@ttf.line_gap * scale_factor)
|
37
38
|
end
|
38
39
|
|
39
40
|
# NOTE: +string+ must be UTF8-encoded.
|
@@ -44,7 +45,7 @@ module Prawn
|
|
44
45
|
if r.is_a?(Numeric)
|
45
46
|
s - r
|
46
47
|
else
|
47
|
-
r.inject(s) { |
|
48
|
+
r.inject(s) { |a, e| a + character_width_by_code(e) }
|
48
49
|
end
|
49
50
|
end * scale
|
50
51
|
else
|
@@ -61,9 +62,12 @@ module Prawn
|
|
61
62
|
end
|
62
63
|
|
63
64
|
# Returns true if the font has kerning data, false otherwise
|
65
|
+
#
|
66
|
+
# rubocop: disable Naming/PredicateName
|
64
67
|
def has_kerning_data?
|
65
68
|
@has_kerning_data
|
66
69
|
end
|
70
|
+
# rubocop: enable Naming/PredicateName
|
67
71
|
|
68
72
|
# Perform any changes to the string that need to happen
|
69
73
|
# before it is rendered to the canvas. Returns an array of
|
@@ -80,7 +84,9 @@ module Prawn
|
|
80
84
|
last_subset = nil
|
81
85
|
kern(text).inject([]) do |result, element|
|
82
86
|
if element.is_a?(Numeric)
|
83
|
-
|
87
|
+
unless result.last[1].is_a?(Array)
|
88
|
+
result.last[1] = [result.last[1]]
|
89
|
+
end
|
84
90
|
result.last[1] << element
|
85
91
|
result
|
86
92
|
else
|
@@ -100,7 +106,7 @@ module Prawn
|
|
100
106
|
end
|
101
107
|
end
|
102
108
|
else
|
103
|
-
@subsets.encode(text.unpack(
|
109
|
+
@subsets.encode(text.unpack('U*'))
|
104
110
|
end
|
105
111
|
end
|
106
112
|
|
@@ -109,7 +115,7 @@ module Prawn
|
|
109
115
|
end
|
110
116
|
|
111
117
|
# not sure how to compute this for true-type fonts...
|
112
|
-
def
|
118
|
+
def stem_v
|
113
119
|
0
|
114
120
|
end
|
115
121
|
|
@@ -118,7 +124,8 @@ module Prawn
|
|
118
124
|
|
119
125
|
if @ttf.postscript.exists?
|
120
126
|
raw = @ttf.postscript.italic_angle
|
121
|
-
hi
|
127
|
+
hi = raw >> 16
|
128
|
+
low = raw & 0xFF
|
122
129
|
hi = -((hi ^ 0xFFFF) + 1) if hi & 0x8000 != 0
|
123
130
|
@italic_angle = "#{hi}.#{low}".to_f
|
124
131
|
else
|
@@ -131,7 +138,7 @@ module Prawn
|
|
131
138
|
def cap_height
|
132
139
|
@cap_height ||= begin
|
133
140
|
height = @ttf.os2.exists? && @ttf.os2.cap_height || 0
|
134
|
-
height
|
141
|
+
height.zero? ? @ascender : height
|
135
142
|
end
|
136
143
|
end
|
137
144
|
|
@@ -154,35 +161,34 @@ module Prawn
|
|
154
161
|
end
|
155
162
|
|
156
163
|
def pdf_flags
|
157
|
-
@
|
164
|
+
@pdf_flags ||= begin
|
158
165
|
flags = 0
|
159
166
|
flags |= 0x0001 if @ttf.postscript.fixed_pitch?
|
160
167
|
flags |= 0x0002 if serif?
|
161
168
|
flags |= 0x0008 if script?
|
162
169
|
flags |= 0x0040 if italic_angle != 0
|
163
|
-
|
170
|
+
# Assume the font contains at least some non-latin characters
|
171
|
+
flags | 0x0004
|
164
172
|
end
|
165
173
|
end
|
166
174
|
|
167
175
|
def normalize_encoding(text)
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
"to use is set correctly"
|
176
|
-
end
|
176
|
+
text.encode(::Encoding::UTF_8)
|
177
|
+
rescue StandardError => e
|
178
|
+
puts e
|
179
|
+
raise Prawn::Errors::IncompatibleStringEncoding, 'Encoding ' \
|
180
|
+
"#{text.encoding} can not be transparently converted to UTF-8. " \
|
181
|
+
'Please ensure the encoding of the string you are attempting ' \
|
182
|
+
'to use is set correctly'
|
177
183
|
end
|
178
184
|
|
179
185
|
def to_utf8(text)
|
180
|
-
text.encode(
|
186
|
+
text.encode('UTF-8')
|
181
187
|
end
|
182
188
|
|
183
189
|
def glyph_present?(char)
|
184
190
|
code = char.codepoints.first
|
185
|
-
cmap[code]
|
191
|
+
cmap[code].positive?
|
186
192
|
end
|
187
193
|
|
188
194
|
# Returns the number of characters in +str+ (a UTF-8-encoded string).
|
@@ -194,7 +200,7 @@ module Prawn
|
|
194
200
|
private
|
195
201
|
|
196
202
|
def cmap
|
197
|
-
@cmap ||= @ttf.cmap.unicode.first
|
203
|
+
(@cmap ||= @ttf.cmap.unicode.first) || raise('no unicode cmap for font')
|
198
204
|
end
|
199
205
|
|
200
206
|
# +string+ must be UTF8-encoded.
|
@@ -220,12 +226,12 @@ module Prawn
|
|
220
226
|
end
|
221
227
|
|
222
228
|
def kern_pairs_table
|
223
|
-
@
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
+
@kern_pairs_table ||=
|
230
|
+
if has_kerning_data?
|
231
|
+
@ttf.kerning.tables.first.pairs
|
232
|
+
else
|
233
|
+
{}
|
234
|
+
end
|
229
235
|
end
|
230
236
|
|
231
237
|
def hmtx
|
@@ -243,16 +249,16 @@ module Prawn
|
|
243
249
|
end
|
244
250
|
|
245
251
|
def scale_factor
|
246
|
-
@
|
252
|
+
@scale_factor ||= 1000.0 / @ttf.header.units_per_em
|
247
253
|
end
|
248
254
|
|
249
255
|
def register(subset)
|
250
|
-
temp_name = @ttf.name.postscript_name.
|
251
|
-
ref = @document.ref!(:
|
256
|
+
temp_name = @ttf.name.postscript_name.delete("\0").to_sym
|
257
|
+
ref = @document.ref!(Type: :Font, BaseFont: temp_name)
|
252
258
|
|
253
259
|
# Embed the font metrics in the document after everything has been
|
254
260
|
# drawn, just before the document is emitted.
|
255
|
-
@document.renderer.before_render { |
|
261
|
+
@document.renderer.before_render { |_doc| embed(ref, subset) }
|
256
262
|
|
257
263
|
ref
|
258
264
|
end
|
@@ -267,29 +273,32 @@ module Prawn
|
|
267
273
|
|
268
274
|
# empirically, it looks like Adobe Reader will not display fonts
|
269
275
|
# if their font name is more than 33 bytes long. Strange. But true.
|
270
|
-
basename = font.name.postscript_name[0, 33].
|
276
|
+
basename = font.name.postscript_name[0, 33].delete("\0")
|
271
277
|
|
272
|
-
|
278
|
+
raise "Can't detect a postscript name for #{file}" if basename.nil?
|
273
279
|
|
274
|
-
fontfile = @document.ref!(:
|
280
|
+
fontfile = @document.ref!(Length1: font_content.size)
|
275
281
|
fontfile.stream << font_content
|
276
282
|
fontfile.stream.compress!
|
277
283
|
|
278
|
-
descriptor = @document.ref!(
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
284
|
+
descriptor = @document.ref!(
|
285
|
+
Type: :FontDescriptor,
|
286
|
+
FontName: basename.to_sym,
|
287
|
+
FontFile2: fontfile,
|
288
|
+
FontBBox: bbox,
|
289
|
+
Flags: pdf_flags,
|
290
|
+
StemV: stem_v,
|
291
|
+
ItalicAngle: italic_angle,
|
292
|
+
Ascent: @ascender,
|
293
|
+
Descent: @descender,
|
294
|
+
CapHeight: cap_height,
|
295
|
+
XHeight: x_height
|
296
|
+
)
|
289
297
|
|
290
298
|
hmtx = font.horizontal_metrics
|
291
|
-
widths = font.cmap.tables.first.code_map.map
|
292
|
-
Integer(hmtx.widths[gid] * scale_factor)
|
299
|
+
widths = font.cmap.tables.first.code_map.map do |gid|
|
300
|
+
Integer(hmtx.widths[gid] * scale_factor)
|
301
|
+
end[32..-1]
|
293
302
|
|
294
303
|
# It would be nice to have Encoding set for the macroman subsets,
|
295
304
|
# and only do a ToUnicode cmap for non-encoded unicode subsets.
|
@@ -304,14 +313,22 @@ module Prawn
|
|
304
313
|
map = @subsets[subset].to_unicode_map
|
305
314
|
|
306
315
|
ranges = [[]]
|
307
|
-
map.keys.sort.inject(
|
316
|
+
map.keys.sort.inject('') do |_s, code|
|
308
317
|
ranges << [] if ranges.last.length >= 100
|
309
318
|
unicode = map[code]
|
310
|
-
ranges.last <<
|
319
|
+
ranges.last << format(
|
320
|
+
'<%<code>02x><%<unicode>04x>',
|
321
|
+
code: code,
|
322
|
+
unicode: unicode
|
323
|
+
)
|
311
324
|
end
|
312
325
|
|
313
|
-
range_blocks = ranges.inject(
|
314
|
-
s <<
|
326
|
+
range_blocks = ranges.inject(+'') do |s, list|
|
327
|
+
s << format(
|
328
|
+
"%<lenght>d beginbfchar\n%<list>s\nendbfchar\n",
|
329
|
+
lenght: list.length,
|
330
|
+
list: list.join("\n")
|
331
|
+
)
|
315
332
|
end
|
316
333
|
|
317
334
|
to_unicode_cmap = UNICODE_CMAP_TEMPLATE % range_blocks.strip
|
@@ -320,16 +337,18 @@ module Prawn
|
|
320
337
|
cmap << to_unicode_cmap
|
321
338
|
cmap.stream.compress!
|
322
339
|
|
323
|
-
reference.data.update(
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
340
|
+
reference.data.update(
|
341
|
+
Subtype: :TrueType,
|
342
|
+
BaseFont: basename.to_sym,
|
343
|
+
FontDescriptor: descriptor,
|
344
|
+
FirstChar: 32,
|
345
|
+
LastChar: 255,
|
346
|
+
Widths: @document.ref!(widths),
|
347
|
+
ToUnicode: cmap
|
348
|
+
)
|
330
349
|
end
|
331
350
|
|
332
|
-
UNICODE_CMAP_TEMPLATE = <<-STR.strip.gsub(/^\s*/,
|
351
|
+
UNICODE_CMAP_TEMPLATE = <<-STR.strip.gsub(/^\s*/, '')
|
333
352
|
/CIDInit /ProcSet findresource begin
|
334
353
|
12 dict begin
|
335
354
|
begincmap
|
data/lib/prawn/graphics.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# graphics.rb : Implements PDF drawing primitives
|
4
4
|
#
|
@@ -6,13 +6,14 @@
|
|
6
6
|
#
|
7
7
|
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
8
|
|
9
|
-
require_relative
|
10
|
-
require_relative
|
11
|
-
require_relative
|
12
|
-
require_relative
|
13
|
-
require_relative
|
14
|
-
require_relative
|
15
|
-
require_relative
|
9
|
+
require_relative 'graphics/blend_mode'
|
10
|
+
require_relative 'graphics/color'
|
11
|
+
require_relative 'graphics/dash'
|
12
|
+
require_relative 'graphics/cap_style'
|
13
|
+
require_relative 'graphics/join_style'
|
14
|
+
require_relative 'graphics/transparency'
|
15
|
+
require_relative 'graphics/transformation'
|
16
|
+
require_relative 'graphics/patterns'
|
16
17
|
|
17
18
|
module Prawn
|
18
19
|
# Implements the drawing facilities for Prawn::Document.
|
@@ -22,6 +23,7 @@ module Prawn
|
|
22
23
|
# ruby-pdf.rubyforge.org
|
23
24
|
#
|
24
25
|
module Graphics
|
26
|
+
include BlendMode
|
25
27
|
include Color
|
26
28
|
include Dash
|
27
29
|
include CapStyle
|
@@ -64,9 +66,11 @@ module Prawn
|
|
64
66
|
# pdf.curve_to [100,100], :bounds => [[90,90],[75,75]]
|
65
67
|
#
|
66
68
|
def curve_to(dest, options = {})
|
67
|
-
options[:bounds]
|
68
|
-
|
69
|
-
|
69
|
+
options[:bounds] || raise(
|
70
|
+
Prawn::Errors::InvalidGraphicsPath,
|
71
|
+
'Bounding points for bezier curve must be specified ' \
|
72
|
+
'as :bounds => [[x1,y1],[x2,y2]]'
|
73
|
+
)
|
70
74
|
|
71
75
|
curve_points = PDF::Core.real_params(
|
72
76
|
(options[:bounds] << dest).flat_map { |e| map_to_absolute(e) }
|
@@ -95,7 +99,9 @@ module Prawn
|
|
95
99
|
#
|
96
100
|
def rounded_rectangle(point, width, height, radius)
|
97
101
|
x, y = point
|
98
|
-
rounded_polygon(
|
102
|
+
rounded_polygon(
|
103
|
+
radius, point, [x + width, y], [x + width, y - height], [x, y - height]
|
104
|
+
)
|
99
105
|
end
|
100
106
|
|
101
107
|
###########################################################
|
@@ -144,11 +150,7 @@ module Prawn
|
|
144
150
|
# horizontal_line 25, 100, :at => 75
|
145
151
|
#
|
146
152
|
def horizontal_line(x1, x2, options = {})
|
147
|
-
|
148
|
-
y1 = options[:at]
|
149
|
-
else
|
150
|
-
y1 = y - bounds.absolute_bottom
|
151
|
-
end
|
153
|
+
y1 = options[:at] || y - bounds.absolute_bottom
|
152
154
|
|
153
155
|
line(x1, y1, x2, y1)
|
154
156
|
end
|
@@ -184,9 +186,9 @@ module Prawn
|
|
184
186
|
#
|
185
187
|
KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0)
|
186
188
|
|
187
|
-
# Draws a circle of radius <tt>radius</tt> with the centre-point at
|
188
|
-
# as a complete subpath. The drawing point will be moved to
|
189
|
-
# centre-point upon completion of the drawing the circle.
|
189
|
+
# Draws a circle of radius <tt>radius</tt> with the centre-point at
|
190
|
+
# <tt>point</tt> as a complete subpath. The drawing point will be moved to
|
191
|
+
# the centre-point upon completion of the drawing the circle.
|
190
192
|
#
|
191
193
|
# pdf.circle [100,100], 25
|
192
194
|
#
|
@@ -194,36 +196,36 @@ module Prawn
|
|
194
196
|
ellipse(center, radius, radius)
|
195
197
|
end
|
196
198
|
|
197
|
-
# Draws an ellipse of +x+ radius <tt>
|
198
|
-
# with the centre-point at <tt>point</tt> as a complete
|
199
|
-
# drawing point will be moved to the centre-point upon
|
200
|
-
# drawing the ellipse.
|
199
|
+
# Draws an ellipse of +x+ radius <tt>radius1</tt> and +y+ radius
|
200
|
+
# <tt>radius2</tt> with the centre-point at <tt>point</tt> as a complete
|
201
|
+
# subpath. The drawing point will be moved to the centre-point upon
|
202
|
+
# completion of the drawing the ellipse.
|
201
203
|
#
|
202
204
|
# # draws an ellipse with x-radius 25 and y-radius 50
|
203
205
|
# pdf.ellipse [100,100], 25, 50
|
204
206
|
#
|
205
|
-
def ellipse(point,
|
207
|
+
def ellipse(point, radius1, radius2 = radius1)
|
206
208
|
x, y = point
|
207
|
-
l1 =
|
208
|
-
l2 =
|
209
|
+
l1 = radius1 * KAPPA
|
210
|
+
l2 = radius2 * KAPPA
|
209
211
|
|
210
|
-
move_to(x +
|
212
|
+
move_to(x + radius1, y)
|
211
213
|
|
212
214
|
# Upper right hand corner
|
213
|
-
curve_to [x, y +
|
214
|
-
|
215
|
+
curve_to [x, y + radius2],
|
216
|
+
bounds: [[x + radius1, y + l2], [x + l1, y + radius2]]
|
215
217
|
|
216
218
|
# Upper left hand corner
|
217
|
-
curve_to [x -
|
218
|
-
|
219
|
+
curve_to [x - radius1, y],
|
220
|
+
bounds: [[x - l1, y + radius2], [x - radius1, y + l2]]
|
219
221
|
|
220
222
|
# Lower left hand corner
|
221
|
-
curve_to [x, y -
|
222
|
-
|
223
|
+
curve_to [x, y - radius2],
|
224
|
+
bounds: [[x - radius1, y - l2], [x - l1, y - radius2]]
|
223
225
|
|
224
226
|
# Lower right hand corner
|
225
|
-
curve_to [x +
|
226
|
-
|
227
|
+
curve_to [x + radius1, y],
|
228
|
+
bounds: [[x + l1, y - radius2], [x + radius1, y - l2]]
|
227
229
|
|
228
230
|
move_to(x, y)
|
229
231
|
end
|
@@ -239,35 +241,47 @@ module Prawn
|
|
239
241
|
line_to(*point)
|
240
242
|
end
|
241
243
|
# close the path
|
242
|
-
renderer.add_content
|
244
|
+
renderer.add_content 'h'
|
243
245
|
end
|
244
246
|
|
245
|
-
# Draws a rounded polygon from specified points using the radius to define
|
247
|
+
# Draws a rounded polygon from specified points using the radius to define
|
248
|
+
# bezier curves
|
246
249
|
#
|
247
|
-
#
|
248
|
-
# pdf.fill_and_stroke_rounded_polygon(
|
249
|
-
#
|
250
|
+
# # draws a rounded filled in polygon
|
251
|
+
# pdf.fill_and_stroke_rounded_polygon(
|
252
|
+
# 10, [100, 250], [200, 300], [300, 250], [300, 150], [200, 100],
|
253
|
+
# [100, 150]
|
254
|
+
# )
|
250
255
|
def rounded_polygon(radius, *points)
|
251
256
|
move_to point_on_line(radius, points[1], points[0])
|
252
257
|
sides = points.size
|
253
258
|
points << points[0] << points[1]
|
254
|
-
|
259
|
+
sides.times do |i|
|
255
260
|
rounded_vertex(radius, points[i], points[i + 1], points[i + 2])
|
256
261
|
end
|
257
262
|
# close the path
|
258
|
-
renderer.add_content
|
263
|
+
renderer.add_content 'h'
|
259
264
|
end
|
260
265
|
|
261
|
-
# Creates a rounded vertex for a line segment used for building a rounded
|
262
|
-
# requires a radius to define bezier curve and three points. The
|
263
|
-
# the line segment and the third point helps define
|
266
|
+
# Creates a rounded vertex for a line segment used for building a rounded
|
267
|
+
# polygon requires a radius to define bezier curve and three points. The
|
268
|
+
# first two points define the line segment and the third point helps define
|
269
|
+
# the curve for the vertex.
|
264
270
|
def rounded_vertex(radius, *points)
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
+
radial_point1 = point_on_line(radius, points[0], points[1])
|
272
|
+
bezier_point1 = point_on_line(
|
273
|
+
(radius - radius * KAPPA),
|
274
|
+
points[0],
|
275
|
+
points[1]
|
276
|
+
)
|
277
|
+
radial_point2 = point_on_line(radius, points[2], points[1])
|
278
|
+
bezier_point2 = point_on_line(
|
279
|
+
(radius - radius * KAPPA),
|
280
|
+
points[2],
|
281
|
+
points[1]
|
282
|
+
)
|
283
|
+
line_to(radial_point1)
|
284
|
+
curve_to(radial_point2, bounds: [bezier_point1, bezier_point2])
|
271
285
|
end
|
272
286
|
|
273
287
|
# Strokes the current path. If a block is provided, yields to the block
|
@@ -275,7 +289,7 @@ module Prawn
|
|
275
289
|
#
|
276
290
|
def stroke
|
277
291
|
yield if block_given?
|
278
|
-
renderer.add_content
|
292
|
+
renderer.add_content 'S'
|
279
293
|
end
|
280
294
|
|
281
295
|
# Closes and strokes the current path. If a block is provided, yields to
|
@@ -283,7 +297,7 @@ module Prawn
|
|
283
297
|
#
|
284
298
|
def close_and_stroke
|
285
299
|
yield if block_given?
|
286
|
-
renderer.add_content
|
300
|
+
renderer.add_content 's'
|
287
301
|
end
|
288
302
|
|
289
303
|
# Draws and strokes a rectangle represented by the current bounding box
|
@@ -318,38 +332,56 @@ module Prawn
|
|
318
332
|
#
|
319
333
|
def stroke_axis(options = {})
|
320
334
|
options = {
|
321
|
-
:
|
322
|
-
:
|
323
|
-
:
|
324
|
-
:
|
325
|
-
:
|
326
|
-
:
|
335
|
+
at: [0, 0],
|
336
|
+
height: bounds.height.to_i - (options[:at] || [0, 0])[1],
|
337
|
+
width: bounds.width.to_i - (options[:at] || [0, 0])[0],
|
338
|
+
step_length: 100,
|
339
|
+
negative_axes_length: 20,
|
340
|
+
color: '000000'
|
327
341
|
}.merge(options)
|
328
342
|
|
329
|
-
Prawn.verify_options(
|
330
|
-
|
343
|
+
Prawn.verify_options(
|
344
|
+
%i[
|
345
|
+
at width height step_length
|
346
|
+
negative_axes_length color
|
347
|
+
], options
|
348
|
+
)
|
331
349
|
|
332
350
|
save_graphics_state do
|
333
351
|
fill_color(options[:color])
|
334
352
|
stroke_color(options[:color])
|
335
353
|
|
336
|
-
dash(1, :
|
337
|
-
stroke_horizontal_line(
|
338
|
-
|
339
|
-
|
340
|
-
|
354
|
+
dash(1, space: 4)
|
355
|
+
stroke_horizontal_line(
|
356
|
+
options[:at][0] - options[:negative_axes_length],
|
357
|
+
options[:at][0] + options[:width], at: options[:at][1]
|
358
|
+
)
|
359
|
+
stroke_vertical_line(
|
360
|
+
options[:at][1] - options[:negative_axes_length],
|
361
|
+
options[:at][1] + options[:height], at: options[:at][0]
|
362
|
+
)
|
341
363
|
undash
|
342
364
|
|
343
365
|
fill_circle(options[:at], 1)
|
344
366
|
|
345
|
-
(options[:step_length]..options[:width])
|
367
|
+
(options[:step_length]..options[:width])
|
368
|
+
.step(options[:step_length]) do |point|
|
346
369
|
fill_circle([options[:at][0] + point, options[:at][1]], 1)
|
347
|
-
draw_text(
|
370
|
+
draw_text(
|
371
|
+
point,
|
372
|
+
at: [options[:at][0] + point - 5, options[:at][1] - 10],
|
373
|
+
size: 7
|
374
|
+
)
|
348
375
|
end
|
349
376
|
|
350
|
-
(options[:step_length]..options[:height])
|
377
|
+
(options[:step_length]..options[:height])
|
378
|
+
.step(options[:step_length]) do |point|
|
351
379
|
fill_circle([options[:at][0], options[:at][1] + point], 1)
|
352
|
-
draw_text(
|
380
|
+
draw_text(
|
381
|
+
point,
|
382
|
+
at: [options[:at][0] - 17, options[:at][1] + point - 2],
|
383
|
+
size: 7
|
384
|
+
)
|
353
385
|
end
|
354
386
|
end
|
355
387
|
end
|
@@ -363,7 +395,7 @@ module Prawn
|
|
363
395
|
#
|
364
396
|
def fill(options = {})
|
365
397
|
yield if block_given?
|
366
|
-
renderer.add_content(options[:fill_rule] == :even_odd ?
|
398
|
+
renderer.add_content(options[:fill_rule] == :even_odd ? 'f*' : 'f')
|
367
399
|
end
|
368
400
|
|
369
401
|
# Closes, fills, and strokes the current path. If a block is provided,
|
@@ -377,13 +409,13 @@ module Prawn
|
|
377
409
|
#
|
378
410
|
def fill_and_stroke(options = {})
|
379
411
|
yield if block_given?
|
380
|
-
renderer.add_content(options[:fill_rule] == :even_odd ?
|
412
|
+
renderer.add_content(options[:fill_rule] == :even_odd ? 'b*' : 'b')
|
381
413
|
end
|
382
414
|
|
383
415
|
# Closes the current path.
|
384
416
|
#
|
385
417
|
def close_path
|
386
|
-
renderer.add_content
|
418
|
+
renderer.add_content 'h'
|
387
419
|
end
|
388
420
|
|
389
421
|
##
|
@@ -592,12 +624,20 @@ module Prawn
|
|
592
624
|
# :call-seq:
|
593
625
|
# fill_and_stroke_rounded_polygon(radius, *points)
|
594
626
|
|
595
|
-
ops
|
596
|
-
shapes = %w
|
597
|
-
|
627
|
+
ops = %w[fill stroke fill_and_stroke]
|
628
|
+
shapes = %w[
|
629
|
+
line_to curve_to rectangle rounded_rectangle line horizontal_line
|
630
|
+
horizontal_rule vertical_line curve circle_at circle ellipse_at ellipse
|
631
|
+
polygon rounded_polygon rounded_vertex
|
632
|
+
]
|
598
633
|
|
599
634
|
ops.product(shapes).each do |operation, shape|
|
600
|
-
class_eval
|
635
|
+
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
636
|
+
def #{operation}_#{shape}(*args)
|
637
|
+
#{shape}(*args)
|
638
|
+
#{operation}
|
639
|
+
end
|
640
|
+
METHOD
|
601
641
|
end
|
602
642
|
|
603
643
|
private
|
@@ -627,8 +667,8 @@ module Prawn
|
|
627
667
|
angle * Math::PI / 180
|
628
668
|
end
|
629
669
|
|
630
|
-
# Returns the coordinates for a point on a line that is a given distance
|
631
|
-
# point defining the line segement
|
670
|
+
# Returns the coordinates for a point on a line that is a given distance
|
671
|
+
# away from the second point defining the line segement
|
632
672
|
def point_on_line(distance_from_end, *points)
|
633
673
|
x0, y0, x1, y1 = points.flatten
|
634
674
|
length = Math.sqrt((x1 - x0)**2 + (y1 - y0)**2)
|