hexapdf 0.32.2 → 0.34.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +104 -1
- data/README.md +9 -0
- data/examples/002-graphics.rb +15 -17
- data/examples/003-arcs.rb +9 -9
- data/examples/009-text_layouter_alignment.rb +1 -1
- data/examples/010-text_layouter_inline_boxes.rb +2 -2
- data/examples/011-text_layouter_line_wrapping.rb +1 -1
- data/examples/012-text_layouter_styling.rb +7 -7
- data/examples/013-text_layouter_shapes.rb +1 -1
- data/examples/014-text_in_polygon.rb +1 -1
- data/examples/015-boxes.rb +8 -7
- data/examples/016-frame_automatic_box_placement.rb +2 -2
- data/examples/017-frame_text_flow.rb +2 -1
- data/examples/018-composer.rb +1 -1
- data/examples/020-column_box.rb +2 -1
- data/examples/025-table_box.rb +46 -0
- data/examples/026-optional_content.rb +55 -0
- data/examples/027-composer_optional_content.rb +83 -0
- data/lib/hexapdf/cli/command.rb +12 -3
- data/lib/hexapdf/cli/fonts.rb +1 -1
- data/lib/hexapdf/cli/form.rb +5 -5
- data/lib/hexapdf/cli/inspect.rb +5 -7
- data/lib/hexapdf/composer.rb +106 -53
- data/lib/hexapdf/configuration.rb +65 -40
- data/lib/hexapdf/content/canvas.rb +445 -267
- data/lib/hexapdf/content/color_space.rb +72 -25
- data/lib/hexapdf/content/graphic_object/arc.rb +57 -24
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -23
- data/lib/hexapdf/content/graphic_object/geom2d.rb +47 -6
- data/lib/hexapdf/content/graphic_object/solid_arc.rb +58 -36
- data/lib/hexapdf/content/graphic_object.rb +6 -7
- data/lib/hexapdf/content/graphics_state.rb +54 -45
- data/lib/hexapdf/content/operator.rb +54 -54
- data/lib/hexapdf/content/parser.rb +2 -2
- data/lib/hexapdf/content/processor.rb +15 -15
- data/lib/hexapdf/content/transformation_matrix.rb +1 -1
- data/lib/hexapdf/content.rb +5 -0
- data/lib/hexapdf/dictionary.rb +7 -5
- data/lib/hexapdf/dictionary_fields.rb +43 -16
- data/lib/hexapdf/digital_signature/cms_handler.rb +2 -2
- data/lib/hexapdf/digital_signature/handler.rb +1 -1
- data/lib/hexapdf/digital_signature/pkcs1_handler.rb +2 -3
- data/lib/hexapdf/digital_signature/signature.rb +6 -6
- data/lib/hexapdf/digital_signature/signatures.rb +13 -12
- data/lib/hexapdf/digital_signature/signing/default_handler.rb +14 -5
- data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +2 -4
- data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +4 -4
- data/lib/hexapdf/digital_signature/signing.rb +4 -0
- data/lib/hexapdf/digital_signature/verification_result.rb +3 -4
- data/lib/hexapdf/digital_signature.rb +7 -2
- data/lib/hexapdf/document/destinations.rb +12 -11
- data/lib/hexapdf/document/files.rb +1 -1
- data/lib/hexapdf/document/fonts.rb +1 -1
- data/lib/hexapdf/document/layout.rb +170 -39
- data/lib/hexapdf/document/pages.rb +4 -3
- data/lib/hexapdf/document.rb +96 -55
- data/lib/hexapdf/encryption/aes.rb +5 -5
- data/lib/hexapdf/encryption/arc4.rb +1 -1
- data/lib/hexapdf/encryption/fast_aes.rb +2 -2
- data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
- data/lib/hexapdf/encryption/identity.rb +1 -1
- data/lib/hexapdf/encryption/ruby_aes.rb +11 -21
- data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
- data/lib/hexapdf/encryption/security_handler.rb +31 -24
- data/lib/hexapdf/encryption/standard_security_handler.rb +45 -36
- data/lib/hexapdf/encryption.rb +7 -2
- data/lib/hexapdf/error.rb +18 -0
- data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
- data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
- data/lib/hexapdf/filter/flate_decode.rb +1 -1
- data/lib/hexapdf/filter/lzw_decode.rb +1 -1
- data/lib/hexapdf/filter/pass_through.rb +1 -1
- data/lib/hexapdf/filter/predictor.rb +1 -1
- data/lib/hexapdf/filter/run_length_decode.rb +1 -1
- data/lib/hexapdf/filter.rb +55 -6
- data/lib/hexapdf/font/cmap/parser.rb +2 -2
- data/lib/hexapdf/font/cmap.rb +1 -1
- data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +2 -2
- data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +3 -3
- data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
- data/lib/hexapdf/font/invalid_glyph.rb +3 -0
- data/lib/hexapdf/font/true_type_wrapper.rb +17 -4
- data/lib/hexapdf/font/type1_wrapper.rb +19 -4
- data/lib/hexapdf/font_loader/from_configuration.rb +5 -2
- data/lib/hexapdf/font_loader/from_file.rb +5 -5
- data/lib/hexapdf/font_loader/standard14.rb +3 -3
- data/lib/hexapdf/font_loader.rb +3 -0
- data/lib/hexapdf/image_loader/jpeg.rb +2 -2
- data/lib/hexapdf/image_loader/pdf.rb +1 -1
- data/lib/hexapdf/image_loader/png.rb +2 -2
- data/lib/hexapdf/image_loader.rb +1 -1
- data/lib/hexapdf/importer.rb +13 -0
- data/lib/hexapdf/layout/box.rb +32 -5
- data/lib/hexapdf/layout/box_fitter.rb +2 -2
- data/lib/hexapdf/layout/column_box.rb +20 -5
- data/lib/hexapdf/layout/frame.rb +53 -18
- data/lib/hexapdf/layout/image_box.rb +5 -0
- data/lib/hexapdf/layout/inline_box.rb +21 -9
- data/lib/hexapdf/layout/list_box.rb +50 -20
- data/lib/hexapdf/layout/page_style.rb +6 -5
- data/lib/hexapdf/layout/style.rb +64 -9
- data/lib/hexapdf/layout/table_box.rb +684 -0
- data/lib/hexapdf/layout/text_box.rb +12 -3
- data/lib/hexapdf/layout/text_fragment.rb +29 -3
- data/lib/hexapdf/layout/text_layouter.rb +32 -8
- data/lib/hexapdf/layout.rb +1 -0
- data/lib/hexapdf/name_tree_node.rb +1 -1
- data/lib/hexapdf/number_tree_node.rb +1 -1
- data/lib/hexapdf/object.rb +18 -7
- data/lib/hexapdf/parser.rb +7 -7
- data/lib/hexapdf/pdf_array.rb +1 -1
- data/lib/hexapdf/rectangle.rb +1 -1
- data/lib/hexapdf/reference.rb +1 -1
- data/lib/hexapdf/revision.rb +1 -1
- data/lib/hexapdf/revisions.rb +3 -3
- data/lib/hexapdf/serializer.rb +15 -15
- data/lib/hexapdf/stream.rb +5 -4
- data/lib/hexapdf/tokenizer.rb +14 -14
- data/lib/hexapdf/type/acro_form/appearance_generator.rb +22 -22
- data/lib/hexapdf/type/acro_form/button_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/field.rb +2 -2
- data/lib/hexapdf/type/acro_form/form.rb +1 -1
- data/lib/hexapdf/type/acro_form/signature_field.rb +4 -4
- data/lib/hexapdf/type/acro_form/text_field.rb +1 -1
- data/lib/hexapdf/type/acro_form/variable_text_field.rb +1 -1
- data/lib/hexapdf/type/acro_form.rb +1 -1
- data/lib/hexapdf/type/action.rb +1 -1
- data/lib/hexapdf/type/actions/go_to.rb +1 -1
- data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
- data/lib/hexapdf/type/actions/launch.rb +1 -1
- data/lib/hexapdf/type/actions/set_ocg_state.rb +86 -0
- data/lib/hexapdf/type/actions/uri.rb +1 -1
- data/lib/hexapdf/type/actions.rb +2 -1
- data/lib/hexapdf/type/annotation.rb +3 -3
- data/lib/hexapdf/type/annotations/link.rb +1 -1
- data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
- data/lib/hexapdf/type/annotations/text.rb +2 -3
- data/lib/hexapdf/type/annotations/widget.rb +2 -2
- data/lib/hexapdf/type/annotations.rb +1 -1
- data/lib/hexapdf/type/catalog.rb +11 -2
- data/lib/hexapdf/type/cid_font.rb +18 -4
- data/lib/hexapdf/type/embedded_file.rb +1 -1
- data/lib/hexapdf/type/file_specification.rb +2 -2
- data/lib/hexapdf/type/font_descriptor.rb +1 -1
- data/lib/hexapdf/type/font_simple.rb +2 -2
- data/lib/hexapdf/type/font_type0.rb +3 -3
- data/lib/hexapdf/type/font_type3.rb +1 -1
- data/lib/hexapdf/type/form.rb +76 -6
- data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
- data/lib/hexapdf/type/icon_fit.rb +1 -1
- data/lib/hexapdf/type/image.rb +1 -1
- data/lib/hexapdf/type/info.rb +1 -1
- data/lib/hexapdf/type/mark_information.rb +1 -1
- data/lib/hexapdf/type/names.rb +2 -2
- data/lib/hexapdf/type/object_stream.rb +2 -1
- data/lib/hexapdf/type/optional_content_configuration.rb +170 -0
- data/lib/hexapdf/type/optional_content_group.rb +370 -0
- data/lib/hexapdf/type/optional_content_membership.rb +63 -0
- data/lib/hexapdf/type/optional_content_properties.rb +158 -0
- data/lib/hexapdf/type/outline.rb +1 -1
- data/lib/hexapdf/type/outline_item.rb +1 -1
- data/lib/hexapdf/type/page.rb +46 -21
- data/lib/hexapdf/type/page_label.rb +5 -9
- data/lib/hexapdf/type/page_tree_node.rb +1 -1
- data/lib/hexapdf/type/resources.rb +1 -1
- data/lib/hexapdf/type/trailer.rb +2 -2
- data/lib/hexapdf/type/viewer_preferences.rb +1 -1
- data/lib/hexapdf/type/xref_stream.rb +2 -2
- data/lib/hexapdf/type.rb +4 -0
- data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -2
- data/lib/hexapdf/version.rb +1 -1
- data/lib/hexapdf/writer.rb +4 -4
- data/lib/hexapdf/xref_section.rb +2 -2
- data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +11 -1
- data/test/hexapdf/content/graphic_object/test_geom2d.rb +7 -0
- data/test/hexapdf/content/test_canvas.rb +49 -1
- data/test/hexapdf/digital_signature/test_signatures.rb +22 -0
- data/test/hexapdf/document/test_files.rb +2 -2
- data/test/hexapdf/document/test_layout.rb +105 -2
- data/test/hexapdf/document/test_pages.rb +6 -6
- data/test/hexapdf/encryption/test_security_handler.rb +12 -11
- data/test/hexapdf/encryption/test_standard_security_handler.rb +35 -23
- data/test/hexapdf/font/test_true_type_wrapper.rb +18 -1
- data/test/hexapdf/font/test_type1_wrapper.rb +15 -1
- data/test/hexapdf/layout/test_box.rb +14 -5
- data/test/hexapdf/layout/test_column_box.rb +65 -21
- data/test/hexapdf/layout/test_frame.rb +27 -15
- data/test/hexapdf/layout/test_image_box.rb +4 -0
- data/test/hexapdf/layout/test_inline_box.rb +17 -3
- data/test/hexapdf/layout/test_list_box.rb +84 -33
- data/test/hexapdf/layout/test_page_style.rb +3 -2
- data/test/hexapdf/layout/test_style.rb +60 -0
- data/test/hexapdf/layout/test_table_box.rb +728 -0
- data/test/hexapdf/layout/test_text_box.rb +26 -0
- data/test/hexapdf/layout/test_text_fragment.rb +33 -0
- data/test/hexapdf/layout/test_text_layouter.rb +36 -5
- data/test/hexapdf/test_composer.rb +10 -0
- data/test/hexapdf/test_dictionary.rb +10 -0
- data/test/hexapdf/test_dictionary_fields.rb +4 -1
- data/test/hexapdf/test_document.rb +5 -0
- data/test/hexapdf/test_filter.rb +8 -0
- data/test/hexapdf/test_importer.rb +9 -0
- data/test/hexapdf/test_object.rb +16 -5
- data/test/hexapdf/test_stream.rb +7 -0
- data/test/hexapdf/test_writer.rb +3 -3
- data/test/hexapdf/type/acro_form/test_appearance_generator.rb +13 -5
- data/test/hexapdf/type/acro_form/test_form.rb +4 -3
- data/test/hexapdf/type/actions/test_set_ocg_state.rb +40 -0
- data/test/hexapdf/type/test_catalog.rb +11 -0
- data/test/hexapdf/type/test_form.rb +119 -0
- data/test/hexapdf/type/test_optional_content_configuration.rb +112 -0
- data/test/hexapdf/type/test_optional_content_group.rb +158 -0
- data/test/hexapdf/type/test_optional_content_properties.rb +109 -0
- data/test/hexapdf/type/test_page.rb +20 -6
- metadata +28 -8
@@ -63,7 +63,7 @@ module HexaPDF
|
|
63
63
|
# The PDF operators themselves are implemented as classes, see Operator. The canvas class uses
|
64
64
|
# the Operator::BaseOperator#invoke and Operator::BaseOperator#serialize methods for applying
|
65
65
|
# changes and serialization, with one exception: color setters don't invoke the corresponding
|
66
|
-
# operator implementation but directly
|
66
|
+
# operator implementation but work directly on the graphics state.
|
67
67
|
#
|
68
68
|
# === General Graphics State Manipulation Methods
|
69
69
|
#
|
@@ -161,7 +161,7 @@ module HexaPDF
|
|
161
161
|
# showing operators, and such groups of operators are allowed to be used only in certain
|
162
162
|
# graphics objects or the page description level.
|
163
163
|
#
|
164
|
-
# Have a look at the PDF specification (
|
164
|
+
# Have a look at the PDF specification (PDF2.0 s8.2) for more details.
|
165
165
|
#
|
166
166
|
# HexaPDF tries to ensure the proper use of the operators and graphics objects and if it
|
167
167
|
# cannot do it, an error is raised. So if you don't modify a content stream directly but via
|
@@ -169,15 +169,20 @@ module HexaPDF
|
|
169
169
|
#
|
170
170
|
# === Graphics State
|
171
171
|
#
|
172
|
-
# Some operators modify the so called graphics state (see
|
173
|
-
#
|
174
|
-
#
|
172
|
+
# Some operators modify the so called graphics state (see GraphicsState). The graphics state is
|
173
|
+
# a collection of settings that is used during processing or creating a content stream. For
|
174
|
+
# example, the path painting operators don't have operands to specify the line width or the
|
175
175
|
# stroke color but take this information from the graphics state.
|
176
176
|
#
|
177
177
|
# One important thing about the graphics state is that it is only possible to restore a prior
|
178
178
|
# state using the save and restore methods. It is not possible to reset the graphics state
|
179
179
|
# while creating the content stream!
|
180
180
|
#
|
181
|
+
# This means, for example, if you use a clipping path (see #clip_path) you should first save the
|
182
|
+
# graphics state (#save_graphics_state) and then restore it afterwards
|
183
|
+
# (#restore_graphics_state). Otherwise all following operations will be clipped to the clipping
|
184
|
+
# path.
|
185
|
+
#
|
181
186
|
# === Paths
|
182
187
|
#
|
183
188
|
# A PDF path object consists of one or more subpaths. Each subpath can be a rectangle or can
|
@@ -200,7 +205,7 @@ module HexaPDF
|
|
200
205
|
# In addition filling may be done using either the nonzero winding number rule or the even-odd
|
201
206
|
# rule.
|
202
207
|
#
|
203
|
-
# See:
|
208
|
+
# See: PDF2.0 s8, s9
|
204
209
|
class Canvas
|
205
210
|
|
206
211
|
include HexaPDF::Utils::MathHelpers
|
@@ -208,12 +213,20 @@ module HexaPDF
|
|
208
213
|
|
209
214
|
# The context for which the canvas was created (a HexaPDF::Type::Page or HexaPDF::Type::Form
|
210
215
|
# object).
|
216
|
+
#
|
217
|
+
# The context object is used for two things:
|
218
|
+
#
|
219
|
+
# * To store the resources (#resources) that are needed by the canvas (e.g. font references).
|
220
|
+
#
|
221
|
+
# * To access the HexaPDF::Document object to which this canvas and the context object
|
222
|
+
# belongs. This is used internally but it is also useful in other situations since some
|
223
|
+
# parts of HexaPDF only yield a canvas object, and not also the underlying document object.
|
211
224
|
attr_reader :context
|
212
225
|
|
213
226
|
# The serialized contents produced by the various canvas operations up to this point.
|
214
227
|
#
|
215
228
|
# Note that the returned string may not be a completely valid PDF content stream since a
|
216
|
-
# graphic object may be open or the graphics state not completely restored.
|
229
|
+
# graphic object may be open or the graphics state may not be completely restored.
|
217
230
|
#
|
218
231
|
# See: #stream_data
|
219
232
|
attr_reader :contents
|
@@ -228,7 +241,7 @@ module HexaPDF
|
|
228
241
|
# canvas!
|
229
242
|
attr_reader :stream_data
|
230
243
|
|
231
|
-
# The
|
244
|
+
# The GraphicsState object containing the current graphics state.
|
232
245
|
#
|
233
246
|
# The graphics state must not be changed directly, only by using the provided methods. If it
|
234
247
|
# is changed directly, the output will not be correct.
|
@@ -236,7 +249,7 @@ module HexaPDF
|
|
236
249
|
|
237
250
|
# The current graphics object.
|
238
251
|
#
|
239
|
-
# The graphics object should not be changed directly
|
252
|
+
# The graphics object should not be changed directly! It is automatically updated by the
|
240
253
|
# invoked methods.
|
241
254
|
#
|
242
255
|
# This attribute can have the following values:
|
@@ -246,13 +259,13 @@ module HexaPDF
|
|
246
259
|
# :clipping_path:: The current graphics object is a clipping path.
|
247
260
|
# :text:: The current graphics object is a text object.
|
248
261
|
#
|
249
|
-
# See:
|
262
|
+
# See: PDF2.0 s8.2
|
250
263
|
attr_accessor :graphics_object
|
251
264
|
|
252
265
|
# The current point [x, y] of the path.
|
253
266
|
#
|
254
|
-
# This attribute holds the current point which is only valid if the current graphics
|
255
|
-
# is :path.
|
267
|
+
# This attribute holds the current point which is only valid if the current graphics object
|
268
|
+
# (see #graphic_object) is :path.
|
256
269
|
#
|
257
270
|
# When the current point changes, the array is modified in place instead of creating a new
|
258
271
|
# array!
|
@@ -260,7 +273,8 @@ module HexaPDF
|
|
260
273
|
|
261
274
|
# The operator name/implementation map used when invoking or serializing an operator.
|
262
275
|
#
|
263
|
-
# Defaults to
|
276
|
+
# Defaults to Operator::DEFAULT_OPERATORS, i.e. the standard implementation provided by
|
277
|
+
# HexaPDF.
|
264
278
|
attr_reader :operators
|
265
279
|
|
266
280
|
# Creates a new Canvas object for the given context object (either a HexaPDF::Type::Page or a
|
@@ -285,7 +299,7 @@ module HexaPDF
|
|
285
299
|
@current_point = [0, 0]
|
286
300
|
@start_point = [0, 0]
|
287
301
|
@contents = ''.b
|
288
|
-
|
302
|
+
source = HexaPDF::Filter.source_from_proc do
|
289
303
|
case graphics_object
|
290
304
|
when :path, :clipping_path then end_path
|
291
305
|
when :text then end_text
|
@@ -293,6 +307,7 @@ module HexaPDF
|
|
293
307
|
restore_graphics_state while graphics_state.saved_states?
|
294
308
|
@contents
|
295
309
|
end
|
310
|
+
@stream_data = HexaPDF::StreamData.new(source)
|
296
311
|
end
|
297
312
|
|
298
313
|
# Returns the resource dictionary of the context object.
|
@@ -302,11 +317,19 @@ module HexaPDF
|
|
302
317
|
@context.resources
|
303
318
|
end
|
304
319
|
|
320
|
+
# Returns the position (x,y) transformed by the current transformation matrix.
|
321
|
+
#
|
322
|
+
# The resulting position should be interpreted in terms of the coordinate system of the
|
323
|
+
# context object (e.g. the page or Form XObject).
|
324
|
+
def pos(x, y)
|
325
|
+
graphics_state.ctm.evaluate(x, y)
|
326
|
+
end
|
327
|
+
|
305
328
|
# :call-seq:
|
306
329
|
# canvas.save_graphics_state => canvas
|
307
330
|
# canvas.save_graphics_state { block } => canvas
|
308
331
|
#
|
309
|
-
# Saves the current graphics state and returns self
|
332
|
+
# Saves the current graphics state and returns +self+.
|
310
333
|
#
|
311
334
|
# If invoked without a block a corresponding call to #restore_graphics_state must be done to
|
312
335
|
# ensure proper nesting. Otherwise, i.e. when invoked with a block, the graphics state is
|
@@ -320,7 +343,7 @@ module HexaPDF
|
|
320
343
|
# #>pdf
|
321
344
|
# # With a block
|
322
345
|
# canvas.save_graphics_state do
|
323
|
-
# canvas.stroke_color("
|
346
|
+
# canvas.stroke_color("hp-blue") # After the block the color is reset
|
324
347
|
# canvas.line(20, 20, 70, 180).stroke
|
325
348
|
# end
|
326
349
|
# canvas.line(60, 20, 110, 180).stroke
|
@@ -332,7 +355,7 @@ module HexaPDF
|
|
332
355
|
# restore_graphics_state
|
333
356
|
# canvas.line(140, 20, 190, 180).stroke
|
334
357
|
#
|
335
|
-
# See:
|
358
|
+
# See: PDF2.0 s8.4.2, #restore_graphics_state
|
336
359
|
def save_graphics_state
|
337
360
|
raise_unless_at_page_description_level
|
338
361
|
invoke0(:q)
|
@@ -347,11 +370,20 @@ module HexaPDF
|
|
347
370
|
# :call-seq:
|
348
371
|
# canvas.restore_graphics_state => canvas
|
349
372
|
#
|
350
|
-
# Restores the
|
373
|
+
# Restores the graphics state to the last saved version and returns +self+.
|
351
374
|
#
|
352
375
|
# Must not be invoked more times than #save_graphics_state.
|
353
376
|
#
|
354
|
-
#
|
377
|
+
# Example:
|
378
|
+
#
|
379
|
+
# #>pdf
|
380
|
+
# canvas.save_graphics_state
|
381
|
+
# canvas.circle(100, 100, 50).clip_path.end_path
|
382
|
+
# canvas.fill_color("hp-blue").rectangle(0, 0, 100, 100).fill
|
383
|
+
# canvas.restore_graphics_state
|
384
|
+
# canvas.rectangle(100, 0, 100, 100).fill
|
385
|
+
#
|
386
|
+
# See: PDF2.0 s8.4.2, #save_graphics_state
|
355
387
|
def restore_graphics_state
|
356
388
|
raise_unless_at_page_description_level
|
357
389
|
invoke0(:Q)
|
@@ -363,7 +395,7 @@ module HexaPDF
|
|
363
395
|
# canvas.transform(a, b, c, d, e, f) => canvas
|
364
396
|
# canvas.transform(a, b, c, d, e, f) { block } => canvas
|
365
397
|
#
|
366
|
-
# Transforms the
|
398
|
+
# Transforms the coordinate system by applying the given matrix to the current transformation
|
367
399
|
# matrix and returns self.
|
368
400
|
#
|
369
401
|
# If invoked with a block, the transformation is only active during the block by saving and
|
@@ -375,16 +407,16 @@ module HexaPDF
|
|
375
407
|
# c d 0
|
376
408
|
# e f 1
|
377
409
|
#
|
378
|
-
#
|
410
|
+
# Example:
|
379
411
|
#
|
380
412
|
# #>pdf
|
381
413
|
# canvas.transform(1, 0, 0, 1, 100, 100) do # Translate origin to (100, 100)
|
382
|
-
# canvas.stroke_color("
|
414
|
+
# canvas.stroke_color("hp-blue").
|
383
415
|
# line(0, 0, 100, 50).stroke # Actually from (100, 100) to (200, 150)
|
384
416
|
# end
|
385
417
|
# canvas.line(0, 0, 100, 50).stroke # Really from (0, 0) to (100, 50)
|
386
418
|
#
|
387
|
-
# See:
|
419
|
+
# See: PDF2.0 s8.3, s8.4.4
|
388
420
|
def transform(a, b, c, d, e, f)
|
389
421
|
raise_unless_at_page_description_level
|
390
422
|
save_graphics_state if block_given?
|
@@ -400,30 +432,31 @@ module HexaPDF
|
|
400
432
|
# canvas.rotate(angle, origin: nil) => canvas
|
401
433
|
# canvas.rotate(angle, origin: nil) { block } => canvas
|
402
434
|
#
|
403
|
-
# Rotates the
|
404
|
-
#
|
435
|
+
# Rotates the coordinate system +angle+ degrees around the origin or around the given point
|
436
|
+
# and returns +self+.
|
405
437
|
#
|
406
|
-
# If invoked with a block, the rotation of the
|
407
|
-
# saving and restoring the graphics state.
|
438
|
+
# If invoked with a block, the rotation of the coordinate system is only active during the
|
439
|
+
# block by saving and restoring the graphics state.
|
408
440
|
#
|
409
441
|
# Note that the origin of the coordinate system itself doesn't change even if the +origin+
|
410
442
|
# argument is given!
|
411
443
|
#
|
412
444
|
# origin::
|
413
|
-
# The point around which the
|
445
|
+
# The point around which the coordinate system should be rotated.
|
414
446
|
#
|
415
447
|
# Examples:
|
416
448
|
#
|
417
449
|
# #>pdf-center
|
418
|
-
# canvas.stroke_color("
|
419
|
-
# rectangle(0, 0, 60, 40).stroke
|
450
|
+
# canvas.stroke_color("hp-gray-light").
|
451
|
+
# rectangle(0, 0, 60, 40).stroke # The rectangle that gets rotated
|
452
|
+
#
|
420
453
|
# canvas.rotate(45) do # Positive x-axis pointing to top-right corner
|
421
|
-
# canvas.stroke_color("
|
454
|
+
# canvas.stroke_color("hp-blue").
|
422
455
|
# rectangle(0, 0, 60, 40).stroke
|
423
456
|
# end
|
424
457
|
#
|
425
458
|
# canvas.rotate(-45, origin: [-50, -50]) do # Rotate around (-50,-50)
|
426
|
-
# canvas.stroke_color("
|
459
|
+
# canvas.stroke_color("hp-orange").
|
427
460
|
# rectangle(0, 0, 60, 40).stroke
|
428
461
|
# end
|
429
462
|
#
|
@@ -443,8 +476,8 @@ module HexaPDF
|
|
443
476
|
# canvas.scale(sx, sy = sx, origin: nil) => canvas
|
444
477
|
# canvas.scale(sx, sy = sx, origin: nil) { block } => canvas
|
445
478
|
#
|
446
|
-
# Scales the
|
447
|
-
# direction and returns self
|
479
|
+
# Scales the coordinate system +sx+ units in the horizontal and +sy+ units in the vertical
|
480
|
+
# direction and returns +self+. If the optional +origin+ is specified, scaling is done from
|
448
481
|
# that point.
|
449
482
|
#
|
450
483
|
# If invoked with a block, the scaling is only active during the block by saving and
|
@@ -454,20 +487,21 @@ module HexaPDF
|
|
454
487
|
# argument is given!
|
455
488
|
#
|
456
489
|
# origin::
|
457
|
-
# The point from which the
|
490
|
+
# The point from which the coordinate system should be scaled.
|
458
491
|
#
|
459
492
|
# Examples:
|
460
493
|
#
|
461
494
|
# #>pdf-center
|
462
|
-
# canvas.stroke_color("
|
463
|
-
# rectangle(10, 10, 10, 10).stroke
|
495
|
+
# canvas.stroke_color("hp-gray-light").
|
496
|
+
# rectangle(10, 10, 10, 10).stroke # The rectangle that gets scaled
|
497
|
+
#
|
464
498
|
# canvas.scale(4, 2) do # Scale from origin
|
465
|
-
# canvas.stroke_color("blue").
|
499
|
+
# canvas.stroke_color("hp-blue").
|
466
500
|
# rectangle(10, 10, 10, 10).stroke # Actually (40, 20) to (80, 40)
|
467
501
|
# end
|
468
502
|
#
|
469
503
|
# canvas.scale(-2, 4, origin: [10, 10]) do # Scale from (10, 10)
|
470
|
-
# canvas.stroke_color("
|
504
|
+
# canvas.stroke_color("hp-orange").
|
471
505
|
# rectangle(10, 10, 10, 10).stroke # Actually (10, 10) to (-10, 40)
|
472
506
|
# end
|
473
507
|
#
|
@@ -484,18 +518,19 @@ module HexaPDF
|
|
484
518
|
# canvas.translate(x, y) => canvas
|
485
519
|
# canvas.translate(x, y) { block } => canvas
|
486
520
|
#
|
487
|
-
# Translates the
|
488
|
-
# and returns self
|
521
|
+
# Translates the coordinate system coordinate system origin to the given +x+ and +y+
|
522
|
+
# coordinates and returns +self+.
|
489
523
|
#
|
490
|
-
# If invoked with a block, the translation of the
|
491
|
-
# by saving and restoring the graphics state.
|
524
|
+
# If invoked with a block, the translation of the coordinate system is only active during the
|
525
|
+
# block by saving and restoring the graphics state.
|
492
526
|
#
|
493
527
|
# Examples:
|
494
528
|
#
|
495
529
|
# #>pdf-center
|
496
|
-
# canvas.
|
530
|
+
# canvas.stroke_color("hp-gray-light").
|
531
|
+
# rectangle(0, 0, 40, 20).stroke # Rectangle from (0, 0) to (40, 20)
|
497
532
|
# canvas.translate(50, 50) do # Origin is now at (50, 50)
|
498
|
-
# canvas.stroke_color("
|
533
|
+
# canvas.stroke_color("hp-blue").
|
499
534
|
# rectangle(0, 0, 40, 20).stroke # Actually (50, 50) to (90, 70)
|
500
535
|
# end
|
501
536
|
#
|
@@ -508,7 +543,7 @@ module HexaPDF
|
|
508
543
|
# canvas.skew(a, b, origin: nil) => canvas
|
509
544
|
# canvas.skew(a, b, origin: nil) { block } => canvas
|
510
545
|
#
|
511
|
-
# Skews the the x-axis by +a+ degrees and the y-axis by +b+ degress and returns self
|
546
|
+
# Skews the the x-axis by +a+ degrees and the y-axis by +b+ degress and returns +self+. If the
|
512
547
|
# optional +origin+ is specified, skewing is done from that point.
|
513
548
|
#
|
514
549
|
# If invoked with a block, the skewing is only active during the block by saving and
|
@@ -522,15 +557,16 @@ module HexaPDF
|
|
522
557
|
# Examples:
|
523
558
|
#
|
524
559
|
# #>pdf-center
|
525
|
-
# canvas.stroke_color("
|
526
|
-
# rectangle(10, 10, 40, 20).stroke
|
560
|
+
# canvas.stroke_color("hp-gray-light").
|
561
|
+
# rectangle(10, 10, 40, 20).stroke # The rectangle that gets skewed
|
562
|
+
#
|
527
563
|
# canvas.skew(0, 30) do # Point (10, 10) is now actually (15, 10)
|
528
|
-
# canvas.stroke_color("blue").
|
564
|
+
# canvas.stroke_color("hp-blue").
|
529
565
|
# rectangle(10, 10, 40, 20).stroke # Now a parallelogram
|
530
566
|
# end
|
531
567
|
#
|
532
568
|
# canvas.skew(30, 30, origin: [-50, 50]) do # Skew from (-50, 50)
|
533
|
-
# canvas.stroke_color("
|
569
|
+
# canvas.stroke_color("hp-orange").
|
534
570
|
# rectangle(-50, 50, 20, 20).stroke
|
535
571
|
# end
|
536
572
|
#
|
@@ -553,9 +589,15 @@ module HexaPDF
|
|
553
589
|
#
|
554
590
|
# The line width determines the thickness of a stroked path.
|
555
591
|
#
|
556
|
-
#
|
557
|
-
#
|
558
|
-
#
|
592
|
+
# Note that half the line width lies on either side of the path. For example, if a path from
|
593
|
+
# (0, 0) to (0, 100) is drawn with a line width of 20, the stroked path is actually 20 units
|
594
|
+
# wide, from -10 to 10. And if a rectangle is drawn stroked, but not filled, from (20, 20)
|
595
|
+
# with a width and height of 20 and a line width of 10, the "inside" of the rectangle would
|
596
|
+
# only be from (25, 25) to (35, 35). Also see the examples below.
|
597
|
+
#
|
598
|
+
# Returns the current line width (see GraphicsState#line_width) when no argument is given.
|
599
|
+
# Otherwise sets the line width to the given +width+ and returns +self+. The setter version
|
600
|
+
# can also be called in the line_width= form.
|
559
601
|
#
|
560
602
|
# If the +width+ and a block are provided, the changed line width is only active during the
|
561
603
|
# block by saving and restoring the graphics state.
|
@@ -564,19 +606,22 @@ module HexaPDF
|
|
564
606
|
#
|
565
607
|
# #>pdf
|
566
608
|
# canvas.line_width(10).
|
567
|
-
# line(10,
|
609
|
+
# line(10, 100, 10, 190).stroke
|
568
610
|
# canvas.line_width # => 10
|
569
611
|
# canvas.line_width = 5 # => 5
|
570
|
-
# canvas.line(60,
|
612
|
+
# canvas.line(60, 100, 60, 190).stroke
|
571
613
|
#
|
572
614
|
# canvas.line_width(10) do
|
573
615
|
# canvas.line_width # => 10
|
574
|
-
# canvas.line(110,
|
616
|
+
# canvas.line(110, 100, 110, 190).stroke
|
575
617
|
# end
|
576
618
|
# canvas.line_width # => 5
|
577
|
-
# canvas.line(160,
|
619
|
+
# canvas.line(160, 100, 160, 190).stroke
|
578
620
|
#
|
579
|
-
#
|
621
|
+
# canvas.line_width(10).rectangle(20, 20, 20, 20).stroke # The rectangle
|
622
|
+
# canvas.fill_color("hp-blue").rectangle(25, 25, 10, 10).fill # The inside
|
623
|
+
#
|
624
|
+
# See: PDF2.0 s8.4.3.2
|
580
625
|
def line_width(width = nil, &block)
|
581
626
|
gs_getter_setter(:line_width, :w, width, &block)
|
582
627
|
end
|
@@ -587,7 +632,7 @@ module HexaPDF
|
|
587
632
|
# canvas.line_cap_style(style) => canvas
|
588
633
|
# canvas.line_cap_style(style) { block } => canvas
|
589
634
|
#
|
590
|
-
# The line cap style specifies how the ends of stroked open paths should look like.
|
635
|
+
# The line cap style specifies how the ends of stroked, open paths should look like.
|
591
636
|
#
|
592
637
|
# The +style+ parameter can be one of (also see LineCapStyle):
|
593
638
|
#
|
@@ -598,11 +643,11 @@ module HexaPDF
|
|
598
643
|
# :projecting_square or 2::
|
599
644
|
# The stroke continues half the line width beyond the endpoint of a path.
|
600
645
|
#
|
601
|
-
# Note that the return value is always a normalized line cap style.
|
646
|
+
# Note that the return value is always a normalized line cap style (i.e. a NamedValue).
|
602
647
|
#
|
603
|
-
# Returns the current line cap style (see
|
604
|
-
#
|
605
|
-
#
|
648
|
+
# Returns the current line cap style (see GraphicsState#line_cap_style) when no argument is
|
649
|
+
# given. Otherwise sets the line cap style to the given +style+ and returns +self+. The setter
|
650
|
+
# version can also be called in the line_cap_style= form.
|
606
651
|
#
|
607
652
|
# If the +style+ and a block are provided, the changed line cap style is only active during
|
608
653
|
# the block by saving and restoring the graphics state.
|
@@ -628,7 +673,7 @@ module HexaPDF
|
|
628
673
|
# line(50 + index * 50, 30, 50 + index * 50, 170).stroke
|
629
674
|
# end
|
630
675
|
#
|
631
|
-
# See:
|
676
|
+
# See: PDF2.0 s8.4.3.3, Content::LineCapStyle
|
632
677
|
def line_cap_style(style = nil, &block)
|
633
678
|
gs_getter_setter(:line_cap_style, :J, style && LineCapStyle.normalize(style), &block)
|
634
679
|
end
|
@@ -651,11 +696,11 @@ module HexaPDF
|
|
651
696
|
# The two segments are finished with butt caps and the space between the ends is filled
|
652
697
|
# with a triangle.
|
653
698
|
#
|
654
|
-
# Note that the return value is always a normalized line join style.
|
699
|
+
# Note that the return value is always a normalized line join style (i.e. a NamedValue).
|
655
700
|
#
|
656
|
-
# Returns the current line join style (see
|
657
|
-
#
|
658
|
-
#
|
701
|
+
# Returns the current line join style (see GraphicsState#line_join_style) when no argument is
|
702
|
+
# given. Otherwise sets the line join style to the given +style+ and returns +self+. The
|
703
|
+
# setter version can also be called in the line_join_style= form.
|
659
704
|
#
|
660
705
|
# If the +style+ and a block are provided, the changed line join style is only active during
|
661
706
|
# the block by saving and restoring the graphics state.
|
@@ -681,7 +726,7 @@ module HexaPDF
|
|
681
726
|
# polyline(20 + index * 60, 30, 40 + index * 60, 170, 60 + index * 60, 30).stroke
|
682
727
|
# end
|
683
728
|
#
|
684
|
-
# See:
|
729
|
+
# See: PDF2.0 s8.4.3.4, Content::LineJoinStyle
|
685
730
|
def line_join_style(style = nil, &block)
|
686
731
|
gs_getter_setter(:line_join_style, :j, style && LineJoinStyle.normalize(style), &block)
|
687
732
|
end
|
@@ -696,9 +741,9 @@ module HexaPDF
|
|
696
741
|
# mitered line joins (see #line_join_style). When the limit is exceeded, a bevel join is
|
697
742
|
# used instead of a miter join.
|
698
743
|
#
|
699
|
-
# Returns the current miter limit (see
|
700
|
-
#
|
701
|
-
#
|
744
|
+
# Returns the current miter limit (see GraphicsState#miter_limit) when no argument is given.
|
745
|
+
# Otherwise sets the miter limit to the given +limit+ and returns +self+. The setter version
|
746
|
+
# can also be called in the miter_limit= form.
|
702
747
|
#
|
703
748
|
# If the +limit+ and a block are provided, the changed miter limit is only active during the
|
704
749
|
# block by saving and restoring the graphics state.
|
@@ -722,7 +767,7 @@ module HexaPDF
|
|
722
767
|
# 60 + index * 80, 30).stroke
|
723
768
|
# end
|
724
769
|
#
|
725
|
-
# See:
|
770
|
+
# See: PDF2.0 s8.4.3.5
|
726
771
|
def miter_limit(limit = nil, &block)
|
727
772
|
gs_getter_setter(:miter_limit, :M, limit, &block)
|
728
773
|
end
|
@@ -740,7 +785,7 @@ module HexaPDF
|
|
740
785
|
#
|
741
786
|
# There are multiple ways to set the line dash pattern:
|
742
787
|
#
|
743
|
-
# * By providing a
|
788
|
+
# * By providing a LineDashPattern object
|
744
789
|
# * By providing a single Integer/Float that is used for both dashes and gaps
|
745
790
|
# * By providing an array of Integers/Floats that specify the alternating dashes and gaps
|
746
791
|
#
|
@@ -749,10 +794,10 @@ module HexaPDF
|
|
749
794
|
#
|
750
795
|
# A solid line can be achieved by using 0 for the length or by using an empty array.
|
751
796
|
#
|
752
|
-
# Returns the current line dash pattern (
|
753
|
-
# argument is given. Otherwise sets the line dash
|
754
|
-
# returns self
|
755
|
-
# without the second argument!).
|
797
|
+
# Returns the current line dash pattern (a LineDashPattern object, see
|
798
|
+
# GraphicsState#line_dash_pattern) when no argument is given. Otherwise sets the line dash
|
799
|
+
# pattern using the given arguments and returns +self+. The setter version can also be called
|
800
|
+
# in the line_dash_pattern= form (but only without the second argument!).
|
756
801
|
#
|
757
802
|
# If arguments and a block are provided, the changed line dash pattern is only active during
|
758
803
|
# the block by saving and restoring the graphics state.
|
@@ -778,7 +823,7 @@ module HexaPDF
|
|
778
823
|
# stroke
|
779
824
|
# end
|
780
825
|
#
|
781
|
-
# See:
|
826
|
+
# See: PDF2.0 s8.4.3.5, LineDashPattern
|
782
827
|
def line_dash_pattern(value = nil, phase = 0, &block)
|
783
828
|
gs_getter_setter(:line_dash_pattern, :d, value && LineDashPattern.normalize(value, phase),
|
784
829
|
&block)
|
@@ -799,9 +844,9 @@ module HexaPDF
|
|
799
844
|
# * +:Saturation+
|
800
845
|
# * +:Perceptual+
|
801
846
|
#
|
802
|
-
# Returns the current rendering intent (see
|
803
|
-
#
|
804
|
-
#
|
847
|
+
# Returns the current rendering intent (see GraphicsState#rendering_intent) when no argument
|
848
|
+
# is given. Otherwise sets the rendering intent using the +intent+ argument and returns
|
849
|
+
# +self+. The setter version can also be called in the rendering_intent= form.
|
805
850
|
#
|
806
851
|
# If the +intent+ and a block are provided, the changed rendering intent is only active
|
807
852
|
# during the block by saving and restoring the graphics state.
|
@@ -817,7 +862,7 @@ module HexaPDF
|
|
817
862
|
# end
|
818
863
|
# canvas.rendering_intent # => :Saturation
|
819
864
|
#
|
820
|
-
# See:
|
865
|
+
# See: PDF2.0 s8.6.5.8, RenderingIntent
|
821
866
|
def rendering_intent(intent = nil, &bk)
|
822
867
|
gs_getter_setter(:rendering_intent, :ri, intent && RenderingIntent.normalize(intent), &bk)
|
823
868
|
end
|
@@ -837,23 +882,30 @@ module HexaPDF
|
|
837
882
|
#
|
838
883
|
# There are several ways to define the color that should be used:
|
839
884
|
#
|
840
|
-
# * A single numeric argument specifies a gray color (see
|
841
|
-
#
|
842
|
-
# * Three numeric arguments specify an RGB color (see
|
885
|
+
# * A single numeric argument specifies a gray color (see ColorSpace::DeviceGray::Color).
|
886
|
+
#
|
887
|
+
# * Three numeric arguments specify an RGB color (see ColorSpace::DeviceRGB::Color).
|
888
|
+
#
|
843
889
|
# * A string in the format "RRGGBB" where "RR" is the hexadecimal number for the red, "GG"
|
844
890
|
# for the green and "BB" for the blue color value also specifies an RGB color.
|
891
|
+
#
|
845
892
|
# * As does a string in the format "RGB" where "RR", "GG" and "BB" would be used as the
|
846
893
|
# hexadecimal numbers for the red, green and blue color values of an RGB color.
|
847
|
-
#
|
848
|
-
#
|
849
|
-
#
|
894
|
+
#
|
895
|
+
# * Any other string is treated as a color name. HexaPDF supports CSS Color Module Level 3
|
896
|
+
# color names (see https://www.w3.org/TR/css-color-3/#svg-color) as well as HexaPDF design
|
897
|
+
# colors.
|
898
|
+
#
|
899
|
+
# * Four numeric arguments specify a CMYK color (see ColorSpace::DeviceCMYK::Color).
|
900
|
+
#
|
850
901
|
# * A color object is used directly (normally used for color spaces other than DeviceRGB,
|
851
902
|
# DeviceCMYK and DeviceGray).
|
903
|
+
#
|
852
904
|
# * An array is treated as if its items were specified separately as arguments.
|
853
905
|
#
|
854
|
-
# Returns the current stroke color (see
|
855
|
-
#
|
856
|
-
#
|
906
|
+
# Returns the current stroke color (see GraphicsState#stroke_color) when no argument is given.
|
907
|
+
# Otherwise sets the stroke color using the given arguments and returns +self+. The setter
|
908
|
+
# version can also be called in the stroke_color= form.
|
857
909
|
#
|
858
910
|
# If the arguments and a block are provided, the changed stroke color is only active during
|
859
911
|
# the block by saving and restoring the graphics state.
|
@@ -896,7 +948,7 @@ module HexaPDF
|
|
896
948
|
# canvas.stroke_color # => ColorSpace::DeviceGray.color(0.4)
|
897
949
|
# end
|
898
950
|
#
|
899
|
-
# See:
|
951
|
+
# See: PDF2.0 s8.6, ColorSpace
|
900
952
|
def stroke_color(*color, &block)
|
901
953
|
color_getter_setter(:stroke_color, color, :RG, :G, :K, :CS, :SCN, &block)
|
902
954
|
end
|
@@ -922,10 +974,10 @@ module HexaPDF
|
|
922
974
|
# the fill alpha value applies not just to fill values but to all non-stroking operations
|
923
975
|
# (e.g. images, ...).
|
924
976
|
#
|
925
|
-
# Returns the current fill alpha (see
|
926
|
-
#
|
977
|
+
# Returns the current fill alpha (see GraphicsState#fill_alpha) and stroke alpha (see
|
978
|
+
# GraphicsState#stroke_alpha) values using a hash with the keys +:fill_alpha+ and
|
927
979
|
# +:stroke_alpha+ when no argument is given. Otherwise sets the fill and stroke alpha values
|
928
|
-
# and returns self
|
980
|
+
# and returns +self+. The setter version can also be called in the #opacity= form.
|
929
981
|
#
|
930
982
|
# If the values are set and a block is provided, the changed alpha values are only active
|
931
983
|
# during the block by saving and restoring the graphics state.
|
@@ -944,15 +996,15 @@ module HexaPDF
|
|
944
996
|
# canvas.opacity # => {fill_alpha: 0.4, stroke_alpha: 0.9}
|
945
997
|
#
|
946
998
|
# # visual example
|
947
|
-
# canvas.opacity(fill_alpha: 1, stroke_alpha: 1)
|
948
|
-
#
|
949
|
-
#
|
999
|
+
# canvas.opacity(fill_alpha: 1, stroke_alpha: 1)
|
1000
|
+
# canvas.fill_color("hp-gray-light"). # background rectangle on right side
|
1001
|
+
# rectangle(100, 0, 100, 200).fill
|
950
1002
|
# canvas.opacity(fill_alpha: 0.5, stroke_alpha: 0.8). # foreground rectangle, with a thick
|
951
1003
|
# line_width(20). # stroke that also overlays the
|
952
|
-
# fill_color("
|
1004
|
+
# fill_color("hp-blue").stroke_color("hp-blue"). # inside of the rectangle, creating
|
953
1005
|
# rectangle(20, 20, 160, 160).fill_stroke # multiple shadings due to opacity
|
954
1006
|
#
|
955
|
-
# See:
|
1007
|
+
# See: PDF2.0 s11.6.4.4
|
956
1008
|
def opacity(fill_alpha: nil, stroke_alpha: nil)
|
957
1009
|
if !fill_alpha.nil? || !stroke_alpha.nil?
|
958
1010
|
raise_unless_at_page_description_level_or_in_text
|
@@ -981,14 +1033,14 @@ module HexaPDF
|
|
981
1033
|
# canvas.move_to(x, y) => canvas
|
982
1034
|
#
|
983
1035
|
# Begins a new subpath (and possibly a new path) by moving the current point to the given
|
984
|
-
# point
|
1036
|
+
# point and returns +self+.
|
985
1037
|
#
|
986
1038
|
# Examples:
|
987
1039
|
#
|
988
1040
|
# canvas.move_to(10, 50)
|
989
1041
|
# canvas.current_point # => [10, 50]
|
990
1042
|
#
|
991
|
-
# See:
|
1043
|
+
# See: PDF2.0 s8.5.2.1, #line_to, #curve_to, #rectangle
|
992
1044
|
def move_to(x, y)
|
993
1045
|
raise_unless_at_page_description_level_or_in_path
|
994
1046
|
invoke2(:m, x, y)
|
@@ -1001,17 +1053,20 @@ module HexaPDF
|
|
1001
1053
|
# canvas.line_to(x, y) => canvas
|
1002
1054
|
#
|
1003
1055
|
# Appends a straight line segment from the current point to the given point (which becomes the
|
1004
|
-
# new current point) to the current subpath
|
1056
|
+
# new current point) to the current subpath and returns +self+.
|
1057
|
+
#
|
1058
|
+
# If there is no current path when the method is invoked, an error is raised since a valid
|
1059
|
+
# current point (#current_point) is needed.
|
1005
1060
|
#
|
1006
1061
|
# Examples:
|
1007
1062
|
#
|
1008
1063
|
# #>pdf-center
|
1009
|
-
# canvas.move_to(10, 50)
|
1010
|
-
#
|
1011
|
-
# canvas.current_point
|
1064
|
+
# canvas.move_to(10, 50)
|
1065
|
+
# canvas.line_to(80, 80)
|
1066
|
+
# canvas.current_point # => [80, 80]
|
1012
1067
|
# canvas.stroke
|
1013
1068
|
#
|
1014
|
-
# See:
|
1069
|
+
# See: PDF2.0 s8.5.2.1, #move_to, #curve_to, #rectangle
|
1015
1070
|
def line_to(x, y)
|
1016
1071
|
raise_unless_in_path
|
1017
1072
|
invoke2(:l, x, y)
|
@@ -1025,8 +1080,11 @@ module HexaPDF
|
|
1025
1080
|
# canvas.curve_to(x, y, p1:) => canvas
|
1026
1081
|
# canvas.curve_to(x, y, p2:) => canvas
|
1027
1082
|
#
|
1028
|
-
# Appends a cubic Bezier curve to the current subpath starting from the current point
|
1029
|
-
# point becomes the new current point.
|
1083
|
+
# Appends a cubic Bezier curve to the current subpath starting from the current point and
|
1084
|
+
# returns +self+. The end point becomes the new current point.
|
1085
|
+
#
|
1086
|
+
# If there is no current path when the method is invoked, an error is raised since a valid
|
1087
|
+
# current point (#current_point) is needed.
|
1030
1088
|
#
|
1031
1089
|
# A Bezier curve consists of the start point, the end point and the two control points +p1+
|
1032
1090
|
# and +p2+. The start point is always the current point and the end point is specified as the
|
@@ -1047,7 +1105,7 @@ module HexaPDF
|
|
1047
1105
|
# canvas.current_point # => [-30, 60]
|
1048
1106
|
# canvas.stroke
|
1049
1107
|
#
|
1050
|
-
# See:
|
1108
|
+
# See: PDF2.0 s8.5.2.2, #move_to, #line_to, #rectangle
|
1051
1109
|
def curve_to(x, y, p1: nil, p2: nil)
|
1052
1110
|
raise_unless_in_path
|
1053
1111
|
if p1 && p2
|
@@ -1069,10 +1127,13 @@ module HexaPDF
|
|
1069
1127
|
#
|
1070
1128
|
# Appends a rectangle to the current path as a complete subpath (drawn in counterclockwise
|
1071
1129
|
# direction), with the bottom left corner specified by +x+ and +y+ and the given +width+ and
|
1072
|
-
# +height+.
|
1130
|
+
# +height+. Returns +self+.
|
1073
1131
|
#
|
1074
1132
|
# If +radius+ is greater than 0, the corners are rounded with the given radius.
|
1075
1133
|
#
|
1134
|
+
# Note that the rectangle degrades to a line if either width or height is zero and to nothing
|
1135
|
+
# if both are zero.
|
1136
|
+
#
|
1076
1137
|
# If there is no current path when the method is invoked, a new path is automatically begun.
|
1077
1138
|
#
|
1078
1139
|
# The current point is set to the bottom left corner if +radius+ is zero, otherwise it is set
|
@@ -1083,10 +1144,10 @@ module HexaPDF
|
|
1083
1144
|
# #>pdf
|
1084
1145
|
# canvas.rectangle(10, 110, 80, 50).stroke
|
1085
1146
|
# canvas.rectangle(110, 110, 80, 50, radius: 10).stroke
|
1086
|
-
# canvas.rectangle(10,
|
1087
|
-
# canvas.rectangle(110,
|
1147
|
+
# canvas.rectangle(10, 90, 80, 0).stroke # Degraded: Just a line
|
1148
|
+
# canvas.rectangle(110, 90, 0, 0).stroke # Degraded: Draws nothing
|
1088
1149
|
#
|
1089
|
-
# See:
|
1150
|
+
# See: PDF2.0 s8.5.2.1, #move_to, #line_to, #curve_to
|
1090
1151
|
def rectangle(x, y, width, height, radius: 0)
|
1091
1152
|
raise_unless_at_page_description_level_or_in_path
|
1092
1153
|
if radius == 0
|
@@ -1103,7 +1164,10 @@ module HexaPDF
|
|
1103
1164
|
# canvas.close_subpath => canvas
|
1104
1165
|
#
|
1105
1166
|
# Closes the current subpath by appending a straight line from the current point to the
|
1106
|
-
# start point of the subpath which also becomes the new current point.
|
1167
|
+
# start point of the subpath which also becomes the new current point. Returns +self+.
|
1168
|
+
#
|
1169
|
+
# If there is no current path when the method is invoked, an error is raised since a valid
|
1170
|
+
# current point (#current_point) is needed.
|
1107
1171
|
#
|
1108
1172
|
# Examples:
|
1109
1173
|
#
|
@@ -1114,7 +1178,7 @@ module HexaPDF
|
|
1114
1178
|
# close_subpath. # Draws the line from (60, 60) to (10, 10)
|
1115
1179
|
# stroke
|
1116
1180
|
#
|
1117
|
-
# See:
|
1181
|
+
# See: PDF2.0 s8.5.2.1
|
1118
1182
|
def close_subpath
|
1119
1183
|
raise_unless_in_path
|
1120
1184
|
invoke0(:h)
|
@@ -1126,13 +1190,16 @@ module HexaPDF
|
|
1126
1190
|
# canvas.line(x0, y0, x1, y1) => canvas
|
1127
1191
|
#
|
1128
1192
|
# Moves the current point to (x0, y0) and appends a line to (x1, y1) to the current path.
|
1193
|
+
# Returns +self+.
|
1129
1194
|
#
|
1130
|
-
#
|
1195
|
+
# If there is no current path when the method is invoked, a new path is automatically begun.
|
1131
1196
|
#
|
1132
1197
|
# Examples:
|
1133
1198
|
#
|
1134
1199
|
# #>pdf
|
1135
1200
|
# canvas.line(10, 10, 100, 100).stroke
|
1201
|
+
#
|
1202
|
+
# See: #move_to, #line_to
|
1136
1203
|
def line(x0, y0, x1, y1)
|
1137
1204
|
move_to(x0, y0)
|
1138
1205
|
line_to(x1, y1)
|
@@ -1143,12 +1210,16 @@ module HexaPDF
|
|
1143
1210
|
#
|
1144
1211
|
# Moves the current point to (x0, y0) and appends line segments between all given
|
1145
1212
|
# consecutive points, i.e. between (x0, y0) and (x1, y1), between (x1, y1) and (x2, y2) and
|
1146
|
-
# so on. The last point becomes the new current point.
|
1213
|
+
# so on. The last point becomes the new current point. Returns +self+.
|
1214
|
+
#
|
1215
|
+
# If there is no current path when the method is invoked, a new path is automatically begun.
|
1147
1216
|
#
|
1148
1217
|
# Examples:
|
1149
1218
|
#
|
1150
1219
|
# #>pdf
|
1151
1220
|
# canvas.polyline(50, 50, 150, 50, 150, 150, 50, 150, 50, 50).stroke
|
1221
|
+
#
|
1222
|
+
# See: #move_to, #line_to, #polygon
|
1152
1223
|
def polyline(*points)
|
1153
1224
|
check_poly_points(points)
|
1154
1225
|
move_to(points[0], points[1])
|
@@ -1163,8 +1234,8 @@ module HexaPDF
|
|
1163
1234
|
# :call-seq:
|
1164
1235
|
# canvas.polygon(x0, y0, x1, y1, x2, y2, ..., radius: 0) => canvas
|
1165
1236
|
#
|
1166
|
-
# Appends a polygon consisting of the given points to the path as a complete subpath
|
1167
|
-
# point (x0, y0 + radius) becomes the new current point.
|
1237
|
+
# Appends a polygon consisting of the given points to the path as a complete subpath and
|
1238
|
+
# returns +self+. The point (x0, y0 + radius) becomes the new current point.
|
1168
1239
|
#
|
1169
1240
|
# If +radius+ is greater than 0, the corners are rounded with the given radius.
|
1170
1241
|
#
|
@@ -1174,8 +1245,10 @@ module HexaPDF
|
|
1174
1245
|
#
|
1175
1246
|
# #>pdf
|
1176
1247
|
# canvas.polygon(10, 10, 90, 10, 70, 90, 20, 100).stroke
|
1177
|
-
# canvas.stroke_color("
|
1248
|
+
# canvas.stroke_color("hp-blue").
|
1178
1249
|
# polygon(130, 130, 150, 100, 170, 150, 130, 190, radius: 10).stroke
|
1250
|
+
#
|
1251
|
+
# See: #polyline
|
1179
1252
|
def polygon(*points, radius: 0)
|
1180
1253
|
if radius == 0
|
1181
1254
|
polyline(*points)
|
@@ -1195,16 +1268,19 @@ module HexaPDF
|
|
1195
1268
|
#
|
1196
1269
|
# Appends a circle with center (cx, cy) and the given radius (in degrees) to the path as a
|
1197
1270
|
# complete subpath (drawn in counterclockwise direction). The point (center_x + radius,
|
1198
|
-
# center_y) becomes the new current point.
|
1271
|
+
# center_y) becomes the new current point. Returns +self+.
|
1199
1272
|
#
|
1200
1273
|
# If there is no current path when the method is invoked, a new path is automatically begun.
|
1201
1274
|
#
|
1202
1275
|
# Examples:
|
1203
1276
|
#
|
1204
1277
|
# #>pdf
|
1205
|
-
# canvas.circle(100, 100, 30)
|
1278
|
+
# canvas.circle(100, 100, 30)
|
1279
|
+
# cp = canvas.current_point
|
1280
|
+
# canvas.stroke
|
1281
|
+
# canvas.stroke_color("hp-orange").line(*cp, 180, 100).stroke
|
1206
1282
|
#
|
1207
|
-
# See: #arc (for approximation accuracy)
|
1283
|
+
# See: #arc (for approximation accuracy), #ellipse
|
1208
1284
|
def circle(cx, cy, radius)
|
1209
1285
|
arc(cx, cy, a: radius)
|
1210
1286
|
close_subpath
|
@@ -1215,7 +1291,8 @@ module HexaPDF
|
|
1215
1291
|
#
|
1216
1292
|
# Appends an ellipse with center (cx, cy), semi-major axis +a+, semi-minor axis +b+ and an
|
1217
1293
|
# inclination from the x-axis of +inclination+ degrees to the path as a complete subpath. The
|
1218
|
-
# outer-most point on the semi-major axis becomes the new current point.
|
1294
|
+
# outer-most point on the positive semi-major axis becomes the new current point. Returns
|
1295
|
+
# self.
|
1219
1296
|
#
|
1220
1297
|
# If there is no current path when the method is invoked, a new path is automatically begun.
|
1221
1298
|
#
|
@@ -1225,11 +1302,15 @@ module HexaPDF
|
|
1225
1302
|
# # Ellipse aligned to x-axis and y-axis
|
1226
1303
|
# canvas.ellipse(50, 50, a: 20, b: 10).stroke
|
1227
1304
|
#
|
1228
|
-
# # Inclined ellipse
|
1229
|
-
# canvas.stroke_color("
|
1230
|
-
# ellipse(150, 150, a: 20, b: 10, inclination: 30)
|
1305
|
+
# # Inclined ellipse with line from the end point
|
1306
|
+
# canvas.stroke_color("hp-blue").
|
1307
|
+
# ellipse(150, 150, a: 20, b: 10, inclination: 30)
|
1308
|
+
# cp = canvas.current_point
|
1309
|
+
# x, y = 2 * canvas.current_point[0] - 150, 2 * canvas.current_point[1] - 150
|
1310
|
+
# canvas.stroke.
|
1311
|
+
# stroke_color("hp-orange").line(*cp, x, y).stroke
|
1231
1312
|
#
|
1232
|
-
# See: #arc (for approximation accuracy)
|
1313
|
+
# See: #arc (for approximation accuracy), #circle
|
1233
1314
|
def ellipse(cx, cy, a:, b:, inclination: 0)
|
1234
1315
|
arc(cx, cy, a: a, b: b, inclination: inclination)
|
1235
1316
|
close_subpath
|
@@ -1238,8 +1319,8 @@ module HexaPDF
|
|
1238
1319
|
# :call-seq:
|
1239
1320
|
# canvas.arc(cx, cy, a:, b: a, start_angle: 0, end_angle: 360, clockwise: false, inclination: 0) => canvas
|
1240
1321
|
#
|
1241
|
-
# Appends an elliptical arc to the path
|
1242
|
-
# point.
|
1322
|
+
# Appends an elliptical arc to the path and returns +self+. The endpoint of the arc becomes
|
1323
|
+
# the new current point.
|
1243
1324
|
#
|
1244
1325
|
# +cx+::
|
1245
1326
|
# x-coordinate of the center point of the arc
|
@@ -1271,6 +1352,9 @@ module HexaPDF
|
|
1271
1352
|
#
|
1272
1353
|
# If there is no current path when the method is invoked, a new path is automatically begun.
|
1273
1354
|
#
|
1355
|
+
# This arc does *not* start from the current point (#current_point). If this functionality is
|
1356
|
+
# needed, use #draw together with GraphicObject::EndpointArc.
|
1357
|
+
#
|
1274
1358
|
# Since PDF doesn't have operators for drawing elliptical or circular arcs, they have to be
|
1275
1359
|
# approximated using Bezier curves (see #curve_to). The accuracy of the approximation can be
|
1276
1360
|
# controlled using the configuration option 'graphic_object.arc.max_curves'.
|
@@ -1284,19 +1368,19 @@ module HexaPDF
|
|
1284
1368
|
# canvas.stroke
|
1285
1369
|
#
|
1286
1370
|
# # Circular and elliptical arcs from 30 degrees to 160 degrees
|
1287
|
-
# canvas.stroke_color("
|
1371
|
+
# canvas.stroke_color("hp-blue")
|
1288
1372
|
# canvas.arc(50, 100, a: 10, start_angle: 30, end_angle: 160)
|
1289
1373
|
# canvas.arc(100, 100, a: 10, b: 5, start_angle: 30, end_angle: 160)
|
1290
1374
|
# canvas.stroke
|
1291
1375
|
#
|
1292
1376
|
# # Arcs from 135 degrees to 30 degrees, the first in counterclockwise direction (i.e. the
|
1293
1377
|
# # big arc), the other in clockwise direction (i.e. the small arc)
|
1294
|
-
# canvas.stroke_color("
|
1378
|
+
# canvas.stroke_color("hp-orange")
|
1295
1379
|
# canvas.arc(50, 50, a: 10, start_angle: 135, end_angle: 30)
|
1296
1380
|
# canvas.arc(100, 50, a: 10, start_angle: 135, end_angle: 30, clockwise: true)
|
1297
1381
|
# canvas.stroke
|
1298
1382
|
#
|
1299
|
-
# See:
|
1383
|
+
# See: #arc, #circle, #ellipse, GraphicObject::Arc, GraphicObject::EndpointArc
|
1300
1384
|
def arc(cx, cy, a:, b: a, start_angle: 0, end_angle: 360, clockwise: false, inclination: 0)
|
1301
1385
|
arc = GraphicObject::Arc.configure(cx: cx, cy: cy, a: a, b: b,
|
1302
1386
|
start_angle: start_angle, end_angle: end_angle,
|
@@ -1314,18 +1398,18 @@ module HexaPDF
|
|
1314
1398
|
# :call-seq:
|
1315
1399
|
# canvas.line_with_rounded_corner(x0 = current_point[0], y0 = current_point[1], x1, y1, x2, y2, in_radius:, out_radius: in_radius)
|
1316
1400
|
#
|
1317
|
-
# Appends a line with a rounded corner at (x1, y1) from the current point
|
1318
|
-
# the rounded corner (i.e. +out_radius+ units from (x1, y1) in the direction
|
1319
|
-
# becomes the current point. In degraded cases the corner point (x1, y1) becomes
|
1320
|
-
# point.
|
1401
|
+
# Appends a line with a rounded corner at (x1, y1) from the current point and returns +self+.
|
1402
|
+
# The end point of the rounded corner (i.e. +out_radius+ units from (x1, y1) in the direction
|
1403
|
+
# of (x2, y2)) becomes the current point. In degraded cases the corner point (x1, y1) becomes
|
1404
|
+
# the current point.
|
1321
1405
|
#
|
1322
1406
|
# The corner is specified by (x0, y0) which defaults to the #current_point of the path, (x1,
|
1323
1407
|
# y1) and (x2, y2) - all of which need to be different points. The +in_radius+ specifies the
|
1324
1408
|
# corner radius into the corner and the +out_radius+ the one out of the corner. Degraded
|
1325
1409
|
# cases, like with (x0, y0) == (x1, y1), are handled gracefully.
|
1326
1410
|
#
|
1327
|
-
# There has to be a current path when this method is invoked
|
1328
|
-
#
|
1411
|
+
# There has to be a current path when this method is invoked, otherwise an error is raised.
|
1412
|
+
# For example, the current point could be estabilshed beforehand using #move_to.
|
1329
1413
|
#
|
1330
1414
|
# Examples:
|
1331
1415
|
#
|
@@ -1338,10 +1422,15 @@ module HexaPDF
|
|
1338
1422
|
# canvas.line_with_rounded_corner(180, 120, 150, 100, in_radius: 0, out_radius: 10)
|
1339
1423
|
# canvas.stroke
|
1340
1424
|
#
|
1341
|
-
# # Special effects when (x0, y0) is not the current point, like when the current
|
1342
|
-
# # would be equal to the corner point
|
1425
|
+
# # Special effects when (x0, y0) is not the current point, like when the current
|
1426
|
+
# # point would be equal to the corner point. Rounded rectangle use this method
|
1427
|
+
# # internally, as high-lighted by the blue segment.
|
1343
1428
|
# canvas.rectangle(10, 10, 60, 60, radius: 60).stroke
|
1344
|
-
# canvas.
|
1429
|
+
# canvas.stroke_color("hp-blue").
|
1430
|
+
# move_to(70, 10). # Start point at the end of the lower-left rounded corner
|
1431
|
+
# line_with_rounded_corner(10, 10, 70, 10, 70, 70, in_radius: 60).stroke
|
1432
|
+
# canvas.stroke_color("black").
|
1433
|
+
# rectangle(110, 10, 60, 60, radius: 70).stroke
|
1345
1434
|
def line_with_rounded_corner(x0 = current_point[0], y0 = current_point[1], x1, y1, x2, y2,
|
1346
1435
|
in_radius:, out_radius: in_radius)
|
1347
1436
|
if in_radius == 0 || out_radius == 0
|
@@ -1367,9 +1456,9 @@ module HexaPDF
|
|
1367
1456
|
#
|
1368
1457
|
# Returns the named graphic object, configured with the given options.
|
1369
1458
|
#
|
1370
|
-
# If an object responding to :configure is given, it is used. Otherwise the graphic object
|
1371
|
-
#
|
1372
|
-
# graphic object is configured with the given options if at least one is given.
|
1459
|
+
# If an object responding to :configure is given, it is used. Otherwise the graphic object is
|
1460
|
+
# looked up via the given name in the configuration option 'graphic_object.map'. Either way,
|
1461
|
+
# the graphic object is then configured with the given options if at least one is given.
|
1373
1462
|
#
|
1374
1463
|
# Examples:
|
1375
1464
|
#
|
@@ -1378,7 +1467,7 @@ module HexaPDF
|
|
1378
1467
|
# outer_a: 50, outer_b: 40, end_angle: 135)
|
1379
1468
|
# canvas.draw(obj).stroke
|
1380
1469
|
#
|
1381
|
-
# See:
|
1470
|
+
# See: #draw, GraphicObject
|
1382
1471
|
def graphic_object(obj, **options)
|
1383
1472
|
unless obj.respond_to?(:configure)
|
1384
1473
|
obj = context.document.config.constantize('graphic_object.map', obj)
|
@@ -1404,7 +1493,7 @@ module HexaPDF
|
|
1404
1493
|
# :call-seq:
|
1405
1494
|
# canvas.stroke => canvas
|
1406
1495
|
#
|
1407
|
-
# Strokes the path
|
1496
|
+
# Strokes the path and returns +self+.
|
1408
1497
|
#
|
1409
1498
|
# Examples:
|
1410
1499
|
#
|
@@ -1412,7 +1501,7 @@ module HexaPDF
|
|
1412
1501
|
# canvas.polyline(10, 10, 120, 40, 50, 160)
|
1413
1502
|
# canvas.stroke
|
1414
1503
|
#
|
1415
|
-
# See:
|
1504
|
+
# See: PDF2.0 s8.5.3.1, s8.5.3.2, #close_stroke, #close_fill_stroke
|
1416
1505
|
def stroke
|
1417
1506
|
raise_unless_in_path_or_clipping_path
|
1418
1507
|
invoke0(:S)
|
@@ -1422,7 +1511,7 @@ module HexaPDF
|
|
1422
1511
|
# :call-seq:
|
1423
1512
|
# canvas.close_stroke => canvas
|
1424
1513
|
#
|
1425
|
-
# Closes the last subpath and then strokes the path.
|
1514
|
+
# Closes the last subpath and then strokes the path. Returns +self+.
|
1426
1515
|
#
|
1427
1516
|
# Examples:
|
1428
1517
|
#
|
@@ -1430,7 +1519,7 @@ module HexaPDF
|
|
1430
1519
|
# canvas.polyline(10, 10, 120, 40, 50, 160) # No line from the top to the left
|
1431
1520
|
# canvas.close_stroke
|
1432
1521
|
#
|
1433
|
-
# See:
|
1522
|
+
# See: PDF2.0 s8.5.3.1, s8.5.3.2, #stroke, #close_fill_stroke
|
1434
1523
|
def close_stroke
|
1435
1524
|
raise_unless_in_path_or_clipping_path
|
1436
1525
|
invoke0(:s)
|
@@ -1440,25 +1529,26 @@ module HexaPDF
|
|
1440
1529
|
# :call-seq:
|
1441
1530
|
# canvas.fill(rule = :nonzero) => canvas
|
1442
1531
|
#
|
1443
|
-
# Fills the path using the given rule
|
1532
|
+
# Fills the path using the given rule and returns +self+.
|
1444
1533
|
#
|
1445
1534
|
# The argument +rule+ may either be +:nonzero+ to use the nonzero winding number rule or
|
1446
1535
|
# +:even_odd+ to use the even-odd rule for determining which regions to fill in. Details on
|
1447
|
-
# how these rules work are found in the PDF
|
1536
|
+
# how these rules work are found in the PDF 2.0 spec section 8.5.3.3 or via Internet search.
|
1448
1537
|
#
|
1449
1538
|
# Any open subpaths are implicitly closed before being filled.
|
1450
1539
|
#
|
1451
1540
|
# Examples:
|
1452
1541
|
#
|
1453
1542
|
# #>pdf
|
1454
|
-
# canvas.
|
1455
|
-
#
|
1543
|
+
# canvas.fill_color("hp-blue").
|
1544
|
+
# polyline(20, 10, 90, 60, 10, 60, 80, 10, 50, 90).
|
1545
|
+
# fill
|
1456
1546
|
#
|
1457
|
-
# canvas.fill_color("
|
1458
|
-
#
|
1459
|
-
#
|
1547
|
+
# canvas.fill_color("hp-orange").
|
1548
|
+
# polyline(120, 110, 190, 160, 110, 160, 180, 110, 150, 190).
|
1549
|
+
# fill(:even_odd)
|
1460
1550
|
#
|
1461
|
-
# See:
|
1551
|
+
# See: PDF2.0 s8.5.3.1, s8.5.3.3, #fill_stroke, #close_fill_stroke
|
1462
1552
|
def fill(rule = :nonzero)
|
1463
1553
|
raise_unless_in_path_or_clipping_path
|
1464
1554
|
invoke0(rule == :nonzero ? :f : :'f*')
|
@@ -1468,26 +1558,27 @@ module HexaPDF
|
|
1468
1558
|
# :call-seq:
|
1469
1559
|
# canvas.fill_stroke(rule = :nonzero) => canvas
|
1470
1560
|
#
|
1471
|
-
# Fills and then strokes the path using the given rule.
|
1561
|
+
# Fills and then strokes the path using the given rule. Returns +self+.
|
1472
1562
|
#
|
1473
1563
|
# The argument +rule+ may either be +:nonzero+ to use the nonzero winding number rule or
|
1474
1564
|
# +:even_odd+ to use the even-odd rule for determining which regions to fill in. Details on
|
1475
|
-
# how these rules work are found in the PDF
|
1565
|
+
# how these rules work are found in the PDF 2.0 spec section 8.5.3.3 or via Internet search.
|
1476
1566
|
#
|
1477
|
-
# Note that any open subpaths are *not* closed
|
1567
|
+
# Note that any open subpaths are *not* closed concerning the stroking operation.
|
1478
1568
|
#
|
1479
1569
|
# Examples:
|
1480
1570
|
#
|
1481
1571
|
# #>pdf
|
1482
|
-
# canvas.stroke_color("
|
1483
|
-
# canvas.
|
1484
|
-
#
|
1572
|
+
# canvas.stroke_color("hp-orange").line_width(3)
|
1573
|
+
# canvas.fill_color("hp-blue").
|
1574
|
+
# polyline(20, 10, 90, 60, 10, 60, 80, 10, 50, 90).
|
1575
|
+
# fill_stroke # Note the missing stroke from the top corner
|
1485
1576
|
#
|
1486
|
-
# canvas.fill_color("
|
1487
|
-
#
|
1488
|
-
#
|
1577
|
+
# canvas.fill_color("hp-teal").
|
1578
|
+
# polyline(120, 110, 190, 160, 110, 160, 180, 110, 150, 190).
|
1579
|
+
# fill_stroke(:even_odd) # Note the missing stroke from the top corner
|
1489
1580
|
#
|
1490
|
-
# See:
|
1581
|
+
# See: PDF2.0 s8.5.3.1, s8.5.3.3, #fill, #close_fill_stroke
|
1491
1582
|
def fill_stroke(rule = :nonzero)
|
1492
1583
|
raise_unless_in_path_or_clipping_path
|
1493
1584
|
invoke0(rule == :nonzero ? :B : :'B*')
|
@@ -1497,24 +1588,26 @@ module HexaPDF
|
|
1497
1588
|
# :call-seq:
|
1498
1589
|
# canvas.close_fill_stroke(rule = :nonzero) => canvas
|
1499
1590
|
#
|
1500
|
-
# Closes the last subpath and then fills and strokes the path using the given rule.
|
1591
|
+
# Closes the last subpath and then fills and strokes the path using the given rule. Returns
|
1592
|
+
# +self+.
|
1501
1593
|
#
|
1502
1594
|
# The argument +rule+ may either be +:nonzero+ to use the nonzero winding number rule or
|
1503
1595
|
# +:even_odd+ to use the even-odd rule for determining which regions to fill in. Details on
|
1504
|
-
# how these rules work are found in the PDF
|
1596
|
+
# how these rules work are found in the PDF 2.0 spec section 8.5.3.3 or via Internet search.
|
1505
1597
|
#
|
1506
1598
|
# Examples:
|
1507
1599
|
#
|
1508
1600
|
# #>pdf
|
1509
|
-
# canvas.stroke_color("
|
1510
|
-
# canvas.
|
1511
|
-
#
|
1601
|
+
# canvas.stroke_color("hp-orange").line_width(3)
|
1602
|
+
# canvas.fill_color("hp-blue").
|
1603
|
+
# polyline(20, 10, 90, 60, 10, 60, 80, 10, 50, 90).
|
1604
|
+
# close_fill_stroke
|
1512
1605
|
#
|
1513
|
-
# canvas.fill_color("
|
1514
|
-
#
|
1515
|
-
#
|
1606
|
+
# canvas.fill_color("hp-teal").
|
1607
|
+
# polyline(120, 110, 190, 160, 110, 160, 180, 110, 150, 190).
|
1608
|
+
# close_fill_stroke(:even_odd)
|
1516
1609
|
#
|
1517
|
-
# See:
|
1610
|
+
# See: PDF2.0 s8.5.3, #fill, #fill_stroke
|
1518
1611
|
def close_fill_stroke(rule = :nonzero)
|
1519
1612
|
raise_unless_in_path_or_clipping_path
|
1520
1613
|
invoke0(rule == :nonzero ? :b : :'b*')
|
@@ -1524,17 +1617,17 @@ module HexaPDF
|
|
1524
1617
|
# :call-seq:
|
1525
1618
|
# canvas.end_path => canvas
|
1526
1619
|
#
|
1527
|
-
# Ends the path without stroking or filling it
|
1620
|
+
# Ends the path without stroking or filling it and returns +self+.
|
1528
1621
|
#
|
1529
|
-
# This method is
|
1530
|
-
# clipping.
|
1622
|
+
# This method is usually used in conjunction with the clipping path methods to define the
|
1623
|
+
# clipping path.
|
1531
1624
|
#
|
1532
1625
|
# Examples:
|
1533
1626
|
#
|
1534
1627
|
# canvas.line(10, 10, 100, 100)
|
1535
1628
|
# canvas.end_path # Nothing to see here!
|
1536
1629
|
#
|
1537
|
-
# See:
|
1630
|
+
# See: PDF2.0 s8.5.3.1, #clip_path
|
1538
1631
|
def end_path
|
1539
1632
|
raise_unless_in_path_or_clipping_path
|
1540
1633
|
invoke0(:n)
|
@@ -1544,11 +1637,11 @@ module HexaPDF
|
|
1544
1637
|
# :call-seq:
|
1545
1638
|
# canvas.clip_path(rule = :nonzero) => canvas
|
1546
1639
|
#
|
1547
|
-
# Modifies the clipping path by intersecting it with the current path.
|
1640
|
+
# Modifies the clipping path by intersecting it with the current path. Returns +self+.
|
1548
1641
|
#
|
1549
1642
|
# The argument +rule+ may either be +:nonzero+ to use the nonzero winding number rule or
|
1550
1643
|
# +:even_odd+ to use the even-odd rule for determining which regions lie inside the clipping
|
1551
|
-
# path. Details on how these rules work are found in the PDF
|
1644
|
+
# path. Details on how these rules work are found in the PDF 2.0 spec section 8.5.3.3 or via
|
1552
1645
|
# Internet search.
|
1553
1646
|
#
|
1554
1647
|
# The initial clipping path includes the entire canvas. Once the clipping path is reduced to a
|
@@ -1566,7 +1659,7 @@ module HexaPDF
|
|
1566
1659
|
# clip_path(:even_odd).end_path
|
1567
1660
|
# canvas.rectangle(0, 0, 200, 200).fill # Fills everything inside the clipping path
|
1568
1661
|
#
|
1569
|
-
# See:
|
1662
|
+
# See: PDF2.0 s8.5.4, #end_path
|
1570
1663
|
def clip_path(rule = :nonzero)
|
1571
1664
|
raise_unless_in_path
|
1572
1665
|
invoke0(rule == :nonzero ? :W : :'W*')
|
@@ -1583,8 +1676,8 @@ module HexaPDF
|
|
1583
1676
|
# position and returns the XObject.
|
1584
1677
|
#
|
1585
1678
|
# Any image format for which a HexaPDF::ImageLoader object is available and registered with
|
1586
|
-
# the configuration option 'image_loader' can be used. PNG
|
1587
|
-
# of the box.
|
1679
|
+
# the configuration option 'image_loader' can be used. PNG (lossless), JPEG (lossy) and PDF
|
1680
|
+
# (vector) images are supported out of the box.
|
1588
1681
|
#
|
1589
1682
|
# If the filename or the IO specifies a PDF file, the first page of this file is used to
|
1590
1683
|
# create a form XObject which is then drawn.
|
@@ -1608,18 +1701,18 @@ module HexaPDF
|
|
1608
1701
|
# #>pdf
|
1609
1702
|
# canvas.xobject(machu_picchu, at: [10, 10], width: 90) # bottom left
|
1610
1703
|
#
|
1611
|
-
# file = File.new(machu_picchu, 'rb')
|
1704
|
+
# file = File.new(machu_picchu, 'rb') # top left
|
1612
1705
|
# canvas.xobject(file, at: [10, 110], height: 50)
|
1613
1706
|
#
|
1614
1707
|
# image = doc.images.add(machu_picchu)
|
1615
1708
|
# canvas.xobject(image, at: [110, 10], width: 50, height: 90) # bottom right
|
1616
1709
|
#
|
1617
1710
|
# form = doc.add({Type: :XObject, Subtype: :Form, BBox: [0, 0, 100, 100]})
|
1618
|
-
# form.canvas.line(10, 10, 90, 90).stroke
|
1711
|
+
# form.canvas.stroke_color("hp-blue").line(10, 10, 90, 90).stroke
|
1619
1712
|
# canvas.line_width = 20
|
1620
1713
|
# canvas.xobject(form, at: [100, 100]) # top right
|
1621
1714
|
#
|
1622
|
-
# See:
|
1715
|
+
# See: PDF2.0 s8.8, s.8.10.1, HexaPDF::Type::Image, HexaPDF::Type::Form, HexaPDF::ImageLoader
|
1623
1716
|
def xobject(obj, at:, width: nil, height: nil)
|
1624
1717
|
unless obj.kind_of?(HexaPDF::Stream)
|
1625
1718
|
obj = context.document.images.add(obj)
|
@@ -1653,14 +1746,18 @@ module HexaPDF
|
|
1653
1746
|
# canvas.character_spacing(amount) => canvas
|
1654
1747
|
# canvas.character_spacing(amount) { block } => canvas
|
1655
1748
|
#
|
1656
|
-
# The character spacing determines how much additional space is added
|
1657
|
-
#
|
1658
|
-
# between two characters, whereas for vertical writing negative values increase the
|
1749
|
+
# The character spacing determines how much additional space is added after each character
|
1750
|
+
# (or, more correctly, after each glyph). For horizontal writing positive values increase the
|
1751
|
+
# distance between two characters, whereas for vertical writing negative values increase the
|
1659
1752
|
# distance.
|
1660
1753
|
#
|
1661
|
-
#
|
1662
|
-
#
|
1663
|
-
#
|
1754
|
+
# Note that the character spacing is applied to all characters that are rendered. This has the
|
1755
|
+
# effect that there is also a space after the last character which might not be wanted in
|
1756
|
+
# certain cases (e.g. when justifying text).
|
1757
|
+
#
|
1758
|
+
# Returns the current character spacing value (see GraphicsState#character_spacing) when no
|
1759
|
+
# argument is given. Otherwise sets the character spacing using the +amount+ argument and
|
1760
|
+
# returns +self+. The setter version can also be called in the character_spacing= form.
|
1664
1761
|
#
|
1665
1762
|
# If the +amount+ and a block are provided, the changed character spacing is only active
|
1666
1763
|
# during the block by saving and restoring the graphics state.
|
@@ -1680,11 +1777,18 @@ module HexaPDF
|
|
1680
1777
|
# # visual example
|
1681
1778
|
# canvas.font("Helvetica", size: 10)
|
1682
1779
|
# canvas.character_spacing = 0 # initial value
|
1683
|
-
# canvas.text("This is an example
|
1684
|
-
#
|
1685
|
-
#
|
1686
|
-
#
|
1687
|
-
#
|
1780
|
+
# canvas.text("This is an example", at: [10, 150])
|
1781
|
+
# # show that the text cursor is directly after the last glyph
|
1782
|
+
# x, y = canvas.text_cursor
|
1783
|
+
# canvas.stroke_color("hp-blue").line(x, y, x, y + 10).stroke
|
1784
|
+
#
|
1785
|
+
# canvas.character_spacing = 5
|
1786
|
+
# canvas.text("This is an example", at: [10, 100])
|
1787
|
+
# # visualize the spacing after the last glyph
|
1788
|
+
# x, y = canvas.text_cursor
|
1789
|
+
# canvas.stroke_color("hp-blue").line(x, y, x, y + 10).stroke
|
1790
|
+
#
|
1791
|
+
# See: PDF2.0 s9.3.2, #word_spacing, #horizontal_scaling
|
1688
1792
|
def character_spacing(amount = nil, &bk)
|
1689
1793
|
gs_getter_setter(:character_spacing, :Tc, amount, &bk)
|
1690
1794
|
end
|
@@ -1703,9 +1807,9 @@ module HexaPDF
|
|
1703
1807
|
# *Important*: In HexaPDF only the standard 14 PDF Type1 fonts support this property! When
|
1704
1808
|
# using any other font, for example a TrueType font, this property has no effect.
|
1705
1809
|
#
|
1706
|
-
# Returns the current word spacing value (see
|
1707
|
-
#
|
1708
|
-
#
|
1810
|
+
# Returns the current word spacing value (see GraphicsState#word_spacing) when no argument is
|
1811
|
+
# given. Otherwise sets the word spacing using the +amount+ argument and returns +self+. The
|
1812
|
+
# setter version can also be called in the word_spacing= form.
|
1709
1813
|
#
|
1710
1814
|
# If the +amount+ and a block are provided, the changed word spacing is only active during
|
1711
1815
|
# the block by saving and restoring the graphics state.
|
@@ -1729,7 +1833,7 @@ module HexaPDF
|
|
1729
1833
|
# canvas.word_spacing = 10
|
1730
1834
|
# canvas.text("This is an example text.", at: [10, 100])
|
1731
1835
|
#
|
1732
|
-
# See:
|
1836
|
+
# See: PDF2.0 s9.3.3, #character_spacing, #horizontal_scaling
|
1733
1837
|
def word_spacing(amount = nil, &bk)
|
1734
1838
|
gs_getter_setter(:word_spacing, :Tw, amount, &bk)
|
1735
1839
|
end
|
@@ -1744,10 +1848,9 @@ module HexaPDF
|
|
1744
1848
|
# compressing them in the horizontal direction. The value is specified as percent of the
|
1745
1849
|
# normal width, so 100 means no scaling.
|
1746
1850
|
#
|
1747
|
-
# Returns the current horizontal scaling value (see
|
1748
|
-
#
|
1749
|
-
#
|
1750
|
-
# form.
|
1851
|
+
# Returns the current horizontal scaling value (see GraphicsState#horizontal_scaling) when no
|
1852
|
+
# argument is given. Otherwise sets the horizontal scaling using the +percent+ argument and
|
1853
|
+
# returns +self+. The setter version can also be called in the horizontal_scaling= form.
|
1751
1854
|
#
|
1752
1855
|
# If the +percent+ and a block are provided, the changed horizontal scaling is only active
|
1753
1856
|
# during the block by saving and restoring the graphics state.
|
@@ -1771,7 +1874,7 @@ module HexaPDF
|
|
1771
1874
|
# canvas.horizontal_scaling = 50
|
1772
1875
|
# canvas.text("This is an example text.", at: [10, 100])
|
1773
1876
|
#
|
1774
|
-
# See:
|
1877
|
+
# See: PDF2.0 s9.3.4, #character_spacing, #word_spacing
|
1775
1878
|
def horizontal_scaling(amount = nil, &bk)
|
1776
1879
|
gs_getter_setter(:horizontal_scaling, :Tz, amount, &bk)
|
1777
1880
|
end
|
@@ -1789,8 +1892,8 @@ module HexaPDF
|
|
1789
1892
|
# There are other PDF content stream operators that would be effected but those are not used
|
1790
1893
|
# by the canvas.
|
1791
1894
|
#
|
1792
|
-
# Returns the current leading value (see
|
1793
|
-
#
|
1895
|
+
# Returns the current leading value (see GraphicsState#leading) when no argument is given.
|
1896
|
+
# Otherwise sets the leading using the +amount+ argument and returns +self+. The setter
|
1794
1897
|
# version can also be called in the leading= form.
|
1795
1898
|
#
|
1796
1899
|
# If the +amount+ and a block are provided, the changed leading is only active during the
|
@@ -1813,7 +1916,7 @@ module HexaPDF
|
|
1813
1916
|
# canvas.leading = 15
|
1814
1917
|
# canvas.text("This is an example text.\nwith a second\nand thrid line", at: [10, 150])
|
1815
1918
|
#
|
1816
|
-
# See:
|
1919
|
+
# See: PDF2.0 s9.3.5, #move_text_cursor
|
1817
1920
|
def leading(amount = nil, &bk)
|
1818
1921
|
gs_getter_setter(:leading, :TL, amount, &bk)
|
1819
1922
|
end
|
@@ -1824,16 +1927,33 @@ module HexaPDF
|
|
1824
1927
|
# canvas.text_rendering_mode(mode) => canvas
|
1825
1928
|
# canvas.text_rendering_mode(mode) { block } => canvas
|
1826
1929
|
#
|
1827
|
-
# The text rendering mode determines if and how glyphs are rendered.
|
1828
|
-
#
|
1829
|
-
#
|
1830
|
-
#
|
1831
|
-
#
|
1832
|
-
#
|
1833
|
-
#
|
1834
|
-
#
|
1835
|
-
#
|
1836
|
-
#
|
1930
|
+
# The text rendering mode determines if and how glyphs are rendered.
|
1931
|
+
#
|
1932
|
+
# The +mode+ parameter can be one of the following (also see TextRenderingMode):
|
1933
|
+
#
|
1934
|
+
# :fill or 0::
|
1935
|
+
# The text is filled (default)
|
1936
|
+
# :stroke or 1::
|
1937
|
+
# The text is stroked.
|
1938
|
+
# :fill_stroke or 2::
|
1939
|
+
# The test is filled, then stroked.
|
1940
|
+
# :invisible or 3::
|
1941
|
+
# The text is neither filled nor stroked.
|
1942
|
+
# :fill_clip or 4::
|
1943
|
+
# The text is filled and added to the clipping path.
|
1944
|
+
# :stroke_clip or 5::
|
1945
|
+
# The text is stroked and added to the clipping path.
|
1946
|
+
# :fill_stroke_clip or 6::
|
1947
|
+
# The text is filled, then stroked and added to the clipping path.
|
1948
|
+
# :clip or 7::
|
1949
|
+
# The text is added to the clipping path.
|
1950
|
+
# either be a valid integer or one of the symbols +:fill+, +:stroke+,
|
1951
|
+
#
|
1952
|
+
# Note that the return value is always a normalized text rendering mode value.
|
1953
|
+
#
|
1954
|
+
# Returns the current text rendering mode value (see GraphicsState#text_rendering_mode) when
|
1955
|
+
# no argument is given. Otherwise sets the text rendering mode using the +mode+ argument and
|
1956
|
+
# returns +self+. The setter version can also be called in the text_rendering_mode= form.
|
1837
1957
|
#
|
1838
1958
|
# If the +mode+ and a block are provided, the changed text rendering mode is only active
|
1839
1959
|
# during the block by saving and restoring the graphics state.
|
@@ -1858,7 +1978,7 @@ module HexaPDF
|
|
1858
1978
|
# canvas.text("#{trm} text.", at: [20, 150 - 30 * index])
|
1859
1979
|
# end
|
1860
1980
|
#
|
1861
|
-
# See:
|
1981
|
+
# See: PDF2.0 s9.3.6, GraphicsState::TextRenderingMode
|
1862
1982
|
def text_rendering_mode(m = nil, &bk)
|
1863
1983
|
gs_getter_setter(:text_rendering_mode, :Tr, m && TextRenderingMode.normalize(m), &bk)
|
1864
1984
|
end
|
@@ -1872,9 +1992,9 @@ module HexaPDF
|
|
1872
1992
|
# The text rise specifies the vertical distance to move the baseline up or down from its
|
1873
1993
|
# default location. Positive values move the baseline up, negative values down.
|
1874
1994
|
#
|
1875
|
-
# Returns the current text rise value (see
|
1876
|
-
#
|
1877
|
-
#
|
1995
|
+
# Returns the current text rise value (see GraphicsState#text_rise) when no argument is given.
|
1996
|
+
# Otherwise sets the text rise using the +amount+ argument and returns +self+. The setter
|
1997
|
+
# version can also be called in the text_rise= form.
|
1878
1998
|
#
|
1879
1999
|
# If the +amount+ and a block are provided, the changed text rise is only active during the
|
1880
2000
|
# block by saving and restoring the graphics state.
|
@@ -1900,7 +2020,7 @@ module HexaPDF
|
|
1900
2020
|
# canvas.text_rise = -10
|
1901
2021
|
# canvas.text("and also down here")
|
1902
2022
|
#
|
1903
|
-
# See:
|
2023
|
+
# See: PDF2.0 s9.3.7
|
1904
2024
|
def text_rise(amount = nil, &bk)
|
1905
2025
|
gs_getter_setter(:text_rise, :Ts, amount, &bk)
|
1906
2026
|
end
|
@@ -1909,7 +2029,7 @@ module HexaPDF
|
|
1909
2029
|
# :call-seq:
|
1910
2030
|
# canvas.begin_text(force_new: false) -> canvas
|
1911
2031
|
#
|
1912
|
-
# Begins a new text object
|
2032
|
+
# Begins a new text object and returns +self+.
|
1913
2033
|
#
|
1914
2034
|
# If +force+ is +true+ and the current graphics object is already a text object, it is ended
|
1915
2035
|
# and a new text object is begun.
|
@@ -1917,7 +2037,7 @@ module HexaPDF
|
|
1917
2037
|
# It is not necessary to invoke this method manually in most cases since it is automatically
|
1918
2038
|
# called when needed by other methods, i.e. the #text method.
|
1919
2039
|
#
|
1920
|
-
# See:
|
2040
|
+
# See: PDF2.0 s9.4.1, #end_text, #text
|
1921
2041
|
def begin_text(force_new: false)
|
1922
2042
|
raise_unless_at_page_description_level_or_in_text
|
1923
2043
|
end_text if force_new
|
@@ -1928,12 +2048,12 @@ module HexaPDF
|
|
1928
2048
|
# :call-seq:
|
1929
2049
|
# canvas.end_text -> canvas
|
1930
2050
|
#
|
1931
|
-
# Ends the current text object
|
2051
|
+
# Ends the current text object and returns +self+.
|
1932
2052
|
#
|
1933
2053
|
# It is not necessary to invoke this method manually in most cases since it is automatically
|
1934
2054
|
# called when needed by other methods, i.e. when creating a new path.
|
1935
2055
|
#
|
1936
|
-
# See:
|
2056
|
+
# See: PDF2.0 s9.4.1, #begin_text
|
1937
2057
|
def end_text
|
1938
2058
|
raise_unless_at_page_description_level_or_in_text
|
1939
2059
|
invoke0(:ET) if graphics_object == :text
|
@@ -1943,7 +2063,12 @@ module HexaPDF
|
|
1943
2063
|
# :call-seq:
|
1944
2064
|
# canvas.text_matrix(a, b, c, d, e, f) => canvas
|
1945
2065
|
#
|
1946
|
-
# Sets the text matrix (and the text line matrix) to the given matrix and returns self
|
2066
|
+
# Sets the text matrix (and the text line matrix) to the given matrix and returns +self+.
|
2067
|
+
#
|
2068
|
+
# The text matrix determines where and how the glyphs are rendered. The most common use is to
|
2069
|
+
# translate the text space origin since the text drawing operations always use the text space
|
2070
|
+
# origin as starting point for drawing the glyphs. This translation operation can more easily
|
2071
|
+
# be specified using #move_text_cursor.
|
1947
2072
|
#
|
1948
2073
|
# The given values are interpreted as a matrix in the following way:
|
1949
2074
|
#
|
@@ -1965,7 +2090,7 @@ module HexaPDF
|
|
1965
2090
|
# canvas.text_matrix(2, 1, 3, 0.5, 50, 50)
|
1966
2091
|
# canvas.text("This is some text")
|
1967
2092
|
#
|
1968
|
-
# See:
|
2093
|
+
# See: PDF2.0 s9.4.2, #move_text_cursor, #text_cursor
|
1969
2094
|
def text_matrix(a, b, c, d, e, f)
|
1970
2095
|
begin_text
|
1971
2096
|
invoke(:Tm, a, b, c, d, e, f)
|
@@ -1975,7 +2100,7 @@ module HexaPDF
|
|
1975
2100
|
# :call-seq:
|
1976
2101
|
# canvas.move_text_cursor(offset: nil, absolute: true) -> canvas
|
1977
2102
|
#
|
1978
|
-
# Moves the text cursor by modifying the text and text line matrices.
|
2103
|
+
# Moves the text cursor by modifying the text and text line matrices. Returns +self+.
|
1979
2104
|
#
|
1980
2105
|
# If +offset+ is not specified, the text cursor is moved to the start of the next text line
|
1981
2106
|
# using #leading as vertical offset.
|
@@ -2010,7 +2135,7 @@ module HexaPDF
|
|
2010
2135
|
# canvas.move_text_cursor
|
2011
2136
|
# canvas.text("Text on next line with leading=30")
|
2012
2137
|
#
|
2013
|
-
# See:
|
2138
|
+
# See: PDF2.0 s9.4.2, #leading, #text_cursor, #text, #show_glyphs
|
2014
2139
|
def move_text_cursor(offset: nil, absolute: true)
|
2015
2140
|
begin_text
|
2016
2141
|
if offset
|
@@ -2028,7 +2153,8 @@ module HexaPDF
|
|
2028
2153
|
# :call-seq:
|
2029
2154
|
# canvas.text_cursor -> [x, y]
|
2030
2155
|
#
|
2031
|
-
# Returns the position of the text cursor, i.e. the origin of
|
2156
|
+
# Returns the position of the text cursor, i.e. the origin of text space. This is where the
|
2157
|
+
# first glyph of the next drawn text will be placed.
|
2032
2158
|
#
|
2033
2159
|
# Note that this method can only be called while the current graphic object is a text object
|
2034
2160
|
# since the text matrix is otherwise undefined.
|
@@ -2038,10 +2164,11 @@ module HexaPDF
|
|
2038
2164
|
# #>pdf
|
2039
2165
|
# canvas.font("Helvetica", size: 10)
|
2040
2166
|
# canvas.text("Some sample text", at: [30, 150])
|
2041
|
-
#
|
2042
|
-
# canvas.
|
2043
|
-
#
|
2044
|
-
#
|
2167
|
+
# tx, ty = canvas.text_cursor # Cursor is directly after the text
|
2168
|
+
# canvas.stroke_color("hp-blue").
|
2169
|
+
# circle(tx, ty, 0.5).
|
2170
|
+
# circle(tx, ty, 5).stroke
|
2171
|
+
# canvas.text("Last cursor: (#{tx.round(2)}, #{ty.round(2)})", at: [30, 100])
|
2045
2172
|
#
|
2046
2173
|
# See: #move_text_cursor
|
2047
2174
|
def text_cursor
|
@@ -2055,7 +2182,7 @@ module HexaPDF
|
|
2055
2182
|
#
|
2056
2183
|
# Specifies the font and optional the font size that should be used when showing text.
|
2057
2184
|
#
|
2058
|
-
# A valid font size
|
2185
|
+
# A valid font size needs to be provided on the first invocation, otherwise an error is raised
|
2059
2186
|
# (this is due to how setting a font works with PDFs).
|
2060
2187
|
#
|
2061
2188
|
# If +size+ is specified, the #font_size method is invoked with it as argument.
|
@@ -2065,8 +2192,9 @@ module HexaPDF
|
|
2065
2192
|
# specifies the font variant to use, with standard values of :none, :italic, :bold and
|
2066
2193
|
# :bold_italic.
|
2067
2194
|
#
|
2068
|
-
# Returns the current font object when no argument is given
|
2069
|
-
# object itself, not the PDF dictionary representing the font
|
2195
|
+
# Returns the current font object when no argument is given, otherwise returns +self+. *Note*
|
2196
|
+
# that this is the font object itself, not the PDF dictionary representing the font that is
|
2197
|
+
# stored in the resources.
|
2070
2198
|
#
|
2071
2199
|
# Examples:
|
2072
2200
|
#
|
@@ -2080,7 +2208,7 @@ module HexaPDF
|
|
2080
2208
|
# canvas.font("Times", variant: :bold_italic, size: 15)
|
2081
2209
|
# canvas.text("Times bold+italic at size 15", at: [10, 100])
|
2082
2210
|
#
|
2083
|
-
# See:
|
2211
|
+
# See: PDF2.0 s9.2.2, #font_size, #text
|
2084
2212
|
def font(name = nil, size: nil, **options)
|
2085
2213
|
if name
|
2086
2214
|
@font = (name.respond_to?(:pdf_object) ? name : context.document.fonts.add(name, **options))
|
@@ -2099,16 +2227,16 @@ module HexaPDF
|
|
2099
2227
|
alias font= font
|
2100
2228
|
|
2101
2229
|
# :call-seq:
|
2102
|
-
# canvas.font_size
|
2103
|
-
# canvas.font_size(size => canvas
|
2230
|
+
# canvas.font_size => font_size
|
2231
|
+
# canvas.font_size(size) => canvas
|
2104
2232
|
#
|
2105
2233
|
# Specifies the font size.
|
2106
2234
|
#
|
2107
2235
|
# Note that an error is raised if no font has been set before via #font (this is due to how
|
2108
2236
|
# setting font and font size works in PDF).
|
2109
2237
|
#
|
2110
|
-
# Returns the current font size when no argument is given
|
2111
|
-
# be called in the font_size= form.
|
2238
|
+
# Returns the current font size when no argument is given, otherwise returns +self+. The
|
2239
|
+
# setter version can also be called in the font_size= form.
|
2112
2240
|
#
|
2113
2241
|
# Examples:
|
2114
2242
|
#
|
@@ -2124,7 +2252,7 @@ module HexaPDF
|
|
2124
2252
|
# canvas.text("Text in size #{size}", at: [15, 180 - index * 20])
|
2125
2253
|
# end
|
2126
2254
|
#
|
2127
|
-
# See:
|
2255
|
+
# See: PDF2.0 s9.2.2, #font, #text
|
2128
2256
|
def font_size(size = nil)
|
2129
2257
|
if size
|
2130
2258
|
unless @font
|
@@ -2142,7 +2270,7 @@ module HexaPDF
|
|
2142
2270
|
# canvas.text(text) -> canvas
|
2143
2271
|
# canvas.text(text, at: [x, y]) -> canvas
|
2144
2272
|
#
|
2145
|
-
# Shows the given text string, either at the current or the provided position.
|
2273
|
+
# Shows the given text string, either at the current or the provided position. Returns +self+.
|
2146
2274
|
#
|
2147
2275
|
# If no position is provided, the text is positioned at the current position of the text
|
2148
2276
|
# cursor (see #text_cursor).
|
@@ -2152,21 +2280,24 @@ module HexaPDF
|
|
2152
2280
|
# equal to the font size will be set..
|
2153
2281
|
#
|
2154
2282
|
# Note that there are no provisions to make sure that all text is visible! So if the text
|
2155
|
-
# string is too long, it
|
2283
|
+
# string is too long, it may be outside the cropped page and be cut off.
|
2156
2284
|
#
|
2157
2285
|
# Examples:
|
2158
2286
|
#
|
2159
2287
|
# #>pdf
|
2160
2288
|
# canvas.font('Times', size: 12)
|
2161
|
-
#
|
2162
|
-
# canvas.text("
|
2289
|
+
# # Sets leading=12 because mulitple lines are drawn
|
2290
|
+
# canvas.text("This is a \n multiline text", at: [15, 150])
|
2291
|
+
# # Starts right after the last text
|
2292
|
+
# canvas.text(". Some more text\nafter the newline.")
|
2163
2293
|
#
|
2164
|
-
# See: #leading,
|
2294
|
+
# See: #leading, #font, #font_size, #show_glyphs,
|
2295
|
+
# http://www.unicode.org/reports/tr18/#Line_Boundaries
|
2165
2296
|
def text(text, at: nil)
|
2166
2297
|
raise_unless_font_set
|
2167
2298
|
move_text_cursor(offset: at) if at
|
2168
|
-
leading(font_size) if leading == 0
|
2169
2299
|
lines = text.split(/\u{D A}|(?!\u{D A})[\u{A}-\u{D}\u{85}\u{2028}\u{2029}]/, -1)
|
2300
|
+
leading(font_size) if leading == 0 && lines.length > 1
|
2170
2301
|
lines.each_with_index do |str, index|
|
2171
2302
|
show_glyphs(@font.decode_utf8(str))
|
2172
2303
|
move_text_cursor unless index == lines.length - 1
|
@@ -2177,7 +2308,7 @@ module HexaPDF
|
|
2177
2308
|
# :call-seq:
|
2178
2309
|
# canvas.show_glyphs(glyphs) -> canvas
|
2179
2310
|
#
|
2180
|
-
# Low-level method for actually showing text on the canvas.
|
2311
|
+
# Low-level method for actually showing text on the canvas. Returns +self+.
|
2181
2312
|
#
|
2182
2313
|
# The argument +glyphs+ needs to be a an array of glyph objects valid for the current font,
|
2183
2314
|
# optionally interspersed with numbers for kerning.
|
@@ -2200,6 +2331,8 @@ module HexaPDF
|
|
2200
2331
|
# canvas.move_text_cursor(offset: [15, 100])
|
2201
2332
|
# canvas.show_glyphs(glyphs)
|
2202
2333
|
# canvas.text(canvas.text_cursor.map(&:to_i).join(", "), at: [15, 80])
|
2334
|
+
#
|
2335
|
+
# See: #text, #text_cursor, #text_matrix, #move_text_cursor, #show_glyphs_only
|
2203
2336
|
def show_glyphs(glyphs)
|
2204
2337
|
return if glyphs.empty?
|
2205
2338
|
raise_unless_font_set
|
@@ -2269,7 +2402,7 @@ module HexaPDF
|
|
2269
2402
|
# :call-seq:
|
2270
2403
|
# canvas.marked_content_point(tag, property_list: nil) -> canvas
|
2271
2404
|
#
|
2272
|
-
# Inserts a marked-content point, optionally associated with a property list.
|
2405
|
+
# Inserts a marked-content point, optionally associated with a property list. Returns +self+.
|
2273
2406
|
#
|
2274
2407
|
# A marked-content point is used to identify a position in the content stream for later use by
|
2275
2408
|
# other applications. The symbol +tag+ is used to uniquely identify the role of the
|
@@ -2284,7 +2417,7 @@ module HexaPDF
|
|
2284
2417
|
# canvas.marked_content_point(:Divider)
|
2285
2418
|
# canvas.marked_content_point(:Divider, property_list: {Key: 'value'})
|
2286
2419
|
#
|
2287
|
-
# See:
|
2420
|
+
# See: PDF2.0 s14.6, #marked_content_sequence, #end_marked_content_sequence
|
2288
2421
|
def marked_content_point(tag, property_list: nil)
|
2289
2422
|
raise_unless_at_page_description_level_or_in_text
|
2290
2423
|
if property_list
|
@@ -2300,7 +2433,8 @@ module HexaPDF
|
|
2300
2433
|
# canvas.marked_content_sequence(tag, property_list: nil) -> canvas
|
2301
2434
|
# canvas.marked_content_sequence(tag, property_list: nil) { block } -> canvas
|
2302
2435
|
#
|
2303
|
-
# Inserts a marked-content sequence, optionally associated with a property list.
|
2436
|
+
# Inserts a marked-content sequence, optionally associated with a property list. Returns
|
2437
|
+
# +self+.
|
2304
2438
|
#
|
2305
2439
|
# A marked-content sequence is used to identify a sequence of complete graphics objects in the
|
2306
2440
|
# content stream for later use by other applications, e.g. for tagged PDF. The symbol +tag+ is
|
@@ -2327,7 +2461,7 @@ module HexaPDF
|
|
2327
2461
|
# # Other instructions
|
2328
2462
|
# end
|
2329
2463
|
#
|
2330
|
-
# See:
|
2464
|
+
# See: PDF2.0 s14.6, #end_marked_content_sequence, #marked_content_point
|
2331
2465
|
def marked_content_sequence(tag, property_list: nil)
|
2332
2466
|
raise_unless_at_page_description_level
|
2333
2467
|
if property_list
|
@@ -2346,22 +2480,66 @@ module HexaPDF
|
|
2346
2480
|
# :call-seq:
|
2347
2481
|
# canvas.end_marked_content_sequence -> canvas
|
2348
2482
|
#
|
2349
|
-
# Ends a marked-content sequence
|
2483
|
+
# Ends a marked-content sequence and returns +self+.
|
2350
2484
|
#
|
2351
2485
|
# See #marked_content_sequence for details.
|
2352
2486
|
#
|
2353
|
-
# See:
|
2487
|
+
# See: PDF2.0 s14.6, #marked_content_sequence, #marked_content_point
|
2354
2488
|
def end_marked_content_sequence
|
2355
2489
|
raise_unless_at_page_description_level
|
2356
2490
|
invoke0(:EMC)
|
2357
2491
|
self
|
2358
2492
|
end
|
2359
2493
|
|
2360
|
-
#
|
2361
|
-
#
|
2494
|
+
# :call-seq:
|
2495
|
+
# canvas.optional_content(ocg, &block) -> canvas
|
2496
|
+
# canvas.optional_content(name, use_existing_ocg: true, &block) -> canvas
|
2497
|
+
#
|
2498
|
+
# Inserts an optional content sequence. Returns +self+.
|
2499
|
+
#
|
2500
|
+
# An optional content sequence marks part of the content stream as belonging to the given
|
2501
|
+
# optional content group. See HexaPDF::Type::OptionalContentProperties for details.
|
2502
|
+
#
|
2503
|
+
# If the first argument is already an optional content group dictionary, it is used.
|
2504
|
+
# Otherwise, the first argument needs to be the name of the optional content group. In that
|
2505
|
+
# case, the +use_existing_ocg+ specifies whether the first found optional content group with
|
2506
|
+
# that name should be used or whether a new OCG should always be created.
|
2507
|
+
#
|
2508
|
+
# If invoked without a block, a corresponding call to #end_optional_content must be done.
|
2509
|
+
# Otherwise the optional content sequence automatically ends when the block is finished.
|
2510
|
+
#
|
2511
|
+
# Examples:
|
2512
|
+
#
|
2513
|
+
# canvas.optional_content('Hints')
|
2514
|
+
# # Other instructions
|
2515
|
+
# canvas.end_optional_content
|
2516
|
+
#
|
2517
|
+
# canvas.optional_content('Hints', use_existing_ocg: false) do
|
2518
|
+
# # Other instructions
|
2519
|
+
# end
|
2520
|
+
#
|
2521
|
+
# See: PDF2.0 s8.11, #end_optional_content, HexaPDF::Type::OptionalContentProperties
|
2522
|
+
def optional_content(ocg, use_existing_ocg: true, &block)
|
2523
|
+
ocg = if ocg.kind_of?(HexaPDF::Dictionary) || !use_existing_ocg
|
2524
|
+
context.document.optional_content.add_ocg(ocg)
|
2525
|
+
else
|
2526
|
+
context.document.optional_content.ocg(ocg, create: true)
|
2527
|
+
end
|
2528
|
+
marked_content_sequence(:OC, property_list: ocg, &block)
|
2529
|
+
end
|
2530
|
+
|
2531
|
+
# Ends an optional content sequence and returns +self+.
|
2532
|
+
#
|
2533
|
+
# See #optional_content for details.
|
2534
|
+
#
|
2535
|
+
# See: PDF2.0 s8.11
|
2536
|
+
alias :end_optional_content :end_marked_content_sequence
|
2537
|
+
|
2538
|
+
# Creates and returns a color object from the given color specification. See #stroke_color for
|
2539
|
+
# details on the possible color specifications.
|
2362
2540
|
#
|
2363
2541
|
# This utility method is meant for use by higher-level methods that need to convert a color
|
2364
|
-
# specification into a color object
|
2542
|
+
# specification into a color object.
|
2365
2543
|
def color_from_specification(spec)
|
2366
2544
|
spec = Array(spec)
|
2367
2545
|
if spec.length == 1 && spec[0].kind_of?(String)
|