prawn 2.1.0 → 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 +36 -49
- data/lib/prawn/document.rb +180 -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 +8 -6
- 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 +102 -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 +119 -81
- data/lib/prawn/graphics/blend_mode.rb +9 -8
- 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 +190 -96
- data/lib/prawn/graphics/transformation.rb +15 -9
- 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 +65 -62
- 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 +53 -32
- 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 +122 -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 +7 -5
- 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 +12 -9
- 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 -40
- 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 +3 -4
- 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 +44 -31
- 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/{image_handler_spec.rb → prawn/image_handler_spec.rb} +14 -14
- 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/{transformation_stack_spec.rb → prawn/transformation_stack_spec.rb} +22 -19
- data/spec/prawn/view_spec.rb +63 -0
- data/spec/prawn_manual_spec.rb +35 -0
- data/spec/spec_helper.rb +18 -19
- metadata +144 -180
- 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/blend_modes_bottom_layer.jpg +0 -0
- data/data/images/blend_modes_top_layer.jpg +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/indexed_transparency.png +0 -0
- data/data/images/indexed_transparency_alpha.dat +0 -0
- data/data/images/indexed_transparency_color.dat +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/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_spec.rb +0 -35
- data/spec/annotations_spec.rb +0 -67
- data/spec/blend_mode_spec.rb +0 -71
- 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 -738
- data/spec/font_metric_cache_spec.rb +0 -52
- data/spec/font_spec.rb +0 -475
- data/spec/formatted_text_arranger_spec.rb +0 -452
- data/spec/formatted_text_box_spec.rb +0 -716
- data/spec/formatted_text_fragment_spec.rb +0 -299
- data/spec/graphics_spec.rb +0 -705
- data/spec/grid_spec.rb +0 -95
- 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 -257
- 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 -1042
- data/spec/text_rendering_mode_spec.rb +0 -45
- data/spec/text_spacing_spec.rb +0 -93
- data/spec/text_spec.rb +0 -543
- 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,14 +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
|
16
|
-
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'
|
17
17
|
|
18
18
|
module Prawn
|
19
19
|
# Implements the drawing facilities for Prawn::Document.
|
@@ -66,9 +66,11 @@ module Prawn
|
|
66
66
|
# pdf.curve_to [100,100], :bounds => [[90,90],[75,75]]
|
67
67
|
#
|
68
68
|
def curve_to(dest, options = {})
|
69
|
-
options[:bounds]
|
70
|
-
|
71
|
-
|
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
|
+
)
|
72
74
|
|
73
75
|
curve_points = PDF::Core.real_params(
|
74
76
|
(options[:bounds] << dest).flat_map { |e| map_to_absolute(e) }
|
@@ -97,7 +99,9 @@ module Prawn
|
|
97
99
|
#
|
98
100
|
def rounded_rectangle(point, width, height, radius)
|
99
101
|
x, y = point
|
100
|
-
rounded_polygon(
|
102
|
+
rounded_polygon(
|
103
|
+
radius, point, [x + width, y], [x + width, y - height], [x, y - height]
|
104
|
+
)
|
101
105
|
end
|
102
106
|
|
103
107
|
###########################################################
|
@@ -146,11 +150,7 @@ module Prawn
|
|
146
150
|
# horizontal_line 25, 100, :at => 75
|
147
151
|
#
|
148
152
|
def horizontal_line(x1, x2, options = {})
|
149
|
-
|
150
|
-
y1 = options[:at]
|
151
|
-
else
|
152
|
-
y1 = y - bounds.absolute_bottom
|
153
|
-
end
|
153
|
+
y1 = options[:at] || y - bounds.absolute_bottom
|
154
154
|
|
155
155
|
line(x1, y1, x2, y1)
|
156
156
|
end
|
@@ -186,9 +186,9 @@ module Prawn
|
|
186
186
|
#
|
187
187
|
KAPPA = 4.0 * ((Math.sqrt(2) - 1.0) / 3.0)
|
188
188
|
|
189
|
-
# Draws a circle of radius <tt>radius</tt> with the centre-point at
|
190
|
-
# as a complete subpath. The drawing point will be moved to
|
191
|
-
# 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.
|
192
192
|
#
|
193
193
|
# pdf.circle [100,100], 25
|
194
194
|
#
|
@@ -196,36 +196,36 @@ module Prawn
|
|
196
196
|
ellipse(center, radius, radius)
|
197
197
|
end
|
198
198
|
|
199
|
-
# Draws an ellipse of +x+ radius <tt>
|
200
|
-
# with the centre-point at <tt>point</tt> as a complete
|
201
|
-
# drawing point will be moved to the centre-point upon
|
202
|
-
# 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.
|
203
203
|
#
|
204
204
|
# # draws an ellipse with x-radius 25 and y-radius 50
|
205
205
|
# pdf.ellipse [100,100], 25, 50
|
206
206
|
#
|
207
|
-
def ellipse(point,
|
207
|
+
def ellipse(point, radius1, radius2 = radius1)
|
208
208
|
x, y = point
|
209
|
-
l1 =
|
210
|
-
l2 =
|
209
|
+
l1 = radius1 * KAPPA
|
210
|
+
l2 = radius2 * KAPPA
|
211
211
|
|
212
|
-
move_to(x +
|
212
|
+
move_to(x + radius1, y)
|
213
213
|
|
214
214
|
# Upper right hand corner
|
215
|
-
curve_to [x, y +
|
216
|
-
|
215
|
+
curve_to [x, y + radius2],
|
216
|
+
bounds: [[x + radius1, y + l2], [x + l1, y + radius2]]
|
217
217
|
|
218
218
|
# Upper left hand corner
|
219
|
-
curve_to [x -
|
220
|
-
|
219
|
+
curve_to [x - radius1, y],
|
220
|
+
bounds: [[x - l1, y + radius2], [x - radius1, y + l2]]
|
221
221
|
|
222
222
|
# Lower left hand corner
|
223
|
-
curve_to [x, y -
|
224
|
-
|
223
|
+
curve_to [x, y - radius2],
|
224
|
+
bounds: [[x - radius1, y - l2], [x - l1, y - radius2]]
|
225
225
|
|
226
226
|
# Lower right hand corner
|
227
|
-
curve_to [x +
|
228
|
-
|
227
|
+
curve_to [x + radius1, y],
|
228
|
+
bounds: [[x + l1, y - radius2], [x + radius1, y - l2]]
|
229
229
|
|
230
230
|
move_to(x, y)
|
231
231
|
end
|
@@ -241,35 +241,47 @@ module Prawn
|
|
241
241
|
line_to(*point)
|
242
242
|
end
|
243
243
|
# close the path
|
244
|
-
renderer.add_content
|
244
|
+
renderer.add_content 'h'
|
245
245
|
end
|
246
246
|
|
247
|
-
# 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
|
248
249
|
#
|
249
|
-
#
|
250
|
-
# pdf.fill_and_stroke_rounded_polygon(
|
251
|
-
#
|
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
|
+
# )
|
252
255
|
def rounded_polygon(radius, *points)
|
253
256
|
move_to point_on_line(radius, points[1], points[0])
|
254
257
|
sides = points.size
|
255
258
|
points << points[0] << points[1]
|
256
|
-
|
259
|
+
sides.times do |i|
|
257
260
|
rounded_vertex(radius, points[i], points[i + 1], points[i + 2])
|
258
261
|
end
|
259
262
|
# close the path
|
260
|
-
renderer.add_content
|
263
|
+
renderer.add_content 'h'
|
261
264
|
end
|
262
265
|
|
263
|
-
# Creates a rounded vertex for a line segment used for building a rounded
|
264
|
-
# requires a radius to define bezier curve and three points. The
|
265
|
-
# 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.
|
266
270
|
def rounded_vertex(radius, *points)
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
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])
|
273
285
|
end
|
274
286
|
|
275
287
|
# Strokes the current path. If a block is provided, yields to the block
|
@@ -277,7 +289,7 @@ module Prawn
|
|
277
289
|
#
|
278
290
|
def stroke
|
279
291
|
yield if block_given?
|
280
|
-
renderer.add_content
|
292
|
+
renderer.add_content 'S'
|
281
293
|
end
|
282
294
|
|
283
295
|
# Closes and strokes the current path. If a block is provided, yields to
|
@@ -285,7 +297,7 @@ module Prawn
|
|
285
297
|
#
|
286
298
|
def close_and_stroke
|
287
299
|
yield if block_given?
|
288
|
-
renderer.add_content
|
300
|
+
renderer.add_content 's'
|
289
301
|
end
|
290
302
|
|
291
303
|
# Draws and strokes a rectangle represented by the current bounding box
|
@@ -320,38 +332,56 @@ module Prawn
|
|
320
332
|
#
|
321
333
|
def stroke_axis(options = {})
|
322
334
|
options = {
|
323
|
-
:
|
324
|
-
:
|
325
|
-
:
|
326
|
-
:
|
327
|
-
:
|
328
|
-
:
|
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'
|
329
341
|
}.merge(options)
|
330
342
|
|
331
|
-
Prawn.verify_options(
|
332
|
-
|
343
|
+
Prawn.verify_options(
|
344
|
+
%i[
|
345
|
+
at width height step_length
|
346
|
+
negative_axes_length color
|
347
|
+
], options
|
348
|
+
)
|
333
349
|
|
334
350
|
save_graphics_state do
|
335
351
|
fill_color(options[:color])
|
336
352
|
stroke_color(options[:color])
|
337
353
|
|
338
|
-
dash(1, :
|
339
|
-
stroke_horizontal_line(
|
340
|
-
|
341
|
-
|
342
|
-
|
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
|
+
)
|
343
363
|
undash
|
344
364
|
|
345
365
|
fill_circle(options[:at], 1)
|
346
366
|
|
347
|
-
(options[:step_length]..options[:width])
|
367
|
+
(options[:step_length]..options[:width])
|
368
|
+
.step(options[:step_length]) do |point|
|
348
369
|
fill_circle([options[:at][0] + point, options[:at][1]], 1)
|
349
|
-
draw_text(
|
370
|
+
draw_text(
|
371
|
+
point,
|
372
|
+
at: [options[:at][0] + point - 5, options[:at][1] - 10],
|
373
|
+
size: 7
|
374
|
+
)
|
350
375
|
end
|
351
376
|
|
352
|
-
(options[:step_length]..options[:height])
|
377
|
+
(options[:step_length]..options[:height])
|
378
|
+
.step(options[:step_length]) do |point|
|
353
379
|
fill_circle([options[:at][0], options[:at][1] + point], 1)
|
354
|
-
draw_text(
|
380
|
+
draw_text(
|
381
|
+
point,
|
382
|
+
at: [options[:at][0] - 17, options[:at][1] + point - 2],
|
383
|
+
size: 7
|
384
|
+
)
|
355
385
|
end
|
356
386
|
end
|
357
387
|
end
|
@@ -365,7 +395,7 @@ module Prawn
|
|
365
395
|
#
|
366
396
|
def fill(options = {})
|
367
397
|
yield if block_given?
|
368
|
-
renderer.add_content(options[:fill_rule] == :even_odd ?
|
398
|
+
renderer.add_content(options[:fill_rule] == :even_odd ? 'f*' : 'f')
|
369
399
|
end
|
370
400
|
|
371
401
|
# Closes, fills, and strokes the current path. If a block is provided,
|
@@ -379,13 +409,13 @@ module Prawn
|
|
379
409
|
#
|
380
410
|
def fill_and_stroke(options = {})
|
381
411
|
yield if block_given?
|
382
|
-
renderer.add_content(options[:fill_rule] == :even_odd ?
|
412
|
+
renderer.add_content(options[:fill_rule] == :even_odd ? 'b*' : 'b')
|
383
413
|
end
|
384
414
|
|
385
415
|
# Closes the current path.
|
386
416
|
#
|
387
417
|
def close_path
|
388
|
-
renderer.add_content
|
418
|
+
renderer.add_content 'h'
|
389
419
|
end
|
390
420
|
|
391
421
|
##
|
@@ -594,12 +624,20 @@ module Prawn
|
|
594
624
|
# :call-seq:
|
595
625
|
# fill_and_stroke_rounded_polygon(radius, *points)
|
596
626
|
|
597
|
-
ops
|
598
|
-
shapes = %w
|
599
|
-
|
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
|
+
]
|
600
633
|
|
601
634
|
ops.product(shapes).each do |operation, shape|
|
602
|
-
class_eval
|
635
|
+
class_eval <<-METHOD, __FILE__, __LINE__ + 1
|
636
|
+
def #{operation}_#{shape}(*args)
|
637
|
+
#{shape}(*args)
|
638
|
+
#{operation}
|
639
|
+
end
|
640
|
+
METHOD
|
603
641
|
end
|
604
642
|
|
605
643
|
private
|
@@ -629,8 +667,8 @@ module Prawn
|
|
629
667
|
angle * Math::PI / 180
|
630
668
|
end
|
631
669
|
|
632
|
-
# Returns the coordinates for a point on a line that is a given distance
|
633
|
-
# 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
|
634
672
|
def point_on_line(distance_from_end, *points)
|
635
673
|
x0, y0, x1, y1 = points.flatten
|
636
674
|
length = Math.sqrt((x1 - x0)**2 + (y1 - y0)**2)
|