hexapdf 0.32.2 → 0.34.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 +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
|