hexapdf 0.10.0 → 0.11.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 +4 -4
- data/CHANGELOG.md +33 -0
- data/CONTRIBUTERS +1 -1
- data/Rakefile +35 -50
- data/VERSION +1 -1
- data/lib/hexapdf/cli.rb +4 -0
- data/lib/hexapdf/cli/command.rb +6 -2
- data/lib/hexapdf/cli/image2pdf.rb +141 -0
- data/lib/hexapdf/cli/info.rb +1 -1
- data/lib/hexapdf/cli/inspect.rb +32 -2
- data/lib/hexapdf/cli/modify.rb +1 -1
- data/lib/hexapdf/cli/optimize.rb +1 -1
- data/lib/hexapdf/cli/watermark.rb +130 -0
- data/lib/hexapdf/composer.rb +2 -2
- data/lib/hexapdf/configuration.rb +7 -1
- data/lib/hexapdf/content/canvas.rb +2 -2
- data/lib/hexapdf/content/graphic_object/arc.rb +2 -2
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +2 -2
- data/lib/hexapdf/content/graphic_object/geom2d.rb +1 -1
- data/lib/hexapdf/content/graphic_object/solid_arc.rb +1 -1
- data/lib/hexapdf/dictionary.rb +11 -3
- data/lib/hexapdf/dictionary_fields.rb +32 -3
- data/lib/hexapdf/document.rb +7 -3
- data/lib/hexapdf/document/files.rb +1 -1
- data/lib/hexapdf/document/fonts.rb +21 -1
- data/lib/hexapdf/document/pages.rb +2 -2
- data/lib/hexapdf/encryption/standard_security_handler.rb +2 -2
- data/lib/hexapdf/font/cmap/parser.rb +1 -1
- data/lib/hexapdf/font/true_type/table/head.rb +2 -2
- data/lib/hexapdf/font/true_type/table/os2.rb +4 -4
- data/lib/hexapdf/font/true_type_wrapper.rb +16 -16
- data/lib/hexapdf/font/type1_wrapper.rb +16 -16
- data/lib/hexapdf/font_loader.rb +2 -0
- data/lib/hexapdf/font_loader/from_configuration.rb +5 -0
- data/lib/hexapdf/font_loader/standard14.rb +5 -0
- data/lib/hexapdf/image_loader/png.rb +1 -1
- data/lib/hexapdf/layout/box.rb +2 -2
- data/lib/hexapdf/layout/image_box.rb +1 -1
- data/lib/hexapdf/layout/style.rb +50 -24
- data/lib/hexapdf/layout/text_box.rb +1 -1
- data/lib/hexapdf/layout/text_fragment.rb +2 -2
- data/lib/hexapdf/layout/text_layouter.rb +14 -10
- data/lib/hexapdf/name_tree_node.rb +3 -3
- data/lib/hexapdf/number_tree_node.rb +3 -3
- data/lib/hexapdf/pdf_array.rb +207 -0
- data/lib/hexapdf/rectangle.rb +12 -12
- data/lib/hexapdf/serializer.rb +1 -1
- data/lib/hexapdf/stream.rb +6 -4
- data/lib/hexapdf/task/optimize.rb +3 -3
- data/lib/hexapdf/type.rb +2 -0
- data/lib/hexapdf/type/acro_form.rb +51 -0
- data/lib/hexapdf/type/acro_form/field.rb +129 -0
- data/lib/hexapdf/type/acro_form/form.rb +124 -0
- data/lib/hexapdf/type/action.rb +1 -1
- data/lib/hexapdf/type/actions/go_to.rb +1 -1
- data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
- data/lib/hexapdf/type/actions/launch.rb +1 -1
- data/lib/hexapdf/type/annotation.rb +2 -2
- data/lib/hexapdf/type/annotations.rb +1 -0
- data/lib/hexapdf/type/annotations/link.rb +4 -15
- data/lib/hexapdf/type/annotations/markup_annotation.rb +2 -1
- data/lib/hexapdf/type/annotations/text.rb +3 -6
- data/lib/hexapdf/type/annotations/widget.rb +90 -0
- data/lib/hexapdf/type/catalog.rb +12 -9
- data/lib/hexapdf/type/cid_font.rb +3 -3
- data/lib/hexapdf/type/file_specification.rb +2 -2
- data/lib/hexapdf/type/font_descriptor.rb +5 -2
- data/lib/hexapdf/type/font_simple.rb +1 -1
- data/lib/hexapdf/type/font_type0.rb +1 -1
- data/lib/hexapdf/type/font_type3.rb +1 -1
- data/lib/hexapdf/type/form.rb +2 -2
- data/lib/hexapdf/type/graphics_state_parameter.rb +11 -6
- data/lib/hexapdf/type/icon_fit.rb +58 -0
- data/lib/hexapdf/type/image.rb +14 -8
- data/lib/hexapdf/type/info.rb +2 -1
- data/lib/hexapdf/type/page.rb +4 -4
- data/lib/hexapdf/type/page_tree_node.rb +3 -7
- data/lib/hexapdf/type/resources.rb +1 -1
- data/lib/hexapdf/type/trailer.rb +4 -4
- data/lib/hexapdf/type/viewer_preferences.rb +7 -4
- data/lib/hexapdf/type/xref_stream.rb +2 -2
- data/lib/hexapdf/utils/sorted_tree_node.rb +1 -1
- data/lib/hexapdf/version.rb +1 -1
- data/man/man1/hexapdf.1 +77 -8
- data/test/hexapdf/content/test_canvas.rb +2 -2
- data/test/hexapdf/content/test_processor.rb +3 -3
- data/test/hexapdf/document/test_files.rb +4 -4
- data/test/hexapdf/document/test_fonts.rb +13 -1
- data/test/hexapdf/document/test_images.rb +6 -6
- data/test/hexapdf/document/test_pages.rb +8 -8
- data/test/hexapdf/encryption/test_security_handler.rb +7 -7
- data/test/hexapdf/encryption/test_standard_security_handler.rb +5 -5
- data/test/hexapdf/font/test_true_type_wrapper.rb +2 -2
- data/test/hexapdf/font_loader/test_from_configuration.rb +4 -0
- data/test/hexapdf/font_loader/test_standard14.rb +10 -0
- data/test/hexapdf/image_loader/test_jpeg.rb +1 -1
- data/test/hexapdf/image_loader/test_png.rb +3 -3
- data/test/hexapdf/layout/test_box.rb +2 -2
- data/test/hexapdf/layout/test_frame.rb +1 -1
- data/test/hexapdf/layout/test_image_box.rb +1 -1
- data/test/hexapdf/layout/test_style.rb +18 -13
- data/test/hexapdf/layout/test_text_box.rb +1 -1
- data/test/hexapdf/layout/test_text_layouter.rb +11 -6
- data/test/hexapdf/task/test_dereference.rb +2 -2
- data/test/hexapdf/task/test_optimize.rb +11 -11
- data/test/hexapdf/test_composer.rb +1 -1
- data/test/hexapdf/test_dictionary.rb +10 -2
- data/test/hexapdf/test_dictionary_fields.rb +27 -3
- data/test/hexapdf/test_document.rb +16 -15
- data/test/hexapdf/test_importer.rb +4 -4
- data/test/hexapdf/test_object.rb +1 -1
- data/test/hexapdf/test_pdf_array.rb +162 -0
- data/test/hexapdf/test_rectangle.rb +3 -5
- data/test/hexapdf/test_serializer.rb +1 -1
- data/test/hexapdf/test_stream.rb +1 -0
- data/test/hexapdf/test_writer.rb +3 -3
- data/test/hexapdf/type/acro_form/test_field.rb +85 -0
- data/test/hexapdf/type/acro_form/test_form.rb +69 -0
- data/test/hexapdf/type/annotations/test_text.rb +2 -6
- data/test/hexapdf/type/annotations/test_widget.rb +24 -0
- data/test/hexapdf/type/test_annotation.rb +1 -1
- data/test/hexapdf/type/test_catalog.rb +1 -1
- data/test/hexapdf/type/test_cid_font.rb +3 -3
- data/test/hexapdf/type/test_font.rb +2 -2
- data/test/hexapdf/type/test_font_descriptor.rb +2 -1
- data/test/hexapdf/type/test_font_simple.rb +3 -3
- data/test/hexapdf/type/test_font_true_type.rb +6 -6
- data/test/hexapdf/type/test_font_type0.rb +5 -5
- data/test/hexapdf/type/test_font_type1.rb +8 -8
- data/test/hexapdf/type/test_font_type3.rb +4 -4
- data/test/hexapdf/type/test_image.rb +16 -12
- data/test/hexapdf/type/test_page.rb +11 -11
- data/test/hexapdf/type/test_page_tree_node.rb +20 -20
- data/test/hexapdf/type/test_resources.rb +6 -6
- data/test/hexapdf/type/test_trailer.rb +5 -2
- data/test/hexapdf/type/test_xref_stream.rb +1 -0
- data/test/hexapdf/utils/test_sorted_tree_node.rb +35 -35
- metadata +23 -7
- data/test/hexapdf/type/annotations/test_link.rb +0 -19
|
@@ -75,10 +75,10 @@ module HexaPDF
|
|
|
75
75
|
# used to change the orientation to :landscape if needed.
|
|
76
76
|
def add(page = nil, orientation: :portrait)
|
|
77
77
|
if page.kind_of?(Array)
|
|
78
|
-
page = @document.add(Type: :Page, MediaBox: page)
|
|
78
|
+
page = @document.add({Type: :Page, MediaBox: page})
|
|
79
79
|
elsif page.kind_of?(Symbol)
|
|
80
80
|
box = Type::Page.media_box(page, orientation: orientation)
|
|
81
|
-
page = @document.add(Type: :Page, MediaBox: box)
|
|
81
|
+
page = @document.add({Type: :Page, MediaBox: box})
|
|
82
82
|
end
|
|
83
83
|
@document.catalog.pages.add_page(page)
|
|
84
84
|
end
|
|
@@ -275,7 +275,7 @@ module HexaPDF
|
|
|
275
275
|
dict[:StmF] = dict[:StrF] = :StdCF
|
|
276
276
|
end
|
|
277
277
|
|
|
278
|
-
if dict[:R] <= 4 && !document.trailer[:ID].kind_of?(
|
|
278
|
+
if dict[:R] <= 4 && !document.trailer[:ID].kind_of?(PDFArray)
|
|
279
279
|
document.trailer.set_random_id
|
|
280
280
|
end
|
|
281
281
|
|
|
@@ -310,7 +310,7 @@ module HexaPDF
|
|
|
310
310
|
elsif ![2, 3, 4, 6].include?(dict[:R])
|
|
311
311
|
raise(HexaPDF::UnsupportedEncryptionError,
|
|
312
312
|
"Invalid /R value for standard security handler")
|
|
313
|
-
elsif dict[:R] <= 4 && !document.trailer[:ID].kind_of?(
|
|
313
|
+
elsif dict[:R] <= 4 && !document.trailer[:ID].kind_of?(PDFArray)
|
|
314
314
|
raise(HexaPDF::EncryptionError,
|
|
315
315
|
"Document ID for needed for decryption")
|
|
316
316
|
end
|
|
@@ -95,7 +95,7 @@ module HexaPDF
|
|
|
95
95
|
when :Supplement
|
|
96
96
|
cmap.supplement = value if value.kind_of?(Integer)
|
|
97
97
|
when :CMapName
|
|
98
|
-
cmap.name = value.to_s.force_encoding(::Encoding::UTF_8) if value.kind_of?(Symbol)
|
|
98
|
+
cmap.name = value.to_s.dup.force_encoding(::Encoding::UTF_8) if value.kind_of?(Symbol)
|
|
99
99
|
when :WMode
|
|
100
100
|
cmap.wmode = value
|
|
101
101
|
end
|
|
@@ -76,8 +76,8 @@ module HexaPDF
|
|
|
76
76
|
|
|
77
77
|
# Apple Mac style information.
|
|
78
78
|
attr_accessor :mac_style
|
|
79
|
-
bit_field(:mac_style, bold: 0, italic: 1, underline: 2, outline: 3, shadow: 4,
|
|
80
|
-
|
|
79
|
+
bit_field(:mac_style, {bold: 0, italic: 1, underline: 2, outline: 3, shadow: 4,
|
|
80
|
+
condensed: 5, extended: 6})
|
|
81
81
|
|
|
82
82
|
# The smallest readable size in pixels per em for this font.
|
|
83
83
|
attr_accessor :smallest_readable_size
|
|
@@ -65,8 +65,8 @@ module HexaPDF
|
|
|
65
65
|
|
|
66
66
|
# Characteristics and properties of this font.
|
|
67
67
|
attr_accessor :type
|
|
68
|
-
bit_field(:type, restricted_license_embedding: 1, preview_and_print_embedding: 2,
|
|
69
|
-
|
|
68
|
+
bit_field(:type, {restricted_license_embedding: 1, preview_and_print_embedding: 2,
|
|
69
|
+
editable_embedding: 3, no_subsetting: 8, bitmap_embedding_only: 9})
|
|
70
70
|
|
|
71
71
|
# Recommended horizontal size in pixels for subscripts
|
|
72
72
|
attr_accessor :subscript_x_size
|
|
@@ -112,8 +112,8 @@ module HexaPDF
|
|
|
112
112
|
|
|
113
113
|
# Information concerning the nature of the font patterns.
|
|
114
114
|
attr_accessor :selection
|
|
115
|
-
bit_field(:selection, italic: 0, underscore: 1, negative: 2, outlined: 3, strikeout: 4,
|
|
116
|
-
|
|
115
|
+
bit_field(:selection, {italic: 0, underscore: 1, negative: 2, outlined: 3, strikeout: 4,
|
|
116
|
+
bold: 5, regular: 6, use_typo_metrics: 7, wws: 8, oblique: 9})
|
|
117
117
|
|
|
118
118
|
# The minimum Unicode index in this font.
|
|
119
119
|
attr_accessor :first_char_index
|
|
@@ -209,15 +209,15 @@ module HexaPDF
|
|
|
209
209
|
#
|
|
210
210
|
# See: #complete_font_dict
|
|
211
211
|
def build_font_dict
|
|
212
|
-
fd = @document.add(Type: :FontDescriptor,
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
212
|
+
fd = @document.add({Type: :FontDescriptor,
|
|
213
|
+
FontName: @wrapped_font.font_name.intern,
|
|
214
|
+
FontWeight: @wrapped_font.weight,
|
|
215
|
+
Flags: 0,
|
|
216
|
+
FontBBox: @wrapped_font.bounding_box.map {|m| m * scaling_factor },
|
|
217
|
+
ItalicAngle: @wrapped_font.italic_angle || 0,
|
|
218
|
+
Ascent: @wrapped_font.ascender * scaling_factor,
|
|
219
|
+
Descent: @wrapped_font.descender * scaling_factor,
|
|
220
|
+
StemV: @wrapped_font.dominant_vertical_stem_width})
|
|
221
221
|
if @wrapped_font[:'OS/2'].version >= 2
|
|
222
222
|
fd[:CapHeight] = @wrapped_font.cap_height * scaling_factor
|
|
223
223
|
fd[:XHeight] = @wrapped_font.x_height * scaling_factor
|
|
@@ -242,13 +242,13 @@ module HexaPDF
|
|
|
242
242
|
@wrapped_font[:'OS/2'].selection_include?(:oblique)
|
|
243
243
|
fd.flag(:symbolic)
|
|
244
244
|
|
|
245
|
-
cid_font = @document.add(Type: :Font, Subtype: :CIDFontType2,
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
@document.add(Type: :Font, Subtype: :Type0, BaseFont: cid_font[:BaseFont],
|
|
251
|
-
|
|
245
|
+
cid_font = @document.add({Type: :Font, Subtype: :CIDFontType2,
|
|
246
|
+
BaseFont: fd[:FontName], FontDescriptor: fd,
|
|
247
|
+
CIDSystemInfo: {Registry: "Adobe", Ordering: "Identity",
|
|
248
|
+
Supplement: 0},
|
|
249
|
+
CIDToGIDMap: :Identity})
|
|
250
|
+
@document.add({Type: :Font, Subtype: :Type0, BaseFont: cid_font[:BaseFont],
|
|
251
|
+
Encoding: :"Identity-H", DescendantFonts: [cid_font]})
|
|
252
252
|
end
|
|
253
253
|
|
|
254
254
|
# Makes sure that the Type0 font object as well as the CIDFont object contain all the needed
|
|
@@ -146,7 +146,7 @@ module HexaPDF
|
|
|
146
146
|
def glyph(name)
|
|
147
147
|
@name_to_glyph[name] ||=
|
|
148
148
|
begin
|
|
149
|
-
str = Encoding::GlyphList.name_to_unicode(name,
|
|
149
|
+
str = Encoding::GlyphList.name_to_unicode(name, **@zapf_dingbats_opt)
|
|
150
150
|
if @wrapped_font.metrics.character_metrics.key?(name)
|
|
151
151
|
Glyph.new(@wrapped_font, name, str)
|
|
152
152
|
else
|
|
@@ -160,7 +160,7 @@ module HexaPDF
|
|
|
160
160
|
str.codepoints.map! do |c|
|
|
161
161
|
@codepoint_to_glyph[c] ||=
|
|
162
162
|
begin
|
|
163
|
-
name = Encoding::GlyphList.unicode_to_name(+'' << c,
|
|
163
|
+
name = Encoding::GlyphList.unicode_to_name(+'' << c, **@zapf_dingbats_opt)
|
|
164
164
|
name = +"u" << c.to_s(16).rjust(6, '0') if name == :'.notdef'
|
|
165
165
|
glyph(name)
|
|
166
166
|
end
|
|
@@ -194,25 +194,25 @@ module HexaPDF
|
|
|
194
194
|
# Generic in the sense that no information regarding the encoding or widths is included.
|
|
195
195
|
def build_font_dict
|
|
196
196
|
unless defined?(@fd)
|
|
197
|
-
@fd = @document.wrap(Type: :FontDescriptor,
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
197
|
+
@fd = @document.wrap({Type: :FontDescriptor,
|
|
198
|
+
FontName: @wrapped_font.font_name.intern,
|
|
199
|
+
FontWeight: @wrapped_font.weight_class,
|
|
200
|
+
FontBBox: @wrapped_font.bounding_box,
|
|
201
|
+
ItalicAngle: @wrapped_font.italic_angle || 0,
|
|
202
|
+
Ascent: @wrapped_font.ascender || 0,
|
|
203
|
+
Descent: @wrapped_font.descender || 0,
|
|
204
|
+
CapHeight: @wrapped_font.cap_height,
|
|
205
|
+
XHeight: @wrapped_font.x_height,
|
|
206
|
+
StemH: @wrapped_font.dominant_horizontal_stem_width,
|
|
207
|
+
StemV: @wrapped_font.dominant_vertical_stem_width || 0})
|
|
208
208
|
@fd.flag(:fixed_pitch) if @wrapped_font.metrics.is_fixed_pitch
|
|
209
209
|
@fd.flag(@wrapped_font.metrics.character_set == 'Special' ? :symbolic : :nonsymbolic)
|
|
210
210
|
@fd.must_be_indirect = true
|
|
211
211
|
end
|
|
212
212
|
|
|
213
|
-
@document.wrap(Type: :Font, Subtype: :Type1,
|
|
214
|
-
|
|
215
|
-
|
|
213
|
+
@document.wrap({Type: :Font, Subtype: :Type1,
|
|
214
|
+
BaseFont: @wrapped_font.font_name.intern, Encoding: :WinAnsiEncoding,
|
|
215
|
+
FontDescriptor: @fd})
|
|
216
216
|
end
|
|
217
217
|
|
|
218
218
|
# Array of valid encoding names in PDF
|
data/lib/hexapdf/font_loader.rb
CHANGED
|
@@ -60,6 +60,8 @@ module HexaPDF
|
|
|
60
60
|
# variant:: The font variant that should be used (e.g. +:none+, +:bold+, +:italic+,
|
|
61
61
|
# +:bold_italic+).
|
|
62
62
|
#
|
|
63
|
+
# Optionally, a font loader can provide a method +available_fonts(document)+ that returns a hash
|
|
64
|
+
# where the keys are the font names and the values are the variants of all the provided fonts.
|
|
63
65
|
#
|
|
64
66
|
# == Font Wrappers
|
|
65
67
|
#
|
|
@@ -69,6 +69,11 @@ module HexaPDF
|
|
|
69
69
|
FromFile.call(document, file, subset: subset)
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
+
# Returns a hash of the form 'font_name => [variants, ...]' of the configured fonts.
|
|
73
|
+
def self.available_fonts(document)
|
|
74
|
+
document.config['font.map'].transform_values(&:keys)
|
|
75
|
+
end
|
|
76
|
+
|
|
72
77
|
end
|
|
73
78
|
|
|
74
79
|
end
|
|
@@ -95,6 +95,11 @@ module HexaPDF
|
|
|
95
95
|
HexaPDF::Font::Type1Wrapper.new(document, font, custom_encoding: custom_encoding)
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
+
# Returns a hash of the form 'font_name => [variants, ...]' of the standard 14 PDF fonts.
|
|
99
|
+
def self.available_fonts(_document)
|
|
100
|
+
MAPPING.transform_values(&:keys)
|
|
101
|
+
end
|
|
102
|
+
|
|
98
103
|
end
|
|
99
104
|
|
|
100
105
|
end
|
|
@@ -295,7 +295,7 @@ module HexaPDF
|
|
|
295
295
|
Columns: dict[:Width],
|
|
296
296
|
}
|
|
297
297
|
stream_opts = (from_indexed ? {} : {filter: :FlateDecode, decode_parms: decode_parms})
|
|
298
|
-
stream = HexaPDF::StreamData.new(lambda { mask_data }, stream_opts)
|
|
298
|
+
stream = HexaPDF::StreamData.new(lambda { mask_data }, **stream_opts)
|
|
299
299
|
|
|
300
300
|
smask_dict = {
|
|
301
301
|
Type: :XObject,
|
data/lib/hexapdf/layout/box.rb
CHANGED
|
@@ -57,7 +57,7 @@ module HexaPDF
|
|
|
57
57
|
# If +content_box+ is +true+, the width and height are taken to mean the content width and
|
|
58
58
|
# height and the style's padding and border are removed from them appropriately.
|
|
59
59
|
def self.create(width: 0, height: 0, content_box: false, **style, &block)
|
|
60
|
-
style = Style.new(style)
|
|
60
|
+
style = Style.new(**style)
|
|
61
61
|
if content_box
|
|
62
62
|
width += style.padding.left + style.padding.right +
|
|
63
63
|
style.border.width.left + style.border.width.right
|
|
@@ -96,7 +96,7 @@ module HexaPDF
|
|
|
96
96
|
def initialize(width: 0, height: 0, style: Style.new, &block)
|
|
97
97
|
@width = @initial_width = width
|
|
98
98
|
@height = @initial_height = height
|
|
99
|
-
@style = (style.kind_of?(Style) ? style : Style.new(style))
|
|
99
|
+
@style = (style.kind_of?(Style) ? style : Style.new(**style))
|
|
100
100
|
@draw_block = block
|
|
101
101
|
end
|
|
102
102
|
|
|
@@ -56,7 +56,7 @@ module HexaPDF
|
|
|
56
56
|
# Creates a new Image box object for the given +image+ argument which needs to be an image
|
|
57
57
|
# object (e.g. returned by HexaPDF::Document::Images#add).
|
|
58
58
|
def initialize(image, **kwargs)
|
|
59
|
-
super(kwargs, &:unused_draw_block)
|
|
59
|
+
super(**kwargs, &:unused_draw_block)
|
|
60
60
|
@image = image
|
|
61
61
|
end
|
|
62
62
|
|
data/lib/hexapdf/layout/style.rb
CHANGED
|
@@ -523,7 +523,7 @@ module HexaPDF
|
|
|
523
523
|
# Example:
|
|
524
524
|
# Style.new(font_size: 15, align: :center, valign: center)
|
|
525
525
|
def initialize(**properties)
|
|
526
|
-
update(properties)
|
|
526
|
+
update(**properties)
|
|
527
527
|
@scaled_item_widths = {}
|
|
528
528
|
end
|
|
529
529
|
|
|
@@ -624,7 +624,8 @@ module HexaPDF
|
|
|
624
624
|
# text_rendering_mode(mode = nil)
|
|
625
625
|
#
|
|
626
626
|
# The text rendering mode, i.e. whether text should be filled, stroked, clipped, invisible or
|
|
627
|
-
# a combination thereof, defaults to :fill.
|
|
627
|
+
# a combination thereof, defaults to :fill. The returned values is always a normalized text
|
|
628
|
+
# rendering mode value.
|
|
628
629
|
#
|
|
629
630
|
# See: HexaPDF::Content::Canvas#text_rendering_mode
|
|
630
631
|
|
|
@@ -698,7 +699,8 @@ module HexaPDF
|
|
|
698
699
|
# :call-seq:
|
|
699
700
|
# stroke_cap_style(style = nil)
|
|
700
701
|
#
|
|
701
|
-
# The line cap style used for stroking operations (e.g. text outlines), defaults to :butt.
|
|
702
|
+
# The line cap style used for stroking operations (e.g. text outlines), defaults to :butt. The
|
|
703
|
+
# returned values is always a normalized line cap style value.
|
|
702
704
|
#
|
|
703
705
|
# See: HexaPDF::Content::Canvas#line_cap_style
|
|
704
706
|
|
|
@@ -708,6 +710,7 @@ module HexaPDF
|
|
|
708
710
|
# stroke_join_style(style = nil)
|
|
709
711
|
#
|
|
710
712
|
# The line join style used for stroking operations (e.g. text outlines), defaults to :miter.
|
|
713
|
+
# The returned values is always a normalized line joine style value.
|
|
711
714
|
#
|
|
712
715
|
# See: HexaPDF::Content::Canvas#line_join_style
|
|
713
716
|
|
|
@@ -839,6 +842,8 @@ module HexaPDF
|
|
|
839
842
|
# the left/right can still be used. The position hint specifies where the box should
|
|
840
843
|
# float.
|
|
841
844
|
#
|
|
845
|
+
# :flow:: Flows the content of the box inside the frame around objects.
|
|
846
|
+
#
|
|
842
847
|
# :absolute:: Position the box at an absolute position relative to the frame. The coordinates
|
|
843
848
|
# are given via the position hint.
|
|
844
849
|
|
|
@@ -877,41 +882,62 @@ module HexaPDF
|
|
|
877
882
|
[:horizontal_scaling, 100],
|
|
878
883
|
[:text_rise, 0],
|
|
879
884
|
[:font_features, {}],
|
|
880
|
-
[:text_rendering_mode,
|
|
881
|
-
|
|
882
|
-
[:
|
|
883
|
-
|
|
884
|
-
|
|
885
|
+
[:text_rendering_mode, "Content::TextRenderingMode::FILL",
|
|
886
|
+
setter: "Content::TextRenderingMode.normalize(value)"],
|
|
887
|
+
[:subscript, false,
|
|
888
|
+
setter: "value; superscript(false) if superscript",
|
|
889
|
+
valid_values: [true, false]],
|
|
890
|
+
[:superscript, false,
|
|
891
|
+
setter: "value; subscript(false) if subscript",
|
|
892
|
+
valid_values: [true, false]],
|
|
893
|
+
[:underline, false, valid_values: [true, false]],
|
|
894
|
+
[:strikeout, false, valid_values: [true, false]],
|
|
885
895
|
[:fill_color, "default_color"],
|
|
886
896
|
[:fill_alpha, 1],
|
|
887
897
|
[:stroke_color, "default_color"],
|
|
888
898
|
[:stroke_alpha, 1],
|
|
889
899
|
[:stroke_width, 1],
|
|
890
|
-
[:stroke_cap_style,
|
|
891
|
-
|
|
900
|
+
[:stroke_cap_style, "Content::LineCapStyle::BUTT_CAP",
|
|
901
|
+
setter: "Content::LineCapStyle.normalize(value)"],
|
|
902
|
+
[:stroke_join_style, "Content::LineJoinStyle::MITER_JOIN",
|
|
903
|
+
setter: "Content::LineJoinStyle.normalize(value)"],
|
|
892
904
|
[:stroke_miter_limit, 10.0],
|
|
893
905
|
[:stroke_dash_pattern, "Content::LineDashPattern.new",
|
|
894
|
-
"Content::LineDashPattern.normalize(value, phase)", ", phase = 0"],
|
|
895
|
-
[:align, :left],
|
|
896
|
-
[:valign, :top],
|
|
906
|
+
setter: "Content::LineDashPattern.normalize(value, phase)", extra_args: ", phase = 0"],
|
|
907
|
+
[:align, :left, valid_values: [:left, :center, :right, :justify]],
|
|
908
|
+
[:valign, :top, valid_values: [:top, :center, :bottom]],
|
|
897
909
|
[:text_indent, 0],
|
|
898
910
|
[:line_spacing, "LineSpacing.new(type: :single)",
|
|
899
|
-
"LineSpacing.new(value.kind_of?(Symbol) ? {type: value, value: extra_arg} : value)",
|
|
900
|
-
", extra_arg = nil"],
|
|
901
|
-
[:last_line_gap, false],
|
|
911
|
+
setter: "LineSpacing.new(**(value.kind_of?(Symbol) ? {type: value, value: extra_arg} : value))",
|
|
912
|
+
extra_args: ", extra_arg = nil"],
|
|
913
|
+
[:last_line_gap, false, valid_values: [true, false]],
|
|
902
914
|
[:background_color, nil],
|
|
903
|
-
[:padding, "Quad.new(0)", "Quad.new(value)"],
|
|
904
|
-
[:margin, "Quad.new(0)", "Quad.new(value)"],
|
|
905
|
-
[:border, "Border.new", "Border.new(value)"],
|
|
906
|
-
[:overlays, "Layers.new", "Layers.new(value)"],
|
|
907
|
-
[:underlays, "Layers.new", "Layers.new(value)"],
|
|
908
|
-
[:position, :default],
|
|
915
|
+
[:padding, "Quad.new(0)", setter: "Quad.new(value)"],
|
|
916
|
+
[:margin, "Quad.new(0)", setter: "Quad.new(value)"],
|
|
917
|
+
[:border, "Border.new", setter: "Border.new(**value)"],
|
|
918
|
+
[:overlays, "Layers.new", setter: "Layers.new(value)"],
|
|
919
|
+
[:underlays, "Layers.new", setter: "Layers.new(value)"],
|
|
920
|
+
[:position, :default, valid_values: [:default, :float, :flow, :absolute]],
|
|
909
921
|
[:position_hint, nil],
|
|
910
|
-
].each do |name, default,
|
|
922
|
+
].each do |name, default, options = {}|
|
|
911
923
|
default = default.inspect unless default.kind_of?(String)
|
|
924
|
+
setter = options.delete(:setter) || "value"
|
|
925
|
+
extra_args = options.delete(:extra_args) || ""
|
|
926
|
+
valid_values = options.delete(:valid_values)
|
|
927
|
+
raise ArgumentError, "Invalid keywords: #{options.keys.join(', ')}" unless options.empty?
|
|
928
|
+
valid_values_const = "#{name}_valid_values".upcase
|
|
929
|
+
const_set(valid_values_const, valid_values)
|
|
912
930
|
module_eval(<<-EOF, __FILE__, __LINE__ + 1)
|
|
913
931
|
def #{name}(value = UNSET#{extra_args})
|
|
914
|
-
value == UNSET
|
|
932
|
+
if value == UNSET
|
|
933
|
+
@#{name} ||= #{default}
|
|
934
|
+
elsif #{valid_values_const} && !#{valid_values_const}.include?(value)
|
|
935
|
+
raise ArgumentError, "\#{value.inspect} is not a valid #{name} value " \\
|
|
936
|
+
"(\#{#{valid_values_const}.map(&:inspect).join(', ')})"
|
|
937
|
+
else
|
|
938
|
+
@#{name} = #{setter}
|
|
939
|
+
self
|
|
940
|
+
end
|
|
915
941
|
end
|
|
916
942
|
def #{name}?
|
|
917
943
|
defined?(@#{name})
|
|
@@ -48,7 +48,7 @@ module HexaPDF
|
|
|
48
48
|
# Creates a new TextBox object with the given inline items (e.g. TextFragment and InlineBox
|
|
49
49
|
# objects).
|
|
50
50
|
def initialize(items, **kwargs)
|
|
51
|
-
super(kwargs)
|
|
51
|
+
super(**kwargs)
|
|
52
52
|
@tl = TextLayouter.new(style)
|
|
53
53
|
@items = items
|
|
54
54
|
@result = nil
|
|
@@ -65,7 +65,7 @@ module HexaPDF
|
|
|
65
65
|
# the +options+ (in which case a new Style object is created). Regardless of the way, the
|
|
66
66
|
# resulting style object needs at least the font set.
|
|
67
67
|
def self.create(text, style = nil, **options)
|
|
68
|
-
style = (style.nil? ? Style.new(options) : style)
|
|
68
|
+
style = (style.nil? ? Style.new(**options) : style)
|
|
69
69
|
fragment = new(style.font.decode_utf8(text), style)
|
|
70
70
|
TextShaper.new.shape_text(fragment)
|
|
71
71
|
end
|
|
@@ -106,7 +106,7 @@ module HexaPDF
|
|
|
106
106
|
# The argument +style+ can either be a Style object or a hash of style options.
|
|
107
107
|
def initialize(items, style)
|
|
108
108
|
@items = items
|
|
109
|
-
@style = (style.kind_of?(Style) ? style : Style.new(style))
|
|
109
|
+
@style = (style.kind_of?(Style) ? style : Style.new(**style))
|
|
110
110
|
end
|
|
111
111
|
|
|
112
112
|
# The precision used to determine whether two floats represent the same value.
|
|
@@ -173,12 +173,6 @@ module HexaPDF
|
|
|
173
173
|
:penalty
|
|
174
174
|
end
|
|
175
175
|
|
|
176
|
-
# Singleton object describing a Penalty for a mandatory paragraph break.
|
|
177
|
-
MandatoryParagraphBreak = new(PARAGRAPH_BREAK)
|
|
178
|
-
|
|
179
|
-
# Singleton object describing a Penalty for a mandatory line break.
|
|
180
|
-
MandatoryLineBreak = new(LINE_BREAK)
|
|
181
|
-
|
|
182
176
|
# Singleton object describing a Penalty for a prohibited break.
|
|
183
177
|
ProhibitedBreak = new(Penalty::INFINITY)
|
|
184
178
|
|
|
@@ -218,6 +212,7 @@ module HexaPDF
|
|
|
218
212
|
def self.call(items)
|
|
219
213
|
result = []
|
|
220
214
|
glues = {}
|
|
215
|
+
penalties = {}
|
|
221
216
|
items.each do |item|
|
|
222
217
|
if item.kind_of?(InlineBox)
|
|
223
218
|
result << Box.new(item)
|
|
@@ -246,13 +241,20 @@ module HexaPDF
|
|
|
246
241
|
Glue.new(TextFragment.new([glyph].freeze, item.style))
|
|
247
242
|
result << glues[item.style]
|
|
248
243
|
when "\n", "\v", "\f", "\u{85}", "\u{2029}"
|
|
249
|
-
|
|
244
|
+
penalties[item.style] ||=
|
|
245
|
+
Penalty.new(Penalty::PARAGRAPH_BREAK, 0,
|
|
246
|
+
item: TextFragment.new([].freeze, item.style))
|
|
247
|
+
result << penalties[item.style]
|
|
250
248
|
when "\u{2028}"
|
|
251
|
-
result << Penalty::
|
|
249
|
+
result << Penalty.new(Penalty::LINE_BREAK, 0,
|
|
250
|
+
item: TextFragment.new([].freeze, item.style))
|
|
252
251
|
when "\r"
|
|
253
252
|
if !item.items[i + 1] || item.items[i + 1].kind_of?(Numeric) ||
|
|
254
253
|
item.items[i + 1].str != "\n"
|
|
255
|
-
|
|
254
|
+
penalties[item.style] ||=
|
|
255
|
+
Penalty.new(Penalty::PARAGRAPH_BREAK, 0,
|
|
256
|
+
item: TextFragment.new([].freeze, item.style))
|
|
257
|
+
result << penalties[item.style]
|
|
256
258
|
end
|
|
257
259
|
when '-'
|
|
258
260
|
result << Penalty::Standard
|
|
@@ -386,6 +388,7 @@ module HexaPDF
|
|
|
386
388
|
end
|
|
387
389
|
when :penalty
|
|
388
390
|
if item.penalty <= -Penalty::INFINITY
|
|
391
|
+
add_box_item(item.item) if item.item
|
|
389
392
|
break unless yield(create_unjustified_line, item)
|
|
390
393
|
reset_after_line_break(index + 1)
|
|
391
394
|
elsif item.penalty >= Penalty::INFINITY
|
|
@@ -455,6 +458,7 @@ module HexaPDF
|
|
|
455
458
|
end
|
|
456
459
|
when :penalty
|
|
457
460
|
if item.penalty <= -Penalty::INFINITY
|
|
461
|
+
add_box_item(item.item) if item.item
|
|
458
462
|
break unless (action = yield(create_unjustified_line, item))
|
|
459
463
|
reset_after_line_break_variable_width(index + 1, true, action)
|
|
460
464
|
elsif item.penalty >= Penalty::INFINITY
|
|
@@ -646,7 +650,7 @@ module HexaPDF
|
|
|
646
650
|
# The +style+ argument can either be a Style object or a hash of style options. See #style for
|
|
647
651
|
# the properties that are used by the layouter.
|
|
648
652
|
def initialize(style = Style.new)
|
|
649
|
-
@style = (style.kind_of?(Style) ? style : Style.new(style))
|
|
653
|
+
@style = (style.kind_of?(Style) ? style : Style.new(**style))
|
|
650
654
|
end
|
|
651
655
|
|
|
652
656
|
# :call-seq:
|