hexapdf 0.10.0 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|