hexapdf 0.5.0 → 0.6.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 +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
|