hexapdf 0.11.9 → 0.13.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.
Files changed (270) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +157 -0
  3. data/LICENSE +1 -1
  4. data/examples/001-hello_world.rb +1 -1
  5. data/examples/002-graphics.rb +1 -1
  6. data/examples/003-arcs.rb +1 -1
  7. data/examples/004-optimizing.rb +1 -1
  8. data/examples/005-merging.rb +1 -1
  9. data/examples/006-standard_pdf_fonts.rb +1 -1
  10. data/examples/007-truetype.rb +1 -1
  11. data/examples/008-show_char_bboxes.rb +1 -1
  12. data/examples/009-text_layouter_alignment.rb +1 -1
  13. data/examples/010-text_layouter_inline_boxes.rb +1 -1
  14. data/examples/011-text_layouter_line_wrapping.rb +1 -1
  15. data/examples/012-text_layouter_styling.rb +1 -1
  16. data/examples/013-text_layouter_shapes.rb +1 -1
  17. data/examples/014-text_in_polygon.rb +1 -1
  18. data/examples/015-boxes.rb +1 -1
  19. data/examples/016-frame_automatic_box_placement.rb +1 -1
  20. data/examples/017-frame_text_flow.rb +1 -1
  21. data/examples/018-composer.rb +1 -1
  22. data/examples/019-acro_form.rb +51 -0
  23. data/lib/hexapdf.rb +1 -1
  24. data/lib/hexapdf/cli.rb +3 -1
  25. data/lib/hexapdf/cli/batch.rb +1 -1
  26. data/lib/hexapdf/cli/command.rb +22 -11
  27. data/lib/hexapdf/cli/files.rb +1 -1
  28. data/lib/hexapdf/cli/form.rb +240 -0
  29. data/lib/hexapdf/cli/image2pdf.rb +3 -2
  30. data/lib/hexapdf/cli/images.rb +1 -1
  31. data/lib/hexapdf/cli/info.rb +52 -3
  32. data/lib/hexapdf/cli/inspect.rb +31 -9
  33. data/lib/hexapdf/cli/merge.rb +2 -2
  34. data/lib/hexapdf/cli/modify.rb +1 -1
  35. data/lib/hexapdf/cli/optimize.rb +1 -1
  36. data/lib/hexapdf/cli/split.rb +1 -1
  37. data/lib/hexapdf/cli/watermark.rb +1 -1
  38. data/lib/hexapdf/composer.rb +2 -2
  39. data/lib/hexapdf/configuration.rb +81 -11
  40. data/lib/hexapdf/content.rb +3 -1
  41. data/lib/hexapdf/content/canvas.rb +5 -18
  42. data/lib/hexapdf/content/color_space.rb +111 -32
  43. data/lib/hexapdf/content/graphic_object.rb +1 -1
  44. data/lib/hexapdf/content/graphic_object/arc.rb +4 -4
  45. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +1 -1
  46. data/lib/hexapdf/content/graphic_object/geom2d.rb +1 -1
  47. data/lib/hexapdf/content/graphic_object/solid_arc.rb +1 -1
  48. data/lib/hexapdf/content/graphics_state.rb +1 -1
  49. data/lib/hexapdf/content/operator.rb +9 -9
  50. data/lib/hexapdf/content/parser.rb +18 -5
  51. data/lib/hexapdf/content/processor.rb +1 -1
  52. data/lib/hexapdf/content/transformation_matrix.rb +1 -1
  53. data/lib/hexapdf/data_dir.rb +1 -1
  54. data/lib/hexapdf/dictionary.rb +5 -5
  55. data/lib/hexapdf/dictionary_fields.rb +2 -10
  56. data/lib/hexapdf/document.rb +45 -17
  57. data/lib/hexapdf/document/files.rb +1 -2
  58. data/lib/hexapdf/document/fonts.rb +1 -1
  59. data/lib/hexapdf/document/images.rb +1 -1
  60. data/lib/hexapdf/document/pages.rb +3 -14
  61. data/lib/hexapdf/encryption.rb +1 -1
  62. data/lib/hexapdf/encryption/aes.rb +1 -1
  63. data/lib/hexapdf/encryption/arc4.rb +1 -1
  64. data/lib/hexapdf/encryption/fast_aes.rb +1 -1
  65. data/lib/hexapdf/encryption/fast_arc4.rb +2 -2
  66. data/lib/hexapdf/encryption/identity.rb +1 -1
  67. data/lib/hexapdf/encryption/ruby_aes.rb +1 -1
  68. data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
  69. data/lib/hexapdf/encryption/security_handler.rb +2 -1
  70. data/lib/hexapdf/encryption/standard_security_handler.rb +2 -1
  71. data/lib/hexapdf/error.rb +1 -1
  72. data/lib/hexapdf/filter.rb +3 -3
  73. data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
  74. data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
  75. data/lib/hexapdf/filter/encryption.rb +1 -1
  76. data/lib/hexapdf/filter/flate_decode.rb +1 -1
  77. data/lib/hexapdf/filter/lzw_decode.rb +1 -1
  78. data/lib/hexapdf/filter/{jpx_decode.rb → pass_through.rb} +5 -5
  79. data/lib/hexapdf/filter/predictor.rb +1 -1
  80. data/lib/hexapdf/filter/run_length_decode.rb +1 -1
  81. data/lib/hexapdf/font/cmap.rb +2 -5
  82. data/lib/hexapdf/font/cmap/parser.rb +1 -1
  83. data/lib/hexapdf/font/cmap/writer.rb +1 -1
  84. data/lib/hexapdf/font/encoding.rb +1 -1
  85. data/lib/hexapdf/font/encoding/base.rb +9 -1
  86. data/lib/hexapdf/font/encoding/difference_encoding.rb +7 -1
  87. data/lib/hexapdf/font/encoding/glyph_list.rb +1 -1
  88. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
  89. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +1 -1
  90. data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
  91. data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
  92. data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +1 -1
  93. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
  94. data/lib/hexapdf/font/invalid_glyph.rb +1 -1
  95. data/lib/hexapdf/font/true_type.rb +1 -1
  96. data/lib/hexapdf/font/true_type/builder.rb +1 -1
  97. data/lib/hexapdf/font/true_type/font.rb +1 -1
  98. data/lib/hexapdf/font/true_type/optimizer.rb +1 -1
  99. data/lib/hexapdf/font/true_type/subsetter.rb +1 -1
  100. data/lib/hexapdf/font/true_type/table.rb +1 -1
  101. data/lib/hexapdf/font/true_type/table/cmap.rb +1 -1
  102. data/lib/hexapdf/font/true_type/table/cmap_subtable.rb +1 -1
  103. data/lib/hexapdf/font/true_type/table/directory.rb +1 -1
  104. data/lib/hexapdf/font/true_type/table/glyf.rb +1 -1
  105. data/lib/hexapdf/font/true_type/table/head.rb +2 -1
  106. data/lib/hexapdf/font/true_type/table/hhea.rb +1 -1
  107. data/lib/hexapdf/font/true_type/table/hmtx.rb +1 -1
  108. data/lib/hexapdf/font/true_type/table/kern.rb +1 -1
  109. data/lib/hexapdf/font/true_type/table/loca.rb +1 -1
  110. data/lib/hexapdf/font/true_type/table/maxp.rb +1 -1
  111. data/lib/hexapdf/font/true_type/table/name.rb +1 -1
  112. data/lib/hexapdf/font/true_type/table/os2.rb +3 -1
  113. data/lib/hexapdf/font/true_type/table/post.rb +1 -1
  114. data/lib/hexapdf/font/true_type_wrapper.rb +54 -51
  115. data/lib/hexapdf/font/type1.rb +1 -1
  116. data/lib/hexapdf/font/type1/afm_parser.rb +1 -1
  117. data/lib/hexapdf/font/type1/character_metrics.rb +1 -1
  118. data/lib/hexapdf/font/type1/font.rb +1 -1
  119. data/lib/hexapdf/font/type1/font_metrics.rb +1 -1
  120. data/lib/hexapdf/font/type1/pfb_parser.rb +1 -1
  121. data/lib/hexapdf/font/type1_wrapper.rb +68 -52
  122. data/lib/hexapdf/font_loader.rb +1 -1
  123. data/lib/hexapdf/font_loader/from_configuration.rb +1 -1
  124. data/lib/hexapdf/font_loader/from_file.rb +1 -1
  125. data/lib/hexapdf/font_loader/standard14.rb +1 -1
  126. data/lib/hexapdf/image_loader.rb +1 -1
  127. data/lib/hexapdf/image_loader/jpeg.rb +1 -1
  128. data/lib/hexapdf/image_loader/pdf.rb +1 -1
  129. data/lib/hexapdf/image_loader/png.rb +4 -3
  130. data/lib/hexapdf/importer.rb +2 -4
  131. data/lib/hexapdf/layout.rb +1 -1
  132. data/lib/hexapdf/layout/box.rb +1 -1
  133. data/lib/hexapdf/layout/frame.rb +1 -1
  134. data/lib/hexapdf/layout/image_box.rb +1 -1
  135. data/lib/hexapdf/layout/inline_box.rb +1 -1
  136. data/lib/hexapdf/layout/line.rb +2 -2
  137. data/lib/hexapdf/layout/numeric_refinements.rb +1 -1
  138. data/lib/hexapdf/layout/style.rb +24 -24
  139. data/lib/hexapdf/layout/text_box.rb +1 -1
  140. data/lib/hexapdf/layout/text_fragment.rb +1 -1
  141. data/lib/hexapdf/layout/text_layouter.rb +1 -1
  142. data/lib/hexapdf/layout/text_shaper.rb +4 -3
  143. data/lib/hexapdf/layout/width_from_polygon.rb +1 -1
  144. data/lib/hexapdf/name_tree_node.rb +1 -1
  145. data/lib/hexapdf/number_tree_node.rb +1 -1
  146. data/lib/hexapdf/object.rb +32 -27
  147. data/lib/hexapdf/parser.rb +69 -6
  148. data/lib/hexapdf/pdf_array.rb +10 -3
  149. data/lib/hexapdf/rectangle.rb +31 -1
  150. data/lib/hexapdf/reference.rb +1 -1
  151. data/lib/hexapdf/revision.rb +2 -1
  152. data/lib/hexapdf/revisions.rb +30 -22
  153. data/lib/hexapdf/serializer.rb +2 -2
  154. data/lib/hexapdf/stream.rb +1 -1
  155. data/lib/hexapdf/task.rb +1 -1
  156. data/lib/hexapdf/task/dereference.rb +1 -1
  157. data/lib/hexapdf/task/optimize.rb +7 -5
  158. data/lib/hexapdf/tokenizer.rb +5 -4
  159. data/lib/hexapdf/type.rb +1 -1
  160. data/lib/hexapdf/type/acro_form.rb +7 -1
  161. data/lib/hexapdf/type/acro_form/appearance_generator.rb +405 -0
  162. data/lib/hexapdf/type/acro_form/button_field.rb +305 -0
  163. data/lib/hexapdf/type/acro_form/choice_field.rb +220 -0
  164. data/lib/hexapdf/type/acro_form/field.rb +250 -17
  165. data/lib/hexapdf/type/acro_form/form.rb +159 -7
  166. data/lib/hexapdf/type/acro_form/text_field.rb +187 -0
  167. data/lib/hexapdf/type/acro_form/variable_text_field.rb +122 -0
  168. data/lib/hexapdf/type/action.rb +1 -1
  169. data/lib/hexapdf/type/actions.rb +1 -1
  170. data/lib/hexapdf/type/actions/go_to.rb +1 -1
  171. data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
  172. data/lib/hexapdf/type/actions/launch.rb +1 -1
  173. data/lib/hexapdf/type/actions/uri.rb +4 -3
  174. data/lib/hexapdf/type/annotation.rb +73 -3
  175. data/lib/hexapdf/type/annotations.rb +1 -1
  176. data/lib/hexapdf/type/annotations/link.rb +2 -2
  177. data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
  178. data/lib/hexapdf/type/annotations/text.rb +1 -1
  179. data/lib/hexapdf/type/annotations/widget.rb +238 -2
  180. data/lib/hexapdf/type/catalog.rb +23 -3
  181. data/lib/hexapdf/type/cid_font.rb +1 -1
  182. data/lib/hexapdf/type/embedded_file.rb +1 -1
  183. data/lib/hexapdf/type/file_specification.rb +2 -2
  184. data/lib/hexapdf/type/font.rb +18 -1
  185. data/lib/hexapdf/type/font_descriptor.rb +2 -2
  186. data/lib/hexapdf/type/font_simple.rb +4 -2
  187. data/lib/hexapdf/type/font_true_type.rb +7 -3
  188. data/lib/hexapdf/type/font_type0.rb +2 -2
  189. data/lib/hexapdf/type/font_type1.rb +16 -1
  190. data/lib/hexapdf/type/font_type3.rb +1 -1
  191. data/lib/hexapdf/type/form.rb +12 -2
  192. data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
  193. data/lib/hexapdf/type/icon_fit.rb +1 -1
  194. data/lib/hexapdf/type/image.rb +5 -3
  195. data/lib/hexapdf/type/info.rb +1 -1
  196. data/lib/hexapdf/type/names.rb +1 -1
  197. data/lib/hexapdf/type/object_stream.rb +1 -1
  198. data/lib/hexapdf/type/page.rb +36 -12
  199. data/lib/hexapdf/type/page_tree_node.rb +37 -16
  200. data/lib/hexapdf/type/resources.rb +17 -3
  201. data/lib/hexapdf/type/trailer.rb +4 -6
  202. data/lib/hexapdf/type/viewer_preferences.rb +1 -1
  203. data/lib/hexapdf/type/xref_stream.rb +1 -1
  204. data/lib/hexapdf/utils/bit_field.rb +38 -24
  205. data/lib/hexapdf/utils/bit_stream.rb +1 -1
  206. data/lib/hexapdf/utils/graphics_helpers.rb +1 -1
  207. data/lib/hexapdf/utils/lru_cache.rb +1 -1
  208. data/lib/hexapdf/utils/math_helpers.rb +1 -1
  209. data/lib/hexapdf/utils/object_hash.rb +1 -1
  210. data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -1
  211. data/lib/hexapdf/utils/sorted_tree_node.rb +19 -16
  212. data/lib/hexapdf/version.rb +2 -2
  213. data/lib/hexapdf/writer.rb +1 -1
  214. data/lib/hexapdf/xref_section.rb +1 -1
  215. data/test/hexapdf/common_tokenizer_tests.rb +6 -1
  216. data/test/hexapdf/content/common.rb +2 -2
  217. data/test/hexapdf/content/graphic_object/test_arc.rb +4 -4
  218. data/test/hexapdf/content/test_canvas.rb +3 -3
  219. data/test/hexapdf/content/test_color_space.rb +71 -8
  220. data/test/hexapdf/content/test_operator.rb +22 -22
  221. data/test/hexapdf/content/test_parser.rb +14 -0
  222. data/test/hexapdf/document/test_fonts.rb +1 -1
  223. data/test/hexapdf/document/test_pages.rb +6 -6
  224. data/test/hexapdf/encryption/test_aes.rb +4 -4
  225. data/test/hexapdf/encryption/test_standard_security_handler.rb +11 -11
  226. data/test/hexapdf/filter/test_ascii85_decode.rb +1 -1
  227. data/test/hexapdf/filter/test_ascii_hex_decode.rb +1 -1
  228. data/test/hexapdf/font/encoding/test_base.rb +10 -0
  229. data/test/hexapdf/font/encoding/test_difference_encoding.rb +8 -0
  230. data/test/hexapdf/font/test_true_type_wrapper.rb +10 -7
  231. data/test/hexapdf/font/test_type1_wrapper.rb +33 -8
  232. data/test/hexapdf/layout/test_style.rb +1 -1
  233. data/test/hexapdf/layout/test_text_layouter.rb +3 -4
  234. data/test/hexapdf/test_configuration.rb +2 -2
  235. data/test/hexapdf/test_dictionary.rb +3 -1
  236. data/test/hexapdf/test_dictionary_fields.rb +2 -2
  237. data/test/hexapdf/test_document.rb +16 -4
  238. data/test/hexapdf/test_object.rb +44 -26
  239. data/test/hexapdf/test_parser.rb +125 -55
  240. data/test/hexapdf/test_pdf_array.rb +7 -0
  241. data/test/hexapdf/test_rectangle.rb +14 -0
  242. data/test/hexapdf/test_revision.rb +3 -0
  243. data/test/hexapdf/test_revisions.rb +35 -0
  244. data/test/hexapdf/test_writer.rb +2 -2
  245. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +521 -0
  246. data/test/hexapdf/type/acro_form/test_button_field.rb +281 -0
  247. data/test/hexapdf/type/acro_form/test_choice_field.rb +137 -0
  248. data/test/hexapdf/type/acro_form/test_field.rb +163 -6
  249. data/test/hexapdf/type/acro_form/test_form.rb +189 -22
  250. data/test/hexapdf/type/acro_form/test_text_field.rb +121 -0
  251. data/test/hexapdf/type/acro_form/test_variable_text_field.rb +77 -0
  252. data/test/hexapdf/type/annotations/test_text.rb +1 -1
  253. data/test/hexapdf/type/annotations/test_widget.rb +199 -0
  254. data/test/hexapdf/type/test_annotation.rb +45 -0
  255. data/test/hexapdf/type/test_catalog.rb +18 -0
  256. data/test/hexapdf/type/test_font.rb +5 -0
  257. data/test/hexapdf/type/test_font_simple.rb +2 -1
  258. data/test/hexapdf/type/test_font_true_type.rb +6 -0
  259. data/test/hexapdf/type/test_font_type1.rb +8 -0
  260. data/test/hexapdf/type/test_form.rb +19 -1
  261. data/test/hexapdf/type/test_image.rb +7 -0
  262. data/test/hexapdf/type/test_page.rb +45 -7
  263. data/test/hexapdf/type/test_page_tree_node.rb +62 -12
  264. data/test/hexapdf/type/test_resources.rb +20 -0
  265. data/test/hexapdf/type/test_trailer.rb +4 -0
  266. data/test/hexapdf/utils/test_bit_field.rb +15 -1
  267. data/test/hexapdf/utils/test_sorted_tree_node.rb +10 -9
  268. data/test/test_helper.rb +1 -1
  269. metadata +34 -21
  270. data/lib/hexapdf/filter/dct_decode.rb +0 -60
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -48,8 +48,12 @@ module HexaPDF
48
48
  private
49
49
 
50
50
  def perform_validation
51
- super
52
- yield("Required field FontDescriptor is not set", false) if self[:FontDescriptor].nil?
51
+ std_font = FontType1::StandardFonts.standard_font?(self[:BaseFont])
52
+ super(ignore_missing_font_fields: std_font)
53
+
54
+ if self[:FontDescriptor].nil? && !std_font
55
+ yield("Required field FontDescriptor is not set", false)
56
+ end
53
57
  end
54
58
 
55
59
  end
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -59,7 +59,7 @@ module HexaPDF
59
59
  # Returns the CID font of this type 0 font.
60
60
  def descendant_font
61
61
  document.cache(@data, :descendant_font) do
62
- document.wrap(document.deref(self[:DescendantFonts][0]))
62
+ document.wrap(self[:DescendantFonts][0])
63
63
  end
64
64
  end
65
65
 
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -37,6 +37,7 @@
37
37
  require 'hexapdf/data_dir'
38
38
  require 'hexapdf/type/font_simple'
39
39
  require 'hexapdf/font/type1'
40
+ require 'hexapdf/font/type1_wrapper'
40
41
 
41
42
  module HexaPDF
42
43
  module Type
@@ -105,6 +106,20 @@ module HexaPDF
105
106
  define_field :Subtype, type: Symbol, required: true, default: :Type1
106
107
  define_field :BaseFont, type: Symbol, required: true
107
108
 
109
+ # Overrides the default to provide a font wrapper in case none is set and the font is one of
110
+ # the standard fonts.
111
+ #
112
+ # See: Font#font_wrapper
113
+ def font_wrapper
114
+ if (tmp = super)
115
+ tmp
116
+ elsif StandardFonts.standard_font?(self[:BaseFont])
117
+ self.font_wrapper = HexaPDF::Font::Type1Wrapper.new(document,
118
+ StandardFonts.font(self[:BaseFont]),
119
+ pdf_object: self)
120
+ end
121
+ end
122
+
108
123
  # Returns the unscaled width of the given code point in glyph units, or 0 if the width for the
109
124
  # code point is missing.
110
125
  def width(code)
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -101,7 +101,8 @@ module HexaPDF
101
101
 
102
102
  # Returns the resource dictionary which is automatically created if it doesn't exist.
103
103
  def resources
104
- self[:Resources] ||= document.wrap({}, type: :XXResources)
104
+ self[:Resources] ||= document.wrap({ProcSet: [:PDF, :Text, :ImageB, :ImageC, :ImageI]},
105
+ type: :XXResources)
105
106
  end
106
107
 
107
108
  # Processes the content stream of the form XObject with the given processor object.
@@ -126,13 +127,22 @@ module HexaPDF
126
127
  # The canvas object is cached once it is created so that its graphics state is correctly
127
128
  # retained without the need for parsing its contents.
128
129
  #
130
+ # If the bounding box of the form XObject doesn't have its origin at (0, 0), the canvas origin
131
+ # is translated into the bottom left corner so that this detail doesn't matter when using the
132
+ # canvas. This means that the canvas' origin is always at the bottom left corner of the
133
+ # bounding box.
134
+ #
129
135
  # *Note* that a canvas can only be retrieved for initially empty form XObjects!
130
136
  def canvas
131
137
  document.cache(@data, :canvas) do
132
138
  unless stream.empty?
133
139
  raise HexaPDF::Error, "Cannot create a canvas for a form XObjects with contents"
134
140
  end
141
+
135
142
  canvas = Content::Canvas.new(self)
143
+ if box.left != 0 || box.bottom != 0
144
+ canvas.save_graphics_state.translate(box.left, box.bottom)
145
+ end
136
146
  self.stream = canvas.stream_data
137
147
  set_filter(:FlateDecode)
138
148
  canvas
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -150,7 +150,7 @@ module HexaPDF
150
150
  color_space, = *self[:ColorSpace]
151
151
  if color_space == :Indexed
152
152
  result.indexed = true
153
- color_space, = *document.deref(self[:ColorSpace][1])
153
+ color_space, = *self[:ColorSpace][1]
154
154
  end
155
155
  case color_space
156
156
  when :DeviceRGB, :CalRGB
@@ -169,6 +169,8 @@ module HexaPDF
169
169
  result.writable = false if result.type == :png
170
170
  end
171
171
 
172
+ result.writable = false if self[:SMask]
173
+
172
174
  result
173
175
  end
174
176
 
@@ -238,7 +240,7 @@ module HexaPDF
238
240
  end
239
241
 
240
242
  if color_type == ImageLoader::PNG::INDEXED
241
- palette_data = document.deref(self[:ColorSpace][3])
243
+ palette_data = self[:ColorSpace][3]
242
244
  palette_data = palette_data.stream unless palette_data.kind_of?(String)
243
245
  palette = ''.b
244
246
  if info.color_space == :rgb
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -304,7 +304,7 @@ module HexaPDF
304
304
  def contents
305
305
  Array(self[:Contents]).each_with_object("".b) do |content_stream, content|
306
306
  content << " " unless content.empty?
307
- content << document.deref(content_stream).stream
307
+ content << content_stream.stream
308
308
  end
309
309
  end
310
310
 
@@ -323,10 +323,11 @@ module HexaPDF
323
323
  end
324
324
  end
325
325
 
326
- # Returns the possibly inherited resource dictionary which is automatically created if it
326
+ # Returns the, possibly inherited, resource dictionary which is automatically created if it
327
327
  # doesn't exist.
328
328
  def resources
329
- self[:Resources] ||= document.wrap({}, type: :XXResources)
329
+ self[:Resources] ||= document.wrap({ProcSet: [:PDF, :Text, :ImageB, :ImageC, :ImageI]},
330
+ type: :XXResources)
330
331
  end
331
332
 
332
333
  # Processes the content streams associated with the page with the given processor object.
@@ -344,8 +345,7 @@ module HexaPDF
344
345
  node = self
345
346
  while (parent_node = node[:Parent])
346
347
  parent_node[:Kids].each do |kid|
347
- kid = document.deref(kid)
348
- break if kid.data == node.data
348
+ break if kid == node
349
349
  idx += (kid.type == :Page ? 1 : kid[:Count])
350
350
  end
351
351
  node = parent_node
@@ -353,11 +353,26 @@ module HexaPDF
353
353
  idx
354
354
  end
355
355
 
356
+ # Returns all parent nodes of the page up to the root of the page tree.
357
+ #
358
+ # The direct parent is the first node in the array and the root node the last.
359
+ def ancestor_nodes
360
+ parent = self[:Parent]
361
+ result = [parent]
362
+ result << parent while (parent = parent[:Parent])
363
+ result
364
+ end
365
+
356
366
  # Returns the requested type of canvas for the page.
357
367
  #
358
368
  # The canvas object is cached once it is created so that its graphics state is correctly
359
369
  # retained without the need for parsing its contents.
360
370
  #
371
+ # If the media box of the page doesn't have its origin at (0, 0), the canvas origin is
372
+ # translated into the bottom left corner so that this detail doesn't matter when using the
373
+ # canvas. This means that the canvas' origin is always at the bottom left corner of the media
374
+ # box.
375
+ #
361
376
  # type::
362
377
  # Can either be
363
378
  # * :page for getting the canvas for the page itself (only valid for initially empty pages)
@@ -374,16 +389,25 @@ module HexaPDF
374
389
  raise HexaPDF::Error, "Cannot get the canvas for a page with contents"
375
390
  end
376
391
 
392
+ create_canvas = lambda do
393
+ Content::Canvas.new(self).tap do |canvas|
394
+ media_box = box(:media)
395
+ if media_box.left != 0 || media_box.bottom != 0
396
+ canvas.translate(media_box.left, media_box.bottom)
397
+ end
398
+ end
399
+ end
400
+
377
401
  contents = self[:Contents]
378
402
  if contents.nil?
379
- page_canvas = document.cache(@data, :page_canvas, Content::Canvas.new(self))
403
+ page_canvas = document.cache(@data, :page_canvas, create_canvas.call)
380
404
  self[:Contents] = document.add({Filter: :FlateDecode},
381
405
  stream: page_canvas.stream_data)
382
406
  end
383
407
 
384
408
  if type == :overlay || type == :underlay
385
- underlay_canvas = document.cache(@data, :underlay_canvas, Content::Canvas.new(self))
386
- overlay_canvas = document.cache(@data, :overlay_canvas, Content::Canvas.new(self))
409
+ underlay_canvas = document.cache(@data, :underlay_canvas, create_canvas.call)
410
+ overlay_canvas = document.cache(@data, :overlay_canvas, create_canvas.call)
387
411
 
388
412
  stream = HexaPDF::StreamData.new do
389
413
  Fiber.yield(" q ")
@@ -396,11 +420,12 @@ module HexaPDF
396
420
  underlay = document.add({Filter: :FlateDecode}, stream: stream)
397
421
 
398
422
  stream = HexaPDF::StreamData.new do
399
- Fiber.yield(" Q ")
423
+ Fiber.yield(" Q q ")
400
424
  fiber = overlay_canvas.stream_data.fiber
401
425
  while fiber.alive? && (data = fiber.resume)
402
426
  Fiber.yield(data)
403
427
  end
428
+ " Q "
404
429
  end
405
430
  overlay = document.add({Filter: :FlateDecode}, stream: stream)
406
431
 
@@ -448,8 +473,7 @@ module HexaPDF
448
473
  REQUIRED_INHERITABLE_FIELDS.each do |name|
449
474
  next if self[name]
450
475
  yield("Inheritable page field #{name} not set", name == :Resources)
451
- self[:Resources] = {}
452
- self[:Resources].validate(&block)
476
+ resources.validate(&block) if name == :Ressources
453
477
  end
454
478
  end
455
479
 
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -35,6 +35,7 @@
35
35
  #++
36
36
 
37
37
  require 'hexapdf/dictionary'
38
+ require 'hexapdf/error'
38
39
 
39
40
  module HexaPDF
40
41
  module Type
@@ -159,38 +160,58 @@ module HexaPDF
159
160
  end
160
161
 
161
162
  # :call-seq:
162
- # pages.delete_page(page) -> page or nil
163
- # pages.delete_page(index) -> page or nil
163
+ # pages.delete_page(page)
164
+ # pages.delete_page(index)
164
165
  #
165
166
  # Deletes the given page or the page at the position specified by the zero-based index from
166
- # the page tree and returns the deleted page object. If the page was not deleted, +nil+ is
167
- # returned.
168
- #
169
- # Note that the page is *not* deleted from the document itself, only from the page tree! This
170
- # also means that the /Parent entry of the page is set to +nil+ if deleted.
167
+ # the page tree and the document.
171
168
  #
172
169
  # Negative indices count backwards from the end, i.e. -1 is the last page.
173
170
  def delete_page(page)
174
171
  page = self.page(page) if page.kind_of?(Integer)
175
- return nil unless page && page[:Parent]
172
+ return unless page && !page.null? && page[:Parent]
176
173
 
177
174
  parent = page[:Parent]
178
- index = parent[:Kids].index {|kid| kid.data == page.data }
175
+ index = parent[:Kids].index(page)
179
176
 
180
177
  if index
181
- ancestors = [parent]
182
- ancestors << parent while (parent = parent[:Parent])
178
+ ancestors = page.ancestor_nodes
183
179
  return nil unless ancestors.include?(self)
184
180
 
185
181
  page[:Parent][:Kids].delete_at(index)
186
182
  page.delete(:Parent)
183
+ document.delete(page)
187
184
  ancestors.each {|node| node[:Count] -= 1 }
188
- page
189
185
  else
190
- nil
186
+ raise HexaPDF::Error, "Given page not found in page tree"
191
187
  end
192
188
  end
193
189
 
190
+ # :call-seq:
191
+ # pages.move_page(page, to_index)
192
+ # pages.move_page(index, to_index)
193
+ #
194
+ # Moves the given page or the page at the position specified by the zero-based index to the
195
+ # +to_index+ position.
196
+ #
197
+ # If the page that should be moved, doesn't exist or is invalid, an error is raised.
198
+ #
199
+ # Negative indices count backwards from the end, i.e. -1 is the last page. When using a
200
+ # negative index, the page will be moved after that element. So using an index of -1 will
201
+ # move the page after the last page.
202
+ def move_page(page, to_index)
203
+ page = self.page(page) if page.kind_of?(Integer)
204
+ if page.nil? || page.null? || !page[:Parent] ||
205
+ !(ancestors = page.ancestor_nodes).include?(self)
206
+ raise HexaPDF::Error, "The page to be moved doesn't exist in this page tree"
207
+ end
208
+
209
+ parent = page[:Parent]
210
+ insert_page(to_index, page)
211
+ ancestors.each {|node| node[:Count] -= 1 }
212
+ parent[:Kids].delete(page)
213
+ end
214
+
194
215
  # :call-seq:
195
216
  # pages.each_page {|page| block } -> pages
196
217
  # pages.each_page -> Enumerator
@@ -225,7 +246,7 @@ module HexaPDF
225
246
  # Ensures that the /Count and /Parent fields of the whole page tree are set up correctly and
226
247
  # that there is at least one page node. This is therefore only done for the root node of the
227
248
  # page tree!
228
- def perform_validation
249
+ def perform_validation(&block)
229
250
  super
230
251
  return if key?(:Parent)
231
252
 
@@ -258,7 +279,7 @@ module HexaPDF
258
279
 
259
280
  if self[:Count] == 0
260
281
  yield("A PDF document needs at least one page", true)
261
- add_page.validate {|msg, correctable| yield(msg, correctable) }
282
+ add_page.validate(&block)
262
283
  end
263
284
  end
264
285
 
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2019 Thomas Leitner
7
+ # Copyright (C) 2014-2020 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -69,11 +69,10 @@ module HexaPDF
69
69
  when :DeviceRGB, :DeviceGray, :DeviceCMYK
70
70
  GlobalConfiguration.constantize('color_space.map', name).new
71
71
  else
72
- space_definition = self[:ColorSpace] && self[:ColorSpace][name]
72
+ space_definition = (name == :Pattern ? name : self[:ColorSpace]&.[](name))
73
73
  if space_definition.nil?
74
74
  raise HexaPDF::Error, "Color space '#{name}' not found in the resources"
75
75
  elsif space_definition.kind_of?(Array)
76
- space_definition.map! {|item| document.deref(item) }
77
76
  space_family = space_definition[0]
78
77
  else
79
78
  space_family = space_definition
@@ -168,6 +167,20 @@ module HexaPDF
168
167
  object_setter(:Properties, 'P', dict)
169
168
  end
170
169
 
170
+ # Returns the pattern dictionary stored under the given name.
171
+ #
172
+ # If the dictionary is not found, an error is raised.
173
+ def pattern(name)
174
+ object_getter(:Pattern, name)
175
+ end
176
+
177
+ # Adds the pattern dictionary to the resources and returns the name under which it is stored.
178
+ #
179
+ # If there already exists a name for the given dictionary, it is just returned.
180
+ def add_pattern(object)
181
+ object_setter(:Pattern, 'P', object)
182
+ end
183
+
171
184
  private
172
185
 
173
186
  # Helper method for returning an entry of a subdictionary.
@@ -206,6 +219,7 @@ module HexaPDF
206
219
  super
207
220
  val = self[:ProcSet]
208
221
  if !val
222
+ yield("No procedure set specified", true)
209
223
  self[:ProcSet] = [:PDF, :Text, :ImageB, :ImageC, :ImageI]
210
224
  else
211
225
  val.reject! do |name|