hexapdf 0.5.0 → 0.6.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 +76 -2
- data/CONTRIBUTERS +1 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/examples/boxes.rb +68 -0
- data/examples/graphics.rb +12 -12
- data/examples/{text_box_alignment.rb → text_layouter_alignment.rb} +14 -14
- data/examples/text_layouter_inline_boxes.rb +66 -0
- data/examples/{text_box_line_wrapping.rb → text_layouter_line_wrapping.rb} +9 -10
- data/examples/{text_box_shapes.rb → text_layouter_shapes.rb} +58 -54
- data/examples/text_layouter_styling.rb +125 -0
- data/examples/truetype.rb +5 -7
- data/lib/hexapdf/cli/command.rb +1 -0
- data/lib/hexapdf/configuration.rb +170 -106
- data/lib/hexapdf/content/canvas.rb +41 -36
- data/lib/hexapdf/content/graphics_state.rb +15 -0
- data/lib/hexapdf/content/operator.rb +1 -1
- data/lib/hexapdf/dictionary.rb +20 -8
- data/lib/hexapdf/dictionary_fields.rb +8 -6
- data/lib/hexapdf/document.rb +25 -26
- data/lib/hexapdf/document/fonts.rb +4 -4
- data/lib/hexapdf/document/images.rb +2 -2
- data/lib/hexapdf/document/pages.rb +16 -16
- data/lib/hexapdf/encryption/security_handler.rb +41 -9
- data/lib/hexapdf/filter/flate_decode.rb +1 -1
- data/lib/hexapdf/filter/lzw_decode.rb +1 -1
- data/lib/hexapdf/filter/predictor.rb +7 -1
- data/lib/hexapdf/font/true_type/font.rb +20 -0
- data/lib/hexapdf/font/type1/font.rb +23 -0
- data/lib/hexapdf/font_loader.rb +1 -0
- data/lib/hexapdf/font_loader/from_configuration.rb +2 -3
- data/lib/hexapdf/font_loader/from_file.rb +65 -0
- data/lib/hexapdf/image_loader/png.rb +2 -2
- data/lib/hexapdf/layout.rb +3 -2
- data/lib/hexapdf/layout/box.rb +146 -0
- data/lib/hexapdf/layout/inline_box.rb +40 -31
- data/lib/hexapdf/layout/{line_fragment.rb → line.rb} +12 -13
- data/lib/hexapdf/layout/style.rb +630 -41
- data/lib/hexapdf/layout/text_fragment.rb +80 -12
- data/lib/hexapdf/layout/{text_box.rb → text_layouter.rb} +164 -109
- data/lib/hexapdf/number_tree_node.rb +1 -1
- data/lib/hexapdf/parser.rb +4 -1
- data/lib/hexapdf/revisions.rb +11 -4
- data/lib/hexapdf/stream.rb +8 -9
- data/lib/hexapdf/tokenizer.rb +5 -3
- data/lib/hexapdf/type.rb +3 -0
- data/lib/hexapdf/type/action.rb +56 -0
- data/lib/hexapdf/type/actions.rb +52 -0
- data/lib/hexapdf/type/actions/go_to.rb +52 -0
- data/lib/hexapdf/type/actions/go_to_r.rb +54 -0
- data/lib/hexapdf/type/actions/launch.rb +73 -0
- data/lib/hexapdf/type/actions/uri.rb +65 -0
- data/lib/hexapdf/type/annotation.rb +85 -0
- data/lib/hexapdf/type/annotations.rb +51 -0
- data/lib/hexapdf/type/annotations/link.rb +70 -0
- data/lib/hexapdf/type/annotations/markup_annotation.rb +70 -0
- data/lib/hexapdf/type/annotations/text.rb +81 -0
- data/lib/hexapdf/type/catalog.rb +3 -1
- data/lib/hexapdf/type/embedded_file.rb +6 -11
- data/lib/hexapdf/type/file_specification.rb +4 -6
- data/lib/hexapdf/type/font.rb +3 -1
- data/lib/hexapdf/type/font_descriptor.rb +18 -16
- data/lib/hexapdf/type/form.rb +3 -1
- data/lib/hexapdf/type/graphics_state_parameter.rb +3 -1
- data/lib/hexapdf/type/image.rb +4 -2
- data/lib/hexapdf/type/info.rb +2 -5
- data/lib/hexapdf/type/names.rb +2 -5
- data/lib/hexapdf/type/object_stream.rb +2 -1
- data/lib/hexapdf/type/page.rb +14 -1
- data/lib/hexapdf/type/page_tree_node.rb +9 -6
- data/lib/hexapdf/type/resources.rb +2 -5
- data/lib/hexapdf/type/trailer.rb +2 -5
- data/lib/hexapdf/type/viewer_preferences.rb +2 -5
- data/lib/hexapdf/type/xref_stream.rb +3 -1
- data/lib/hexapdf/version.rb +1 -1
- data/test/hexapdf/common_tokenizer_tests.rb +3 -1
- data/test/hexapdf/content/test_canvas.rb +29 -3
- data/test/hexapdf/content/test_graphics_state.rb +11 -0
- data/test/hexapdf/content/test_operator.rb +3 -2
- data/test/hexapdf/document/test_fonts.rb +8 -8
- data/test/hexapdf/document/test_images.rb +4 -12
- data/test/hexapdf/document/test_pages.rb +7 -7
- data/test/hexapdf/encryption/test_security_handler.rb +1 -5
- data/test/hexapdf/filter/test_predictor.rb +40 -12
- data/test/hexapdf/font/true_type/test_font.rb +16 -0
- data/test/hexapdf/font/type1/test_font.rb +30 -0
- data/test/hexapdf/font_loader/test_from_file.rb +29 -0
- data/test/hexapdf/font_loader/test_standard14.rb +4 -3
- data/test/hexapdf/layout/test_box.rb +104 -0
- data/test/hexapdf/layout/test_inline_box.rb +24 -10
- data/test/hexapdf/layout/{test_line_fragment.rb → test_line.rb} +9 -9
- data/test/hexapdf/layout/test_style.rb +519 -31
- data/test/hexapdf/layout/test_text_fragment.rb +136 -15
- data/test/hexapdf/layout/{test_text_box.rb → test_text_layouter.rb} +224 -144
- data/test/hexapdf/layout/test_text_shaper.rb +1 -1
- data/test/hexapdf/test_configuration.rb +12 -6
- data/test/hexapdf/test_dictionary.rb +27 -2
- data/test/hexapdf/test_dictionary_fields.rb +10 -1
- data/test/hexapdf/test_document.rb +14 -13
- data/test/hexapdf/test_parser.rb +12 -0
- data/test/hexapdf/test_revisions.rb +34 -0
- data/test/hexapdf/test_stream.rb +1 -1
- data/test/hexapdf/test_type.rb +18 -0
- data/test/hexapdf/test_writer.rb +2 -2
- data/test/hexapdf/type/actions/test_launch.rb +24 -0
- data/test/hexapdf/type/actions/test_uri.rb +23 -0
- data/test/hexapdf/type/annotations/test_link.rb +19 -0
- data/test/hexapdf/type/annotations/test_markup_annotation.rb +22 -0
- data/test/hexapdf/type/annotations/test_text.rb +38 -0
- data/test/hexapdf/type/test_annotation.rb +38 -0
- data/test/hexapdf/type/test_file_specification.rb +0 -7
- data/test/hexapdf/type/test_info.rb +0 -5
- data/test/hexapdf/type/test_page.rb +14 -0
- data/test/hexapdf/type/test_page_tree_node.rb +4 -1
- data/test/hexapdf/type/test_trailer.rb +0 -4
- data/test/test_helper.rb +6 -3
- metadata +36 -15
- data/examples/text_box_inline_boxes.rb +0 -56
- data/examples/text_box_styling.rb +0 -72
- data/test/hexapdf/type/test_embedded_file.rb +0 -16
- data/test/hexapdf/type/test_names.rb +0 -9
@@ -195,6 +195,7 @@ module HexaPDF
|
|
195
195
|
@graphics_state = GraphicsState.new
|
196
196
|
@graphics_object = :none
|
197
197
|
@font = nil
|
198
|
+
@font_stack = []
|
198
199
|
@serializer = HexaPDF::Serializer.new
|
199
200
|
@current_point = [0, 0]
|
200
201
|
@start_point = [0, 0]
|
@@ -241,6 +242,7 @@ module HexaPDF
|
|
241
242
|
def save_graphics_state
|
242
243
|
raise_unless_at_page_description_level
|
243
244
|
invoke0(:q)
|
245
|
+
@font_stack.push(@font)
|
244
246
|
if block_given?
|
245
247
|
yield
|
246
248
|
restore_graphics_state
|
@@ -259,6 +261,7 @@ module HexaPDF
|
|
259
261
|
def restore_graphics_state
|
260
262
|
raise_unless_at_page_description_level
|
261
263
|
invoke0(:Q)
|
264
|
+
@font = @font_stack.pop
|
262
265
|
self
|
263
266
|
end
|
264
267
|
|
@@ -607,16 +610,8 @@ module HexaPDF
|
|
607
610
|
#
|
608
611
|
# See: PDF1.7 s8.4.3.5, LineDashPattern
|
609
612
|
def line_dash_pattern(value = nil, phase = 0, &block)
|
610
|
-
|
611
|
-
|
612
|
-
when Array
|
613
|
-
value = LineDashPattern.new(value, phase)
|
614
|
-
when 0
|
615
|
-
value = LineDashPattern.new([], 0)
|
616
|
-
else
|
617
|
-
value = LineDashPattern.new([value], phase)
|
618
|
-
end
|
619
|
-
gs_getter_setter(:line_dash_pattern, :d, value, &block)
|
613
|
+
gs_getter_setter(:line_dash_pattern, :d, value && LineDashPattern.normalize(value, phase),
|
614
|
+
&block)
|
620
615
|
end
|
621
616
|
alias :line_dash_pattern= :line_dash_pattern
|
622
617
|
|
@@ -1612,7 +1607,7 @@ module HexaPDF
|
|
1612
1607
|
# See: PDF1.7 s9.2.2
|
1613
1608
|
def font(name = nil, size: nil, **options)
|
1614
1609
|
if name
|
1615
|
-
@font = (name.respond_to?(:dict) ? name : context.document.fonts.
|
1610
|
+
@font = (name.respond_to?(:dict) ? name : context.document.fonts.add(name, options))
|
1616
1611
|
if size
|
1617
1612
|
font_size(size)
|
1618
1613
|
else
|
@@ -1684,6 +1679,7 @@ module HexaPDF
|
|
1684
1679
|
#
|
1685
1680
|
# See: http://www.unicode.org/reports/tr18/#Line_Boundaries
|
1686
1681
|
def text(text, at: nil)
|
1682
|
+
raise_unless_font_set
|
1687
1683
|
move_text_cursor(offset: at) if at
|
1688
1684
|
lines = text.split(/\u{D A}|(?!\u{D A})[\u{A}-\u{D}\u{85}\u{2028}\u{2029}]/, -1)
|
1689
1685
|
lines.each_with_index do |str, index|
|
@@ -1709,6 +1705,7 @@ module HexaPDF
|
|
1709
1705
|
#
|
1710
1706
|
# This method is usually not invoked directly but by higher level methods like #text.
|
1711
1707
|
def show_glyphs(glyphs)
|
1708
|
+
raise_unless_font_set
|
1712
1709
|
begin_text
|
1713
1710
|
|
1714
1711
|
result = [''.b]
|
@@ -1744,6 +1741,7 @@ module HexaPDF
|
|
1744
1741
|
# #text_cursor and other methods using the current text matrix are invalid until the next call
|
1745
1742
|
# to #text_matrix or #end_text.
|
1746
1743
|
def show_glyphs_only(glyphs)
|
1744
|
+
raise_unless_font_set
|
1747
1745
|
begin_text
|
1748
1746
|
|
1749
1747
|
result = [''.b]
|
@@ -1850,6 +1848,18 @@ module HexaPDF
|
|
1850
1848
|
self
|
1851
1849
|
end
|
1852
1850
|
|
1851
|
+
# Creates a color object from the given color specification. See #stroke_color for details
|
1852
|
+
# on the possible color specifications.
|
1853
|
+
def color_from_specification(spec)
|
1854
|
+
if spec.length == 1 && spec[0].kind_of?(String)
|
1855
|
+
resources.color_space(:DeviceRGB).color(*spec[0].scan(/../).map!(&:hex))
|
1856
|
+
elsif spec.length == 1 && spec[0].respond_to?(:color_space)
|
1857
|
+
spec[0]
|
1858
|
+
else
|
1859
|
+
resources.color_space(color_space_for_components(spec)).color(*spec)
|
1860
|
+
end
|
1861
|
+
end
|
1862
|
+
|
1853
1863
|
private
|
1854
1864
|
|
1855
1865
|
# Invokes the given operator with the operands and serializes it.
|
@@ -1895,15 +1905,15 @@ module HexaPDF
|
|
1895
1905
|
|
1896
1906
|
# Raises an error unless the current graphics object is a path.
|
1897
1907
|
def raise_unless_in_path
|
1898
|
-
|
1899
|
-
raise HexaPDF::Error, "Operation only allowed
|
1908
|
+
unless graphics_object == :path
|
1909
|
+
raise HexaPDF::Error, "Operation only allowed if current graphics object is a path"
|
1900
1910
|
end
|
1901
1911
|
end
|
1902
1912
|
|
1903
1913
|
# Raises an error unless the current graphics object is a path or a clipping path.
|
1904
1914
|
def raise_unless_in_path_or_clipping_path
|
1905
|
-
|
1906
|
-
raise HexaPDF::Error, "Operation only allowed
|
1915
|
+
unless graphics_object == :path || graphics_object == :clipping_path
|
1916
|
+
raise HexaPDF::Error, "Operation only allowed if current graphics object is a " \
|
1907
1917
|
"path or clipping path"
|
1908
1918
|
end
|
1909
1919
|
end
|
@@ -1912,15 +1922,15 @@ module HexaPDF
|
|
1912
1922
|
# level.
|
1913
1923
|
def raise_unless_at_page_description_level
|
1914
1924
|
end_text if graphics_object == :text
|
1915
|
-
|
1916
|
-
raise HexaPDF::Error, "Operation only allowed
|
1925
|
+
unless graphics_object == :none
|
1926
|
+
raise HexaPDF::Error, "Operation only allowed if there is no current graphics object"
|
1917
1927
|
end
|
1918
1928
|
end
|
1919
1929
|
|
1920
1930
|
# Raises an error unless the current graphics object is none or a text object.
|
1921
1931
|
def raise_unless_at_page_description_level_or_in_text
|
1922
|
-
|
1923
|
-
raise HexaPDF::Error, "Operation only allowed
|
1932
|
+
unless graphics_object == :none || graphics_object == :text
|
1933
|
+
raise HexaPDF::Error, "Operation only allowed if current graphics object is a " \
|
1924
1934
|
"text object or if there is no current object"
|
1925
1935
|
end
|
1926
1936
|
end
|
@@ -1928,20 +1938,27 @@ module HexaPDF
|
|
1928
1938
|
# Raises an error unless the current graphics object is none or a path object.
|
1929
1939
|
def raise_unless_at_page_description_level_or_in_path
|
1930
1940
|
end_text if graphics_object == :text
|
1931
|
-
|
1932
|
-
raise HexaPDF::Error, "Operation only allowed
|
1941
|
+
unless graphics_object == :none || graphics_object == :path
|
1942
|
+
raise HexaPDF::Error, "Operation only allowed if current graphics object is a " \
|
1933
1943
|
"path object or if there is no current object"
|
1934
1944
|
end
|
1935
1945
|
end
|
1936
1946
|
|
1937
1947
|
# Raises an error unless the current graphics object is a text object.
|
1938
1948
|
def raise_unless_in_text
|
1939
|
-
|
1940
|
-
raise HexaPDF::Error, "Operation only allowed
|
1949
|
+
unless graphics_object == :text
|
1950
|
+
raise HexaPDF::Error, "Operation only allowed if current graphics object is a " \
|
1941
1951
|
"text object"
|
1942
1952
|
end
|
1943
1953
|
end
|
1944
1954
|
|
1955
|
+
# Raises an error unless a font has been set.
|
1956
|
+
def raise_unless_font_set
|
1957
|
+
unless @font
|
1958
|
+
raise HexaPDF::Error, "Operation only allowed if a font is set"
|
1959
|
+
end
|
1960
|
+
end
|
1961
|
+
|
1945
1962
|
# Utility method that abstracts the implementation of the stroke and fill color methods.
|
1946
1963
|
def color_getter_setter(name, color, rg, g, k, cs, scn)
|
1947
1964
|
color.flatten!
|
@@ -1950,7 +1967,7 @@ module HexaPDF
|
|
1950
1967
|
color = color_from_specification(color)
|
1951
1968
|
|
1952
1969
|
save_graphics_state if block_given?
|
1953
|
-
|
1970
|
+
unless color == graphics_state.send(name)
|
1954
1971
|
case color.color_space.family
|
1955
1972
|
when :DeviceRGB then serialize(rg, *color.components)
|
1956
1973
|
when :DeviceGray then serialize(g, *color.components)
|
@@ -1977,18 +1994,6 @@ module HexaPDF
|
|
1977
1994
|
end
|
1978
1995
|
end
|
1979
1996
|
|
1980
|
-
# Creates a color object from the given color specification. See #stroke_color for details
|
1981
|
-
# on the possible color specifications.
|
1982
|
-
def color_from_specification(spec)
|
1983
|
-
if spec.length == 1 && spec[0].kind_of?(String)
|
1984
|
-
resources.color_space(:DeviceRGB).color(*spec[0].scan(/../).map!(&:hex))
|
1985
|
-
elsif spec.length == 1 && spec[0].respond_to?(:color_space)
|
1986
|
-
spec[0]
|
1987
|
-
else
|
1988
|
-
resources.color_space(color_space_for_components(spec)).color(*spec)
|
1989
|
-
end
|
1990
|
-
end
|
1991
|
-
|
1992
1997
|
# Returns the name of the device color space that should be used for creating a color object
|
1993
1998
|
# from the components array.
|
1994
1999
|
def color_space_for_components(components)
|
@@ -159,6 +159,21 @@ module HexaPDF
|
|
159
159
|
# See: PDF1.7 s8.4.3.6
|
160
160
|
class LineDashPattern
|
161
161
|
|
162
|
+
# Returns the arguments normalized to a valid LineDashPattern instance.
|
163
|
+
#
|
164
|
+
# If +array+ is 0, the default line dash pattern representing a solid line will be used. If it
|
165
|
+
# is a single number, it will be converted into an array holding that number.
|
166
|
+
def self.normalize(array, phase = 0)
|
167
|
+
case array
|
168
|
+
when LineDashPattern then array
|
169
|
+
when Array then new(array, phase)
|
170
|
+
when 0 then new
|
171
|
+
when Numeric then new([array], phase)
|
172
|
+
else
|
173
|
+
raise ArgumentError, "Unknown line dash pattern: #{array} / #{phase}"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
162
177
|
# The dash array.
|
163
178
|
attr_reader :array
|
164
179
|
|
@@ -784,7 +784,7 @@ module HexaPDF
|
|
784
784
|
end
|
785
785
|
|
786
786
|
def invoke(processor, rendering_mode) #:nodoc:
|
787
|
-
processor.graphics_state.text_rendering_mode = rendering_mode
|
787
|
+
processor.graphics_state.text_rendering_mode = TextRenderingMode.normalize(rendering_mode)
|
788
788
|
end
|
789
789
|
|
790
790
|
end
|
data/lib/hexapdf/dictionary.rb
CHANGED
@@ -117,6 +117,19 @@ module HexaPDF
|
|
117
117
|
@fields.each(&block) if defined?(@fields)
|
118
118
|
end
|
119
119
|
|
120
|
+
# Defines the static PDF type of the class in cases where this is possible, i.e. when the class
|
121
|
+
# implements one specific PDF type (e.g. the HexaPDF::Type::Catalog class).
|
122
|
+
def self.define_type(type)
|
123
|
+
@type = type
|
124
|
+
end
|
125
|
+
|
126
|
+
# Returns the statically defined PDF type of the class.
|
127
|
+
#
|
128
|
+
# See ::define_type
|
129
|
+
def self.type
|
130
|
+
defined?(@type) && @type
|
131
|
+
end
|
132
|
+
|
120
133
|
|
121
134
|
# Returns the value for the given dictionary entry.
|
122
135
|
#
|
@@ -166,9 +179,9 @@ module HexaPDF
|
|
166
179
|
end
|
167
180
|
end
|
168
181
|
|
169
|
-
# Returns +true+ if the given key is present in the dictionary
|
182
|
+
# Returns +true+ if the given key is present in the dictionary and not +nil+.
|
170
183
|
def key?(key)
|
171
|
-
value.
|
184
|
+
!value[key].nil?
|
172
185
|
end
|
173
186
|
|
174
187
|
# Deletes the name-value pair from the dictionary and returns the value. If such a pair does
|
@@ -190,9 +203,10 @@ module HexaPDF
|
|
190
203
|
self
|
191
204
|
end
|
192
205
|
|
193
|
-
# Returns the value of the /Type field or
|
206
|
+
# Returns, in order or availability, the value of ::type, the /Type field or the result of
|
207
|
+
# Object#type.
|
194
208
|
def type
|
195
|
-
self[:Type] || super
|
209
|
+
self.class.type || self[:Type] || super
|
196
210
|
end
|
197
211
|
|
198
212
|
# Returns +true+ if the dictionary contains no entries.
|
@@ -201,11 +215,9 @@ module HexaPDF
|
|
201
215
|
end
|
202
216
|
|
203
217
|
# Returns a dup of the underlying hash.
|
204
|
-
def
|
218
|
+
def to_h
|
205
219
|
value.dup
|
206
220
|
end
|
207
|
-
alias :to_h :to_hash
|
208
|
-
|
209
221
|
|
210
222
|
private
|
211
223
|
|
@@ -242,7 +254,7 @@ module HexaPDF
|
|
242
254
|
def perform_validation(&block)
|
243
255
|
super
|
244
256
|
each_set_key_or_required_field do |name, field|
|
245
|
-
obj = key?(name)
|
257
|
+
obj = key?(name) ? self[name] : nil
|
246
258
|
|
247
259
|
# Validate nested objects
|
248
260
|
validate_nested(obj, &block)
|
@@ -325,24 +325,26 @@ module HexaPDF
|
|
325
325
|
# converted to the corresponding file specification dictionary.
|
326
326
|
module FileSpecificationConverter
|
327
327
|
|
328
|
-
# This converter is only used for the :
|
328
|
+
# This converter is only used for the :Filespec type.
|
329
329
|
def self.usable_for?(type)
|
330
330
|
type == :Filespec
|
331
331
|
end
|
332
332
|
|
333
|
-
#
|
333
|
+
# Filespecs can also be simple hashes or strings.
|
334
334
|
def self.additional_types
|
335
335
|
[Hash, String]
|
336
336
|
end
|
337
337
|
|
338
338
|
# Returns +true+ if the given data is a string file specification.
|
339
|
-
def self.convert?(data,
|
340
|
-
data.kind_of?(
|
339
|
+
def self.convert?(data, type)
|
340
|
+
!data.kind_of?(type.first) &&
|
341
|
+
(data.kind_of?(Hash) || data.kind_of?(HexaPDF::Dictionary) || data.kind_of?(String))
|
341
342
|
end
|
342
343
|
|
343
|
-
# Converts
|
344
|
+
# Converts a string file specification or a hash into a full file specification.
|
344
345
|
def self.convert(data, type, document)
|
345
|
-
|
346
|
+
data = {F: data} if data.kind_of?(String)
|
347
|
+
document.wrap(data, type: type.first)
|
346
348
|
end
|
347
349
|
|
348
350
|
end
|
data/lib/hexapdf/document.rb
CHANGED
@@ -276,16 +276,15 @@ module HexaPDF
|
|
276
276
|
# of the +type+ and +subtype+ options as well as on the 'object.type_map' and
|
277
277
|
# 'object.subtype_map' global configuration options:
|
278
278
|
#
|
279
|
-
# *
|
280
|
-
# used.
|
279
|
+
# * First +type+ is used to try to determine the class. If it is already a Class object, it is
|
280
|
+
# used, otherwise the type is looked up in 'object.type_map'.
|
281
281
|
#
|
282
|
-
# * If
|
283
|
-
#
|
284
|
-
#
|
282
|
+
# * If +subtype+ is provided or can be determined because +obj+ is a hash with a :Subtype or :S
|
283
|
+
# field, the type and subtype together are used to look up a special subtype class in
|
284
|
+
# 'object.subtype_map'.
|
285
285
|
#
|
286
|
-
# * If there is no valid class after the above steps, HexaPDF::Stream is used if a stream
|
287
|
-
#
|
288
|
-
# HexaPDF::Object is used.
|
286
|
+
# * If there is no valid class after the above steps, HexaPDF::Stream is used if a stream is
|
287
|
+
# given, HexaPDF::Dictionary if the given objecct is a hash or else HexaPDF::Object is used.
|
289
288
|
#
|
290
289
|
# Options:
|
291
290
|
#
|
@@ -316,27 +315,27 @@ module HexaPDF
|
|
316
315
|
|
317
316
|
if type.kind_of?(Class)
|
318
317
|
klass = type
|
318
|
+
type = (klass <= HexaPDF::Dictionary ? klass.type : nil)
|
319
319
|
else
|
320
|
-
if data.value.kind_of?(Hash)
|
321
|
-
|
322
|
-
|
323
|
-
end
|
320
|
+
type ||= deref(data.value[:Type]) if data.value.kind_of?(Hash)
|
321
|
+
klass = GlobalConfiguration.constantize('object.type_map'.freeze, type) { nil } if type
|
322
|
+
end
|
324
323
|
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
end
|
331
|
-
klass ||= if data.stream
|
332
|
-
HexaPDF::Stream
|
333
|
-
elsif data.value.kind_of?(Hash)
|
334
|
-
HexaPDF::Dictionary
|
335
|
-
else
|
336
|
-
HexaPDF::Object
|
337
|
-
end
|
324
|
+
if data.value.kind_of?(Hash)
|
325
|
+
subtype ||= deref(data.value[:Subtype]) || deref(data.value[:S])
|
326
|
+
end
|
327
|
+
if subtype
|
328
|
+
klass = GlobalConfiguration.constantize('object.subtype_map'.freeze, type, subtype) { klass }
|
338
329
|
end
|
339
330
|
|
331
|
+
klass ||= if data.stream
|
332
|
+
HexaPDF::Stream
|
333
|
+
elsif data.value.kind_of?(Hash)
|
334
|
+
HexaPDF::Dictionary
|
335
|
+
else
|
336
|
+
HexaPDF::Object
|
337
|
+
end
|
338
|
+
|
340
339
|
klass.new(data, document: self)
|
341
340
|
end
|
342
341
|
|
@@ -478,7 +477,7 @@ module HexaPDF
|
|
478
477
|
#
|
479
478
|
# See Task for more information.
|
480
479
|
def task(name, **opts, &block)
|
481
|
-
task =
|
480
|
+
task = config.constantize('task.map'.freeze, name) do
|
482
481
|
raise HexaPDF::Error, "No task named '#{name}' is available"
|
483
482
|
end
|
484
483
|
task.call(self, **opts, &block)
|
@@ -48,13 +48,13 @@ module HexaPDF
|
|
48
48
|
end
|
49
49
|
|
50
50
|
# :call-seq:
|
51
|
-
# fonts.
|
51
|
+
# fonts.add(name, **options) -> font
|
52
52
|
#
|
53
|
-
#
|
54
|
-
# 'font_loaders').
|
53
|
+
# Adds the font to the document and returns if (using the loaders specified with the
|
54
|
+
# configuration option 'font_loaders').
|
55
55
|
#
|
56
56
|
# If a font with the same parameters has been loaded before, the cached font object is used.
|
57
|
-
def
|
57
|
+
def add(name, **options)
|
58
58
|
options[:variant] ||= :none # assign default value for consistency with caching
|
59
59
|
font = @loaded_fonts_cache[[name, options]]
|
60
60
|
return font if font
|
@@ -101,8 +101,8 @@ module HexaPDF
|
|
101
101
|
# Returns the image loader (see HexaPDF::ImageLoader) for the given file or IO stream or
|
102
102
|
# raises an error if no suitable image loader is found.
|
103
103
|
def image_loader_for(file_or_io)
|
104
|
-
|
105
|
-
loader =
|
104
|
+
@document.config['image_loader'].each_index do |index|
|
105
|
+
loader = @document.config.constantize('image_loader', index) do
|
106
106
|
raise HexaPDF::Error, "Couldn't retrieve image loader from configuration"
|
107
107
|
end
|
108
108
|
return loader if loader.handles?(file_or_io)
|
@@ -55,27 +55,27 @@ module HexaPDF
|
|
55
55
|
end
|
56
56
|
|
57
57
|
# :call-seq:
|
58
|
-
# pages.add
|
59
|
-
# pages.add(media_box) -> new_page
|
60
|
-
# pages.add(page)
|
58
|
+
# pages.add -> new_page
|
59
|
+
# pages.add(media_box, orientation: :portrait) -> new_page
|
60
|
+
# pages.add(page) -> page
|
61
61
|
#
|
62
62
|
# Adds the page or a new empty page at the end and returns it.
|
63
63
|
#
|
64
64
|
# If no argument is given, a new page with the default dimensions (see configuration option
|
65
|
-
# 'page.default_media_box') is used.
|
66
|
-
#
|
67
|
-
#
|
68
|
-
|
69
|
-
|
70
|
-
|
65
|
+
# 'page.default_media_box') is used.
|
66
|
+
#
|
67
|
+
# If the single argument is an array with four numbers (specifying the media box), the new
|
68
|
+
# page will have these dimensions.
|
69
|
+
#
|
70
|
+
# If the single argument is a symbol, it is taken as referencing a pre-defined media box in
|
71
|
+
# HexaPDF::Type::Page::PAPER_SIZE for the new page. The optional argument +orientation+ can be
|
72
|
+
# used to change the orientation to :landscape if needed.
|
73
|
+
def add(page = nil, orientation: :portrait)
|
74
|
+
if page.kind_of?(Array)
|
71
75
|
page = @document.add(Type: :Page, MediaBox: page)
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
page = @document.add(Type: :Page, MediaBox: media_box)
|
76
|
-
else
|
77
|
-
raise HexaPDF::Error, "Invalid page format specified: #{page}"
|
78
|
-
end
|
76
|
+
elsif page.kind_of?(Symbol)
|
77
|
+
box = Type::Page.media_box(page, orientation: orientation)
|
78
|
+
page = @document.add(Type: :Page, MediaBox: box)
|
79
79
|
end
|
80
80
|
@document.catalog.pages.add_page(page)
|
81
81
|
end
|