prawn 1.1.0 → 2.4.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/.yardopts +1 -0
- data/GPLv2 +20 -21
- data/Gemfile +3 -9
- data/Rakefile +9 -40
- data/lib/prawn/document/bounding_box.rb +54 -40
- data/lib/prawn/document/column_box.rb +8 -10
- data/lib/prawn/document/internals.rb +39 -146
- data/lib/prawn/document/span.rb +23 -17
- data/lib/prawn/document.rb +217 -182
- data/lib/prawn/encoding.rb +69 -101
- data/lib/prawn/errors.rb +47 -43
- data/lib/prawn/font.rb +124 -104
- data/lib/prawn/font_metric_cache.rb +23 -21
- data/lib/prawn/fonts/afm.rb +292 -0
- data/lib/prawn/{font → fonts}/dfont.rb +5 -12
- data/lib/prawn/fonts/otf.rb +11 -0
- data/lib/prawn/fonts/ttc.rb +36 -0
- data/lib/prawn/{font → fonts}/ttf.rb +140 -88
- data/lib/prawn/graphics/blend_mode.rb +65 -0
- data/lib/prawn/graphics/cap_style.rb +5 -5
- data/lib/prawn/graphics/color.rb +46 -44
- data/lib/prawn/graphics/dash.rb +27 -11
- data/lib/prawn/graphics/join_style.rb +11 -6
- data/lib/prawn/graphics/patterns.rb +220 -78
- data/lib/prawn/graphics/transformation.rb +20 -12
- data/lib/prawn/graphics/transparency.rb +20 -18
- data/lib/prawn/graphics.rb +153 -115
- data/lib/prawn/grid.rb +93 -50
- data/lib/prawn/image_handler.rb +4 -4
- data/lib/prawn/images/image.rb +3 -2
- data/lib/prawn/images/jpg.rb +31 -24
- data/lib/prawn/images/png.rb +101 -68
- data/lib/prawn/images.rb +64 -56
- data/lib/prawn/measurement_extensions.rb +10 -9
- data/lib/prawn/measurements.rb +20 -23
- data/lib/prawn/outline.rb +96 -75
- data/lib/prawn/repeater.rb +16 -16
- data/lib/prawn/security/arcfour.rb +2 -2
- data/lib/prawn/security.rb +100 -85
- data/lib/prawn/soft_mask.rb +37 -38
- data/lib/prawn/stamp.rb +28 -13
- data/lib/prawn/text/box.rb +24 -29
- data/lib/prawn/text/formatted/arranger.rb +108 -63
- data/lib/prawn/text/formatted/box.rb +187 -124
- data/lib/prawn/text/formatted/fragment.rb +24 -20
- data/lib/prawn/text/formatted/line_wrap.rb +133 -73
- data/lib/prawn/text/formatted/parser.rb +147 -127
- data/lib/prawn/text/formatted/wrap.rb +48 -35
- data/lib/prawn/text/formatted.rb +5 -5
- data/lib/prawn/text.rb +103 -68
- data/lib/prawn/transformation_stack.rb +44 -0
- data/lib/prawn/utilities.rb +10 -22
- data/lib/prawn/version.rb +5 -0
- data/lib/prawn/view.rb +101 -0
- data/lib/prawn.rb +39 -54
- data/manual/basic_concepts/adding_pages.rb +6 -7
- data/manual/basic_concepts/basic_concepts.rb +34 -25
- data/manual/basic_concepts/creation.rb +10 -11
- data/manual/basic_concepts/cursor.rb +4 -5
- data/manual/basic_concepts/measurement.rb +8 -9
- data/manual/basic_concepts/origin.rb +5 -6
- data/manual/basic_concepts/other_cursor_helpers.rb +11 -12
- data/manual/basic_concepts/view.rb +48 -0
- data/manual/bounding_box/bounding_box.rb +30 -28
- data/manual/bounding_box/bounds.rb +12 -13
- data/manual/bounding_box/canvas.rb +7 -8
- data/manual/bounding_box/creation.rb +6 -7
- data/manual/bounding_box/indentation.rb +14 -15
- data/manual/bounding_box/nesting.rb +25 -18
- data/manual/bounding_box/russian_boxes.rb +18 -18
- data/manual/bounding_box/stretchy.rb +12 -14
- data/manual/contents.rb +28 -22
- data/manual/cover.rb +33 -32
- data/manual/document_and_page_options/background.rb +15 -13
- data/manual/document_and_page_options/document_and_page_options.rb +24 -22
- data/manual/document_and_page_options/metadata.rb +20 -18
- data/manual/document_and_page_options/page_margins.rb +18 -20
- data/manual/document_and_page_options/page_size.rb +13 -13
- data/manual/document_and_page_options/print_scaling.rb +18 -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 +5 -6
- data/manual/graphics/fill_rules.rb +12 -11
- data/manual/graphics/gradients.rb +27 -21
- data/manual/graphics/graphics.rb +46 -40
- data/manual/graphics/helper.rb +19 -9
- data/manual/graphics/line_width.rb +8 -7
- data/manual/graphics/lines_and_curves.rb +8 -9
- data/manual/graphics/polygon.rb +6 -8
- data/manual/graphics/rectangle.rb +4 -5
- data/manual/graphics/rotate.rb +6 -9
- data/manual/graphics/scale.rb +14 -13
- data/manual/graphics/soft_masks.rb +4 -6
- data/manual/graphics/stroke_cap.rb +7 -8
- data/manual/graphics/stroke_dash.rb +15 -16
- data/manual/graphics/stroke_join.rb +6 -7
- data/manual/graphics/translate.rb +10 -10
- data/manual/graphics/transparency.rb +7 -9
- data/manual/how_to_read_this_manual.rb +8 -9
- data/manual/images/absolute_position.rb +6 -7
- data/manual/images/fit.rb +7 -8
- data/manual/images/horizontal.rb +10 -11
- data/manual/images/images.rb +28 -27
- data/manual/images/plain_image.rb +5 -6
- data/manual/images/scale.rb +9 -10
- data/manual/images/vertical.rb +16 -14
- data/manual/images/width_and_height.rb +10 -11
- data/manual/layout/boxes.rb +10 -11
- data/manual/layout/content.rb +9 -10
- data/manual/layout/layout.rb +17 -18
- 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 +22 -21
- data/manual/outline/sections_and_pages.rb +17 -18
- data/manual/repeatable_content/alternate_page_numbering.rb +36 -0
- data/manual/repeatable_content/page_numbering.rb +17 -16
- data/manual/repeatable_content/repeatable_content.rb +27 -23
- data/manual/repeatable_content/repeater.rb +15 -16
- data/manual/repeatable_content/stamp.rb +14 -15
- data/manual/security/encryption.rb +8 -11
- data/manual/security/permissions.rb +20 -15
- data/manual/security/security.rb +18 -18
- data/manual/table.rb +16 -0
- data/manual/text/alignment.rb +16 -17
- data/manual/text/color.rb +12 -12
- data/manual/text/column_box.rb +9 -11
- 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 +10 -8
- data/manual/text/formatted_callbacks.rb +33 -23
- data/manual/text/formatted_text.rb +36 -25
- data/manual/text/free_flowing_text.rb +22 -23
- 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 +15 -10
- data/manual/text/positioned_text.rb +16 -17
- data/manual/text/registering_families.rb +27 -24
- data/manual/text/rendering_and_color.rb +9 -10
- data/manual/text/right_to_left_text.rb +30 -19
- data/manual/text/rotation.rb +33 -24
- data/manual/text/single_usage.rb +8 -9
- data/manual/text/text.rb +56 -54
- 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 +24 -17
- data/manual/text/utf8.rb +12 -13
- data/manual/text/win_ansi_charset.rb +28 -25
- data/prawn.gemspec +45 -50
- data/spec/extensions/encoding_helpers.rb +3 -3
- data/spec/prawn/document/bounding_box_spec.rb +550 -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 +44 -0
- data/spec/prawn/document_spec.rb +805 -0
- data/spec/prawn/font_metric_cache_spec.rb +54 -0
- data/spec/prawn/font_spec.rb +544 -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 +872 -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 +229 -0
- data/spec/prawn/measurements_extensions_spec.rb +24 -0
- data/spec/prawn/outline_spec.rb +512 -0
- data/spec/prawn/repeater_spec.rb +166 -0
- data/spec/prawn/soft_mask_spec.rb +74 -0
- data/spec/prawn/stamp_spec.rb +173 -0
- data/spec/prawn/text/box_spec.rb +1110 -0
- data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
- data/spec/prawn/text/formatted/box_spec.rb +849 -0
- data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
- data/spec/prawn/text/formatted/line_wrap_spec.rb +495 -0
- data/spec/prawn/text/formatted/parser_spec.rb +697 -0
- data/spec/prawn/text_draw_text_spec.rb +150 -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 -25
- data.tar.gz.sig +0 -0
- metadata +113 -276
- metadata.gz.sig +0 -0
- data/data/encodings/win_ansi.txt +0 -29
- 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/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/lib/prawn/document/graphics_state.rb +0 -73
- data/lib/prawn/font/afm.rb +0 -247
- data/lib/prawn/table/cell/image.rb +0 -69
- data/lib/prawn/table/cell/in_table.rb +0 -33
- data/lib/prawn/table/cell/span_dummy.rb +0 -93
- data/lib/prawn/table/cell/subtable.rb +0 -66
- data/lib/prawn/table/cell/text.rb +0 -154
- data/lib/prawn/table/cell.rb +0 -772
- data/lib/prawn/table/cells.rb +0 -255
- data/lib/prawn/table/column_width_calculator.rb +0 -182
- data/lib/prawn/table.rb +0 -644
- data/manual/table/basic_block.rb +0 -53
- data/manual/table/before_rendering_page.rb +0 -26
- data/manual/table/cell_border_lines.rb +0 -24
- data/manual/table/cell_borders_and_bg.rb +0 -31
- data/manual/table/cell_dimensions.rb +0 -30
- data/manual/table/cell_text.rb +0 -38
- data/manual/table/column_widths.rb +0 -30
- data/manual/table/content_and_subtables.rb +0 -39
- data/manual/table/creation.rb +0 -27
- data/manual/table/filtering.rb +0 -36
- data/manual/table/flow_and_header.rb +0 -17
- data/manual/table/image_cells.rb +0 -33
- data/manual/table/position.rb +0 -29
- data/manual/table/row_colors.rb +0 -20
- data/manual/table/span.rb +0 -30
- data/manual/table/style.rb +0 -22
- data/manual/table/table.rb +0 -52
- data/manual/table/width.rb +0 -27
- data/spec/acceptance/png.rb +0 -25
- data/spec/annotations_spec.rb +0 -74
- data/spec/bounding_box_spec.rb +0 -510
- data/spec/cell_spec.rb +0 -629
- data/spec/column_box_spec.rb +0 -65
- data/spec/destinations_spec.rb +0 -15
- data/spec/document_spec.rb +0 -730
- data/spec/extensions/mocha.rb +0 -46
- data/spec/font_metric_cache_spec.rb +0 -52
- data/spec/font_spec.rb +0 -449
- data/spec/formatted_text_arranger_spec.rb +0 -421
- data/spec/formatted_text_box_spec.rb +0 -639
- data/spec/formatted_text_fragment_spec.rb +0 -298
- data/spec/graphics_spec.rb +0 -669
- data/spec/grid_spec.rb +0 -96
- data/spec/image_handler_spec.rb +0 -54
- data/spec/images_spec.rb +0 -153
- data/spec/inline_formatted_text_parser_spec.rb +0 -564
- data/spec/jpg_spec.rb +0 -25
- data/spec/line_wrap_spec.rb +0 -344
- data/spec/measurement_units_spec.rb +0 -25
- data/spec/outline_spec.rb +0 -430
- data/spec/png_spec.rb +0 -237
- data/spec/reference_spec.rb +0 -25
- data/spec/repeater_spec.rb +0 -160
- data/spec/security_spec.rb +0 -158
- data/spec/soft_mask_spec.rb +0 -79
- data/spec/span_spec.rb +0 -44
- data/spec/stamp_spec.rb +0 -160
- data/spec/stroke_styles_spec.rb +0 -211
- data/spec/table/span_dummy_spec.rb +0 -17
- data/spec/table_spec.rb +0 -1527
- data/spec/text_at_spec.rb +0 -115
- data/spec/text_box_spec.rb +0 -1034
- data/spec/text_rendering_mode_spec.rb +0 -45
- data/spec/text_spacing_spec.rb +0 -93
- data/spec/text_spec.rb +0 -437
- data/spec/text_with_inline_formatting_spec.rb +0 -35
- data/spec/transparency_spec.rb +0 -91
@@ -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,45 +11,68 @@ require 'ttfunk'
|
|
11
11
|
require 'ttfunk/subset_collection'
|
12
12
|
|
13
13
|
module Prawn
|
14
|
-
|
15
|
-
|
14
|
+
module Fonts
|
16
15
|
# @private
|
17
16
|
class TTF < Font
|
17
|
+
class Error < StandardError
|
18
|
+
DEFAULT_MESSAGE = 'TTF font error'
|
19
|
+
MESSAGE_WITH_FONT = 'TTF font error in font %<font>s'
|
20
|
+
|
21
|
+
def initialize(message = DEFAULT_MESSAGE, font: nil)
|
22
|
+
if font && message == DEFAULT_MESSAGE
|
23
|
+
super format(MESSAGE_WITH_FONT, font: font)
|
24
|
+
else
|
25
|
+
super message
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class NoUnicodeCMap < Error
|
31
|
+
DEFAULT_MESSAGE = 'No unicode cmap found in font'
|
32
|
+
MESSAGE_WITH_FONT = 'No unicode cmap found in font %<font>s'
|
33
|
+
end
|
34
|
+
|
35
|
+
class NoPostscriptName < Error
|
36
|
+
DEFAULT_MESSAGE = 'Can not detect a postscript name'
|
37
|
+
MESSAGE_WITH_FONT = 'Can not detect a postscript name in font %<font>s'
|
38
|
+
end
|
39
|
+
|
18
40
|
attr_reader :ttf, :subsets
|
19
41
|
|
20
42
|
def unicode?
|
21
43
|
true
|
22
44
|
end
|
23
45
|
|
24
|
-
def initialize(document, name, options={})
|
46
|
+
def initialize(document, name, options = {})
|
25
47
|
super
|
26
48
|
|
27
|
-
@ttf
|
28
|
-
@subsets
|
49
|
+
@ttf = read_ttf_file
|
50
|
+
@subsets = TTFunk::SubsetCollection.new(@ttf)
|
51
|
+
@italic_angle = nil
|
29
52
|
|
30
|
-
@attributes
|
31
|
-
@bounding_boxes
|
32
|
-
@char_widths
|
53
|
+
@attributes = {}
|
54
|
+
@bounding_boxes = {}
|
55
|
+
@char_widths = {}
|
33
56
|
@has_kerning_data = @ttf.kerning.exists? && @ttf.kerning.tables.any?
|
34
57
|
|
35
|
-
@ascender
|
36
|
-
@descender
|
37
|
-
@line_gap
|
58
|
+
@ascender = Integer(@ttf.ascent * scale_factor)
|
59
|
+
@descender = Integer(@ttf.descent * scale_factor)
|
60
|
+
@line_gap = Integer(@ttf.line_gap * scale_factor)
|
38
61
|
end
|
39
62
|
|
40
63
|
# NOTE: +string+ must be UTF8-encoded.
|
41
|
-
def compute_width_of(string, options={}) #:nodoc:
|
64
|
+
def compute_width_of(string, options = {}) #:nodoc:
|
42
65
|
scale = (options[:size] || size) / 1000.0
|
43
66
|
if options[:kerning]
|
44
|
-
kern(string).
|
67
|
+
kern(string).reduce(0) do |s, r|
|
45
68
|
if r.is_a?(Numeric)
|
46
69
|
s - r
|
47
70
|
else
|
48
|
-
r.
|
71
|
+
r.reduce(s) { |a, e| a + character_width_by_code(e) }
|
49
72
|
end
|
50
73
|
end * scale
|
51
74
|
else
|
52
|
-
string.codepoints.
|
75
|
+
string.codepoints.reduce(0) do |s, r|
|
53
76
|
s + character_width_by_code(r)
|
54
77
|
end * scale
|
55
78
|
end
|
@@ -62,9 +85,12 @@ module Prawn
|
|
62
85
|
end
|
63
86
|
|
64
87
|
# Returns true if the font has kerning data, false otherwise
|
88
|
+
#
|
89
|
+
# rubocop: disable Naming/PredicateName
|
65
90
|
def has_kerning_data?
|
66
91
|
@has_kerning_data
|
67
92
|
end
|
93
|
+
# rubocop: enable Naming/PredicateName
|
68
94
|
|
69
95
|
# Perform any changes to the string that need to happen
|
70
96
|
# before it is rendered to the canvas. Returns an array of
|
@@ -74,14 +100,16 @@ module Prawn
|
|
74
100
|
#
|
75
101
|
# The +text+ parameter must be UTF8-encoded.
|
76
102
|
#
|
77
|
-
def encode_text(text,options={})
|
103
|
+
def encode_text(text, options = {})
|
78
104
|
text = text.chomp
|
79
105
|
|
80
106
|
if options[:kerning]
|
81
107
|
last_subset = nil
|
82
|
-
kern(text).
|
108
|
+
kern(text).reduce([]) do |result, element|
|
83
109
|
if element.is_a?(Numeric)
|
84
|
-
|
110
|
+
unless result.last[1].is_a?(Array)
|
111
|
+
result.last[1] = [result.last[1]]
|
112
|
+
end
|
85
113
|
result.last[1] << element
|
86
114
|
result
|
87
115
|
else
|
@@ -101,7 +129,7 @@ module Prawn
|
|
101
129
|
end
|
102
130
|
end
|
103
131
|
else
|
104
|
-
@subsets.encode(text.unpack(
|
132
|
+
@subsets.encode(text.unpack('U*'))
|
105
133
|
end
|
106
134
|
end
|
107
135
|
|
@@ -110,26 +138,32 @@ module Prawn
|
|
110
138
|
end
|
111
139
|
|
112
140
|
# not sure how to compute this for true-type fonts...
|
113
|
-
def
|
141
|
+
def stem_v
|
114
142
|
0
|
115
143
|
end
|
116
144
|
|
117
145
|
def italic_angle
|
118
|
-
@italic_angle
|
146
|
+
return @italic_angle if @italic_angle
|
147
|
+
|
148
|
+
if @ttf.postscript.exists?
|
119
149
|
raw = @ttf.postscript.italic_angle
|
120
|
-
hi
|
150
|
+
hi = raw >> 16
|
151
|
+
low = raw & 0xFF
|
121
152
|
hi = -((hi ^ 0xFFFF) + 1) if hi & 0x8000 != 0
|
122
|
-
"#{hi}.#{low}".to_f
|
153
|
+
@italic_angle = "#{hi}.#{low}".to_f
|
123
154
|
else
|
124
|
-
0
|
155
|
+
@italic_angle = 0
|
125
156
|
end
|
157
|
+
|
158
|
+
@italic_angle
|
126
159
|
end
|
127
160
|
|
128
161
|
def cap_height
|
129
|
-
@cap_height ||=
|
130
|
-
|
131
|
-
|
132
|
-
|
162
|
+
@cap_height ||=
|
163
|
+
begin
|
164
|
+
height = @ttf.os2.exists? && @ttf.os2.cap_height || 0
|
165
|
+
height.zero? ? @ascender : height
|
166
|
+
end
|
133
167
|
end
|
134
168
|
|
135
169
|
def x_height
|
@@ -143,7 +177,7 @@ module Prawn
|
|
143
177
|
end
|
144
178
|
|
145
179
|
def serif?
|
146
|
-
@serif ||= [1,2,3,4,5,7].include?(family_class)
|
180
|
+
@serif ||= [1, 2, 3, 4, 5, 7].include?(family_class)
|
147
181
|
end
|
148
182
|
|
149
183
|
def script?
|
@@ -151,31 +185,35 @@ module Prawn
|
|
151
185
|
end
|
152
186
|
|
153
187
|
def pdf_flags
|
154
|
-
@
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
188
|
+
@pdf_flags ||=
|
189
|
+
begin
|
190
|
+
flags = 0
|
191
|
+
flags |= 0x0001 if @ttf.postscript.fixed_pitch?
|
192
|
+
flags |= 0x0002 if serif?
|
193
|
+
flags |= 0x0008 if script?
|
194
|
+
flags |= 0x0040 if italic_angle != 0
|
195
|
+
# Assume the font contains at least some non-latin characters
|
196
|
+
flags | 0x0004
|
197
|
+
end
|
162
198
|
end
|
163
199
|
|
164
200
|
def normalize_encoding(text)
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
201
|
+
text.encode(::Encoding::UTF_8)
|
202
|
+
rescue StandardError => e
|
203
|
+
puts e
|
204
|
+
raise Prawn::Errors::IncompatibleStringEncoding,
|
205
|
+
"Encoding #{text.encoding} can not be transparently converted to UTF-8. " \
|
206
|
+
'Please ensure the encoding of the string you are attempting ' \
|
207
|
+
'to use is set correctly'
|
208
|
+
end
|
209
|
+
|
210
|
+
def to_utf8(text)
|
211
|
+
text.encode('UTF-8')
|
174
212
|
end
|
175
213
|
|
176
214
|
def glyph_present?(char)
|
177
215
|
code = char.codepoints.first
|
178
|
-
cmap[code]
|
216
|
+
cmap[code].positive?
|
179
217
|
end
|
180
218
|
|
181
219
|
# Returns the number of characters in +str+ (a UTF-8-encoded string).
|
@@ -187,7 +225,7 @@ module Prawn
|
|
187
225
|
private
|
188
226
|
|
189
227
|
def cmap
|
190
|
-
@cmap ||= @ttf.cmap.unicode.first
|
228
|
+
(@cmap ||= @ttf.cmap.unicode.first) || raise(NoUnicodeCMap.new(font: name))
|
191
229
|
end
|
192
230
|
|
193
231
|
# +string+ must be UTF8-encoded.
|
@@ -213,12 +251,12 @@ module Prawn
|
|
213
251
|
end
|
214
252
|
|
215
253
|
def kern_pairs_table
|
216
|
-
@
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
254
|
+
@kern_pairs_table ||=
|
255
|
+
if has_kerning_data?
|
256
|
+
@ttf.kerning.tables.first.pairs
|
257
|
+
else
|
258
|
+
{}
|
259
|
+
end
|
222
260
|
end
|
223
261
|
|
224
262
|
def hmtx
|
@@ -236,16 +274,16 @@ module Prawn
|
|
236
274
|
end
|
237
275
|
|
238
276
|
def scale_factor
|
239
|
-
@
|
277
|
+
@scale_factor ||= 1000.0 / @ttf.header.units_per_em
|
240
278
|
end
|
241
279
|
|
242
280
|
def register(subset)
|
243
|
-
temp_name = @ttf.name.postscript_name.
|
244
|
-
ref = @document.ref!(:
|
281
|
+
temp_name = @ttf.name.postscript_name.delete("\0").to_sym
|
282
|
+
ref = @document.ref!(Type: :Font, BaseFont: temp_name)
|
245
283
|
|
246
284
|
# Embed the font metrics in the document after everything has been
|
247
285
|
# drawn, just before the document is emitted.
|
248
|
-
@document.before_render { |
|
286
|
+
@document.renderer.before_render { |_doc| embed(ref, subset) }
|
249
287
|
|
250
288
|
ref
|
251
289
|
end
|
@@ -260,29 +298,32 @@ module Prawn
|
|
260
298
|
|
261
299
|
# empirically, it looks like Adobe Reader will not display fonts
|
262
300
|
# if their font name is more than 33 bytes long. Strange. But true.
|
263
|
-
basename = font.name.postscript_name[0, 33].
|
301
|
+
basename = font.name.postscript_name[0, 33].delete("\0")
|
264
302
|
|
265
|
-
raise
|
303
|
+
raise NoPostscriptName.new(font: font) if basename.nil?
|
266
304
|
|
267
|
-
fontfile = @document.ref!(:
|
305
|
+
fontfile = @document.ref!(Length1: font_content.size)
|
268
306
|
fontfile.stream << font_content
|
269
307
|
fontfile.stream.compress!
|
270
308
|
|
271
|
-
descriptor = @document.ref!(
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
309
|
+
descriptor = @document.ref!(
|
310
|
+
Type: :FontDescriptor,
|
311
|
+
FontName: basename.to_sym,
|
312
|
+
FontFile2: fontfile,
|
313
|
+
FontBBox: bbox,
|
314
|
+
Flags: pdf_flags,
|
315
|
+
StemV: stem_v,
|
316
|
+
ItalicAngle: italic_angle,
|
317
|
+
Ascent: @ascender,
|
318
|
+
Descent: @descender,
|
319
|
+
CapHeight: cap_height,
|
320
|
+
XHeight: x_height
|
321
|
+
)
|
282
322
|
|
283
323
|
hmtx = font.horizontal_metrics
|
284
|
-
widths = font.cmap.tables.first.code_map.map
|
285
|
-
Integer(hmtx.widths[gid] * scale_factor)
|
324
|
+
widths = font.cmap.tables.first.code_map.map do |gid|
|
325
|
+
Integer(hmtx.widths[gid] * scale_factor)
|
326
|
+
end[32..-1]
|
286
327
|
|
287
328
|
# It would be nice to have Encoding set for the macroman subsets,
|
288
329
|
# and only do a ToUnicode cmap for non-encoded unicode subsets.
|
@@ -297,15 +338,24 @@ module Prawn
|
|
297
338
|
map = @subsets[subset].to_unicode_map
|
298
339
|
|
299
340
|
ranges = [[]]
|
300
|
-
map.keys.sort.
|
341
|
+
map.keys.sort.reduce('') do |_s, code|
|
301
342
|
ranges << [] if ranges.last.length >= 100
|
302
343
|
unicode = map[code]
|
303
|
-
ranges.last <<
|
344
|
+
ranges.last << format(
|
345
|
+
'<%<code>02x><%<unicode>04x>',
|
346
|
+
code: code,
|
347
|
+
unicode: unicode
|
348
|
+
)
|
304
349
|
end
|
305
350
|
|
306
|
-
range_blocks =
|
307
|
-
|
308
|
-
|
351
|
+
range_blocks =
|
352
|
+
ranges.reduce(+'') do |s, list|
|
353
|
+
s << format(
|
354
|
+
"%<lenght>d beginbfchar\n%<list>s\nendbfchar\n",
|
355
|
+
lenght: list.length,
|
356
|
+
list: list.join("\n")
|
357
|
+
)
|
358
|
+
end
|
309
359
|
|
310
360
|
to_unicode_cmap = UNICODE_CMAP_TEMPLATE % range_blocks.strip
|
311
361
|
|
@@ -313,16 +363,18 @@ module Prawn
|
|
313
363
|
cmap << to_unicode_cmap
|
314
364
|
cmap.stream.compress!
|
315
365
|
|
316
|
-
reference.data.update(
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
366
|
+
reference.data.update(
|
367
|
+
Subtype: :TrueType,
|
368
|
+
BaseFont: basename.to_sym,
|
369
|
+
FontDescriptor: descriptor,
|
370
|
+
FirstChar: 32,
|
371
|
+
LastChar: 255,
|
372
|
+
Widths: @document.ref!(widths),
|
373
|
+
ToUnicode: cmap
|
374
|
+
)
|
323
375
|
end
|
324
376
|
|
325
|
-
UNICODE_CMAP_TEMPLATE = <<-STR.strip.gsub(/^\s*/,
|
377
|
+
UNICODE_CMAP_TEMPLATE = <<-STR.strip.gsub(/^\s*/, '')
|
326
378
|
/CIDInit /ProcSet findresource begin
|
327
379
|
12 dict begin
|
328
380
|
begincmap
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# blend_mode.rb : Implements blend modes
|
4
|
+
#
|
5
|
+
# Contributed by John Ford. October, 2015
|
6
|
+
#
|
7
|
+
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
|
+
#
|
9
|
+
|
10
|
+
module Prawn
|
11
|
+
module Graphics
|
12
|
+
# The Prawn::BlendMode module is used to change the way
|
13
|
+
# two layers are blended together.
|
14
|
+
#
|
15
|
+
# Passing an array of blend modes is allowed. PDF viewers should
|
16
|
+
# blend layers based on the first recognized blend mode.
|
17
|
+
#
|
18
|
+
# Valid blend modes in v1.4 of the PDF spec include :Normal, :Multiply,
|
19
|
+
# :Screen, :Overlay, :Darken, :Lighten, :ColorDodge, :ColorBurn, :HardLight,
|
20
|
+
# :SoftLight, :Difference, :Exclusion, :Hue, :Saturation, :Color, and
|
21
|
+
# :Luminosity.
|
22
|
+
#
|
23
|
+
# Example:
|
24
|
+
# pdf.fill_color('0000ff')
|
25
|
+
# pdf.fill_rectangle([x, y+25], 50, 50)
|
26
|
+
# pdf.blend_mode(:Multiply) do
|
27
|
+
# pdf.fill_color('ff0000')
|
28
|
+
# pdf.fill_circle([x, y], 25)
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
module BlendMode
|
32
|
+
# @group Stable API
|
33
|
+
|
34
|
+
def blend_mode(blend_mode = :Normal)
|
35
|
+
renderer.min_version(1.4)
|
36
|
+
|
37
|
+
save_graphics_state if block_given?
|
38
|
+
renderer.add_content "/#{blend_mode_dictionary_name(blend_mode)} gs"
|
39
|
+
if block_given?
|
40
|
+
yield
|
41
|
+
restore_graphics_state
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def blend_mode_dictionary_registry
|
48
|
+
@blend_mode_dictionary_registry ||= {}
|
49
|
+
end
|
50
|
+
|
51
|
+
def blend_mode_dictionary_name(blend_mode)
|
52
|
+
key = Array(blend_mode).join('')
|
53
|
+
dictionary_name = "BM#{key}"
|
54
|
+
|
55
|
+
dictionary = blend_mode_dictionary_registry[dictionary_name] ||= ref!(
|
56
|
+
Type: :ExtGState,
|
57
|
+
BM: blend_mode
|
58
|
+
)
|
59
|
+
|
60
|
+
page.ext_gstates[dictionary_name] = dictionary
|
61
|
+
dictionary_name
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# cap_style.rb : Implements stroke cap styling
|
4
4
|
#
|
@@ -11,7 +11,7 @@ module Prawn
|
|
11
11
|
module CapStyle
|
12
12
|
# @group Stable API
|
13
13
|
|
14
|
-
CAP_STYLES = { :
|
14
|
+
CAP_STYLES = { butt: 0, round: 1, projecting_square: 2 }.freeze
|
15
15
|
|
16
16
|
# Sets the cap style for stroked lines and curves
|
17
17
|
#
|
@@ -19,7 +19,7 @@ module Prawn
|
|
19
19
|
#
|
20
20
|
# NOTE: If this method is never called, :butt will be used by default.
|
21
21
|
#
|
22
|
-
def cap_style(style=nil)
|
22
|
+
def cap_style(style = nil)
|
23
23
|
return current_cap_style || :butt if style.nil?
|
24
24
|
|
25
25
|
self.current_cap_style = style
|
@@ -27,7 +27,7 @@ module Prawn
|
|
27
27
|
write_stroke_cap_style
|
28
28
|
end
|
29
29
|
|
30
|
-
|
30
|
+
alias cap_style= cap_style
|
31
31
|
|
32
32
|
private
|
33
33
|
|
@@ -40,7 +40,7 @@ module Prawn
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def write_stroke_cap_style
|
43
|
-
add_content "#{CAP_STYLES[current_cap_style]} J"
|
43
|
+
renderer.add_content "#{CAP_STYLES[current_cap_style]} J"
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
data/lib/prawn/graphics/color.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# color.rb : Implements color handling
|
4
4
|
#
|
@@ -27,11 +27,12 @@ module Prawn
|
|
27
27
|
#
|
28
28
|
def fill_color(*color)
|
29
29
|
return current_fill_color if color.empty?
|
30
|
+
|
30
31
|
self.current_fill_color = process_color(*color)
|
31
32
|
set_fill_color
|
32
33
|
end
|
33
34
|
|
34
|
-
|
35
|
+
alias fill_color= fill_color
|
35
36
|
|
36
37
|
# Sets or returns the line stroking color.
|
37
38
|
#
|
@@ -49,12 +50,13 @@ module Prawn
|
|
49
50
|
#
|
50
51
|
def stroke_color(*color)
|
51
52
|
return current_stroke_color if color.empty?
|
53
|
+
|
52
54
|
color = process_color(*color)
|
53
55
|
self.current_stroke_color = color
|
54
56
|
set_stroke_color(color)
|
55
57
|
end
|
56
58
|
|
57
|
-
|
59
|
+
alias stroke_color= stroke_color
|
58
60
|
|
59
61
|
module_function
|
60
62
|
|
@@ -65,7 +67,7 @@ module Prawn
|
|
65
67
|
# => "ff7808"
|
66
68
|
#
|
67
69
|
def rgb2hex(rgb)
|
68
|
-
rgb.map { |e|
|
70
|
+
rgb.map { |e| format '%<value>02x', value: e }.join
|
69
71
|
end
|
70
72
|
|
71
73
|
# Converts hex string into RGB value array:
|
@@ -74,14 +76,16 @@ module Prawn
|
|
74
76
|
# => [255, 120, 8]
|
75
77
|
#
|
76
78
|
def hex2rgb(hex)
|
77
|
-
r
|
78
|
-
|
79
|
+
r = hex[0..1]
|
80
|
+
g = hex[2..3]
|
81
|
+
b = hex[4..5]
|
82
|
+
[r, g, b].map { |e| e.to_i(16) }
|
79
83
|
end
|
80
84
|
|
81
85
|
private
|
82
86
|
|
83
87
|
def process_color(*color)
|
84
|
-
case
|
88
|
+
case color.size
|
85
89
|
when 1
|
86
90
|
color[0]
|
87
91
|
when 4
|
@@ -94,7 +98,11 @@ module Prawn
|
|
94
98
|
def color_type(color)
|
95
99
|
case color
|
96
100
|
when String
|
97
|
-
|
101
|
+
if /\A\h{6}\z/.match?(color)
|
102
|
+
:RGB
|
103
|
+
else
|
104
|
+
raise ArgumentError, "Unknown type of color: #{color.inspect}"
|
105
|
+
end
|
98
106
|
when Array
|
99
107
|
case color.length
|
100
108
|
when 3
|
@@ -110,16 +118,16 @@ module Prawn
|
|
110
118
|
def normalize_color(color)
|
111
119
|
case color_type(color)
|
112
120
|
when :RGB
|
113
|
-
r,g,b = hex2rgb(color)
|
121
|
+
r, g, b = hex2rgb(color)
|
114
122
|
[r / 255.0, g / 255.0, b / 255.0]
|
115
123
|
when :CMYK
|
116
|
-
c,m,y,k = *color
|
124
|
+
c, m, y, k = *color
|
117
125
|
[c / 100.0, m / 100.0, y / 100.0, k / 100.0]
|
118
126
|
end
|
119
127
|
end
|
120
128
|
|
121
129
|
def color_to_s(color)
|
122
|
-
normalize_color(color)
|
130
|
+
PDF::Core.real_params normalize_color(color)
|
123
131
|
end
|
124
132
|
|
125
133
|
def color_space(color)
|
@@ -131,42 +139,48 @@ module Prawn
|
|
131
139
|
end
|
132
140
|
end
|
133
141
|
|
134
|
-
COLOR_SPACES = [
|
142
|
+
COLOR_SPACES = %i[DeviceRGB DeviceCMYK Pattern].freeze
|
135
143
|
|
136
144
|
def set_color_space(type, color_space)
|
137
145
|
# don't set the same color space again
|
138
|
-
|
146
|
+
if current_color_space(type) == color_space &&
|
147
|
+
!state.page.in_stamp_stream?
|
148
|
+
return
|
149
|
+
end
|
150
|
+
|
139
151
|
set_current_color_space(color_space, type)
|
140
152
|
|
141
153
|
unless COLOR_SPACES.include?(color_space)
|
142
154
|
raise ArgumentError, "unknown color space: '#{color_space}'"
|
143
155
|
end
|
144
156
|
|
145
|
-
operator =
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
157
|
+
operator =
|
158
|
+
case type
|
159
|
+
when :fill
|
160
|
+
'cs'
|
161
|
+
when :stroke
|
162
|
+
'CS'
|
163
|
+
else
|
164
|
+
raise ArgumentError, "unknown type '#{type}'"
|
165
|
+
end
|
153
166
|
|
154
|
-
add_content "/#{color_space} #{operator}"
|
167
|
+
renderer.add_content "/#{color_space} #{operator}"
|
155
168
|
end
|
156
169
|
|
157
170
|
def set_color(type, color, options = {})
|
158
|
-
operator =
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
171
|
+
operator =
|
172
|
+
case type
|
173
|
+
when :fill
|
174
|
+
'scn'
|
175
|
+
when :stroke
|
176
|
+
'SCN'
|
177
|
+
else
|
178
|
+
raise ArgumentError, "unknown type '#{type}'"
|
179
|
+
end
|
166
180
|
|
167
181
|
if options[:pattern]
|
168
182
|
set_color_space type, :Pattern
|
169
|
-
add_content "/#{color} #{operator}"
|
183
|
+
renderer.add_content "/#{color} #{operator}"
|
170
184
|
else
|
171
185
|
set_color_space type, color_space(color)
|
172
186
|
color = color_to_s(color)
|
@@ -187,8 +201,6 @@ module Prawn
|
|
187
201
|
set_stroke_color
|
188
202
|
end
|
189
203
|
|
190
|
-
private
|
191
|
-
|
192
204
|
def current_color_space(type)
|
193
205
|
graphic_state.color_space[type]
|
194
206
|
end
|
@@ -214,19 +226,9 @@ module Prawn
|
|
214
226
|
graphic_state.stroke_color = color
|
215
227
|
end
|
216
228
|
|
217
|
-
def write_fill_color
|
218
|
-
write_color(current_fill_color, 'scn')
|
219
|
-
end
|
220
|
-
|
221
|
-
def write_stroke_color
|
222
|
-
write_color(current_fill_color, 'SCN')
|
223
|
-
end
|
224
|
-
|
225
229
|
def write_color(color, operator)
|
226
|
-
add_content "#{color} #{operator}"
|
230
|
+
renderer.add_content "#{color} #{operator}"
|
227
231
|
end
|
228
|
-
|
229
232
|
end
|
230
233
|
end
|
231
234
|
end
|
232
|
-
|