hexapdf 0.32.2 → 0.33.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 (202) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +63 -1
  3. data/README.md +9 -0
  4. data/examples/002-graphics.rb +15 -17
  5. data/examples/003-arcs.rb +9 -9
  6. data/examples/009-text_layouter_alignment.rb +1 -1
  7. data/examples/010-text_layouter_inline_boxes.rb +2 -2
  8. data/examples/011-text_layouter_line_wrapping.rb +1 -1
  9. data/examples/012-text_layouter_styling.rb +7 -7
  10. data/examples/013-text_layouter_shapes.rb +1 -1
  11. data/examples/014-text_in_polygon.rb +1 -1
  12. data/examples/015-boxes.rb +8 -7
  13. data/examples/016-frame_automatic_box_placement.rb +2 -2
  14. data/examples/017-frame_text_flow.rb +2 -1
  15. data/examples/018-composer.rb +1 -1
  16. data/examples/020-column_box.rb +2 -1
  17. data/examples/025-table_box.rb +46 -0
  18. data/lib/hexapdf/cli/command.rb +5 -2
  19. data/lib/hexapdf/cli/form.rb +5 -5
  20. data/lib/hexapdf/cli/inspect.rb +3 -3
  21. data/lib/hexapdf/composer.rb +104 -52
  22. data/lib/hexapdf/configuration.rb +44 -39
  23. data/lib/hexapdf/content/canvas.rb +393 -267
  24. data/lib/hexapdf/content/color_space.rb +72 -25
  25. data/lib/hexapdf/content/graphic_object/arc.rb +57 -24
  26. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -23
  27. data/lib/hexapdf/content/graphic_object/geom2d.rb +47 -6
  28. data/lib/hexapdf/content/graphic_object/solid_arc.rb +58 -36
  29. data/lib/hexapdf/content/graphic_object.rb +6 -7
  30. data/lib/hexapdf/content/graphics_state.rb +54 -45
  31. data/lib/hexapdf/content/operator.rb +52 -54
  32. data/lib/hexapdf/content/parser.rb +2 -2
  33. data/lib/hexapdf/content/processor.rb +15 -15
  34. data/lib/hexapdf/content/transformation_matrix.rb +1 -1
  35. data/lib/hexapdf/content.rb +5 -0
  36. data/lib/hexapdf/dictionary.rb +6 -5
  37. data/lib/hexapdf/dictionary_fields.rb +42 -14
  38. data/lib/hexapdf/digital_signature/cms_handler.rb +2 -2
  39. data/lib/hexapdf/digital_signature/handler.rb +1 -1
  40. data/lib/hexapdf/digital_signature/pkcs1_handler.rb +2 -3
  41. data/lib/hexapdf/digital_signature/signature.rb +6 -6
  42. data/lib/hexapdf/digital_signature/signatures.rb +13 -12
  43. data/lib/hexapdf/digital_signature/signing/default_handler.rb +14 -5
  44. data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +2 -4
  45. data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +4 -4
  46. data/lib/hexapdf/digital_signature/signing.rb +4 -0
  47. data/lib/hexapdf/digital_signature/verification_result.rb +2 -2
  48. data/lib/hexapdf/digital_signature.rb +7 -2
  49. data/lib/hexapdf/document/destinations.rb +12 -11
  50. data/lib/hexapdf/document/files.rb +1 -1
  51. data/lib/hexapdf/document/fonts.rb +1 -1
  52. data/lib/hexapdf/document/layout.rb +167 -39
  53. data/lib/hexapdf/document/pages.rb +3 -2
  54. data/lib/hexapdf/document.rb +89 -55
  55. data/lib/hexapdf/encryption/aes.rb +5 -5
  56. data/lib/hexapdf/encryption/arc4.rb +1 -1
  57. data/lib/hexapdf/encryption/fast_aes.rb +2 -2
  58. data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
  59. data/lib/hexapdf/encryption/identity.rb +1 -1
  60. data/lib/hexapdf/encryption/ruby_aes.rb +1 -1
  61. data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
  62. data/lib/hexapdf/encryption/security_handler.rb +31 -24
  63. data/lib/hexapdf/encryption/standard_security_handler.rb +45 -36
  64. data/lib/hexapdf/encryption.rb +7 -2
  65. data/lib/hexapdf/error.rb +18 -0
  66. data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
  67. data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
  68. data/lib/hexapdf/filter/flate_decode.rb +1 -1
  69. data/lib/hexapdf/filter/lzw_decode.rb +1 -1
  70. data/lib/hexapdf/filter/pass_through.rb +1 -1
  71. data/lib/hexapdf/filter/predictor.rb +1 -1
  72. data/lib/hexapdf/filter/run_length_decode.rb +1 -1
  73. data/lib/hexapdf/filter.rb +55 -6
  74. data/lib/hexapdf/font/cmap/parser.rb +2 -2
  75. data/lib/hexapdf/font/cmap.rb +1 -1
  76. data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
  77. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
  78. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +2 -2
  79. data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
  80. data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
  81. data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +3 -3
  82. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
  83. data/lib/hexapdf/font/invalid_glyph.rb +3 -0
  84. data/lib/hexapdf/font/true_type_wrapper.rb +17 -4
  85. data/lib/hexapdf/font/type1_wrapper.rb +19 -4
  86. data/lib/hexapdf/font_loader/from_configuration.rb +5 -2
  87. data/lib/hexapdf/font_loader/from_file.rb +5 -5
  88. data/lib/hexapdf/font_loader/standard14.rb +3 -3
  89. data/lib/hexapdf/font_loader.rb +3 -0
  90. data/lib/hexapdf/image_loader/jpeg.rb +2 -2
  91. data/lib/hexapdf/image_loader/pdf.rb +1 -1
  92. data/lib/hexapdf/image_loader/png.rb +2 -2
  93. data/lib/hexapdf/image_loader.rb +1 -1
  94. data/lib/hexapdf/importer.rb +13 -0
  95. data/lib/hexapdf/layout/box.rb +9 -2
  96. data/lib/hexapdf/layout/box_fitter.rb +2 -2
  97. data/lib/hexapdf/layout/column_box.rb +18 -4
  98. data/lib/hexapdf/layout/frame.rb +30 -12
  99. data/lib/hexapdf/layout/image_box.rb +5 -0
  100. data/lib/hexapdf/layout/inline_box.rb +1 -0
  101. data/lib/hexapdf/layout/list_box.rb +17 -1
  102. data/lib/hexapdf/layout/page_style.rb +4 -4
  103. data/lib/hexapdf/layout/style.rb +18 -3
  104. data/lib/hexapdf/layout/table_box.rb +682 -0
  105. data/lib/hexapdf/layout/text_box.rb +5 -3
  106. data/lib/hexapdf/layout/text_fragment.rb +1 -1
  107. data/lib/hexapdf/layout/text_layouter.rb +12 -4
  108. data/lib/hexapdf/layout.rb +1 -0
  109. data/lib/hexapdf/name_tree_node.rb +1 -1
  110. data/lib/hexapdf/number_tree_node.rb +1 -1
  111. data/lib/hexapdf/object.rb +18 -7
  112. data/lib/hexapdf/parser.rb +7 -7
  113. data/lib/hexapdf/pdf_array.rb +1 -1
  114. data/lib/hexapdf/rectangle.rb +1 -1
  115. data/lib/hexapdf/reference.rb +1 -1
  116. data/lib/hexapdf/revision.rb +1 -1
  117. data/lib/hexapdf/revisions.rb +3 -3
  118. data/lib/hexapdf/serializer.rb +15 -15
  119. data/lib/hexapdf/stream.rb +4 -2
  120. data/lib/hexapdf/tokenizer.rb +14 -14
  121. data/lib/hexapdf/type/acro_form/appearance_generator.rb +22 -22
  122. data/lib/hexapdf/type/acro_form/button_field.rb +1 -1
  123. data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
  124. data/lib/hexapdf/type/acro_form/field.rb +2 -2
  125. data/lib/hexapdf/type/acro_form/form.rb +1 -1
  126. data/lib/hexapdf/type/acro_form/signature_field.rb +4 -4
  127. data/lib/hexapdf/type/acro_form/text_field.rb +1 -1
  128. data/lib/hexapdf/type/acro_form/variable_text_field.rb +1 -1
  129. data/lib/hexapdf/type/acro_form.rb +1 -1
  130. data/lib/hexapdf/type/action.rb +1 -1
  131. data/lib/hexapdf/type/actions/go_to.rb +1 -1
  132. data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
  133. data/lib/hexapdf/type/actions/launch.rb +1 -1
  134. data/lib/hexapdf/type/actions/uri.rb +1 -1
  135. data/lib/hexapdf/type/actions.rb +1 -1
  136. data/lib/hexapdf/type/annotation.rb +3 -3
  137. data/lib/hexapdf/type/annotations/link.rb +1 -1
  138. data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
  139. data/lib/hexapdf/type/annotations/text.rb +1 -1
  140. data/lib/hexapdf/type/annotations/widget.rb +2 -2
  141. data/lib/hexapdf/type/annotations.rb +1 -1
  142. data/lib/hexapdf/type/catalog.rb +1 -1
  143. data/lib/hexapdf/type/cid_font.rb +3 -3
  144. data/lib/hexapdf/type/embedded_file.rb +1 -1
  145. data/lib/hexapdf/type/file_specification.rb +2 -2
  146. data/lib/hexapdf/type/font_descriptor.rb +1 -1
  147. data/lib/hexapdf/type/font_simple.rb +2 -2
  148. data/lib/hexapdf/type/font_type0.rb +3 -3
  149. data/lib/hexapdf/type/font_type3.rb +1 -1
  150. data/lib/hexapdf/type/form.rb +1 -1
  151. data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
  152. data/lib/hexapdf/type/icon_fit.rb +1 -1
  153. data/lib/hexapdf/type/image.rb +1 -1
  154. data/lib/hexapdf/type/info.rb +1 -1
  155. data/lib/hexapdf/type/mark_information.rb +1 -1
  156. data/lib/hexapdf/type/names.rb +2 -2
  157. data/lib/hexapdf/type/object_stream.rb +2 -1
  158. data/lib/hexapdf/type/outline.rb +1 -1
  159. data/lib/hexapdf/type/outline_item.rb +1 -1
  160. data/lib/hexapdf/type/page.rb +19 -10
  161. data/lib/hexapdf/type/page_label.rb +1 -1
  162. data/lib/hexapdf/type/page_tree_node.rb +1 -1
  163. data/lib/hexapdf/type/resources.rb +1 -1
  164. data/lib/hexapdf/type/trailer.rb +2 -2
  165. data/lib/hexapdf/type/viewer_preferences.rb +1 -1
  166. data/lib/hexapdf/type/xref_stream.rb +2 -2
  167. data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -1
  168. data/lib/hexapdf/version.rb +1 -1
  169. data/lib/hexapdf/writer.rb +4 -4
  170. data/lib/hexapdf/xref_section.rb +2 -2
  171. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +11 -1
  172. data/test/hexapdf/content/graphic_object/test_geom2d.rb +7 -0
  173. data/test/hexapdf/content/test_canvas.rb +0 -1
  174. data/test/hexapdf/digital_signature/test_signatures.rb +22 -0
  175. data/test/hexapdf/document/test_files.rb +2 -2
  176. data/test/hexapdf/document/test_layout.rb +98 -0
  177. data/test/hexapdf/encryption/test_security_handler.rb +12 -11
  178. data/test/hexapdf/encryption/test_standard_security_handler.rb +35 -23
  179. data/test/hexapdf/font/test_true_type_wrapper.rb +18 -1
  180. data/test/hexapdf/font/test_type1_wrapper.rb +15 -1
  181. data/test/hexapdf/layout/test_box.rb +1 -1
  182. data/test/hexapdf/layout/test_column_box.rb +65 -21
  183. data/test/hexapdf/layout/test_frame.rb +14 -14
  184. data/test/hexapdf/layout/test_image_box.rb +4 -0
  185. data/test/hexapdf/layout/test_inline_box.rb +5 -0
  186. data/test/hexapdf/layout/test_list_box.rb +40 -6
  187. data/test/hexapdf/layout/test_page_style.rb +3 -2
  188. data/test/hexapdf/layout/test_style.rb +50 -0
  189. data/test/hexapdf/layout/test_table_box.rb +722 -0
  190. data/test/hexapdf/layout/test_text_box.rb +18 -0
  191. data/test/hexapdf/layout/test_text_layouter.rb +4 -0
  192. data/test/hexapdf/test_dictionary_fields.rb +4 -1
  193. data/test/hexapdf/test_document.rb +1 -0
  194. data/test/hexapdf/test_filter.rb +8 -0
  195. data/test/hexapdf/test_importer.rb +9 -0
  196. data/test/hexapdf/test_object.rb +16 -5
  197. data/test/hexapdf/test_stream.rb +7 -0
  198. data/test/hexapdf/test_writer.rb +3 -3
  199. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +13 -5
  200. data/test/hexapdf/type/acro_form/test_form.rb +4 -3
  201. data/test/hexapdf/type/test_page.rb +18 -4
  202. metadata +17 -8
@@ -51,17 +51,18 @@ module HexaPDF
51
51
  # On creation a HexaPDF::Document object is created as well the first page and an accompanying
52
52
  # HexaPDF::Layout::Frame object. The frame is used by the various methods for general document
53
53
  # layout tasks, like positioning of text, images, and so on. By default, it covers the whole page
54
- # except the margin area. How the frame gets created can be customized by overriding the
55
- # #create_frame method.
54
+ # except the margin area. How the frame gets created can be customized by defining a custom page
55
+ # style, see #page_style. Use the +skip_page_creation+ argument to avoid the initial page
56
+ # creation when creating a Composer instance.
56
57
  #
57
58
  # Once the Composer object is created, its methods can be used to draw text, images, ... on the
58
- # page. Behind the scenes HexaPDF::Layout::Box (and subclass) objects are created and drawn on the
59
- # page via the frame.
59
+ # page. Behind the scenes HexaPDF::Layout::Box (and subclass) objects are created using the
60
+ # HexaPDF::Document::Layout methods and drawn on the page via the frame.
60
61
  #
61
62
  # If the frame of a page is full and a box doesn't fit anymore, a new page is automatically
62
63
  # created. The box is either split into two boxes where one fits on the first page and the other
63
64
  # on the new page, or it is drawn completely on the new page. A new page can also be created by
64
- # calling the #new_page method.
65
+ # calling the #new_page method, optionally providing a page style.
65
66
  #
66
67
  # The #x and #y methods provide the point where the next box would be drawn if it fits the
67
68
  # available space. This information can be used, for example, for custom drawing operations
@@ -75,30 +76,36 @@ module HexaPDF
75
76
  #
76
77
  # == Example
77
78
  #
78
- # HexaPDF::Composer.create('output.pdf', margin: 36) do |pdf|
79
- # pdf.base_style.font_size(20).align(:center)
79
+ # #>pdf-full
80
+ # HexaPDF::Composer.create('out.pdf', page_size: :A6, margin: 36) do |pdf|
81
+ # pdf.style(:base, font_size: 20, align: :center)
80
82
  # pdf.text("Hello World", valign: :center)
81
83
  # end
84
+ #
85
+ # See: HexaPDF::Document::Layout, HexaPDF::Layout::Frame, HexaPDF::Layout::Box
82
86
  class Composer
83
87
 
84
- # Creates a new PDF document and writes it to +output+. The +options+ are passed to ::new.
88
+ # Creates a new PDF document and writes it to +output+. The argument +options+ and +block+ are
89
+ # passed to ::new.
85
90
  #
86
91
  # Example:
87
92
  #
88
- # HexaPDF::Composer.create('output.pdf', margin: 36) do |pdf|
93
+ # HexaPDF::Composer.create('out.pdf', margin: 36) do |pdf|
89
94
  # ...
90
95
  # end
91
96
  def self.create(output, **options, &block)
92
97
  new(**options, &block).write(output)
93
98
  end
94
99
 
95
- # The PDF document that is created.
100
+ # The PDF document (HexaPDF::Document) that is created.
96
101
  attr_reader :document
97
102
 
98
103
  # The current page (a HexaPDF::Type::Page object).
99
104
  attr_reader :page
100
105
 
101
- # The Content::Canvas of the current page. Can be used to perform arbitrary drawing operations.
106
+ # The canvas instance (a Content::Canvas object) of the current page.
107
+ #
108
+ # Can be used to perform arbitrary drawing operations.
102
109
  attr_reader :canvas
103
110
 
104
111
  # The HexaPDF::Layout::Frame for automatic box placement.
@@ -107,43 +114,53 @@ module HexaPDF
107
114
  # Creates a new Composer object and optionally yields it to the given block.
108
115
  #
109
116
  # skip_page_creation::
110
- # If this argument is +true+ (the default), the arguments +page_size+, +page_orientation+
111
- # and +margin+ are used to create a page style with the name :default and an initial page is
112
- # created as well.
117
+ # If this argument is +false+ (the default), the arguments +page_size+, +page_orientation+
118
+ # and +margin+ are used to create a page style with the name :default. Additionally, an
119
+ # initial page/frame is created using this page style.
113
120
  #
114
- # Otherwise, i.e. when this argument is +false+, no initial page or default page style is
115
- # created. This has to be done manually using the #page_style and #new_page methods.
121
+ # Otherwise, i.e. when this argument is +true+, no initial page or default page style is
122
+ # created. This is useful when the first page needs a custom page style. The #page_style
123
+ # method needs to be used to define a page style which is then used with the #new_page
124
+ # method to create the initial page/frame.
116
125
  #
117
126
  # page_size::
118
127
  # Can be any valid predefined page size (see Type::Page::PAPER_SIZE) or an array [llx, lly,
119
128
  # urx, ury] specifying a custom page size.
120
129
  #
130
+ # Only used if +skip_page_creation+ is +false+.
131
+ #
121
132
  # page_orientation::
122
- # Specifies the orientation of the page, either +:portrait+ or +:landscape+. Only used if
123
- # +page_size+ is one of the predefined page sizes.
133
+ # Specifies the orientation of the page, either +:portrait+ or +:landscape+, if +page_size+
134
+ # is one of the predefined page sizes.
135
+ #
136
+ # Only used if +skip_page_creation+ is +false+.
124
137
  #
125
138
  # margin::
126
139
  # The margin to use. See HexaPDF::Layout::Style::Quad#set for possible values.
127
140
  #
141
+ # Only used if +skip_page_creation+ is +false+.
142
+ #
128
143
  # Example:
129
144
  #
130
- # composer = HexaPDF::Composer.new # uses the default values
145
+ # # Uses the default values
146
+ # composer = HexaPDF::Composer.new
131
147
  #
132
148
  # HexaPDF::Composer.new(page_size: :Letter, margin: 72) do |composer|
133
149
  # #...
134
150
  # end
135
151
  #
136
152
  # HexaPDF::Composer.new(skip_page_creation: true) do |composer|
137
- # page_template = lambda {|canvas, style| style.create_frame(canvas.context, 36) }
138
- # page_style(:default, template: page_template)
139
- # new_page
153
+ # composer.page_style(:default) do |canvas, style|
154
+ # style.frame = style.create_frame(canvas.context, 36)
155
+ # end
156
+ # composer.new_page
140
157
  # # ...
141
158
  # end
142
159
  def initialize(skip_page_creation: false, page_size: :A4, page_orientation: :portrait,
143
160
  margin: 36) #:yields: composer
144
161
  @document = HexaPDF::Document.new
145
162
  @page_styles = {}
146
- @page_style = :default
163
+ @next_page_style = :default
147
164
  unless skip_page_creation
148
165
  page_style(:default, page_size: page_size, orientation: page_orientation) do |canvas, style|
149
166
  style.frame = style.create_frame(canvas.context, margin)
@@ -155,41 +172,61 @@ module HexaPDF
155
172
 
156
173
  # Creates a new page, making it the current one.
157
174
  #
158
- # The page style to use for the new page can be set via the +style+ argument. If not provided,
159
- # the currently set page style is used.
175
+ # The page style (see #page_style) to use for the new page can be set via the +style+ argument.
176
+ # If not provided, the currently set page style is used (:default is the initial value for
177
+ # @next_page_style).
160
178
  #
161
- # The used page style determines the page style that should be used for the following new pages.
162
- # If this information is not provided, the used page style is used again.
179
+ # The applied page style determines the page style that should be used for the following new
180
+ # pages (see Layout::PageStyle#next_style). If this information is not provided by the applied
181
+ # page style, that page style is used again.
163
182
  #
164
183
  # Examples:
165
184
  #
166
- # composer.page_style(:cover, page_size: :A4).next_style = :content
185
+ # # Define two page styles
186
+ # composer.page_style(:cover, page_size: :A4, next_style: :content)
167
187
  # composer.page_style(:content, page_size: :A4)
188
+ #
168
189
  # composer.new_page(:cover) # uses the :cover style, set next style to :content
169
190
  # composer.new_page # uses the :content style, next style again :content
170
- def new_page(style = @page_style)
191
+ def new_page(style = @next_page_style)
171
192
  page_style = @page_styles.fetch(style) do |key|
172
193
  raise ArgumentError, "Page style #{key} has not been defined"
173
194
  end
174
195
  @page = @document.pages.add(page_style.create_page(@document))
175
196
  @canvas = @page.canvas
176
197
  @frame = page_style.frame
177
- @page_style = page_style.next_style || style
198
+ @next_page_style = page_style.next_style || style
178
199
  end
179
200
 
180
- # The x-position of the cursor inside the current frame.
201
+ # The x-position inside the current frame where the next box (provided it fits) will be placed.
202
+ #
203
+ # Example:
204
+ #
205
+ # #>pdf-composer
206
+ # composer.text("Hello", position: :float)
207
+ # composer.canvas.stroke_color("hp-blue").
208
+ # circle(composer.x, composer.y, 0.5).fill.
209
+ # circle(composer.x, composer.y, 5).stroke
181
210
  def x
182
211
  @frame.x
183
212
  end
184
213
 
185
- # The y-position of the cursor inside the current frame.
214
+ # The y-position inside the current frame.where the next box (provided it fits) will be placed.
215
+ #
216
+ # Example:
217
+ #
218
+ # #>pdf-composer
219
+ # composer.text("Hello", position: :float)
220
+ # composer.canvas.stroke_color("hp-blue").
221
+ # circle(composer.x, composer.y, 0.5).fill.
222
+ # circle(composer.x, composer.y, 5).stroke
186
223
  def y
187
224
  @frame.y
188
225
  end
189
226
 
190
- # Writes the PDF document to the given output.
227
+ # Writes the created PDF document to the given output.
191
228
  #
192
- # See Document#write for details.
229
+ # See HexaPDF::Document#write for details.
193
230
  def write(output, optimize: true, **options)
194
231
  @document.write(output, optimize: optimize, **options)
195
232
  end
@@ -201,6 +238,8 @@ module HexaPDF
201
238
  # Creates or updates the HexaPDF::Layout::Style object called +name+ with the given property
202
239
  # values and returns it.
203
240
  #
241
+ # If neither +base+ nor any style properties are specified, the style +name+ is just returned.
242
+ #
204
243
  # See HexaPDF::Document::Layout#style for details; this method is just a thin wrapper around
205
244
  # that method.
206
245
  #
@@ -225,15 +264,15 @@ module HexaPDF
225
264
  # +nil+ is returned.
226
265
  #
227
266
  # If one or more page style attributes are given, a new HexaPDF::Layout::PageStyle object with
228
- # those attribute values is created, stored under +name+ and returned. If a block is provided,
229
- # it is used to define the page template.
267
+ # those attribute values is created, stored under +name+ and returned. Additionally, if a block
268
+ # is provided, it is used to define the page template.
230
269
  #
231
270
  # Example:
232
271
  #
233
272
  # composer.page_style(:default)
234
273
  # composer.page_style(:cover, page_size: :A4) do |canvas, style|
235
274
  # page_box = canvas.context.box
236
- # canvas.fill_color("fd0") do
275
+ # canvas.fill_color("green") do
237
276
  # canvas.rectangle(0, 0, page_box.width, page_box.height).
238
277
  # fill
239
278
  # end
@@ -251,9 +290,9 @@ module HexaPDF
251
290
 
252
291
  # Draws the given text at the current position into the current frame.
253
292
  #
254
- # The text will be positioned at the current position if possible. Otherwise the next best
255
- # position is used. If the text doesn't fit onto the current page or only partially, new pages
256
- # are created automatically.
293
+ # The text will be positioned at the current position (see #x and #y) if possible. Otherwise the
294
+ # next best position is used. If the text doesn't fit onto the current page or only partially,
295
+ # one or more new pages are created automatically.
257
296
  #
258
297
  # This method is of the two main methods for creating text boxes, the other being
259
298
  # #formatted_text. It uses HexaPDF::Document::Layout#text_box behind the scenes to create the
@@ -264,18 +303,21 @@ module HexaPDF
264
303
  # Examples:
265
304
  #
266
305
  # #>pdf-composer
267
- # composer.text("Test " * 15)
306
+ # composer.text("Test it now " * 15)
268
307
  # composer.text("Now " * 7, width: 100)
269
- # composer.text("Another test", font_size: 15, fill_color: "green")
308
+ # composer.text("Another test", font_size: 15, fill_color: "hp-blue")
270
309
  # composer.text("Different box style", fill_color: 'white', box_style: {
271
310
  # underlays: [->(c, b) { c.rectangle(0, 0, b.content_width, b.content_height).fill }]
272
311
  # })
312
+ #
313
+ # See: #formatted_text, HexaPDF::Layout::TextBox, HexaPDF::Layout::TextFragment
273
314
  def text(str, width: 0, height: 0, style: nil, box_style: nil, **style_properties)
274
315
  draw_box(@document.layout.text_box(str, width: width, height: height, style: style,
275
316
  box_style: box_style, **style_properties))
276
317
  end
277
318
 
278
- # Draws text like #text but allows parts of the text to be formatted differently.
319
+ # Draws text like #text but allows parts of the text to be formatted differently and
320
+ # interspersing with inline boxes.
279
321
  #
280
322
  # It uses HexaPDF::Document::Layout#formatted_text_box behind the scenes to create the
281
323
  # HexaPDF::Layout::TextBox that does the actual work. See that method for details on the
@@ -285,10 +327,13 @@ module HexaPDF
285
327
  #
286
328
  # #>pdf-composer
287
329
  # composer.formatted_text(["Some string"])
288
- # composer.formatted_text(["Some ", {text: "string", fill_color: 128}])
330
+ # composer.formatted_text(["Some ", {text: "string", fill_color: "hp-orange"}])
289
331
  # composer.formatted_text(["Some ", {link: "https://example.com",
290
- # fill_color: 'blue', text: "Example"}])
332
+ # fill_color: 'hp-blue', text: "Example"}])
291
333
  # composer.formatted_text(["Some ", {text: "string", style: {font_size: 20}}])
334
+ # block = lambda {|list| list.text("First item"); list.text("Second item") }
335
+ # composer.formatted_text(["Some ", {box: :list, width: 50,
336
+ # valign: :bottom, block: block}])
292
337
  #
293
338
  # See: #text, HexaPDF::Layout::TextBox, HexaPDF::Layout::TextFragment
294
339
  def formatted_text(data, width: 0, height: 0, style: nil, box_style: nil, **style_properties)
@@ -296,7 +341,7 @@ module HexaPDF
296
341
  box_style: box_style, **style_properties))
297
342
  end
298
343
 
299
- # Draws the given image at the current position.
344
+ # Draws the given image at the current position (see #x and #y).
300
345
  #
301
346
  # It uses HexaPDF::Document::Layout#image_box behind the scenes to create the
302
347
  # HexaPDF::Layout::ImageBox that does the actual work. See that method for details on the
@@ -314,7 +359,7 @@ module HexaPDF
314
359
  style: style, **style_properties))
315
360
  end
316
361
 
317
- # Draws the named box at the current position.
362
+ # Draws the named box at the current position (see #x and #y).
318
363
  #
319
364
  # It uses HexaPDF::Document::Layout#box behind the scenes to create the named box. See that
320
365
  # method for details on the arguments.
@@ -331,11 +376,19 @@ module HexaPDF
331
376
 
332
377
  # Draws any custom box that can be created using HexaPDF::Document::Layout.
333
378
  #
379
+ # This includes all named boxes defined in the 'layout.boxes.map' configuration option.
380
+ #
334
381
  # Examples:
335
382
  #
336
383
  # #>pdf-composer
337
- # composer.lorem_ipsum
338
- # composer.column {|column| column.lorem_ipsum }
384
+ # composer.lorem_ipsum(sentences: 1, margin: [0, 0, 5])
385
+ # composer.list(item_spacing: 2) do |list|
386
+ # composer.document.config['layout.boxes.map'].each do |name, klass|
387
+ # list.formatted_text([{text: name.to_s, fill_color: "hp-blue-dark"}, "\n#{klass}"])
388
+ # end
389
+ # end
390
+ #
391
+ # See: HexaPDF::Document::Layout#box
339
392
  def method_missing(name, *args, **kwargs, &block)
340
393
  if @document.layout.box_creation_method?(name)
341
394
  draw_box(@document.layout.send(name, *args, **kwargs, &block))
@@ -344,8 +397,7 @@ module HexaPDF
344
397
  end
345
398
  end
346
399
 
347
- # :nodoc:
348
- def respond_to_missing?(name, _private)
400
+ def respond_to_missing?(name, _private) # :nodoc:
349
401
  @document.layout.box_creation_method?(name) || super
350
402
  end
351
403
 
@@ -393,7 +445,7 @@ module HexaPDF
393
445
  #
394
446
  # #>pdf-composer
395
447
  # stamp = composer.create_stamp(50, 50) do |canvas|
396
- # canvas.fill_color("red").line_width(5).
448
+ # canvas.fill_color("hp-blue").line_width(5).
397
449
  # rectangle(10, 10, 30, 30).fill_stroke
398
450
  # end
399
451
  # composer.image(stamp, width: 20, height: 20)
@@ -44,12 +44,12 @@ module HexaPDF
44
44
  # == Overview
45
45
  #
46
46
  # HexaPDF allows detailed control over many aspects of PDF manipulation. If there is a need to
47
- # use a certain default value somewhere, it is defined as configuration options so that it can
47
+ # use a certain default value somewhere, it is defined as a configuration option so that it can
48
48
  # easily be changed.
49
49
  #
50
50
  # Some options are defined as global options because they are needed on the class level - see
51
- # HexaPDF::GlobalConfiguration[index.html#GlobalConfiguration]. Other options can be configured for
52
- # individual documents as they allow to fine-tune some behavior - see
51
+ # HexaPDF::GlobalConfiguration[index.html#GlobalConfiguration]. Other options can be configured
52
+ # for individual documents as they allow to fine-tune some behavior - see
53
53
  # HexaPDF::DefaultDocumentConfiguration[index.html#DefaultDocumentConfiguration].
54
54
  #
55
55
  # A configuration option name is dot-separted to provide a hierarchy of option names. For
@@ -155,9 +155,6 @@ module HexaPDF
155
155
  # A boolean specifying whether an AcroForm field's appearances should automatically be
156
156
  # generated if they are missing.
157
157
  #
158
- # acro_form.text_field.default_width::
159
- # A number specifying the default width of AcroForm text fields which should be auto-sized.
160
- #
161
158
  # acro_form.default_font_size::
162
159
  # A number specifying the default font size of AcroForm text fields which should be auto-sized.
163
160
  #
@@ -248,7 +245,7 @@ module HexaPDF
248
245
  #
249
246
  # The most often used filters are implemented and readily available.
250
247
  #
251
- # See PDF1.7 s7.4.1, ADB sH.3 3.3
248
+ # See PDF2.0 s7.4.1, ADB sH.3 3.3
252
249
  #
253
250
  # font.map::
254
251
  # Defines a mapping from font names and variants to font files.
@@ -278,7 +275,14 @@ module HexaPDF
278
275
  # was called, you can use +font_wrapper.pdf_object.document+.
279
276
  #
280
277
  # The default implementation returns an object of class HexaPDF::Font::InvalidGlyph which, when
281
- # not removed before encoding, will raise an error.
278
+ # not removed before encoding, will raise a HexaPDF::MissingGlyphError.
279
+ #
280
+ # If a replacement glyph should be displayed instead of an error, the following provides a good
281
+ # starting implementation:
282
+ #
283
+ # doc.config['font.on_missing_glyph'] = lambda do |character, font_wrapper|
284
+ # font_wrapper.custom_glyph(font_wrapper.font_type == :Type1 ? :question : 0, character)
285
+ # end
282
286
  #
283
287
  # font.on_missing_unicode_mapping::
284
288
  # Callback hook when a character code point cannot be converted to a Unicode character.
@@ -298,11 +302,6 @@ module HexaPDF
298
302
  #
299
303
  # See the HexaPDF::FontLoader module for information on how to implement a font loader object.
300
304
  #
301
- # graphic_object.map::
302
- # A mapping from graphic object names to graphic object factories.
303
- #
304
- # See HexaPDF::Content::GraphicObject for more information.
305
- #
306
305
  # graphic_object.arc.max_curves::
307
306
  # The maximum number of curves used for approximating a complete ellipse using Bezier curves.
308
307
  #
@@ -310,6 +309,11 @@ module HexaPDF
310
309
  # to compute. It should not be set to values lower than 4, otherwise the approximation of a
311
310
  # complete ellipse is visibly false.
312
311
  #
312
+ # graphic_object.map::
313
+ # A mapping from graphic object names to graphic object factories.
314
+ #
315
+ # See HexaPDF::Content::GraphicObject for more information.
316
+ #
313
317
  # image_loader::
314
318
  # An array with image loader implementations. When an image should be loaded, the array is
315
319
  # iterated in sequence to find a suitable image loader.
@@ -381,14 +385,6 @@ module HexaPDF
381
385
  #
382
386
  # Defaults to +true+.
383
387
  #
384
- # sorted_tree.max_leaf_node_size::
385
- # The maximum number of nodes that should be in a leaf node of a node tree.
386
- #
387
- # style.layers_map::
388
- # A mapping from style layer names to layer objects.
389
- #
390
- # See HexaPDF::Layout::Style::Layers for more information.
391
- #
392
388
  # signature.signing_handler::
393
389
  # A mapping from a Symbol to a signing handler class (see
394
390
  # HexaPDF::Document::Signatures::DefaultHandler). If the value is a String, it should contain
@@ -403,6 +399,14 @@ module HexaPDF
403
399
  # filter value of a signature dictionary is ignored since we only support the standard
404
400
  # signature algorithms.
405
401
  #
402
+ # sorted_tree.max_leaf_node_size::
403
+ # The maximum number of nodes that should be in a leaf node of a node tree.
404
+ #
405
+ # style.layers_map::
406
+ # A mapping from style layer names to layer objects.
407
+ #
408
+ # See HexaPDF::Layout::Style::Layers for more information.
409
+ #
406
410
  # task.map::
407
411
  # A mapping from task names to callable task objects. See HexaPDF::Task for more information.
408
412
  DefaultDocumentConfiguration =
@@ -459,13 +463,13 @@ module HexaPDF
459
463
  'HexaPDF::FontLoader::FromConfiguration',
460
464
  'HexaPDF::FontLoader::FromFile',
461
465
  ],
466
+ 'graphic_object.arc.max_curves' => 6,
462
467
  'graphic_object.map' => {
463
468
  arc: 'HexaPDF::Content::GraphicObject::Arc',
464
469
  endpoint_arc: 'HexaPDF::Content::GraphicObject::EndpointArc',
465
470
  solid_arc: 'HexaPDF::Content::GraphicObject::SolidArc',
466
471
  geom2d: 'HexaPDF::Content::GraphicObject::Geom2D',
467
472
  },
468
- 'graphic_object.arc.max_curves' => 6,
469
473
  'image_loader' => [
470
474
  'HexaPDF::ImageLoader::JPEG',
471
475
  'HexaPDF::ImageLoader::PNG',
@@ -479,15 +483,12 @@ module HexaPDF
479
483
  image: 'HexaPDF::Layout::ImageBox',
480
484
  column: 'HexaPDF::Layout::ColumnBox',
481
485
  list: 'HexaPDF::Layout::ListBox',
486
+ table: 'HexaPDF::Layout::TableBox',
482
487
  },
483
488
  'page.default_media_box' => :A4,
484
489
  'page.default_media_orientation' => :portrait,
485
490
  'parser.on_correctable_error' => proc { false },
486
491
  'parser.try_xref_reconstruction' => true,
487
- 'sorted_tree.max_leaf_node_size' => 64,
488
- 'style.layers_map' => {
489
- link: 'HexaPDF::Layout::Style::LinkLayer',
490
- },
491
492
  'signature.signing_handler' => {
492
493
  default: 'HexaPDF::DigitalSignature::Signing::DefaultHandler',
493
494
  timestamp: 'HexaPDF::DigitalSignature::Signing::TimestampHandler',
@@ -498,6 +499,10 @@ module HexaPDF
498
499
  'ETSI.CAdES.detached': 'HexaPDF::DigitalSignature::CMSHandler',
499
500
  'ETSI.RFC3161': 'HexaPDF::DigitalSignature::CMSHandler',
500
501
  },
502
+ 'sorted_tree.max_leaf_node_size' => 64,
503
+ 'style.layers_map' => {
504
+ link: 'HexaPDF::Layout::Style::LinkLayer',
505
+ },
501
506
  'task.map' => {
502
507
  optimize: 'HexaPDF::Task::Optimize',
503
508
  dereference: 'HexaPDF::Task::Dereference',
@@ -512,12 +517,19 @@ module HexaPDF
512
517
  #
513
518
  # Classes for the most often used color space families are implemented and readily available.
514
519
  #
515
- # See PDF1.7 s8.6
520
+ # See PDF2.0 s8.6
516
521
  #
517
522
  # filter.flate.compression::
518
523
  # Specifies the compression level that should be used with the FlateDecode filter. The level
519
524
  # can range from 0 (no compression), 1 (best speed) to 9 (best compression, default).
520
525
  #
526
+ # filter.flate.memory::
527
+ # Specifies the memory level that should be used with the FlateDecode filter. The level can
528
+ # range from 1 (minimum memory usage; slow, reduces compression) to 9 (maximum memory usage).
529
+ #
530
+ # The HexaPDF default value of 6 has been found in tests to be nearly equivalent to the Zlib
531
+ # default of 8 in terms of speed and compression level but uses less memory.
532
+ #
521
533
  # filter.flate.on_error::
522
534
  # Callback hook when a potentially recoverable Zlib error occurs in the FlateDecode filter.
523
535
  #
@@ -527,13 +539,6 @@ module HexaPDF
527
539
  #
528
540
  # The default implementation prevents errors from being raised.
529
541
  #
530
- # filter.flate.memory::
531
- # Specifies the memory level that should be used with the FlateDecode filter. The level can
532
- # range from 1 (minimum memory usage; slow, reduces compression) to 9 (maximum memory usage).
533
- #
534
- # The HexaPDF default value of 6 has been found in tests to be nearly equivalent to the Zlib
535
- # default of 8 in terms of speed and compression level but uses less memory.
536
- #
537
542
  # filter.predictor.strict::
538
543
  # Specifies whether the predictor algorithm used by LZWDecode and FlateDecode should operate in
539
544
  # strict mode, i.e. adhering to the PDF specification without correcting for common deficiences
@@ -555,15 +560,15 @@ module HexaPDF
555
560
  # This mapping is used to provide automatic wrapping of objects in the HexaPDF::Document#wrap
556
561
  # method.
557
562
  GlobalConfiguration =
558
- Configuration.new('filter.flate.compression' => 9,
559
- 'filter.flate.on_error' => proc { false },
560
- 'filter.flate.memory' => 6,
561
- 'filter.predictor.strict' => false,
562
- 'color_space.map' => {
563
+ Configuration.new('color_space.map' => {
563
564
  DeviceRGB: 'HexaPDF::Content::ColorSpace::DeviceRGB',
564
565
  DeviceCMYK: 'HexaPDF::Content::ColorSpace::DeviceCMYK',
565
566
  DeviceGray: 'HexaPDF::Content::ColorSpace::DeviceGray',
566
567
  },
568
+ 'filter.flate.compression' => 9,
569
+ 'filter.flate.memory' => 6,
570
+ 'filter.flate.on_error' => proc { false },
571
+ 'filter.predictor.strict' => false,
567
572
  'object.type_map' => {
568
573
  XRef: 'HexaPDF::Type::XRefStream',
569
574
  ObjStm: 'HexaPDF::Type::ObjectStream',