hexapdf 0.32.2 → 0.33.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (202) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +63 -1
  3. data/README.md +9 -0
  4. data/examples/002-graphics.rb +15 -17
  5. data/examples/003-arcs.rb +9 -9
  6. data/examples/009-text_layouter_alignment.rb +1 -1
  7. data/examples/010-text_layouter_inline_boxes.rb +2 -2
  8. data/examples/011-text_layouter_line_wrapping.rb +1 -1
  9. data/examples/012-text_layouter_styling.rb +7 -7
  10. data/examples/013-text_layouter_shapes.rb +1 -1
  11. data/examples/014-text_in_polygon.rb +1 -1
  12. data/examples/015-boxes.rb +8 -7
  13. data/examples/016-frame_automatic_box_placement.rb +2 -2
  14. data/examples/017-frame_text_flow.rb +2 -1
  15. data/examples/018-composer.rb +1 -1
  16. data/examples/020-column_box.rb +2 -1
  17. data/examples/025-table_box.rb +46 -0
  18. data/lib/hexapdf/cli/command.rb +5 -2
  19. data/lib/hexapdf/cli/form.rb +5 -5
  20. data/lib/hexapdf/cli/inspect.rb +3 -3
  21. data/lib/hexapdf/composer.rb +104 -52
  22. data/lib/hexapdf/configuration.rb +44 -39
  23. data/lib/hexapdf/content/canvas.rb +393 -267
  24. data/lib/hexapdf/content/color_space.rb +72 -25
  25. data/lib/hexapdf/content/graphic_object/arc.rb +57 -24
  26. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -23
  27. data/lib/hexapdf/content/graphic_object/geom2d.rb +47 -6
  28. data/lib/hexapdf/content/graphic_object/solid_arc.rb +58 -36
  29. data/lib/hexapdf/content/graphic_object.rb +6 -7
  30. data/lib/hexapdf/content/graphics_state.rb +54 -45
  31. data/lib/hexapdf/content/operator.rb +52 -54
  32. data/lib/hexapdf/content/parser.rb +2 -2
  33. data/lib/hexapdf/content/processor.rb +15 -15
  34. data/lib/hexapdf/content/transformation_matrix.rb +1 -1
  35. data/lib/hexapdf/content.rb +5 -0
  36. data/lib/hexapdf/dictionary.rb +6 -5
  37. data/lib/hexapdf/dictionary_fields.rb +42 -14
  38. data/lib/hexapdf/digital_signature/cms_handler.rb +2 -2
  39. data/lib/hexapdf/digital_signature/handler.rb +1 -1
  40. data/lib/hexapdf/digital_signature/pkcs1_handler.rb +2 -3
  41. data/lib/hexapdf/digital_signature/signature.rb +6 -6
  42. data/lib/hexapdf/digital_signature/signatures.rb +13 -12
  43. data/lib/hexapdf/digital_signature/signing/default_handler.rb +14 -5
  44. data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +2 -4
  45. data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +4 -4
  46. data/lib/hexapdf/digital_signature/signing.rb +4 -0
  47. data/lib/hexapdf/digital_signature/verification_result.rb +2 -2
  48. data/lib/hexapdf/digital_signature.rb +7 -2
  49. data/lib/hexapdf/document/destinations.rb +12 -11
  50. data/lib/hexapdf/document/files.rb +1 -1
  51. data/lib/hexapdf/document/fonts.rb +1 -1
  52. data/lib/hexapdf/document/layout.rb +167 -39
  53. data/lib/hexapdf/document/pages.rb +3 -2
  54. data/lib/hexapdf/document.rb +89 -55
  55. data/lib/hexapdf/encryption/aes.rb +5 -5
  56. data/lib/hexapdf/encryption/arc4.rb +1 -1
  57. data/lib/hexapdf/encryption/fast_aes.rb +2 -2
  58. data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
  59. data/lib/hexapdf/encryption/identity.rb +1 -1
  60. data/lib/hexapdf/encryption/ruby_aes.rb +1 -1
  61. data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
  62. data/lib/hexapdf/encryption/security_handler.rb +31 -24
  63. data/lib/hexapdf/encryption/standard_security_handler.rb +45 -36
  64. data/lib/hexapdf/encryption.rb +7 -2
  65. data/lib/hexapdf/error.rb +18 -0
  66. data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
  67. data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
  68. data/lib/hexapdf/filter/flate_decode.rb +1 -1
  69. data/lib/hexapdf/filter/lzw_decode.rb +1 -1
  70. data/lib/hexapdf/filter/pass_through.rb +1 -1
  71. data/lib/hexapdf/filter/predictor.rb +1 -1
  72. data/lib/hexapdf/filter/run_length_decode.rb +1 -1
  73. data/lib/hexapdf/filter.rb +55 -6
  74. data/lib/hexapdf/font/cmap/parser.rb +2 -2
  75. data/lib/hexapdf/font/cmap.rb +1 -1
  76. data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
  77. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
  78. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +2 -2
  79. data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
  80. data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
  81. data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +3 -3
  82. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
  83. data/lib/hexapdf/font/invalid_glyph.rb +3 -0
  84. data/lib/hexapdf/font/true_type_wrapper.rb +17 -4
  85. data/lib/hexapdf/font/type1_wrapper.rb +19 -4
  86. data/lib/hexapdf/font_loader/from_configuration.rb +5 -2
  87. data/lib/hexapdf/font_loader/from_file.rb +5 -5
  88. data/lib/hexapdf/font_loader/standard14.rb +3 -3
  89. data/lib/hexapdf/font_loader.rb +3 -0
  90. data/lib/hexapdf/image_loader/jpeg.rb +2 -2
  91. data/lib/hexapdf/image_loader/pdf.rb +1 -1
  92. data/lib/hexapdf/image_loader/png.rb +2 -2
  93. data/lib/hexapdf/image_loader.rb +1 -1
  94. data/lib/hexapdf/importer.rb +13 -0
  95. data/lib/hexapdf/layout/box.rb +9 -2
  96. data/lib/hexapdf/layout/box_fitter.rb +2 -2
  97. data/lib/hexapdf/layout/column_box.rb +18 -4
  98. data/lib/hexapdf/layout/frame.rb +30 -12
  99. data/lib/hexapdf/layout/image_box.rb +5 -0
  100. data/lib/hexapdf/layout/inline_box.rb +1 -0
  101. data/lib/hexapdf/layout/list_box.rb +17 -1
  102. data/lib/hexapdf/layout/page_style.rb +4 -4
  103. data/lib/hexapdf/layout/style.rb +18 -3
  104. data/lib/hexapdf/layout/table_box.rb +682 -0
  105. data/lib/hexapdf/layout/text_box.rb +5 -3
  106. data/lib/hexapdf/layout/text_fragment.rb +1 -1
  107. data/lib/hexapdf/layout/text_layouter.rb +12 -4
  108. data/lib/hexapdf/layout.rb +1 -0
  109. data/lib/hexapdf/name_tree_node.rb +1 -1
  110. data/lib/hexapdf/number_tree_node.rb +1 -1
  111. data/lib/hexapdf/object.rb +18 -7
  112. data/lib/hexapdf/parser.rb +7 -7
  113. data/lib/hexapdf/pdf_array.rb +1 -1
  114. data/lib/hexapdf/rectangle.rb +1 -1
  115. data/lib/hexapdf/reference.rb +1 -1
  116. data/lib/hexapdf/revision.rb +1 -1
  117. data/lib/hexapdf/revisions.rb +3 -3
  118. data/lib/hexapdf/serializer.rb +15 -15
  119. data/lib/hexapdf/stream.rb +4 -2
  120. data/lib/hexapdf/tokenizer.rb +14 -14
  121. data/lib/hexapdf/type/acro_form/appearance_generator.rb +22 -22
  122. data/lib/hexapdf/type/acro_form/button_field.rb +1 -1
  123. data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
  124. data/lib/hexapdf/type/acro_form/field.rb +2 -2
  125. data/lib/hexapdf/type/acro_form/form.rb +1 -1
  126. data/lib/hexapdf/type/acro_form/signature_field.rb +4 -4
  127. data/lib/hexapdf/type/acro_form/text_field.rb +1 -1
  128. data/lib/hexapdf/type/acro_form/variable_text_field.rb +1 -1
  129. data/lib/hexapdf/type/acro_form.rb +1 -1
  130. data/lib/hexapdf/type/action.rb +1 -1
  131. data/lib/hexapdf/type/actions/go_to.rb +1 -1
  132. data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
  133. data/lib/hexapdf/type/actions/launch.rb +1 -1
  134. data/lib/hexapdf/type/actions/uri.rb +1 -1
  135. data/lib/hexapdf/type/actions.rb +1 -1
  136. data/lib/hexapdf/type/annotation.rb +3 -3
  137. data/lib/hexapdf/type/annotations/link.rb +1 -1
  138. data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
  139. data/lib/hexapdf/type/annotations/text.rb +1 -1
  140. data/lib/hexapdf/type/annotations/widget.rb +2 -2
  141. data/lib/hexapdf/type/annotations.rb +1 -1
  142. data/lib/hexapdf/type/catalog.rb +1 -1
  143. data/lib/hexapdf/type/cid_font.rb +3 -3
  144. data/lib/hexapdf/type/embedded_file.rb +1 -1
  145. data/lib/hexapdf/type/file_specification.rb +2 -2
  146. data/lib/hexapdf/type/font_descriptor.rb +1 -1
  147. data/lib/hexapdf/type/font_simple.rb +2 -2
  148. data/lib/hexapdf/type/font_type0.rb +3 -3
  149. data/lib/hexapdf/type/font_type3.rb +1 -1
  150. data/lib/hexapdf/type/form.rb +1 -1
  151. data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
  152. data/lib/hexapdf/type/icon_fit.rb +1 -1
  153. data/lib/hexapdf/type/image.rb +1 -1
  154. data/lib/hexapdf/type/info.rb +1 -1
  155. data/lib/hexapdf/type/mark_information.rb +1 -1
  156. data/lib/hexapdf/type/names.rb +2 -2
  157. data/lib/hexapdf/type/object_stream.rb +2 -1
  158. data/lib/hexapdf/type/outline.rb +1 -1
  159. data/lib/hexapdf/type/outline_item.rb +1 -1
  160. data/lib/hexapdf/type/page.rb +19 -10
  161. data/lib/hexapdf/type/page_label.rb +1 -1
  162. data/lib/hexapdf/type/page_tree_node.rb +1 -1
  163. data/lib/hexapdf/type/resources.rb +1 -1
  164. data/lib/hexapdf/type/trailer.rb +2 -2
  165. data/lib/hexapdf/type/viewer_preferences.rb +1 -1
  166. data/lib/hexapdf/type/xref_stream.rb +2 -2
  167. data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -1
  168. data/lib/hexapdf/version.rb +1 -1
  169. data/lib/hexapdf/writer.rb +4 -4
  170. data/lib/hexapdf/xref_section.rb +2 -2
  171. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +11 -1
  172. data/test/hexapdf/content/graphic_object/test_geom2d.rb +7 -0
  173. data/test/hexapdf/content/test_canvas.rb +0 -1
  174. data/test/hexapdf/digital_signature/test_signatures.rb +22 -0
  175. data/test/hexapdf/document/test_files.rb +2 -2
  176. data/test/hexapdf/document/test_layout.rb +98 -0
  177. data/test/hexapdf/encryption/test_security_handler.rb +12 -11
  178. data/test/hexapdf/encryption/test_standard_security_handler.rb +35 -23
  179. data/test/hexapdf/font/test_true_type_wrapper.rb +18 -1
  180. data/test/hexapdf/font/test_type1_wrapper.rb +15 -1
  181. data/test/hexapdf/layout/test_box.rb +1 -1
  182. data/test/hexapdf/layout/test_column_box.rb +65 -21
  183. data/test/hexapdf/layout/test_frame.rb +14 -14
  184. data/test/hexapdf/layout/test_image_box.rb +4 -0
  185. data/test/hexapdf/layout/test_inline_box.rb +5 -0
  186. data/test/hexapdf/layout/test_list_box.rb +40 -6
  187. data/test/hexapdf/layout/test_page_style.rb +3 -2
  188. data/test/hexapdf/layout/test_style.rb +50 -0
  189. data/test/hexapdf/layout/test_table_box.rb +722 -0
  190. data/test/hexapdf/layout/test_text_box.rb +18 -0
  191. data/test/hexapdf/layout/test_text_layouter.rb +4 -0
  192. data/test/hexapdf/test_dictionary_fields.rb +4 -1
  193. data/test/hexapdf/test_document.rb +1 -0
  194. data/test/hexapdf/test_filter.rb +8 -0
  195. data/test/hexapdf/test_importer.rb +9 -0
  196. data/test/hexapdf/test_object.rb +16 -5
  197. data/test/hexapdf/test_stream.rb +7 -0
  198. data/test/hexapdf/test_writer.rb +3 -3
  199. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +13 -5
  200. data/test/hexapdf/type/acro_form/test_form.rb +4 -3
  201. data/test/hexapdf/type/test_page.rb +18 -4
  202. metadata +17 -8
@@ -87,6 +87,9 @@ module HexaPDF
87
87
  # Returns the color corresponding to the given arguments without applying value normalization.
88
88
  # The number and types of the arguments differ from one color space to another.
89
89
  #
90
+ # This method should be used when the arguments are already normalized (e.g. when loaded from
91
+ # a content stream).
92
+ #
90
93
  # The class representing a color in the color space needs to respond to the following methods:
91
94
  #
92
95
  # #color_space::
@@ -95,24 +98,26 @@ module HexaPDF
95
98
  # #components::
96
99
  # Returns an array of components that uniquely identifies this color within the color space.
97
100
  #
98
- # See: PDF1.7 s8.6
101
+ # See: PDF2.0 s8.6
99
102
  module ColorSpace
100
103
 
101
- # Mapping of CSS Color Module Level 3 names to RGB values.
104
+ # Mapping of color names (CSS Color Module Level 3 names - see
105
+ # https://www.w3.org/TR/css-color-3/#svg-color - and HexaPDF design color names) to RGB and
106
+ # gray values.
102
107
  #
103
108
  # Visual listing of all colors:
104
109
  #
105
110
  # #>pdf-big
106
- # canvas.font("Helvetica", size: 8)
107
- # map = HexaPDF::Content::ColorSpace::CSS_COLOR_NAMES
108
- # map.each_slice(38).each_with_index do |slice, col|
111
+ # canvas.font("Helvetica", size: 7.5)
112
+ # map = HexaPDF::Content::ColorSpace::COLOR_NAMES
113
+ # map.each_slice(43).each_with_index do |slice, col|
109
114
  # x = 10 + col * 100
110
115
  # slice.each_with_index do |(name, rgb), row|
111
- # canvas.fill_color(rgb).rectangle(x, 380 - row * 10, 10, 10).fill
112
- # canvas.fill_color("black").text(name, at: [x + 15, 380 - row * 10 + 2])
116
+ # canvas.fill_color(rgb).rectangle(x, 380 - row * 9, 9, 9).fill
117
+ # canvas.fill_color("black").text(name, at: [x + 15, 380 - row * 9 + 2])
113
118
  # end
114
119
  # end
115
- CSS_COLOR_NAMES = {
120
+ COLOR_NAMES = {
116
121
  "aliceblue" => [240, 248, 255],
117
122
  "antiquewhite" => [250, 235, 215],
118
123
  "aqua" => [0, 255, 255],
@@ -137,9 +142,9 @@ module HexaPDF
137
142
  "darkblue" => [0, 0, 139],
138
143
  "darkcyan" => [0, 139, 139],
139
144
  "darkgoldenrod" => [184, 134, 11],
140
- "darkgray" => [169, 169, 169],
145
+ "darkgray" => [169],
141
146
  "darkgreen" => [0, 100, 0],
142
- "darkgrey" => [169, 169, 169],
147
+ "darkgrey" => [169],
143
148
  "darkkhaki" => [189, 183, 107],
144
149
  "darkmagenta" => [139, 0, 139],
145
150
  "darkolivegreen" => [85, 107, 47],
@@ -155,8 +160,8 @@ module HexaPDF
155
160
  "darkviolet" => [148, 0, 211],
156
161
  "deeppink" => [255, 20, 147],
157
162
  "deepskyblue" => [0, 191, 255],
158
- "dimgray" => [105, 105, 105],
159
- "dimgrey" => [105, 105, 105],
163
+ "dimgray" => [105],
164
+ "dimgrey" => [105],
160
165
  "dodgerblue" => [30, 144, 255],
161
166
  "firebrick" => [178, 34, 34],
162
167
  "floralwhite" => [255, 250, 240],
@@ -166,10 +171,10 @@ module HexaPDF
166
171
  "ghostwhite" => [248, 248, 255],
167
172
  "gold" => [255, 215, 0],
168
173
  "goldenrod" => [218, 165, 32],
169
- "gray" => [128, 128, 128],
174
+ "gray" => [128],
170
175
  "green" => [0, 128, 0],
171
176
  "greenyellow" => [173, 255, 47],
172
- "grey" => [128, 128, 128],
177
+ "grey" => [128],
173
178
  "honeydew" => [240, 255, 240],
174
179
  "hotpink" => [255, 105, 180],
175
180
  "indianred" => [205, 92, 92],
@@ -184,7 +189,7 @@ module HexaPDF
184
189
  "lightcoral" => [240, 128, 128],
185
190
  "lightcyan" => [224, 255, 255],
186
191
  "lightgoldenrodyellow" => [250, 250, 210],
187
- "lightgray" => [211, 211, 211],
192
+ "lightgray" => [211],
188
193
  "lightgreen" => [144, 238, 144],
189
194
  "lightgrey" => [211, 211, 211],
190
195
  "lightpink" => [255, 182, 193],
@@ -260,6 +265,24 @@ module HexaPDF
260
265
  "whitesmoke" => [245, 245, 245],
261
266
  "yellow" => [255, 255, 0],
262
267
  "yellowgreen" => [154, 205, 50],
268
+ "hp-blue" => [0, 128, 255],
269
+ "hp-blue-dark" => [28, 91, 216],
270
+ "hp-blue-dark2" => [34, 57, 184],
271
+ "hp-blue-light" => [86, 176, 255],
272
+ "hp-blue-light2" => [185, 220, 255],
273
+ "hp-orange" => [255, 128, 0],
274
+ "hp-orange-light" => [255, 195, 29],
275
+ "hp-orange-light2" => [255, 246, 153],
276
+ "hp-teal" => [0, 140, 130],
277
+ "hp-teal-dark" => [5, 100, 94],
278
+ "hp-teal-dark2" => [6, 70, 63],
279
+ "hp-teal-light" => [75, 177, 176],
280
+ "hp-teal-light2" => [177, 221, 221],
281
+ "hp-gray" => [158],
282
+ "hp-gray-dark" => [97],
283
+ "hp-gray-dark2" => [33],
284
+ "hp-gray-light" => [224],
285
+ "hp-gray-light2" => [245],
263
286
  }.freeze
264
287
 
265
288
  # :call-seq:
@@ -269,7 +292,7 @@ module HexaPDF
269
292
  # ColorSpace.device_color_from_specification(string) => color
270
293
  # ColorSpace.device_color_from_specification(array) => color
271
294
  #
272
- # Creates a device color object from the given color specification.
295
+ # Creates and returns a device color object from the given color specification.
273
296
  #
274
297
  # There are several ways to define the color that should be used:
275
298
  #
@@ -279,8 +302,8 @@ module HexaPDF
279
302
  # for the green and "BB" for the blue color value also specifies an RGB color.
280
303
  # * As does a string in the format "RGB" where "RR", "GG" and "BB" would be used as the
281
304
  # hexadecimal numbers for the red, green and blue color values of an RGB color.
282
- # * Any other string is treated as a CSS Color Module Level 3 color name, see
283
- # https://www.w3.org/TR/css-color-3/#svg-color.
305
+ # * Any other string is treated as a color name (CSS Color Module Level 3 and HexaPDF design
306
+ # color names are supported - see COLOR_NAMES).
284
307
  # * Four numeric arguments specify a CMYK color (see DeviceCMYK::Color).
285
308
  # * An array is treated as if its items were specified separately as arguments.
286
309
  #
@@ -288,7 +311,30 @@ module HexaPDF
288
311
  # values are first normalized (expected range by the PDF specification is 0.0 - 1.0) - see
289
312
  # DeviceGray#color, DeviceRGB#color and DeviceCMYK#color for details.
290
313
  #
291
- # For examples see HexaPDF::Content::Canvas#stroke_color.
314
+ # Examples:
315
+ #
316
+ # #>pdf
317
+ # cs = HexaPDF::Content::ColorSpace
318
+ # canvas.line_width(5)
319
+ #
320
+ # # Note that Canvas#stroke_color implicitly uses this method, so
321
+ # # explicitly using it like in this example is not needed
322
+ # canvas.stroke_color(cs.device_color_from_specification(160))
323
+ # canvas.line(10, 10, 10, 190).stroke
324
+ # canvas.stroke_color(cs.device_color_from_specification(0, 128, 255))
325
+ # canvas.line(35, 10, 35, 190).stroke
326
+ # canvas.stroke_color(cs.device_color_from_specification("0088FF"))
327
+ # canvas.line(60, 10, 60, 190).stroke
328
+ # canvas.stroke_color(cs.device_color_from_specification("08F"))
329
+ # canvas.line(85, 10, 85, 190).stroke
330
+ # canvas.stroke_color(cs.device_color_from_specification("gold"))
331
+ # canvas.line(110, 10, 110, 190).stroke
332
+ # canvas.stroke_color(cs.device_color_from_specification("hp-blue"))
333
+ # canvas.line(135, 10, 135, 190).stroke
334
+ # canvas.stroke_color(cs.device_color_from_specification(10, 50, 0, 60))
335
+ # canvas.line(160, 10, 160, 190).stroke
336
+ # canvas.stroke_color(cs.device_color_from_specification([0, 128, 255]))
337
+ # canvas.line(185, 10, 185, 190).stroke
292
338
  def self.device_color_from_specification(*spec)
293
339
  spec.flatten!
294
340
  first_item = spec[0]
@@ -297,10 +343,11 @@ module HexaPDF
297
343
  first_item.scan(/../).map!(&:hex)
298
344
  elsif first_item.match?(/\A\h{3}\z/)
299
345
  first_item.each_char.map {|x| (x * 2).hex }
300
- elsif CSS_COLOR_NAMES.key?(first_item)
301
- CSS_COLOR_NAMES[first_item]
346
+ elsif COLOR_NAMES.key?(first_item)
347
+ COLOR_NAMES[first_item]
302
348
  else
303
- raise ArgumentError, "Given string is neither a hex color nor a color name"
349
+ raise ArgumentError, "Given string '#{first_item}' is neither a hex color " \
350
+ "nor a color name"
304
351
  end
305
352
  end
306
353
  GlobalConfiguration.constantize('color_space.map', for_components(spec)).new.color(*spec)
@@ -470,7 +517,7 @@ module HexaPDF
470
517
 
471
518
  # A color in the DeviceRGB color space.
472
519
  #
473
- # See: PDF1.7 s8.6.4.3
520
+ # See: PDF2.0 s8.6.4.3
474
521
  class Color
475
522
 
476
523
  include ColorUtils
@@ -540,7 +587,7 @@ module HexaPDF
540
587
 
541
588
  # A color in the DeviceCMYK color space.
542
589
  #
543
- # See: PDF1.7 s8.6.4.4
590
+ # See: PDF2.0 s8.6.4.4
544
591
  class Color
545
592
 
546
593
  include ColorUtils
@@ -610,7 +657,7 @@ module HexaPDF
610
657
 
611
658
  # A color in the DeviceGray color space.
612
659
  #
613
- # See: PDF1.7 s8.6.4.2
660
+ # See: PDF2.0 s8.6.4.2
614
661
  class Color
615
662
 
616
663
  include ColorUtils
@@ -45,6 +45,9 @@ module HexaPDF
45
45
  # all either in clockwise or counterclockwise direction and optionally inclined in respect to
46
46
  # the x-axis.
47
47
  #
48
+ # Note that only the path of the arc itself is added to the canvas. So depending on the
49
+ # use-case the path itself still has to be, for example, stroked.
50
+ #
48
51
  # This graphic object is registered under the :arc key for use with the
49
52
  # HexaPDF::Content::Canvas class.
50
53
  #
@@ -75,66 +78,64 @@ module HexaPDF
75
78
  # Examples:
76
79
  #
77
80
  # #>pdf-center
78
- # arc = canvas.graphic_object(:arc, cx: -50, a: 40, b: 40)
79
- # arc.max_curves = 2
81
+ # arc = canvas.graphic_object(:arc, cx: -50, a: 40, b: 40, max_curves: 2)
80
82
  # canvas.draw(arc)
81
- # arc.max_curves = 10
82
- # canvas.draw(arc, cx: 50)
83
+ # canvas.draw(arc, cx: 50, max_curves: 10)
83
84
  # canvas.stroke
84
85
  attr_accessor :max_curves
85
86
 
86
- # x-coordinate of center point
87
+ # x-coordinate of center point, defaults to 0.
87
88
  #
88
89
  # Examples:
89
90
  #
90
91
  # #>pdf-center
91
92
  # arc = canvas.graphic_object(:arc, a: 30, b: 20)
92
93
  # canvas.draw(arc).stroke
93
- # canvas.stroke_color("red").draw(arc, cx: -50).stroke
94
+ # canvas.stroke_color("hp-blue").draw(arc, cx: 50).stroke
94
95
  attr_reader :cx
95
96
 
96
- # y-coordinate of center point
97
+ # y-coordinate of center point, defaults to 0.
97
98
  #
98
99
  # Examples:
99
100
  #
100
101
  # #>pdf-center
101
102
  # arc = canvas.graphic_object(:arc, a: 30, b: 20)
102
103
  # canvas.draw(arc).stroke
103
- # canvas.stroke_color("red").draw(arc, cy: 50).stroke
104
+ # canvas.stroke_color("hp-blue").draw(arc, cy: 50).stroke
104
105
  attr_reader :cy
105
106
 
106
107
  # Length of semi-major axis which (without altering the #inclination) is parallel to the
107
- # x-axis
108
+ # x-axis, defaults to 1.
108
109
  #
109
110
  # Examples:
110
111
  #
111
112
  # #>pdf-center
112
113
  # arc = canvas.graphic_object(:arc, a: 30, b: 30)
113
114
  # canvas.draw(arc).stroke
114
- # canvas.stroke_color("red").draw(arc, a: 60).stroke
115
+ # canvas.stroke_color("hp-blue").draw(arc, a: 60).stroke
115
116
  attr_reader :a
116
117
 
117
118
  # Length of semi-minor axis which (without altering the #inclination) is parallel to the
118
- # y-axis
119
+ # y-axis, defaults to 1.
119
120
  #
120
121
  # Examples:
121
122
  #
122
123
  # #>pdf-center
123
124
  # arc = canvas.graphic_object(:arc, a: 30, b: 30)
124
125
  # canvas.draw(arc).stroke
125
- # canvas.stroke_color("red").draw(arc, b: 60).stroke
126
+ # canvas.stroke_color("hp-blue").draw(arc, b: 60).stroke
126
127
  attr_reader :b
127
128
 
128
- # Start angle of the arc in degrees
129
+ # Start angle of the arc in degrees, defaults to 0.
129
130
  #
130
131
  # Examples:
131
132
  #
132
133
  # #>pdf-center
133
134
  # arc = canvas.graphic_object(:arc, a: 30, b: 30)
134
- # canvas.draw(arc, start_angle: 45).stroke
135
+ # canvas.draw(arc, start_angle: 110).stroke
135
136
  attr_reader :start_angle
136
137
 
137
- # End angle of the arc in degrees
138
+ # End angle of the arc in degrees, defaults to 0.
138
139
  #
139
140
  # Examples:
140
141
  #
@@ -143,7 +144,7 @@ module HexaPDF
143
144
  # canvas.draw(arc, end_angle: 160).stroke
144
145
  attr_reader :end_angle
145
146
 
146
- # Inclination in degrees of the semi-major axis with respect to the x-axis
147
+ # Inclination in degrees of the semi-major axis with respect to the x-axis, defaults to 0.
147
148
  #
148
149
  # Examples:
149
150
  #
@@ -153,6 +154,7 @@ module HexaPDF
153
154
  attr_reader :inclination
154
155
 
155
156
  # Direction of arc - if +true+ in clockwise direction, else in counterclockwise direction
157
+ # (the default).
156
158
  #
157
159
  # This is needed when filling paths using the nonzero winding number rule to achieve
158
160
  # different effects.
@@ -161,7 +163,8 @@ module HexaPDF
161
163
  #
162
164
  # #>pdf-center
163
165
  # arc = canvas.graphic_object(:arc, a: 40, b: 40)
164
- # canvas.draw(arc, cx: -50).draw(arc, cx: 50).
166
+ # canvas.fill_color("hp-blue").
167
+ # draw(arc, cx: -50).draw(arc, cx: 50).
165
168
  # draw(arc, cx: -50, b: 80).
166
169
  # draw(arc, cx: 50, b: 80, clockwise: true).
167
170
  # fill(:nonzero)
@@ -192,17 +195,27 @@ module HexaPDF
192
195
  # * semi-minor axis +b+,
193
196
  # * start angle of +start_angle+ degrees,
194
197
  # * end angle of +end_angle+ degrees and
195
- # * an inclination in respect to the x-axis of +inclination+ degrees.
198
+ # * an inclination in respect to the x-axis of +inclination+ degrees,
199
+ # * as well as the maximal number of curves +max_curves+ used for approximation.
196
200
  #
197
201
  # The +clockwise+ argument determines if the arc is drawn in the counterclockwise direction
198
202
  # (+false+) or in the clockwise direction (+true+).
199
203
  #
204
+ # For the meaning of +max_curves+ see the description of #max_curves.
205
+ #
200
206
  # Any arguments not specified are not modified and retain their old value, see #initialize
201
207
  # for the inital values.
202
208
  #
203
209
  # Returns self.
210
+ #
211
+ # Examples:
212
+ #
213
+ # #>pdf-center
214
+ # arc = canvas.graphic_object(:arc)
215
+ # arc.configure(cx: 50, a: 40, b: 20, inclination: 10)
216
+ # canvas.draw(arc).stroke
204
217
  def configure(cx: nil, cy: nil, a: nil, b: nil, start_angle: nil, end_angle: nil,
205
- inclination: nil, clockwise: nil)
218
+ inclination: nil, clockwise: nil, max_curves: nil)
206
219
  @cx = cx if cx
207
220
  @cy = cy if cy
208
221
  @a = a.abs if a
@@ -214,6 +227,7 @@ module HexaPDF
214
227
  @end_angle = end_angle if end_angle
215
228
  @inclination = inclination if inclination
216
229
  @clockwise = clockwise unless clockwise.nil?
230
+ @max_curves = max_curves if max_curves
217
231
  calculate_cached_values
218
232
  self
219
233
  end
@@ -225,7 +239,7 @@ module HexaPDF
225
239
  # #>pdf-center
226
240
  # arc = canvas.graphic_object(:arc, a: 40, b: 30, start_angle: 60)
227
241
  # canvas.draw(arc).stroke
228
- # canvas.fill_color("red").circle(*arc.start_point, 2).fill
242
+ # canvas.fill_color("hp-blue").circle(*arc.start_point, 2).fill
229
243
  def start_point
230
244
  evaluate(@start_eta)
231
245
  end
@@ -237,7 +251,7 @@ module HexaPDF
237
251
  # #>pdf-center
238
252
  # arc = canvas.graphic_object(:arc, a: 40, b: 30, end_angle: 245)
239
253
  # canvas.draw(arc).stroke
240
- # canvas.fill_color("red").circle(*arc.end_point, 2).fill
254
+ # canvas.fill_color("hp-blue").circle(*arc.end_point, 2).fill
241
255
  def end_point
242
256
  evaluate(@end_eta)
243
257
  end
@@ -245,18 +259,37 @@ module HexaPDF
245
259
  # Returns the point at +angle+ degrees on the ellipse.
246
260
  #
247
261
  # Note that the point may not lie on the arc itself!
262
+ #
263
+ # Examples:
264
+ #
265
+ # #>pdf-center
266
+ # arc = canvas.graphic_object(:arc, a: 40, b: 30, end_angle: 245)
267
+ # canvas.draw(arc).stroke
268
+ # canvas.fill_color("hp-blue").
269
+ # circle(*arc.point_at(150), 2).
270
+ # circle(*arc.point_at(290), 2).
271
+ # fill
248
272
  def point_at(angle)
249
273
  evaluate(angle_to_param(angle))
250
274
  end
251
275
 
252
276
  # Draws the arc on the given Canvas.
253
277
  #
254
- # If the argument +move_to_start+ is +true+, a Canvas#move_to operation is executed to
255
- # move the current point to the start point of the arc. Otherwise it is assumed that the
256
- # current point already coincides with the start point
278
+ # If the argument +move_to_start+ is +true+, a Canvas#move_to operation is executed to move
279
+ # the current point to the start point of the arc. Otherwise it is assumed that the current
280
+ # point already coincides with the start point. This functionality is used, for example, by
281
+ # the SolidArc implementation.
257
282
  #
258
283
  # The #max_curves value, if not already changed, is set to the value of the configuration
259
284
  # option 'graphic_object.arc.max_curves' before drawing.
285
+ #
286
+ # Examples:
287
+ #
288
+ # #>pdf-center
289
+ # arc = canvas.graphic_object(:arc, a: 40, b: 30)
290
+ # canvas.stroke_color("hp-blue").move_to(-50, 0)
291
+ # arc.draw(canvas, move_to_start: false)
292
+ # canvas.stroke
260
293
  def draw(canvas, move_to_start: true)
261
294
  @max_curves ||= canvas.context.document.config['graphic_object.arc.max_curves']
262
295
  canvas.move_to(*start_point) if move_to_start
@@ -41,7 +41,12 @@ module HexaPDF
41
41
  module GraphicObject
42
42
 
43
43
  # This class describes an elliptical arc in endpoint parameterization. It allows one to
44
- # generate an arc from the current point to a given point, similar to Content::Canvas#line_to.
44
+ # generate an arc from the current point to a given point, similar to Canvas#line_to. Behind
45
+ # the scenes the endpoint parameterization is turned into a center parameterization and drawn
46
+ # with Arc.
47
+ #
48
+ # Note that only the path of the arc itself is added to the canvas. So depending on the
49
+ # use-case the path itself still has to be, for example, stroked.
45
50
  #
46
51
  # This graphic object is registered under the :endpoint_arc key for use with the
47
52
  # HexaPDF::Content::Canvas class.
@@ -52,10 +57,12 @@ module HexaPDF
52
57
  # arc = canvas.graphic_object(:endpoint_arc, x: 50, y: 20, a: 30, b: 10)
53
58
  # canvas.move_to(0, 0).draw(arc).stroke
54
59
  #
55
- # See: GraphicObject::Arc, ARC - https://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes
60
+ # See: Arc, ARC - https://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes (in the
61
+ # version of about 2016, see
62
+ # https://web.archive.org/web/20160310153722/https://www.w3.org/TR/SVG/implnote.html).
56
63
  class EndpointArc
57
64
 
58
- EPSILON = 1e-10
65
+ EPSILON = 1e-10 # :nodoc:
59
66
 
60
67
  include Utils::MathHelpers
61
68
 
@@ -66,80 +73,95 @@ module HexaPDF
66
73
  new.configure(**kwargs)
67
74
  end
68
75
 
69
- # x-coordinate of endpoint
76
+ # x-coordinate of endpoint, defaults to 0.
70
77
  #
71
78
  # Examples:
72
79
  #
73
80
  # #>pdf-center
74
81
  # arc = canvas.graphic_object(:endpoint_arc, x: 50, y: 20, a: 30, b: 20)
75
82
  # canvas.move_to(0, 0).draw(arc).stroke
76
- # canvas.stroke_color("red").move_to(0, 0).draw(arc, x: -50).stroke
83
+ # canvas.stroke_color("hp-blue").move_to(0, 0).draw(arc, x: -50).stroke
77
84
  attr_reader :x
78
85
 
79
- # y-coordinate of endpoint
86
+ # y-coordinate of endpoint, defaults to 0.
80
87
  #
81
88
  # Examples:
82
89
  #
83
90
  # #>pdf-center
84
91
  # arc = canvas.graphic_object(:endpoint_arc, x: 50, y: 20, a: 30, b: 20)
85
92
  # canvas.move_to(0, 0).draw(arc).stroke
86
- # canvas.stroke_color("red").move_to(0, 0).draw(arc, y: -20).stroke
93
+ # canvas.stroke_color("hp-blue").move_to(0, 0).draw(arc, y: -20).stroke
87
94
  attr_reader :y
88
95
 
89
- # Length of semi-major axis
96
+ # Length of semi-major axis, defaults to 0.
90
97
  #
91
98
  # Examples:
92
99
  #
93
100
  # #>pdf-center
94
101
  # arc = canvas.graphic_object(:endpoint_arc, x: 50, y: 20, a: 30, b: 20)
95
102
  # canvas.move_to(0, 0).draw(arc).stroke
96
- # canvas.stroke_color("red").move_to(0, 0).draw(arc, a: 40).stroke
103
+ # canvas.stroke_color("hp-blue").move_to(0, 0).draw(arc, a: 40).stroke
97
104
  attr_reader :a
98
105
 
99
- # Length of semi-minor axis
106
+ # Length of semi-minor axis, defaults to 0.
100
107
  #
101
108
  # Examples:
102
109
  #
103
110
  # #>pdf-center
104
111
  # arc = canvas.graphic_object(:endpoint_arc, x: 50, y: 20, a: 30, b: 20)
105
112
  # canvas.move_to(0, 0).draw(arc).stroke
106
- # canvas.stroke_color("red").move_to(0, 0).draw(arc, b: 50).stroke
113
+ # canvas.stroke_color("hp-blue").move_to(0, 0).draw(arc, b: 50).stroke
107
114
  attr_reader :b
108
115
 
109
- # Inclination in degrees of semi-major axis in respect to x-axis
116
+ # Inclination in degrees of semi-major axis in respect to x-axis, defaults to 0.
110
117
  #
111
118
  # Examples:
112
119
  #
113
120
  # #>pdf-center
114
121
  # arc = canvas.graphic_object(:endpoint_arc, x: 50, y: 20, a: 30, b: 20)
115
122
  # canvas.move_to(0, 0).draw(arc).stroke
116
- # canvas.stroke_color("red").move_to(0, 0).draw(arc, inclination: 45).stroke
123
+ # canvas.stroke_color("hp-blue").move_to(0, 0).draw(arc, inclination: 45).stroke
117
124
  attr_reader :inclination
118
125
 
119
- # Large arc choice - if +true+ use the large arc (i.e. the one spanning more than 180
120
- # degrees), else the small arc
126
+ # Large arc choice - if +true+ (the default) use the large arc (i.e. the one spanning more
127
+ # than 180 degrees), else the small arc
121
128
  #
122
129
  # Examples:
123
130
  #
124
131
  # #>pdf-center
125
132
  # arc = canvas.graphic_object(:endpoint_arc, x: 50, y: 20, a: 30, b: 20)
126
133
  # canvas.move_to(0, 0).draw(arc).stroke
127
- # canvas.stroke_color("red").move_to(0, 0).draw(arc, large_arc: false, clockwise: true).stroke
134
+ # canvas.stroke_color("hp-blue").
135
+ # move_to(0, 0).draw(arc, large_arc: false, clockwise: true).stroke
128
136
  attr_reader :large_arc
129
137
 
130
138
  # Direction of arc - if +true+ in clockwise direction, else in counterclockwise direction
139
+ # (the default).
131
140
  #
132
- # This is needed, for example, when filling paths using the nonzero winding number rule to achieve
133
- # different effects.
141
+ # This is needed, for example, when filling paths using the nonzero winding number rule to
142
+ # achieve different effects.
134
143
  #
135
144
  # Examples:
136
145
  #
137
146
  # #>pdf-center
138
147
  # arc = canvas.graphic_object(:endpoint_arc, x: 50, y: 20, a: 30, b: 20)
139
148
  # canvas.move_to(0, 0).draw(arc).stroke
140
- # canvas.stroke_color("red").move_to(0, 0).draw(arc, clockwise: true).stroke
149
+ # canvas.stroke_color("hp-blue").move_to(0, 0).draw(arc, clockwise: true).stroke
141
150
  attr_reader :clockwise
142
151
 
152
+ # The maximal number of curves used for approximating a complete ellipse.
153
+ #
154
+ # See Arc#max_curves for details.
155
+ #
156
+ # Examples:
157
+ #
158
+ # #>pdf-center
159
+ # arc = canvas.graphic_object(:endpoint_arc, x: 50, y: 20, a: 30, b: 20)
160
+ # canvas.move_to(0, 0).draw(arc, max_curves: 1).stroke
161
+ # canvas.stroke_color("hp-blue").
162
+ # move_to(0, 0).draw(arc, max_curves: 2).stroke
163
+ attr_accessor :max_curves
164
+
143
165
  # Creates an endpoint arc with default values x=0, y=0, a=0, b=0, inclination=0,
144
166
  # large_arc=true, clockwise=false (a line to the origin).
145
167
  #
@@ -153,6 +175,7 @@ module HexaPDF
153
175
  @inclination = 0
154
176
  @large_arc = true
155
177
  @clockwise = false
178
+ @max_curves = nil
156
179
  end
157
180
 
158
181
  # Configures the endpoint arc with
@@ -161,8 +184,9 @@ module HexaPDF
161
184
  # * semi-major axis +a+,
162
185
  # * semi-minor axis +b+,
163
186
  # * an inclination in respect to the x-axis of +inclination+ degrees,
164
- # * the given large_arc flag and
165
- # * the given clockwise flag.
187
+ # * the given large_arc flag,
188
+ # * the given clockwise flag and.
189
+ # * the given maximum number of approximation curves.
166
190
  #
167
191
  # The +large_arc+ option determines whether the large arc, i.e. the one spanning more than
168
192
  # 180 degrees, is used (+true+) or the small arc (+false+).
@@ -174,8 +198,15 @@ module HexaPDF
174
198
  # for the inital values.
175
199
  #
176
200
  # Returns self.
201
+ #
202
+ # Examples:
203
+ #
204
+ # #>pdf-center
205
+ # arc = canvas.graphic_object(:endpoint_arc)
206
+ # arc.configure(x: 50, y: 20, a: 30, b: 10)
207
+ # canvas.move_to(0, 0).draw(arc).stroke
177
208
  def configure(x: nil, y: nil, a: nil, b: nil, inclination: nil, large_arc: nil,
178
- clockwise: nil)
209
+ clockwise: nil, max_curves: nil)
179
210
  @x = x if x
180
211
  @y = y if y
181
212
  @a = a.abs if a
@@ -183,11 +214,23 @@ module HexaPDF
183
214
  @inclination = inclination % 360 if inclination
184
215
  @large_arc = large_arc unless large_arc.nil?
185
216
  @clockwise = clockwise unless clockwise.nil?
217
+ @max_curves = max_curves if max_curves
186
218
 
187
219
  self
188
220
  end
189
221
 
190
222
  # Draws the arc on the given Canvas.
223
+ #
224
+ # Since this method doesn't have any other arguments than +canvas+, it is usually better and
225
+ # easier to use Canvas#draw.
226
+ #
227
+ # Examples:
228
+ #
229
+ # #>pdf-center
230
+ # arc = canvas.graphic_object(:endpoint_arc, x: 50, y: 20, a: 30, b: 10)
231
+ # canvas.move_to(-20, -20)
232
+ # arc.draw(canvas)
233
+ # canvas.stroke
191
234
  def draw(canvas)
192
235
  x1, y1 = *canvas.current_point
193
236
 
@@ -257,7 +300,7 @@ module HexaPDF
257
300
  end_angle = compute_angle_to_x_axis((-x1p - cxp), (-y1p - cyp)) % 360
258
301
 
259
302
  {cx: cx, cy: cy, a: rx, b: ry, start_angle: start_angle, end_angle: end_angle,
260
- inclination: @inclination, clockwise: @clockwise}
303
+ inclination: @inclination, clockwise: @clockwise, max_curves: @max_curves}
261
304
  end
262
305
 
263
306
  # Compares two float numbers if they are within a certain delta.