hexapdf 0.32.1 → 0.33.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (205) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +76 -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/cli.rb +4 -0
  22. data/lib/hexapdf/composer.rb +104 -52
  23. data/lib/hexapdf/configuration.rb +44 -39
  24. data/lib/hexapdf/content/canvas.rb +393 -267
  25. data/lib/hexapdf/content/color_space.rb +72 -25
  26. data/lib/hexapdf/content/graphic_object/arc.rb +57 -24
  27. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -23
  28. data/lib/hexapdf/content/graphic_object/geom2d.rb +47 -6
  29. data/lib/hexapdf/content/graphic_object/solid_arc.rb +58 -36
  30. data/lib/hexapdf/content/graphic_object.rb +6 -7
  31. data/lib/hexapdf/content/graphics_state.rb +54 -45
  32. data/lib/hexapdf/content/operator.rb +52 -54
  33. data/lib/hexapdf/content/parser.rb +2 -2
  34. data/lib/hexapdf/content/processor.rb +15 -15
  35. data/lib/hexapdf/content/transformation_matrix.rb +1 -1
  36. data/lib/hexapdf/content.rb +5 -0
  37. data/lib/hexapdf/dictionary.rb +6 -5
  38. data/lib/hexapdf/dictionary_fields.rb +42 -14
  39. data/lib/hexapdf/digital_signature/cms_handler.rb +2 -2
  40. data/lib/hexapdf/digital_signature/handler.rb +1 -1
  41. data/lib/hexapdf/digital_signature/pkcs1_handler.rb +2 -3
  42. data/lib/hexapdf/digital_signature/signature.rb +6 -6
  43. data/lib/hexapdf/digital_signature/signatures.rb +13 -12
  44. data/lib/hexapdf/digital_signature/signing/default_handler.rb +14 -5
  45. data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +2 -4
  46. data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +4 -4
  47. data/lib/hexapdf/digital_signature/signing.rb +4 -0
  48. data/lib/hexapdf/digital_signature/verification_result.rb +2 -2
  49. data/lib/hexapdf/digital_signature.rb +7 -2
  50. data/lib/hexapdf/document/destinations.rb +12 -11
  51. data/lib/hexapdf/document/files.rb +1 -1
  52. data/lib/hexapdf/document/fonts.rb +1 -1
  53. data/lib/hexapdf/document/layout.rb +167 -39
  54. data/lib/hexapdf/document/pages.rb +3 -2
  55. data/lib/hexapdf/document.rb +89 -55
  56. data/lib/hexapdf/encryption/aes.rb +5 -5
  57. data/lib/hexapdf/encryption/arc4.rb +1 -1
  58. data/lib/hexapdf/encryption/fast_aes.rb +2 -2
  59. data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
  60. data/lib/hexapdf/encryption/identity.rb +1 -1
  61. data/lib/hexapdf/encryption/ruby_aes.rb +1 -1
  62. data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
  63. data/lib/hexapdf/encryption/security_handler.rb +31 -24
  64. data/lib/hexapdf/encryption/standard_security_handler.rb +45 -36
  65. data/lib/hexapdf/encryption.rb +7 -2
  66. data/lib/hexapdf/error.rb +18 -0
  67. data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
  68. data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
  69. data/lib/hexapdf/filter/flate_decode.rb +1 -1
  70. data/lib/hexapdf/filter/lzw_decode.rb +1 -1
  71. data/lib/hexapdf/filter/pass_through.rb +1 -1
  72. data/lib/hexapdf/filter/predictor.rb +1 -1
  73. data/lib/hexapdf/filter/run_length_decode.rb +1 -1
  74. data/lib/hexapdf/filter.rb +55 -6
  75. data/lib/hexapdf/font/cmap/parser.rb +2 -2
  76. data/lib/hexapdf/font/cmap.rb +1 -1
  77. data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
  78. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
  79. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +2 -2
  80. data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
  81. data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
  82. data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +3 -3
  83. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
  84. data/lib/hexapdf/font/invalid_glyph.rb +3 -0
  85. data/lib/hexapdf/font/true_type_wrapper.rb +17 -4
  86. data/lib/hexapdf/font/type1_wrapper.rb +19 -4
  87. data/lib/hexapdf/font_loader/from_configuration.rb +5 -2
  88. data/lib/hexapdf/font_loader/from_file.rb +5 -5
  89. data/lib/hexapdf/font_loader/standard14.rb +3 -3
  90. data/lib/hexapdf/font_loader.rb +3 -0
  91. data/lib/hexapdf/image_loader/jpeg.rb +2 -2
  92. data/lib/hexapdf/image_loader/pdf.rb +1 -1
  93. data/lib/hexapdf/image_loader/png.rb +2 -2
  94. data/lib/hexapdf/image_loader.rb +1 -1
  95. data/lib/hexapdf/importer.rb +13 -0
  96. data/lib/hexapdf/layout/box.rb +9 -2
  97. data/lib/hexapdf/layout/box_fitter.rb +2 -2
  98. data/lib/hexapdf/layout/column_box.rb +18 -4
  99. data/lib/hexapdf/layout/frame.rb +30 -12
  100. data/lib/hexapdf/layout/image_box.rb +5 -0
  101. data/lib/hexapdf/layout/inline_box.rb +1 -0
  102. data/lib/hexapdf/layout/list_box.rb +17 -1
  103. data/lib/hexapdf/layout/page_style.rb +4 -4
  104. data/lib/hexapdf/layout/style.rb +18 -3
  105. data/lib/hexapdf/layout/table_box.rb +682 -0
  106. data/lib/hexapdf/layout/text_box.rb +5 -3
  107. data/lib/hexapdf/layout/text_fragment.rb +1 -1
  108. data/lib/hexapdf/layout/text_layouter.rb +12 -4
  109. data/lib/hexapdf/layout.rb +1 -0
  110. data/lib/hexapdf/name_tree_node.rb +1 -1
  111. data/lib/hexapdf/number_tree_node.rb +1 -1
  112. data/lib/hexapdf/object.rb +18 -7
  113. data/lib/hexapdf/parser.rb +8 -8
  114. data/lib/hexapdf/pdf_array.rb +1 -1
  115. data/lib/hexapdf/rectangle.rb +1 -1
  116. data/lib/hexapdf/reference.rb +1 -1
  117. data/lib/hexapdf/revision.rb +1 -1
  118. data/lib/hexapdf/revisions.rb +3 -3
  119. data/lib/hexapdf/serializer.rb +15 -15
  120. data/lib/hexapdf/stream.rb +4 -2
  121. data/lib/hexapdf/tokenizer.rb +14 -14
  122. data/lib/hexapdf/type/acro_form/appearance_generator.rb +22 -22
  123. data/lib/hexapdf/type/acro_form/button_field.rb +1 -1
  124. data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
  125. data/lib/hexapdf/type/acro_form/field.rb +2 -2
  126. data/lib/hexapdf/type/acro_form/form.rb +1 -1
  127. data/lib/hexapdf/type/acro_form/signature_field.rb +4 -4
  128. data/lib/hexapdf/type/acro_form/text_field.rb +1 -1
  129. data/lib/hexapdf/type/acro_form/variable_text_field.rb +1 -1
  130. data/lib/hexapdf/type/acro_form.rb +1 -1
  131. data/lib/hexapdf/type/action.rb +1 -1
  132. data/lib/hexapdf/type/actions/go_to.rb +1 -1
  133. data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
  134. data/lib/hexapdf/type/actions/launch.rb +1 -1
  135. data/lib/hexapdf/type/actions/uri.rb +1 -1
  136. data/lib/hexapdf/type/actions.rb +1 -1
  137. data/lib/hexapdf/type/annotation.rb +3 -3
  138. data/lib/hexapdf/type/annotations/link.rb +1 -1
  139. data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
  140. data/lib/hexapdf/type/annotations/text.rb +1 -1
  141. data/lib/hexapdf/type/annotations/widget.rb +2 -2
  142. data/lib/hexapdf/type/annotations.rb +1 -1
  143. data/lib/hexapdf/type/catalog.rb +1 -1
  144. data/lib/hexapdf/type/cid_font.rb +3 -3
  145. data/lib/hexapdf/type/embedded_file.rb +1 -1
  146. data/lib/hexapdf/type/file_specification.rb +2 -2
  147. data/lib/hexapdf/type/font_descriptor.rb +1 -1
  148. data/lib/hexapdf/type/font_simple.rb +2 -2
  149. data/lib/hexapdf/type/font_type0.rb +3 -3
  150. data/lib/hexapdf/type/font_type3.rb +1 -1
  151. data/lib/hexapdf/type/form.rb +1 -1
  152. data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
  153. data/lib/hexapdf/type/icon_fit.rb +1 -1
  154. data/lib/hexapdf/type/image.rb +1 -1
  155. data/lib/hexapdf/type/info.rb +1 -1
  156. data/lib/hexapdf/type/mark_information.rb +1 -1
  157. data/lib/hexapdf/type/names.rb +2 -2
  158. data/lib/hexapdf/type/object_stream.rb +7 -3
  159. data/lib/hexapdf/type/outline.rb +1 -1
  160. data/lib/hexapdf/type/outline_item.rb +1 -1
  161. data/lib/hexapdf/type/page.rb +19 -10
  162. data/lib/hexapdf/type/page_label.rb +1 -1
  163. data/lib/hexapdf/type/page_tree_node.rb +1 -1
  164. data/lib/hexapdf/type/resources.rb +1 -1
  165. data/lib/hexapdf/type/trailer.rb +2 -2
  166. data/lib/hexapdf/type/viewer_preferences.rb +1 -1
  167. data/lib/hexapdf/type/xref_stream.rb +2 -2
  168. data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -1
  169. data/lib/hexapdf/version.rb +1 -1
  170. data/lib/hexapdf/writer.rb +4 -4
  171. data/lib/hexapdf/xref_section.rb +2 -2
  172. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +11 -1
  173. data/test/hexapdf/content/graphic_object/test_geom2d.rb +7 -0
  174. data/test/hexapdf/content/test_canvas.rb +0 -1
  175. data/test/hexapdf/digital_signature/test_signatures.rb +22 -0
  176. data/test/hexapdf/document/test_files.rb +2 -2
  177. data/test/hexapdf/document/test_layout.rb +98 -0
  178. data/test/hexapdf/encryption/test_security_handler.rb +12 -11
  179. data/test/hexapdf/encryption/test_standard_security_handler.rb +35 -23
  180. data/test/hexapdf/font/test_true_type_wrapper.rb +18 -1
  181. data/test/hexapdf/font/test_type1_wrapper.rb +15 -1
  182. data/test/hexapdf/layout/test_box.rb +1 -1
  183. data/test/hexapdf/layout/test_column_box.rb +65 -21
  184. data/test/hexapdf/layout/test_frame.rb +14 -14
  185. data/test/hexapdf/layout/test_image_box.rb +4 -0
  186. data/test/hexapdf/layout/test_inline_box.rb +5 -0
  187. data/test/hexapdf/layout/test_list_box.rb +40 -6
  188. data/test/hexapdf/layout/test_page_style.rb +3 -2
  189. data/test/hexapdf/layout/test_style.rb +50 -0
  190. data/test/hexapdf/layout/test_table_box.rb +722 -0
  191. data/test/hexapdf/layout/test_text_box.rb +18 -0
  192. data/test/hexapdf/layout/test_text_layouter.rb +4 -0
  193. data/test/hexapdf/test_dictionary_fields.rb +4 -1
  194. data/test/hexapdf/test_document.rb +1 -0
  195. data/test/hexapdf/test_filter.rb +8 -0
  196. data/test/hexapdf/test_importer.rb +9 -0
  197. data/test/hexapdf/test_object.rb +16 -5
  198. data/test/hexapdf/test_parser.rb +1 -1
  199. data/test/hexapdf/test_stream.rb +7 -0
  200. data/test/hexapdf/test_writer.rb +3 -3
  201. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +13 -5
  202. data/test/hexapdf/type/acro_form/test_form.rb +4 -3
  203. data/test/hexapdf/type/test_object_stream.rb +9 -3
  204. data/test/hexapdf/type/test_page.rb +18 -4
  205. 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',