hexapdf 0.32.2 → 0.34.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 +104 -1
- data/README.md +9 -0
- data/examples/002-graphics.rb +15 -17
- data/examples/003-arcs.rb +9 -9
- data/examples/009-text_layouter_alignment.rb +1 -1
- data/examples/010-text_layouter_inline_boxes.rb +2 -2
- data/examples/011-text_layouter_line_wrapping.rb +1 -1
- data/examples/012-text_layouter_styling.rb +7 -7
- data/examples/013-text_layouter_shapes.rb +1 -1
- data/examples/014-text_in_polygon.rb +1 -1
- data/examples/015-boxes.rb +8 -7
- data/examples/016-frame_automatic_box_placement.rb +2 -2
- data/examples/017-frame_text_flow.rb +2 -1
- data/examples/018-composer.rb +1 -1
- data/examples/020-column_box.rb +2 -1
- data/examples/025-table_box.rb +46 -0
- data/examples/026-optional_content.rb +55 -0
- data/examples/027-composer_optional_content.rb +83 -0
- data/lib/hexapdf/cli/command.rb +12 -3
- data/lib/hexapdf/cli/fonts.rb +1 -1
- data/lib/hexapdf/cli/form.rb +5 -5
- data/lib/hexapdf/cli/inspect.rb +5 -7
- data/lib/hexapdf/composer.rb +106 -53
- data/lib/hexapdf/configuration.rb +65 -40
- data/lib/hexapdf/content/canvas.rb +445 -267
- data/lib/hexapdf/content/color_space.rb +72 -25
- data/lib/hexapdf/content/graphic_object/arc.rb +57 -24
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -23
- data/lib/hexapdf/content/graphic_object/geom2d.rb +47 -6
- data/lib/hexapdf/content/graphic_object/solid_arc.rb +58 -36
- data/lib/hexapdf/content/graphic_object.rb +6 -7
- data/lib/hexapdf/content/graphics_state.rb +54 -45
- data/lib/hexapdf/content/operator.rb +54 -54
- data/lib/hexapdf/content/parser.rb +2 -2
- data/lib/hexapdf/content/processor.rb +15 -15
- data/lib/hexapdf/content/transformation_matrix.rb +1 -1
- data/lib/hexapdf/content.rb +5 -0
- data/lib/hexapdf/dictionary.rb +7 -5
- data/lib/hexapdf/dictionary_fields.rb +43 -16
- data/lib/hexapdf/digital_signature/cms_handler.rb +2 -2
- data/lib/hexapdf/digital_signature/handler.rb +1 -1
- data/lib/hexapdf/digital_signature/pkcs1_handler.rb +2 -3
- data/lib/hexapdf/digital_signature/signature.rb +6 -6
- data/lib/hexapdf/digital_signature/signatures.rb +13 -12
- data/lib/hexapdf/digital_signature/signing/default_handler.rb +14 -5
- data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +2 -4
- data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +4 -4
- data/lib/hexapdf/digital_signature/signing.rb +4 -0
- data/lib/hexapdf/digital_signature/verification_result.rb +3 -4
- data/lib/hexapdf/digital_signature.rb +7 -2
- data/lib/hexapdf/document/destinations.rb +12 -11
- data/lib/hexapdf/document/files.rb +1 -1
- data/lib/hexapdf/document/fonts.rb +1 -1
- data/lib/hexapdf/document/layout.rb +170 -39
- data/lib/hexapdf/document/pages.rb +4 -3
- data/lib/hexapdf/document.rb +96 -55
- data/lib/hexapdf/encryption/aes.rb +5 -5
- data/lib/hexapdf/encryption/arc4.rb +1 -1
- data/lib/hexapdf/encryption/fast_aes.rb +2 -2
- data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
- data/lib/hexapdf/encryption/identity.rb +1 -1
- data/lib/hexapdf/encryption/ruby_aes.rb +11 -21
- data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
- data/lib/hexapdf/encryption/security_handler.rb +31 -24
- data/lib/hexapdf/encryption/standard_security_handler.rb +45 -36
- data/lib/hexapdf/encryption.rb +7 -2
- data/lib/hexapdf/error.rb +18 -0
- data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
- data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
- data/lib/hexapdf/filter/flate_decode.rb +1 -1
- data/lib/hexapdf/filter/lzw_decode.rb +1 -1
- data/lib/hexapdf/filter/pass_through.rb +1 -1
- data/lib/hexapdf/filter/predictor.rb +1 -1
- data/lib/hexapdf/filter/run_length_decode.rb +1 -1
- data/lib/hexapdf/filter.rb +55 -6
- data/lib/hexapdf/font/cmap/parser.rb +2 -2
- data/lib/hexapdf/font/cmap.rb +1 -1
- data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +2 -2
- data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +3 -3
- data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
- data/lib/hexapdf/font/invalid_glyph.rb +3 -0
- data/lib/hexapdf/font/true_type_wrapper.rb +17 -4
- data/lib/hexapdf/font/type1_wrapper.rb +19 -4
- data/lib/hexapdf/font_loader/from_configuration.rb +5 -2
- data/lib/hexapdf/font_loader/from_file.rb +5 -5
- data/lib/hexapdf/font_loader/standard14.rb +3 -3
- data/lib/hexapdf/font_loader.rb +3 -0
- data/lib/hexapdf/image_loader/jpeg.rb +2 -2
- data/lib/hexapdf/image_loader/pdf.rb +1 -1
- data/lib/hexapdf/image_loader/png.rb +2 -2
- data/lib/hexapdf/image_loader.rb +1 -1
- data/lib/hexapdf/importer.rb +13 -0
- data/lib/hexapdf/layout/box.rb +32 -5
- data/lib/hexapdf/layout/box_fitter.rb +2 -2
- data/lib/hexapdf/layout/column_box.rb +20 -5
- data/lib/hexapdf/layout/frame.rb +53 -18
- data/lib/hexapdf/layout/image_box.rb +5 -0
- data/lib/hexapdf/layout/inline_box.rb +21 -9
- data/lib/hexapdf/layout/list_box.rb +50 -20
- data/lib/hexapdf/layout/page_style.rb +6 -5
- data/lib/hexapdf/layout/style.rb +64 -9
- data/lib/hexapdf/layout/table_box.rb +684 -0
- data/lib/hexapdf/layout/text_box.rb +12 -3
- data/lib/hexapdf/layout/text_fragment.rb +29 -3
- data/lib/hexapdf/layout/text_layouter.rb +32 -8
- data/lib/hexapdf/layout.rb +1 -0
- data/lib/hexapdf/name_tree_node.rb +1 -1
- data/lib/hexapdf/number_tree_node.rb +1 -1
- data/lib/hexapdf/object.rb +18 -7
- data/lib/hexapdf/parser.rb +7 -7
- data/lib/hexapdf/pdf_array.rb +1 -1
- data/lib/hexapdf/rectangle.rb +1 -1
- data/lib/hexapdf/reference.rb +1 -1
- data/lib/hexapdf/revision.rb +1 -1
- data/lib/hexapdf/revisions.rb +3 -3
- data/lib/hexapdf/serializer.rb +15 -15
- data/lib/hexapdf/stream.rb +5 -4
- data/lib/hexapdf/tokenizer.rb +14 -14
- data/lib/hexapdf/type/acro_form/appearance_generator.rb +22 -22
- data/lib/hexapdf/type/acro_form/button_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/field.rb +2 -2
- data/lib/hexapdf/type/acro_form/form.rb +1 -1
- data/lib/hexapdf/type/acro_form/signature_field.rb +4 -4
- data/lib/hexapdf/type/acro_form/text_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/variable_text_field.rb +1 -1
- data/lib/hexapdf/type/acro_form.rb +1 -1
- 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/actions/set_ocg_state.rb +86 -0
- data/lib/hexapdf/type/actions/uri.rb +1 -1
- data/lib/hexapdf/type/actions.rb +2 -1
- data/lib/hexapdf/type/annotation.rb +3 -3
- data/lib/hexapdf/type/annotations/link.rb +1 -1
- data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
- data/lib/hexapdf/type/annotations/text.rb +2 -3
- data/lib/hexapdf/type/annotations/widget.rb +2 -2
- data/lib/hexapdf/type/annotations.rb +1 -1
- data/lib/hexapdf/type/catalog.rb +11 -2
- data/lib/hexapdf/type/cid_font.rb +18 -4
- data/lib/hexapdf/type/embedded_file.rb +1 -1
- data/lib/hexapdf/type/file_specification.rb +2 -2
- data/lib/hexapdf/type/font_descriptor.rb +1 -1
- data/lib/hexapdf/type/font_simple.rb +2 -2
- data/lib/hexapdf/type/font_type0.rb +3 -3
- data/lib/hexapdf/type/font_type3.rb +1 -1
- data/lib/hexapdf/type/form.rb +76 -6
- data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
- data/lib/hexapdf/type/icon_fit.rb +1 -1
- data/lib/hexapdf/type/image.rb +1 -1
- data/lib/hexapdf/type/info.rb +1 -1
- data/lib/hexapdf/type/mark_information.rb +1 -1
- data/lib/hexapdf/type/names.rb +2 -2
- data/lib/hexapdf/type/object_stream.rb +2 -1
- data/lib/hexapdf/type/optional_content_configuration.rb +170 -0
- data/lib/hexapdf/type/optional_content_group.rb +370 -0
- data/lib/hexapdf/type/optional_content_membership.rb +63 -0
- data/lib/hexapdf/type/optional_content_properties.rb +158 -0
- data/lib/hexapdf/type/outline.rb +1 -1
- data/lib/hexapdf/type/outline_item.rb +1 -1
- data/lib/hexapdf/type/page.rb +46 -21
- data/lib/hexapdf/type/page_label.rb +5 -9
- data/lib/hexapdf/type/page_tree_node.rb +1 -1
- data/lib/hexapdf/type/resources.rb +1 -1
- data/lib/hexapdf/type/trailer.rb +2 -2
- data/lib/hexapdf/type/viewer_preferences.rb +1 -1
- data/lib/hexapdf/type/xref_stream.rb +2 -2
- data/lib/hexapdf/type.rb +4 -0
- data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -2
- data/lib/hexapdf/version.rb +1 -1
- data/lib/hexapdf/writer.rb +4 -4
- data/lib/hexapdf/xref_section.rb +2 -2
- data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +11 -1
- data/test/hexapdf/content/graphic_object/test_geom2d.rb +7 -0
- data/test/hexapdf/content/test_canvas.rb +49 -1
- data/test/hexapdf/digital_signature/test_signatures.rb +22 -0
- data/test/hexapdf/document/test_files.rb +2 -2
- data/test/hexapdf/document/test_layout.rb +105 -2
- data/test/hexapdf/document/test_pages.rb +6 -6
- data/test/hexapdf/encryption/test_security_handler.rb +12 -11
- data/test/hexapdf/encryption/test_standard_security_handler.rb +35 -23
- data/test/hexapdf/font/test_true_type_wrapper.rb +18 -1
- data/test/hexapdf/font/test_type1_wrapper.rb +15 -1
- data/test/hexapdf/layout/test_box.rb +14 -5
- data/test/hexapdf/layout/test_column_box.rb +65 -21
- data/test/hexapdf/layout/test_frame.rb +27 -15
- data/test/hexapdf/layout/test_image_box.rb +4 -0
- data/test/hexapdf/layout/test_inline_box.rb +17 -3
- data/test/hexapdf/layout/test_list_box.rb +84 -33
- data/test/hexapdf/layout/test_page_style.rb +3 -2
- data/test/hexapdf/layout/test_style.rb +60 -0
- data/test/hexapdf/layout/test_table_box.rb +728 -0
- data/test/hexapdf/layout/test_text_box.rb +26 -0
- data/test/hexapdf/layout/test_text_fragment.rb +33 -0
- data/test/hexapdf/layout/test_text_layouter.rb +36 -5
- data/test/hexapdf/test_composer.rb +10 -0
- data/test/hexapdf/test_dictionary.rb +10 -0
- data/test/hexapdf/test_dictionary_fields.rb +4 -1
- data/test/hexapdf/test_document.rb +5 -0
- data/test/hexapdf/test_filter.rb +8 -0
- data/test/hexapdf/test_importer.rb +9 -0
- data/test/hexapdf/test_object.rb +16 -5
- data/test/hexapdf/test_stream.rb +7 -0
- data/test/hexapdf/test_writer.rb +3 -3
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +13 -5
- data/test/hexapdf/type/acro_form/test_form.rb +4 -3
- data/test/hexapdf/type/actions/test_set_ocg_state.rb +40 -0
- data/test/hexapdf/type/test_catalog.rb +11 -0
- data/test/hexapdf/type/test_form.rb +119 -0
- data/test/hexapdf/type/test_optional_content_configuration.rb +112 -0
- data/test/hexapdf/type/test_optional_content_group.rb +158 -0
- data/test/hexapdf/type/test_optional_content_properties.rb +109 -0
- data/test/hexapdf/type/test_page.rb +20 -6
- metadata +28 -8
|
@@ -42,7 +42,7 @@ module HexaPDF
|
|
|
42
42
|
|
|
43
43
|
# The Mac Roman standard encoding for Latin texts.
|
|
44
44
|
#
|
|
45
|
-
# See:
|
|
45
|
+
# See: PDF2.0 sD.1, sD.2
|
|
46
46
|
class MacRomanEncoding < Base
|
|
47
47
|
|
|
48
48
|
def initialize #:nodoc:
|
|
@@ -256,7 +256,7 @@ module HexaPDF
|
|
|
256
256
|
0264 => :yen,
|
|
257
257
|
0172 => :z,
|
|
258
258
|
0060 => :zero,
|
|
259
|
-
# additions due to
|
|
259
|
+
# additions due to PDF2.0 sD.2 footnote 6
|
|
260
260
|
0312 => :space,
|
|
261
261
|
}
|
|
262
262
|
end
|
|
@@ -42,7 +42,7 @@ module HexaPDF
|
|
|
42
42
|
|
|
43
43
|
# The Windows Code Page 1252, the standard Windows encoding for Latin texts.
|
|
44
44
|
#
|
|
45
|
-
# See:
|
|
45
|
+
# See: PDF2.0 sD.1, sD.2
|
|
46
46
|
class WinAnsiEncoding < Base
|
|
47
47
|
|
|
48
48
|
def initialize #:nodoc:
|
|
@@ -265,11 +265,11 @@ module HexaPDF
|
|
|
265
265
|
0172 => :z,
|
|
266
266
|
0236 => :zcaron,
|
|
267
267
|
0060 => :zero,
|
|
268
|
-
# additions due to
|
|
268
|
+
# additions due to PDF2.0 sD.2 footnote 5,6
|
|
269
269
|
0240 => :space,
|
|
270
270
|
0255 => :hyphen,
|
|
271
271
|
}
|
|
272
|
-
# additions due to
|
|
272
|
+
# additions due to PDF2.0 sD.2 footnote 3
|
|
273
273
|
041.upto(255) do |i|
|
|
274
274
|
next if @code_to_name.key?(i)
|
|
275
275
|
@code_to_name[i] = :bullet
|
|
@@ -51,7 +51,7 @@ module HexaPDF
|
|
|
51
51
|
#
|
|
52
52
|
# * By using a composite font more than 256 characters can be encoded with one font object.
|
|
53
53
|
# * Fonts for vertical writing can potentially be used.
|
|
54
|
-
# * The PDF specification recommends using a composite font (see
|
|
54
|
+
# * The PDF specification recommends using a composite font (see PDF2.0 s9.9.1 at the end).
|
|
55
55
|
#
|
|
56
56
|
# Additionally, TrueType fonts are *always* embedded.
|
|
57
57
|
class TrueTypeWrapper
|
|
@@ -59,6 +59,9 @@ module HexaPDF
|
|
|
59
59
|
# Represents a single glyph of the wrapped font.
|
|
60
60
|
class Glyph
|
|
61
61
|
|
|
62
|
+
# The associated font object.
|
|
63
|
+
attr_reader :font
|
|
64
|
+
|
|
62
65
|
# The glyph ID.
|
|
63
66
|
attr_reader :id
|
|
64
67
|
|
|
@@ -171,6 +174,18 @@ module HexaPDF
|
|
|
171
174
|
end
|
|
172
175
|
end
|
|
173
176
|
|
|
177
|
+
# Returns a custom Glyph object which represents the given +string+ via the given glyph +id+.
|
|
178
|
+
#
|
|
179
|
+
# This functionality can be used to associate a single glyph id with multiple, different
|
|
180
|
+
# strings for replacement glyph purposes. When used in such a way, the used glyph id is often
|
|
181
|
+
# 0 which represents the missing glyph.
|
|
182
|
+
def custom_glyph(id, string)
|
|
183
|
+
if id < 0 || id >= @wrapped_font[:maxp].num_glyphs
|
|
184
|
+
raise HexaPDF::Error, "Glyph ID #{id} is invalid for font '#{@wrapped_font.full_name}'"
|
|
185
|
+
end
|
|
186
|
+
Glyph.new(@wrapped_font, id, string)
|
|
187
|
+
end
|
|
188
|
+
|
|
174
189
|
# Returns an array of glyph objects representing the characters in the UTF-8 encoded string.
|
|
175
190
|
def decode_utf8(str)
|
|
176
191
|
str.codepoints.map! do |c|
|
|
@@ -187,9 +202,7 @@ module HexaPDF
|
|
|
187
202
|
def encode(glyph)
|
|
188
203
|
(@encoded_glyphs[glyph.id] ||=
|
|
189
204
|
begin
|
|
190
|
-
if glyph.kind_of?(InvalidGlyph)
|
|
191
|
-
raise HexaPDF::Error, "Glyph for #{glyph.str.inspect} missing"
|
|
192
|
-
end
|
|
205
|
+
raise HexaPDF::MissingGlyphError.new(glyph) if glyph.kind_of?(InvalidGlyph)
|
|
193
206
|
if @subsetter
|
|
194
207
|
[[@subsetter.use_glyph(glyph.id)].pack('n'), glyph]
|
|
195
208
|
else
|
|
@@ -48,6 +48,9 @@ module HexaPDF
|
|
|
48
48
|
# Represents a single glyph of the wrapped font.
|
|
49
49
|
class Glyph
|
|
50
50
|
|
|
51
|
+
# The associated font object.
|
|
52
|
+
attr_reader :font
|
|
53
|
+
|
|
51
54
|
# The name of the glyph.
|
|
52
55
|
attr_reader :name
|
|
53
56
|
alias id name
|
|
@@ -164,6 +167,20 @@ module HexaPDF
|
|
|
164
167
|
end
|
|
165
168
|
end
|
|
166
169
|
|
|
170
|
+
# Returns a custom Glyph object which represents the given +string+ via the given glyph
|
|
171
|
+
# +name+.
|
|
172
|
+
#
|
|
173
|
+
# This functionality can be used to associate a single glyph name with multiple, different
|
|
174
|
+
# strings for replacement glyph purposes. When used in such a way, the used glyph name is
|
|
175
|
+
# often :question.
|
|
176
|
+
def custom_glyph(name, string)
|
|
177
|
+
unless @wrapped_font.metrics.character_metrics.key?(name)
|
|
178
|
+
raise HexaPDF::Error, "Glyph named #{name.inspect} not found in " \
|
|
179
|
+
"font '#{@wrapped_font.full_name}'"
|
|
180
|
+
end
|
|
181
|
+
Glyph.new(@wrapped_font, name, string)
|
|
182
|
+
end
|
|
183
|
+
|
|
167
184
|
# Returns an array of glyph objects representing the characters in the UTF-8 encoded string.
|
|
168
185
|
#
|
|
169
186
|
# If a Unicode codepoint is not available as glyph object, it is tried to map the codepoint
|
|
@@ -188,9 +205,7 @@ module HexaPDF
|
|
|
188
205
|
def encode(glyph)
|
|
189
206
|
@encoded_glyphs[glyph.name] ||=
|
|
190
207
|
begin
|
|
191
|
-
|
|
192
|
-
raise HexaPDF::Error, "Glyph for #{glyph.str.inspect} missing"
|
|
193
|
-
end
|
|
208
|
+
raise HexaPDF::MissingGlyphError.new(glyph) if glyph.kind_of?(InvalidGlyph)
|
|
194
209
|
code = @encoding.code(glyph.name)
|
|
195
210
|
if code
|
|
196
211
|
code.chr.freeze
|
|
@@ -199,7 +214,7 @@ module HexaPDF
|
|
|
199
214
|
@encoding.code_to_name[@max_code] = glyph.name
|
|
200
215
|
@max_code.chr.freeze
|
|
201
216
|
else
|
|
202
|
-
raise HexaPDF::Error, "Type1 encoding has no codepoint for #{glyph.name}"
|
|
217
|
+
raise HexaPDF::Error, "Used Type1 encoding has no codepoint for #{glyph.name.inspect}"
|
|
203
218
|
end
|
|
204
219
|
end
|
|
205
220
|
end
|
|
@@ -43,13 +43,14 @@ module HexaPDF
|
|
|
43
43
|
# This module uses the configuration option 'font.map' for loading a font.
|
|
44
44
|
module FromConfiguration
|
|
45
45
|
|
|
46
|
-
#
|
|
46
|
+
# Returns a TrueType font wrapper for the given font by looking up the needed file in the
|
|
47
|
+
# 'font.map' configuration option.
|
|
47
48
|
#
|
|
48
49
|
# The file object representing the font file is *not* closed and if needed must be closed by
|
|
49
50
|
# the caller once the font is not needed anymore.
|
|
50
51
|
#
|
|
51
52
|
# +document+::
|
|
52
|
-
# The PDF document to associate the font
|
|
53
|
+
# The PDF document to associate the font wrapper with.
|
|
53
54
|
#
|
|
54
55
|
# +name+::
|
|
55
56
|
# The name of the font.
|
|
@@ -59,6 +60,8 @@ module HexaPDF
|
|
|
59
60
|
#
|
|
60
61
|
# +subset+::
|
|
61
62
|
# Specifies whether the font should be subset if possible.
|
|
63
|
+
#
|
|
64
|
+
# This method uses the FromFile font loader behind the scenes.
|
|
62
65
|
def self.call(document, name, variant: :none, subset: true)
|
|
63
66
|
file = document.config['font.map'].dig(name, variant)
|
|
64
67
|
return nil if file.nil?
|
|
@@ -39,15 +39,15 @@ require 'hexapdf/font/true_type_wrapper'
|
|
|
39
39
|
module HexaPDF
|
|
40
40
|
module FontLoader
|
|
41
41
|
|
|
42
|
-
# This module interprets the font name either as file name and tries to load it, or as
|
|
43
|
-
# object to be wrapped directly.
|
|
42
|
+
# This module interprets the font name either as file name and tries to load it, or as TrueType
|
|
43
|
+
# font object to be wrapped directly.
|
|
44
44
|
module FromFile
|
|
45
45
|
|
|
46
46
|
# :call-seq:
|
|
47
47
|
# FromFile.call(document, file_name, subset: true, **) -> wrapped_font
|
|
48
48
|
# FromFile.call(document, font_object, subset: true, **) -> wrapped_font
|
|
49
49
|
#
|
|
50
|
-
# Returns an appropriate font wrapper for the given file name or font object.
|
|
50
|
+
# Returns an appropriate font wrapper for the given file name or TrueType font object.
|
|
51
51
|
#
|
|
52
52
|
# If a file name is given, the file object representing the font file is *not* closed and if
|
|
53
53
|
# needed must be closed by the caller once the font is not needed anymore.
|
|
@@ -57,10 +57,10 @@ module HexaPDF
|
|
|
57
57
|
# font file.
|
|
58
58
|
#
|
|
59
59
|
# +document+::
|
|
60
|
-
# The PDF document to associate the font
|
|
60
|
+
# The PDF document to associate the font wrapper with.
|
|
61
61
|
#
|
|
62
62
|
# +file_name+/+font_object+::
|
|
63
|
-
# The file name or TrueType
|
|
63
|
+
# The file name or a HexaPDF::Font::TrueType::Font object.
|
|
64
64
|
#
|
|
65
65
|
# +subset+::
|
|
66
66
|
# Specifies whether the font should be subset if possible.
|
|
@@ -71,10 +71,10 @@ module HexaPDF
|
|
|
71
71
|
},
|
|
72
72
|
}.freeze
|
|
73
73
|
|
|
74
|
-
#
|
|
74
|
+
# Returns a font wrapper for the named Standard PDF font.
|
|
75
75
|
#
|
|
76
76
|
# +document+::
|
|
77
|
-
# The PDF document to associate the font
|
|
77
|
+
# The PDF document to associate the font wrapper with.
|
|
78
78
|
#
|
|
79
79
|
# +name+::
|
|
80
80
|
# The name of the built-in font. One of Times, Helvetica, Courier, Symbol or ZapfDingbats.
|
|
@@ -85,7 +85,7 @@ module HexaPDF
|
|
|
85
85
|
#
|
|
86
86
|
# +custom_encoding+::
|
|
87
87
|
# For Times, Helvetica and Courier the standard encoding WinAnsiEncoding is used. If this
|
|
88
|
-
#
|
|
88
|
+
# is not wanted because access to other glyphs is needed, set this to +true+
|
|
89
89
|
def self.call(document, name, variant: :none, custom_encoding: false, **)
|
|
90
90
|
name = MAPPING[name] && MAPPING[name][variant]
|
|
91
91
|
return nil if name.nil?
|
data/lib/hexapdf/font_loader.rb
CHANGED
|
@@ -63,6 +63,7 @@ module HexaPDF
|
|
|
63
63
|
# Optionally, a font loader can provide a method +available_fonts(document)+ that returns a hash
|
|
64
64
|
# where the keys are the font names and the values are the variants of all the provided fonts.
|
|
65
65
|
#
|
|
66
|
+
#
|
|
66
67
|
# == Font Wrappers
|
|
67
68
|
#
|
|
68
69
|
# A font wrapper needs to provide the following generic interface so that it can be used correctly
|
|
@@ -80,6 +81,8 @@ module HexaPDF
|
|
|
80
81
|
# and returns an encoded string that can be decoded with the font dictionary returned by
|
|
81
82
|
# \#dict.
|
|
82
83
|
#
|
|
84
|
+
# HexaPDF contains a font wrapper implementation for the Standard 14 PDF fonts (see
|
|
85
|
+
# HexaPDF::Font::Type1Wrapper) and one for TrueType fonts (see HexaPDF::Font::TrueTypeWrapper).
|
|
83
86
|
module FontLoader
|
|
84
87
|
|
|
85
88
|
autoload(:Standard14, 'hexapdf/font_loader/standard14')
|
|
@@ -41,7 +41,7 @@ module HexaPDF
|
|
|
41
41
|
|
|
42
42
|
# This module is used for loading images in the JPEG format from files or IO streams.
|
|
43
43
|
#
|
|
44
|
-
# See:
|
|
44
|
+
# See: PDF2.0 s7.4.8, ITU T.81 Annex B, ITU T.872
|
|
45
45
|
module JPEG
|
|
46
46
|
|
|
47
47
|
# The magic marker that tells us if the file/IO contains an image in JPEG format.
|
|
@@ -139,7 +139,7 @@ module HexaPDF
|
|
|
139
139
|
break if components != 4 || invert_colors
|
|
140
140
|
end
|
|
141
141
|
|
|
142
|
-
#
|
|
142
|
+
# PDF2.0 s8.9.5.1
|
|
143
143
|
if bits != 8
|
|
144
144
|
raise HexaPDF::Error, "Unsupported number of bits per component: #{bits}"
|
|
145
145
|
end
|
|
@@ -46,7 +46,7 @@ module HexaPDF
|
|
|
46
46
|
# image/xobject drawing methods of HexaPDF::Content::Canvas know how to handle them correctly so
|
|
47
47
|
# that this doesn't matter from a user's point of view.
|
|
48
48
|
#
|
|
49
|
-
# See:
|
|
49
|
+
# See: PDF2.0 s8.10
|
|
50
50
|
module PDF
|
|
51
51
|
|
|
52
52
|
# The magic marker that tells us if the file/IO contains an PDF file.
|
|
@@ -52,7 +52,7 @@ module HexaPDF
|
|
|
52
52
|
#
|
|
53
53
|
# All PNG specification section references are in reference to http://www.w3.org/TR/PNG/.
|
|
54
54
|
#
|
|
55
|
-
# See:
|
|
55
|
+
# See: PDF2.0 s7.4.4., s8.9
|
|
56
56
|
class PNG
|
|
57
57
|
|
|
58
58
|
# The magic marker that tells us if the file/IO contains an image in PNG format.
|
|
@@ -261,7 +261,7 @@ module HexaPDF
|
|
|
261
261
|
# Returns a hash for a CalRGB color space definition using the x,y chromaticity coordinates
|
|
262
262
|
# of the white point and the red, green and blue primaries.
|
|
263
263
|
#
|
|
264
|
-
# See:
|
|
264
|
+
# See: PDF2.0 s8.6.5.3
|
|
265
265
|
def calrgb_definition_from_chrm(xw, yw, xr, yr, xg, yg, xb, yb)
|
|
266
266
|
z = yw * ((xg - xb) * yr - (xr - xb) * yg + (xr - xg) * yb)
|
|
267
267
|
|
data/lib/hexapdf/image_loader.rb
CHANGED
|
@@ -59,7 +59,7 @@ module HexaPDF
|
|
|
59
59
|
# The image XObject may use any implemented filter. For example, an image loader for JPEG files
|
|
60
60
|
# would typically use the DCTDecode filter instead of decoding the image itself.
|
|
61
61
|
#
|
|
62
|
-
# See:
|
|
62
|
+
# See: PDF2.0 s8.9
|
|
63
63
|
module ImageLoader
|
|
64
64
|
|
|
65
65
|
autoload(:JPEG, 'hexapdf/image_loader/jpeg')
|
data/lib/hexapdf/importer.rb
CHANGED
|
@@ -68,6 +68,19 @@ module HexaPDF
|
|
|
68
68
|
@map[destination.hash] ||= new(destination)
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
+
# Imports the given +object+ (belonging to the +source+ document) by completely copying it and
|
|
72
|
+
# all referenced objects into the +destination+ object.
|
|
73
|
+
#
|
|
74
|
+
# Specifying +source+ is optionial if it can be determined through +object+.
|
|
75
|
+
#
|
|
76
|
+
# After the operation is finished, all state is discarded. This means that another call to this
|
|
77
|
+
# method for the same object will yield a new - and different - object. This is in contrast to
|
|
78
|
+
# using ::for together with #import which remembers and returns already imported objects (which
|
|
79
|
+
# is generally what one wants).
|
|
80
|
+
def self.copy(destination, object, source: nil)
|
|
81
|
+
new(NullableWeakRef.new(destination)).import(object, source: source)
|
|
82
|
+
end
|
|
83
|
+
|
|
71
84
|
private_class_method :new
|
|
72
85
|
|
|
73
86
|
attr_reader :destination #:nodoc:
|
data/lib/hexapdf/layout/box.rb
CHANGED
|
@@ -60,18 +60,25 @@ module HexaPDF
|
|
|
60
60
|
# instantiated from the common convenience method HexaPDF::Document::Layout#box. To use this
|
|
61
61
|
# facility subclasses need to be registered with the configuration option 'layout.boxes.map'.
|
|
62
62
|
#
|
|
63
|
-
# The methods #fit, #split or #split_content, and #draw or
|
|
64
|
-
# according to the subclass's use case.
|
|
63
|
+
# The methods #fit, #supports_position_flow?, #split or #split_content, #empty?, and #draw or
|
|
64
|
+
# #draw_content need to be customized according to the subclass's use case.
|
|
65
65
|
#
|
|
66
66
|
# #fit:: This method should return +true+ if fitting was successful. Additionally, the
|
|
67
67
|
# @fit_successful instance variable needs to be set to the fit result as it is used in
|
|
68
68
|
# #split.
|
|
69
69
|
#
|
|
70
|
+
# #supports_position_flow?::
|
|
71
|
+
# If the subclass supports the value :flow of the 'position' style property, this method
|
|
72
|
+
# needs to be overridden to return +true+.
|
|
73
|
+
#
|
|
70
74
|
# #split:: This method splits the content so that the available space is used as good as
|
|
71
75
|
# possible. The default implementation should be fine for most use-cases, so only
|
|
72
76
|
# #split_content needs to be implemented. The method #create_split_box should be used
|
|
73
77
|
# for getting a basic cloned box.
|
|
74
78
|
#
|
|
79
|
+
# #empty?:: This method should return +true+ if the subclass won't draw anything when #draw is
|
|
80
|
+
# called.
|
|
81
|
+
#
|
|
75
82
|
# #draw:: This method draws the content and the default implementation already handles things
|
|
76
83
|
# like drawing the border and background. Therefore it's best to implement #draw_content
|
|
77
84
|
# which should just draw the content.
|
|
@@ -120,10 +127,24 @@ module HexaPDF
|
|
|
120
127
|
#
|
|
121
128
|
# This can be used to store arbitrary information on boxes for later use. For example, a
|
|
122
129
|
# generic style layer could use one or more custom properties for its work.
|
|
130
|
+
#
|
|
131
|
+
# The Box class itself uses the following properties:
|
|
132
|
+
#
|
|
133
|
+
# optional_content::
|
|
134
|
+
#
|
|
135
|
+
# If this property is set, it needs to be an optional content group dictionary, a String
|
|
136
|
+
# defining an (optionally existing) optional content group dictionary, or an optional
|
|
137
|
+
# content membership dictionary.
|
|
138
|
+
#
|
|
139
|
+
# The whole content of the box, i.e. including padding, border, background..., is
|
|
140
|
+
# wrapped with the appropriate commands so that the optional content group or membership
|
|
141
|
+
# dictionary specifies whether the content is shown or not.
|
|
142
|
+
#
|
|
143
|
+
# See: HexaPDF::Type::OptionalContentProperties
|
|
123
144
|
attr_reader :properties
|
|
124
145
|
|
|
125
146
|
# :call-seq:
|
|
126
|
-
# Box.new(width: 0, height: 0, style: nil, properties:
|
|
147
|
+
# Box.new(width: 0, height: 0, style: nil, properties: nil) {|canv, box| block} -> box
|
|
127
148
|
#
|
|
128
149
|
# Creates a new Box object with the given width and height that uses the provided block when
|
|
129
150
|
# it is asked to draw itself on a canvas (see #draw).
|
|
@@ -131,11 +152,11 @@ module HexaPDF
|
|
|
131
152
|
# Since the final location of the box is not known beforehand, the drawing operations inside
|
|
132
153
|
# the block should draw inside the rectangle (0, 0, content_width, content_height) - note that
|
|
133
154
|
# the width and height of the box may not be known beforehand.
|
|
134
|
-
def initialize(width: 0, height: 0, style: nil, properties:
|
|
155
|
+
def initialize(width: 0, height: 0, style: nil, properties: nil, &block)
|
|
135
156
|
@width = @initial_width = width
|
|
136
157
|
@height = @initial_height = height
|
|
137
158
|
@style = Style.create(style)
|
|
138
|
-
@properties = properties
|
|
159
|
+
@properties = properties || {}
|
|
139
160
|
@draw_block = block
|
|
140
161
|
@fit_successful = false
|
|
141
162
|
@split_box = false
|
|
@@ -213,6 +234,10 @@ module HexaPDF
|
|
|
213
234
|
# instance variable to +nil+ or a valid block. This is useful to avoid unnecessary set-up
|
|
214
235
|
# operations when the block does nothing.
|
|
215
236
|
def draw(canvas, x, y)
|
|
237
|
+
if (oc = properties['optional_content'])
|
|
238
|
+
canvas.optional_content(oc)
|
|
239
|
+
end
|
|
240
|
+
|
|
216
241
|
if style.background_color? && style.background_color
|
|
217
242
|
canvas.save_graphics_state do
|
|
218
243
|
canvas.opacity(fill_alpha: style.background_alpha).
|
|
@@ -226,6 +251,8 @@ module HexaPDF
|
|
|
226
251
|
draw_content(canvas, x + reserved_width_left, y + reserved_height_bottom)
|
|
227
252
|
|
|
228
253
|
style.overlays.draw(canvas, x, y, self) if style.overlays?
|
|
254
|
+
|
|
255
|
+
canvas.end_optional_content if oc
|
|
229
256
|
end
|
|
230
257
|
|
|
231
258
|
# Returns +true+ if no drawing operations are performed.
|
|
@@ -98,7 +98,7 @@ module HexaPDF
|
|
|
98
98
|
if result.success?
|
|
99
99
|
current_frame.remove_area(result.mask)
|
|
100
100
|
@content_heights[@frame_index] = [@content_heights[@frame_index],
|
|
101
|
-
@initial_frame_y[@frame_index] - result.mask
|
|
101
|
+
@initial_frame_y[@frame_index] - result.mask.y].max
|
|
102
102
|
@fit_results << result
|
|
103
103
|
box = nil
|
|
104
104
|
break
|
|
@@ -109,7 +109,7 @@ module HexaPDF
|
|
|
109
109
|
if draw_box
|
|
110
110
|
current_frame.remove_area(result.mask)
|
|
111
111
|
@content_heights[@frame_index] = [@content_heights[@frame_index],
|
|
112
|
-
@initial_frame_y[@frame_index] - result.mask
|
|
112
|
+
@initial_frame_y[@frame_index] - result.mask.y].max
|
|
113
113
|
@fit_results << result
|
|
114
114
|
elsif !current_frame.find_next_region
|
|
115
115
|
@frame_index += 1
|
|
@@ -62,8 +62,9 @@ module HexaPDF
|
|
|
62
62
|
|
|
63
63
|
# The columns definition.
|
|
64
64
|
#
|
|
65
|
-
#
|
|
66
|
-
# of columns.
|
|
65
|
+
# If the value is an array, it needs to contain the widths of the columns. The size of the
|
|
66
|
+
# array determines the number of columns. Otherwise, if the value is an integer, the value
|
|
67
|
+
# defines the number of equally sized columns, i.e. a value of +N+ is equal to [-1]*N.
|
|
67
68
|
#
|
|
68
69
|
# If a negative integer is used for the width, the column is auto-sized. Such columns split
|
|
69
70
|
# the remaining width (after substracting the widths of the fixed columns) proportionally
|
|
@@ -132,6 +133,11 @@ module HexaPDF
|
|
|
132
133
|
true
|
|
133
134
|
end
|
|
134
135
|
|
|
136
|
+
# Returns +true+ if no box was fitted into the columns.
|
|
137
|
+
def empty?
|
|
138
|
+
super && (!@box_fitter || @box_fitter.fit_results.empty?)
|
|
139
|
+
end
|
|
140
|
+
|
|
135
141
|
# Fits the column box into the available space.
|
|
136
142
|
#
|
|
137
143
|
# If the style property 'position' is set to :flow, the columns might not be rectangles but
|
|
@@ -171,7 +177,8 @@ module HexaPDF
|
|
|
171
177
|
[column_left, column_bottom + height])
|
|
172
178
|
shape = Geom2D::Algorithms::PolygonOperation.run(frame.shape, rect, :intersection)
|
|
173
179
|
end
|
|
174
|
-
column_frame = Frame.new(column_left, column_bottom, column_width, height,
|
|
180
|
+
column_frame = Frame.new(column_left, column_bottom, column_width, height,
|
|
181
|
+
shape: shape, context: frame.context)
|
|
175
182
|
@box_fitter << column_frame
|
|
176
183
|
end
|
|
177
184
|
|
|
@@ -199,6 +206,8 @@ module HexaPDF
|
|
|
199
206
|
|
|
200
207
|
@width = columns[-1].sum + reserved_width
|
|
201
208
|
@height = @box_fitter.content_heights.max + reserved_height
|
|
209
|
+
@draw_pos_x = frame.x + reserved_width_left
|
|
210
|
+
@draw_pos_y = frame.y - @height + reserved_height_bottom
|
|
202
211
|
|
|
203
212
|
@box_fitter.fit_successful?
|
|
204
213
|
end
|
|
@@ -237,8 +246,14 @@ module HexaPDF
|
|
|
237
246
|
end
|
|
238
247
|
|
|
239
248
|
# Draws the child boxes onto the canvas at position [x, y].
|
|
240
|
-
def draw_content(canvas,
|
|
241
|
-
|
|
249
|
+
def draw_content(canvas, x, y)
|
|
250
|
+
if style.position != :flow && (x != @draw_pos_x || y != @draw_pos_y)
|
|
251
|
+
canvas.translate(x - @draw_pos_x, y - @draw_pos_y) do
|
|
252
|
+
@box_fitter.fit_results.each {|result| result.draw(canvas) }
|
|
253
|
+
end
|
|
254
|
+
else
|
|
255
|
+
@box_fitter.fit_results.each {|result| result.draw(canvas) }
|
|
256
|
+
end
|
|
242
257
|
end
|
|
243
258
|
|
|
244
259
|
end
|