hexapdf 0.32.2 → 0.33.0

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