hexapdf 0.15.8 → 0.17.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (446) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hexapdf/cli/batch.rb +1 -1
  3. data/lib/hexapdf/cli/command.rb +10 -1
  4. data/lib/hexapdf/cli/files.rb +1 -1
  5. data/lib/hexapdf/cli/fonts.rb +145 -0
  6. data/lib/hexapdf/cli/form.rb +27 -26
  7. data/lib/hexapdf/cli/image2pdf.rb +1 -1
  8. data/lib/hexapdf/cli/images.rb +1 -10
  9. data/lib/hexapdf/cli/info.rb +1 -1
  10. data/lib/hexapdf/cli/inspect.rb +1 -1
  11. data/lib/hexapdf/cli/merge.rb +1 -1
  12. data/lib/hexapdf/cli/modify.rb +1 -1
  13. data/lib/hexapdf/cli/optimize.rb +1 -1
  14. data/lib/hexapdf/cli/split.rb +1 -1
  15. data/lib/hexapdf/cli/watermark.rb +1 -1
  16. data/lib/hexapdf/cli.rb +3 -1
  17. data/lib/hexapdf/composer.rb +1 -1
  18. data/lib/hexapdf/configuration.rb +11 -2
  19. data/lib/hexapdf/content/canvas.rb +658 -167
  20. data/lib/hexapdf/content/color_space.rb +185 -3
  21. data/lib/hexapdf/content/graphic_object/arc.rb +111 -12
  22. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +1 -1
  23. data/lib/hexapdf/content/graphic_object/geom2d.rb +1 -1
  24. data/lib/hexapdf/content/graphic_object/solid_arc.rb +1 -1
  25. data/lib/hexapdf/content/graphic_object.rb +1 -1
  26. data/lib/hexapdf/content/graphics_state.rb +1 -1
  27. data/lib/hexapdf/content/operator.rb +1 -1
  28. data/lib/hexapdf/content/parser.rb +1 -1
  29. data/lib/hexapdf/content/processor.rb +1 -1
  30. data/lib/hexapdf/content/transformation_matrix.rb +1 -1
  31. data/lib/hexapdf/content.rb +1 -1
  32. data/lib/hexapdf/data_dir.rb +1 -1
  33. data/lib/hexapdf/dictionary.rb +1 -1
  34. data/lib/hexapdf/dictionary_fields.rb +30 -4
  35. data/lib/hexapdf/document/files.rb +3 -3
  36. data/lib/hexapdf/document/fonts.rb +1 -1
  37. data/lib/hexapdf/document/images.rb +1 -1
  38. data/lib/hexapdf/document/pages.rb +1 -1
  39. data/lib/hexapdf/document.rb +1 -1
  40. data/lib/hexapdf/encryption/aes.rb +1 -1
  41. data/lib/hexapdf/encryption/arc4.rb +1 -1
  42. data/lib/hexapdf/encryption/fast_aes.rb +1 -1
  43. data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
  44. data/lib/hexapdf/encryption/identity.rb +1 -1
  45. data/lib/hexapdf/encryption/ruby_aes.rb +1 -1
  46. data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
  47. data/lib/hexapdf/encryption/security_handler.rb +1 -1
  48. data/lib/hexapdf/encryption/standard_security_handler.rb +1 -1
  49. data/lib/hexapdf/encryption.rb +1 -1
  50. data/lib/hexapdf/error.rb +1 -1
  51. data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
  52. data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
  53. data/lib/hexapdf/filter/crypt.rb +1 -1
  54. data/lib/hexapdf/filter/encryption.rb +1 -1
  55. data/lib/hexapdf/filter/flate_decode.rb +1 -1
  56. data/lib/hexapdf/filter/lzw_decode.rb +1 -1
  57. data/lib/hexapdf/filter/pass_through.rb +1 -1
  58. data/lib/hexapdf/filter/predictor.rb +1 -1
  59. data/lib/hexapdf/filter/run_length_decode.rb +1 -1
  60. data/lib/hexapdf/filter.rb +1 -1
  61. data/lib/hexapdf/font/cmap/parser.rb +1 -1
  62. data/lib/hexapdf/font/cmap/writer.rb +1 -1
  63. data/lib/hexapdf/font/cmap.rb +1 -1
  64. data/lib/hexapdf/font/encoding/base.rb +1 -1
  65. data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
  66. data/lib/hexapdf/font/encoding/glyph_list.rb +1 -1
  67. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
  68. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +1 -1
  69. data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
  70. data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
  71. data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +1 -1
  72. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
  73. data/lib/hexapdf/font/encoding.rb +1 -1
  74. data/lib/hexapdf/font/invalid_glyph.rb +1 -1
  75. data/lib/hexapdf/font/true_type/builder.rb +1 -1
  76. data/lib/hexapdf/font/true_type/font.rb +1 -1
  77. data/lib/hexapdf/font/true_type/optimizer.rb +1 -1
  78. data/lib/hexapdf/font/true_type/subsetter.rb +1 -1
  79. data/lib/hexapdf/font/true_type/table/cmap.rb +1 -1
  80. data/lib/hexapdf/font/true_type/table/cmap_subtable.rb +1 -1
  81. data/lib/hexapdf/font/true_type/table/directory.rb +1 -1
  82. data/lib/hexapdf/font/true_type/table/glyf.rb +1 -1
  83. data/lib/hexapdf/font/true_type/table/head.rb +1 -1
  84. data/lib/hexapdf/font/true_type/table/hhea.rb +1 -1
  85. data/lib/hexapdf/font/true_type/table/hmtx.rb +1 -1
  86. data/lib/hexapdf/font/true_type/table/kern.rb +1 -1
  87. data/lib/hexapdf/font/true_type/table/loca.rb +1 -1
  88. data/lib/hexapdf/font/true_type/table/maxp.rb +1 -1
  89. data/lib/hexapdf/font/true_type/table/name.rb +1 -1
  90. data/lib/hexapdf/font/true_type/table/os2.rb +1 -1
  91. data/lib/hexapdf/font/true_type/table/post.rb +1 -1
  92. data/lib/hexapdf/font/true_type/table.rb +1 -1
  93. data/lib/hexapdf/font/true_type.rb +1 -1
  94. data/lib/hexapdf/font/true_type_wrapper.rb +1 -1
  95. data/lib/hexapdf/font/type1/afm_parser.rb +1 -1
  96. data/lib/hexapdf/font/type1/character_metrics.rb +1 -1
  97. data/lib/hexapdf/font/type1/font.rb +1 -1
  98. data/lib/hexapdf/font/type1/font_metrics.rb +1 -1
  99. data/lib/hexapdf/font/type1/pfb_parser.rb +1 -1
  100. data/lib/hexapdf/font/type1.rb +1 -1
  101. data/lib/hexapdf/font/type1_wrapper.rb +1 -1
  102. data/lib/hexapdf/font_loader/from_configuration.rb +1 -1
  103. data/lib/hexapdf/font_loader/from_file.rb +1 -1
  104. data/lib/hexapdf/font_loader/standard14.rb +1 -1
  105. data/lib/hexapdf/font_loader.rb +1 -1
  106. data/lib/hexapdf/image_loader/jpeg.rb +1 -1
  107. data/lib/hexapdf/image_loader/pdf.rb +1 -1
  108. data/lib/hexapdf/image_loader/png.rb +1 -1
  109. data/lib/hexapdf/image_loader.rb +1 -1
  110. data/lib/hexapdf/importer.rb +1 -1
  111. data/lib/hexapdf/layout/box.rb +4 -2
  112. data/lib/hexapdf/layout/frame.rb +1 -1
  113. data/lib/hexapdf/layout/image_box.rb +1 -1
  114. data/lib/hexapdf/layout/inline_box.rb +1 -1
  115. data/lib/hexapdf/layout/line.rb +1 -1
  116. data/lib/hexapdf/layout/numeric_refinements.rb +1 -1
  117. data/lib/hexapdf/layout/style.rb +40 -2
  118. data/lib/hexapdf/layout/text_box.rb +1 -1
  119. data/lib/hexapdf/layout/text_fragment.rb +1 -1
  120. data/lib/hexapdf/layout/text_layouter.rb +1 -1
  121. data/lib/hexapdf/layout/text_shaper.rb +1 -1
  122. data/lib/hexapdf/layout/width_from_polygon.rb +2 -2
  123. data/lib/hexapdf/layout.rb +1 -1
  124. data/lib/hexapdf/name_tree_node.rb +1 -1
  125. data/lib/hexapdf/number_tree_node.rb +1 -1
  126. data/lib/hexapdf/object.rb +1 -1
  127. data/lib/hexapdf/parser.rb +2 -2
  128. data/lib/hexapdf/pdf_array.rb +1 -1
  129. data/lib/hexapdf/rectangle.rb +1 -1
  130. data/lib/hexapdf/reference.rb +1 -1
  131. data/lib/hexapdf/revision.rb +1 -1
  132. data/lib/hexapdf/revisions.rb +1 -1
  133. data/lib/hexapdf/serializer.rb +1 -1
  134. data/lib/hexapdf/stream.rb +1 -1
  135. data/lib/hexapdf/task/dereference.rb +1 -1
  136. data/lib/hexapdf/task/optimize.rb +1 -1
  137. data/lib/hexapdf/task.rb +1 -1
  138. data/lib/hexapdf/tokenizer.rb +1 -1
  139. data/lib/hexapdf/type/acro_form/appearance_generator.rb +14 -7
  140. data/lib/hexapdf/type/acro_form/button_field.rb +53 -28
  141. data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
  142. data/lib/hexapdf/type/acro_form/field.rb +21 -2
  143. data/lib/hexapdf/type/acro_form/form.rb +48 -29
  144. data/lib/hexapdf/type/acro_form/text_field.rb +2 -2
  145. data/lib/hexapdf/type/acro_form/variable_text_field.rb +17 -9
  146. data/lib/hexapdf/type/acro_form.rb +1 -1
  147. data/lib/hexapdf/type/action.rb +1 -1
  148. data/lib/hexapdf/type/actions/go_to.rb +1 -1
  149. data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
  150. data/lib/hexapdf/type/actions/launch.rb +1 -1
  151. data/lib/hexapdf/type/actions/uri.rb +1 -1
  152. data/lib/hexapdf/type/actions.rb +1 -1
  153. data/lib/hexapdf/type/annotation.rb +1 -1
  154. data/lib/hexapdf/type/annotations/link.rb +1 -1
  155. data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
  156. data/lib/hexapdf/type/annotations/text.rb +1 -1
  157. data/lib/hexapdf/type/annotations/widget.rb +2 -2
  158. data/lib/hexapdf/type/annotations.rb +1 -1
  159. data/lib/hexapdf/type/catalog.rb +1 -1
  160. data/lib/hexapdf/type/cid_font.rb +1 -1
  161. data/lib/hexapdf/type/embedded_file.rb +1 -1
  162. data/lib/hexapdf/type/file_specification.rb +1 -1
  163. data/lib/hexapdf/type/font.rb +1 -1
  164. data/lib/hexapdf/type/font_descriptor.rb +1 -1
  165. data/lib/hexapdf/type/font_simple.rb +1 -1
  166. data/lib/hexapdf/type/font_true_type.rb +1 -1
  167. data/lib/hexapdf/type/font_type0.rb +1 -1
  168. data/lib/hexapdf/type/font_type1.rb +1 -1
  169. data/lib/hexapdf/type/font_type3.rb +1 -1
  170. data/lib/hexapdf/type/form.rb +1 -1
  171. data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
  172. data/lib/hexapdf/type/icon_fit.rb +1 -1
  173. data/lib/hexapdf/type/image.rb +1 -1
  174. data/lib/hexapdf/type/info.rb +1 -1
  175. data/lib/hexapdf/type/names.rb +1 -1
  176. data/lib/hexapdf/type/object_stream.rb +1 -1
  177. data/lib/hexapdf/type/page.rb +15 -1
  178. data/lib/hexapdf/type/page_tree_node.rb +1 -1
  179. data/lib/hexapdf/type/resources.rb +1 -1
  180. data/lib/hexapdf/type/trailer.rb +1 -1
  181. data/lib/hexapdf/type/viewer_preferences.rb +1 -1
  182. data/lib/hexapdf/type/xref_stream.rb +1 -1
  183. data/lib/hexapdf/type.rb +1 -1
  184. data/lib/hexapdf/utils/bit_field.rb +1 -1
  185. data/lib/hexapdf/utils/bit_stream.rb +1 -1
  186. data/lib/hexapdf/utils/graphics_helpers.rb +1 -1
  187. data/lib/hexapdf/utils/lru_cache.rb +1 -1
  188. data/lib/hexapdf/utils/math_helpers.rb +1 -1
  189. data/lib/hexapdf/utils/object_hash.rb +1 -1
  190. data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -1
  191. data/lib/hexapdf/utils/sorted_tree_node.rb +1 -1
  192. data/lib/hexapdf/version.rb +2 -2
  193. data/lib/hexapdf/writer.rb +1 -1
  194. data/lib/hexapdf/xref_section.rb +1 -1
  195. data/lib/hexapdf.rb +1 -1
  196. metadata +5 -264
  197. data/CHANGELOG.md +0 -954
  198. data/LICENSE +0 -29
  199. data/README.md +0 -120
  200. data/Rakefile +0 -108
  201. data/agpl-3.0.txt +0 -661
  202. data/examples/001-hello_world.rb +0 -16
  203. data/examples/002-graphics.rb +0 -275
  204. data/examples/003-arcs.rb +0 -50
  205. data/examples/004-optimizing.rb +0 -23
  206. data/examples/005-merging.rb +0 -27
  207. data/examples/006-standard_pdf_fonts.rb +0 -73
  208. data/examples/007-truetype.rb +0 -42
  209. data/examples/008-show_char_bboxes.rb +0 -55
  210. data/examples/009-text_layouter_alignment.rb +0 -47
  211. data/examples/010-text_layouter_inline_boxes.rb +0 -64
  212. data/examples/011-text_layouter_line_wrapping.rb +0 -57
  213. data/examples/012-text_layouter_styling.rb +0 -122
  214. data/examples/013-text_layouter_shapes.rb +0 -176
  215. data/examples/014-text_in_polygon.rb +0 -60
  216. data/examples/015-boxes.rb +0 -76
  217. data/examples/016-frame_automatic_box_placement.rb +0 -90
  218. data/examples/017-frame_text_flow.rb +0 -60
  219. data/examples/018-composer.rb +0 -44
  220. data/examples/019-acro_form.rb +0 -88
  221. data/examples/emoji-smile.png +0 -0
  222. data/examples/emoji-wink.png +0 -0
  223. data/examples/machupicchu.jpg +0 -0
  224. data/test/data/aes-test-vectors/CBCGFSbox-128-decrypt.data.gz +0 -0
  225. data/test/data/aes-test-vectors/CBCGFSbox-128-encrypt.data.gz +0 -0
  226. data/test/data/aes-test-vectors/CBCGFSbox-192-decrypt.data.gz +0 -0
  227. data/test/data/aes-test-vectors/CBCGFSbox-192-encrypt.data.gz +0 -0
  228. data/test/data/aes-test-vectors/CBCGFSbox-256-decrypt.data.gz +0 -0
  229. data/test/data/aes-test-vectors/CBCGFSbox-256-encrypt.data.gz +0 -0
  230. data/test/data/aes-test-vectors/CBCKeySbox-128-decrypt.data.gz +0 -0
  231. data/test/data/aes-test-vectors/CBCKeySbox-128-encrypt.data.gz +0 -0
  232. data/test/data/aes-test-vectors/CBCKeySbox-192-decrypt.data.gz +0 -0
  233. data/test/data/aes-test-vectors/CBCKeySbox-192-encrypt.data.gz +0 -0
  234. data/test/data/aes-test-vectors/CBCKeySbox-256-decrypt.data.gz +0 -0
  235. data/test/data/aes-test-vectors/CBCKeySbox-256-encrypt.data.gz +0 -0
  236. data/test/data/aes-test-vectors/CBCVarKey-128-decrypt.data.gz +0 -0
  237. data/test/data/aes-test-vectors/CBCVarKey-128-encrypt.data.gz +0 -0
  238. data/test/data/aes-test-vectors/CBCVarKey-192-decrypt.data.gz +0 -0
  239. data/test/data/aes-test-vectors/CBCVarKey-192-encrypt.data.gz +0 -0
  240. data/test/data/aes-test-vectors/CBCVarKey-256-decrypt.data.gz +0 -0
  241. data/test/data/aes-test-vectors/CBCVarKey-256-encrypt.data.gz +0 -0
  242. data/test/data/aes-test-vectors/CBCVarTxt-128-decrypt.data.gz +0 -0
  243. data/test/data/aes-test-vectors/CBCVarTxt-128-encrypt.data.gz +0 -0
  244. data/test/data/aes-test-vectors/CBCVarTxt-192-decrypt.data.gz +0 -0
  245. data/test/data/aes-test-vectors/CBCVarTxt-192-encrypt.data.gz +0 -0
  246. data/test/data/aes-test-vectors/CBCVarTxt-256-decrypt.data.gz +0 -0
  247. data/test/data/aes-test-vectors/CBCVarTxt-256-encrypt.data.gz +0 -0
  248. data/test/data/fonts/Ubuntu-Title.ttf +0 -0
  249. data/test/data/images/cmyk.jpg +0 -0
  250. data/test/data/images/fillbytes.jpg +0 -0
  251. data/test/data/images/gray.jpg +0 -0
  252. data/test/data/images/greyscale-1bit.png +0 -0
  253. data/test/data/images/greyscale-2bit.png +0 -0
  254. data/test/data/images/greyscale-4bit.png +0 -0
  255. data/test/data/images/greyscale-8bit.png +0 -0
  256. data/test/data/images/greyscale-alpha-8bit.png +0 -0
  257. data/test/data/images/greyscale-trns-8bit.png +0 -0
  258. data/test/data/images/greyscale-with-gamma1.0.png +0 -0
  259. data/test/data/images/greyscale-with-gamma1.5.png +0 -0
  260. data/test/data/images/indexed-1bit.png +0 -0
  261. data/test/data/images/indexed-2bit.png +0 -0
  262. data/test/data/images/indexed-4bit.png +0 -0
  263. data/test/data/images/indexed-8bit.png +0 -0
  264. data/test/data/images/indexed-alpha-4bit.png +0 -0
  265. data/test/data/images/indexed-alpha-8bit.png +0 -0
  266. data/test/data/images/rgb.jpg +0 -0
  267. data/test/data/images/truecolour-8bit.png +0 -0
  268. data/test/data/images/truecolour-alpha-8bit.png +0 -0
  269. data/test/data/images/truecolour-gama-chrm-8bit.png +0 -0
  270. data/test/data/images/truecolour-srgb-8bit.png +0 -0
  271. data/test/data/images/ycck.jpg +0 -0
  272. data/test/data/minimal.pdf +0 -44
  273. data/test/data/standard-security-handler/README +0 -9
  274. data/test/data/standard-security-handler/bothpwd-aes-128bit-V4.pdf +0 -44
  275. data/test/data/standard-security-handler/bothpwd-aes-256bit-V5.pdf +0 -0
  276. data/test/data/standard-security-handler/bothpwd-arc4-128bit-V2.pdf +0 -43
  277. data/test/data/standard-security-handler/bothpwd-arc4-128bit-V4.pdf +0 -43
  278. data/test/data/standard-security-handler/bothpwd-arc4-40bit-V1.pdf +0 -0
  279. data/test/data/standard-security-handler/nopwd-aes-128bit-V4.pdf +0 -43
  280. data/test/data/standard-security-handler/nopwd-aes-256bit-V5.pdf +0 -0
  281. data/test/data/standard-security-handler/nopwd-arc4-128bit-V2.pdf +0 -43
  282. data/test/data/standard-security-handler/nopwd-arc4-128bit-V4.pdf +0 -43
  283. data/test/data/standard-security-handler/nopwd-arc4-40bit-V1.pdf +0 -43
  284. data/test/data/standard-security-handler/ownerpwd-aes-128bit-V4.pdf +0 -0
  285. data/test/data/standard-security-handler/ownerpwd-aes-256bit-V5.pdf +0 -43
  286. data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V2.pdf +0 -43
  287. data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V4.pdf +0 -43
  288. data/test/data/standard-security-handler/ownerpwd-arc4-40bit-V1.pdf +0 -43
  289. data/test/data/standard-security-handler/userpwd-aes-128bit-V4.pdf +0 -43
  290. data/test/data/standard-security-handler/userpwd-aes-256bit-V5.pdf +0 -43
  291. data/test/data/standard-security-handler/userpwd-arc4-128bit-V2.pdf +0 -0
  292. data/test/data/standard-security-handler/userpwd-arc4-128bit-V4.pdf +0 -0
  293. data/test/data/standard-security-handler/userpwd-arc4-40bit-V1.pdf +0 -43
  294. data/test/hexapdf/common_tokenizer_tests.rb +0 -236
  295. data/test/hexapdf/content/common.rb +0 -39
  296. data/test/hexapdf/content/graphic_object/test_arc.rb +0 -93
  297. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +0 -90
  298. data/test/hexapdf/content/graphic_object/test_geom2d.rb +0 -79
  299. data/test/hexapdf/content/graphic_object/test_solid_arc.rb +0 -86
  300. data/test/hexapdf/content/test_canvas.rb +0 -1216
  301. data/test/hexapdf/content/test_color_space.rb +0 -164
  302. data/test/hexapdf/content/test_graphics_state.rb +0 -151
  303. data/test/hexapdf/content/test_operator.rb +0 -619
  304. data/test/hexapdf/content/test_parser.rb +0 -99
  305. data/test/hexapdf/content/test_processor.rb +0 -163
  306. data/test/hexapdf/content/test_transformation_matrix.rb +0 -64
  307. data/test/hexapdf/document/test_files.rb +0 -72
  308. data/test/hexapdf/document/test_fonts.rb +0 -60
  309. data/test/hexapdf/document/test_images.rb +0 -72
  310. data/test/hexapdf/document/test_pages.rb +0 -130
  311. data/test/hexapdf/encryption/common.rb +0 -87
  312. data/test/hexapdf/encryption/test_aes.rb +0 -129
  313. data/test/hexapdf/encryption/test_arc4.rb +0 -39
  314. data/test/hexapdf/encryption/test_fast_aes.rb +0 -17
  315. data/test/hexapdf/encryption/test_fast_arc4.rb +0 -12
  316. data/test/hexapdf/encryption/test_identity.rb +0 -21
  317. data/test/hexapdf/encryption/test_ruby_aes.rb +0 -23
  318. data/test/hexapdf/encryption/test_ruby_arc4.rb +0 -20
  319. data/test/hexapdf/encryption/test_security_handler.rb +0 -380
  320. data/test/hexapdf/encryption/test_standard_security_handler.rb +0 -322
  321. data/test/hexapdf/filter/common.rb +0 -53
  322. data/test/hexapdf/filter/test_ascii85_decode.rb +0 -59
  323. data/test/hexapdf/filter/test_ascii_hex_decode.rb +0 -38
  324. data/test/hexapdf/filter/test_crypt.rb +0 -21
  325. data/test/hexapdf/filter/test_encryption.rb +0 -24
  326. data/test/hexapdf/filter/test_flate_decode.rb +0 -44
  327. data/test/hexapdf/filter/test_lzw_decode.rb +0 -52
  328. data/test/hexapdf/filter/test_predictor.rb +0 -219
  329. data/test/hexapdf/filter/test_run_length_decode.rb +0 -32
  330. data/test/hexapdf/font/cmap/test_parser.rb +0 -102
  331. data/test/hexapdf/font/cmap/test_writer.rb +0 -66
  332. data/test/hexapdf/font/encoding/test_base.rb +0 -45
  333. data/test/hexapdf/font/encoding/test_difference_encoding.rb +0 -29
  334. data/test/hexapdf/font/encoding/test_glyph_list.rb +0 -59
  335. data/test/hexapdf/font/encoding/test_zapf_dingbats_encoding.rb +0 -16
  336. data/test/hexapdf/font/test_cmap.rb +0 -104
  337. data/test/hexapdf/font/test_encoding.rb +0 -27
  338. data/test/hexapdf/font/test_invalid_glyph.rb +0 -34
  339. data/test/hexapdf/font/test_true_type_wrapper.rb +0 -186
  340. data/test/hexapdf/font/test_type1_wrapper.rb +0 -107
  341. data/test/hexapdf/font/true_type/common.rb +0 -17
  342. data/test/hexapdf/font/true_type/table/common.rb +0 -27
  343. data/test/hexapdf/font/true_type/table/test_cmap.rb +0 -47
  344. data/test/hexapdf/font/true_type/table/test_cmap_subtable.rb +0 -141
  345. data/test/hexapdf/font/true_type/table/test_directory.rb +0 -30
  346. data/test/hexapdf/font/true_type/table/test_glyf.rb +0 -58
  347. data/test/hexapdf/font/true_type/table/test_head.rb +0 -56
  348. data/test/hexapdf/font/true_type/table/test_hhea.rb +0 -26
  349. data/test/hexapdf/font/true_type/table/test_hmtx.rb +0 -30
  350. data/test/hexapdf/font/true_type/table/test_kern.rb +0 -61
  351. data/test/hexapdf/font/true_type/table/test_loca.rb +0 -33
  352. data/test/hexapdf/font/true_type/table/test_maxp.rb +0 -50
  353. data/test/hexapdf/font/true_type/table/test_name.rb +0 -76
  354. data/test/hexapdf/font/true_type/table/test_os2.rb +0 -55
  355. data/test/hexapdf/font/true_type/table/test_post.rb +0 -78
  356. data/test/hexapdf/font/true_type/test_builder.rb +0 -42
  357. data/test/hexapdf/font/true_type/test_font.rb +0 -116
  358. data/test/hexapdf/font/true_type/test_optimizer.rb +0 -26
  359. data/test/hexapdf/font/true_type/test_subsetter.rb +0 -73
  360. data/test/hexapdf/font/true_type/test_table.rb +0 -48
  361. data/test/hexapdf/font/type1/common.rb +0 -6
  362. data/test/hexapdf/font/type1/test_afm_parser.rb +0 -65
  363. data/test/hexapdf/font/type1/test_font.rb +0 -104
  364. data/test/hexapdf/font/type1/test_font_metrics.rb +0 -22
  365. data/test/hexapdf/font/type1/test_pfb_parser.rb +0 -37
  366. data/test/hexapdf/font_loader/test_from_configuration.rb +0 -43
  367. data/test/hexapdf/font_loader/test_from_file.rb +0 -36
  368. data/test/hexapdf/font_loader/test_standard14.rb +0 -33
  369. data/test/hexapdf/image_loader/test_jpeg.rb +0 -93
  370. data/test/hexapdf/image_loader/test_pdf.rb +0 -47
  371. data/test/hexapdf/image_loader/test_png.rb +0 -259
  372. data/test/hexapdf/layout/test_box.rb +0 -152
  373. data/test/hexapdf/layout/test_frame.rb +0 -350
  374. data/test/hexapdf/layout/test_image_box.rb +0 -73
  375. data/test/hexapdf/layout/test_inline_box.rb +0 -71
  376. data/test/hexapdf/layout/test_line.rb +0 -206
  377. data/test/hexapdf/layout/test_style.rb +0 -779
  378. data/test/hexapdf/layout/test_text_box.rb +0 -140
  379. data/test/hexapdf/layout/test_text_fragment.rb +0 -375
  380. data/test/hexapdf/layout/test_text_layouter.rb +0 -758
  381. data/test/hexapdf/layout/test_text_shaper.rb +0 -62
  382. data/test/hexapdf/layout/test_width_from_polygon.rb +0 -108
  383. data/test/hexapdf/task/test_dereference.rb +0 -51
  384. data/test/hexapdf/task/test_optimize.rb +0 -162
  385. data/test/hexapdf/test_composer.rb +0 -258
  386. data/test/hexapdf/test_configuration.rb +0 -93
  387. data/test/hexapdf/test_data_dir.rb +0 -32
  388. data/test/hexapdf/test_dictionary.rb +0 -340
  389. data/test/hexapdf/test_dictionary_fields.rb +0 -245
  390. data/test/hexapdf/test_document.rb +0 -641
  391. data/test/hexapdf/test_filter.rb +0 -100
  392. data/test/hexapdf/test_importer.rb +0 -106
  393. data/test/hexapdf/test_object.rb +0 -258
  394. data/test/hexapdf/test_parser.rb +0 -637
  395. data/test/hexapdf/test_pdf_array.rb +0 -169
  396. data/test/hexapdf/test_rectangle.rb +0 -73
  397. data/test/hexapdf/test_reference.rb +0 -50
  398. data/test/hexapdf/test_revision.rb +0 -188
  399. data/test/hexapdf/test_revisions.rb +0 -196
  400. data/test/hexapdf/test_serializer.rb +0 -195
  401. data/test/hexapdf/test_stream.rb +0 -274
  402. data/test/hexapdf/test_tokenizer.rb +0 -80
  403. data/test/hexapdf/test_type.rb +0 -18
  404. data/test/hexapdf/test_writer.rb +0 -140
  405. data/test/hexapdf/test_xref_section.rb +0 -61
  406. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +0 -794
  407. data/test/hexapdf/type/acro_form/test_button_field.rb +0 -302
  408. data/test/hexapdf/type/acro_form/test_choice_field.rb +0 -220
  409. data/test/hexapdf/type/acro_form/test_field.rb +0 -247
  410. data/test/hexapdf/type/acro_form/test_form.rb +0 -353
  411. data/test/hexapdf/type/acro_form/test_signature_field.rb +0 -38
  412. data/test/hexapdf/type/acro_form/test_text_field.rb +0 -195
  413. data/test/hexapdf/type/acro_form/test_variable_text_field.rb +0 -77
  414. data/test/hexapdf/type/actions/test_launch.rb +0 -24
  415. data/test/hexapdf/type/actions/test_uri.rb +0 -23
  416. data/test/hexapdf/type/annotations/test_markup_annotation.rb +0 -22
  417. data/test/hexapdf/type/annotations/test_text.rb +0 -34
  418. data/test/hexapdf/type/annotations/test_widget.rb +0 -225
  419. data/test/hexapdf/type/test_annotation.rb +0 -97
  420. data/test/hexapdf/type/test_catalog.rb +0 -48
  421. data/test/hexapdf/type/test_cid_font.rb +0 -61
  422. data/test/hexapdf/type/test_file_specification.rb +0 -141
  423. data/test/hexapdf/type/test_font.rb +0 -67
  424. data/test/hexapdf/type/test_font_descriptor.rb +0 -61
  425. data/test/hexapdf/type/test_font_simple.rb +0 -176
  426. data/test/hexapdf/type/test_font_true_type.rb +0 -31
  427. data/test/hexapdf/type/test_font_type0.rb +0 -120
  428. data/test/hexapdf/type/test_font_type1.rb +0 -142
  429. data/test/hexapdf/type/test_font_type3.rb +0 -26
  430. data/test/hexapdf/type/test_form.rb +0 -120
  431. data/test/hexapdf/type/test_image.rb +0 -261
  432. data/test/hexapdf/type/test_info.rb +0 -9
  433. data/test/hexapdf/type/test_object_stream.rb +0 -117
  434. data/test/hexapdf/type/test_page.rb +0 -587
  435. data/test/hexapdf/type/test_page_tree_node.rb +0 -315
  436. data/test/hexapdf/type/test_resources.rb +0 -209
  437. data/test/hexapdf/type/test_trailer.rb +0 -116
  438. data/test/hexapdf/type/test_xref_stream.rb +0 -143
  439. data/test/hexapdf/utils/test_bit_field.rb +0 -63
  440. data/test/hexapdf/utils/test_bit_stream.rb +0 -69
  441. data/test/hexapdf/utils/test_graphics_helpers.rb +0 -37
  442. data/test/hexapdf/utils/test_lru_cache.rb +0 -22
  443. data/test/hexapdf/utils/test_object_hash.rb +0 -120
  444. data/test/hexapdf/utils/test_pdf_doc_encoding.rb +0 -18
  445. data/test/hexapdf/utils/test_sorted_tree_node.rb +0 -239
  446. data/test/test_helper.rb +0 -58
@@ -4,7 +4,7 @@
4
4
  # This file is part of HexaPDF.
5
5
  #
6
6
  # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
- # Copyright (C) 2014-2020 Thomas Leitner
7
+ # Copyright (C) 2014-2021 Thomas Leitner
8
8
  #
9
9
  # HexaPDF is free software: you can redistribute it and/or modify it
10
10
  # under the terms of the GNU Affero General Public License version 3 as
@@ -56,7 +56,7 @@ module HexaPDF
56
56
  # know all operators and their operands.
57
57
  #
58
58
  # This is rather tedious and therefore this class exists. It allows one to modify a content
59
- # stream by invoking methods that should be familiar to anyone that has ever used a graphic
59
+ # stream by invoking methods that should be familiar to anyone that has ever used a graphics
60
60
  # API. There are methods for moving the current point, drawing lines and curves, setting the
61
61
  # color, line width and so on.
62
62
  #
@@ -65,6 +65,84 @@ module HexaPDF
65
65
  # changes and serialization, with one exception: color setters don't invoke the corresponding
66
66
  # operator implementation but directly work on the graphics state.
67
67
  #
68
+ # === General Graphics State Manipulation Methods
69
+ #
70
+ # * #save_graphics_state
71
+ # * #restore_graphics_state
72
+ # * #fill_color
73
+ # * #stroke_color
74
+ # * #opacity
75
+ # * #rendering_intent
76
+ #
77
+ # === Transformation Methods
78
+ #
79
+ # * #transform
80
+ # * #translate
81
+ # * #scale
82
+ # * #rotate
83
+ # * #skew
84
+ #
85
+ # === Path Construction Methods
86
+ #
87
+ # * #move_to
88
+ # * #line_to
89
+ # * #curve_to
90
+ # * #rectangle
91
+ # * #line
92
+ # * #polyline
93
+ # * #polygon
94
+ # * #circle
95
+ # * #ellipse
96
+ # * #arc
97
+ # * #close_subpath
98
+ # * #end_path
99
+ #
100
+ # === Path Painting Methods
101
+ #
102
+ # * #fill
103
+ # * #stroke
104
+ # * #fill_stroke
105
+ # * #close_stroke
106
+ # * #close_fill_stroke
107
+ # * #clip_path
108
+ #
109
+ # === Path Related Graphics State Methods
110
+ #
111
+ # * #line_cap_style
112
+ # * #line_dash_pattern
113
+ # * #line_join_style
114
+ # * #line_width
115
+ # * #miter_limit
116
+ #
117
+ # === Text Related Methods
118
+ #
119
+ # * #begin_text
120
+ # * #end_text
121
+ # * #text
122
+ # * #show_glyphs
123
+ # * #show_glyphs_only
124
+ # * #text_cursor
125
+ # * #move_text_cursor
126
+ # * #font
127
+ # * #font_size
128
+ # * #character_spacing
129
+ # * #horizontal_scaling
130
+ # * #text_rise
131
+ # * #word_spacing
132
+ # * #leading
133
+ # * #text_matrix
134
+ # * #text_rendering_mode
135
+ #
136
+ # === Other Methods
137
+ #
138
+ # * #image
139
+ # * #xobject
140
+ # * #graphic_object
141
+ # * #draw
142
+ # * #marked_content_point
143
+ # * #marked_content_sequence
144
+ # * #end_marked_content_sequence
145
+ #
68
146
  #
69
147
  # == PDF Graphics
70
148
  #
@@ -122,16 +200,6 @@ module HexaPDF
122
200
  # In addition filling may be done using either the nonzero winding number rule or the even-odd
123
201
  # rule.
124
202
  #
125
- #
126
- # == Special Graphics State Methods
127
- #
128
- # These methods are only allowed when the current graphics object is :none, i.e. operations are
129
- # done on the page description level.
130
- #
131
- # * #save_graphics_state
132
- # * #restore_graphics_state
133
- # * #transform, #rotate, #scale, #translate, #skew
134
- #
135
203
  # See: PDF1.7 s8, s9
136
204
  class Canvas
137
205
 
@@ -154,8 +222,10 @@ module HexaPDF
154
222
  # operations.
155
223
  #
156
224
  # In contrast to #contents, it is ensured that an open graphics object is closed and all saved
157
- # graphics states are restored when the contents of the stream data object is read. *Note*
158
- # that this means that reading the stream data object may change the state of the canvas.
225
+ # graphics states are restored when the contents of the stream data object is read.
226
+ #
227
+ # *Note* that this means that reading the stream data object may change the state of the
228
+ # canvas!
159
229
  attr_reader :stream_data
160
230
 
161
231
  # The Content::GraphicsState object containing the current graphics state.
@@ -166,8 +236,8 @@ module HexaPDF
166
236
 
167
237
  # The current graphics object.
168
238
  #
169
- # The graphics object should not be changed directly. It is automatically updated according
170
- # to the invoked methods.
239
+ # The graphics object should not be changed directly. It is automatically updated by the
240
+ # invoked methods.
171
241
  #
172
242
  # This attribute can have the following values:
173
243
  #
@@ -189,9 +259,21 @@ module HexaPDF
189
259
  attr_reader :current_point
190
260
 
191
261
  # The operator name/implementation map used when invoking or serializing an operator.
262
+ #
263
+ # Defaults to Content::Operator::DEFAULT_OPERATORS.
192
264
  attr_reader :operators
193
265
 
194
- # Creates a new Canvas object for the given context object (either a Page or a Form).
266
+ # Creates a new Canvas object for the given context object (either a HexaPDF::Type::Page or a
267
+ # HexaPDF::Type::Form).
268
+ #
269
+ # This method is usually not invoked directly but through HexaPDF::Type::Page#canvas or
270
+ # HexaPDF::Type::Form#canvas to make sure the contents of the canvas is properly assigned to
271
+ # the context object.
272
+ #
273
+ # Examples:
274
+ #
275
+ # doc = HexaPDF::Document.new
276
+ # canvas = doc.pages.add.canvas
195
277
  def initialize(context)
196
278
  @context = context
197
279
  @operators = Operator::DEFAULT_OPERATORS.dup
@@ -214,6 +296,8 @@ module HexaPDF
214
296
  end
215
297
 
216
298
  # Returns the resource dictionary of the context object.
299
+ #
300
+ # See HexaPDF::Type::Resources
217
301
  def resources
218
302
  @context.resources
219
303
  end
@@ -224,22 +308,29 @@ module HexaPDF
224
308
  #
225
309
  # Saves the current graphics state and returns self.
226
310
  #
227
- # If invoked without a block a corresponding call to #restore_graphics_state must be done.
228
- # Otherwise the graphics state is automatically restored when the block is finished.
311
+ # If invoked without a block a corresponding call to #restore_graphics_state must be done to
312
+ # ensure proper nesting. Otherwise, i.e. when invoked with a block, the graphics state is
313
+ # automatically restored when the block is finished.
314
+ #
315
+ # Any saved graphics states are also restored when the content stream associated with the
316
+ # canvas is serialized to ensure proper nesting.
229
317
  #
230
318
  # Examples:
231
319
  #
320
+ # #>pdf
232
321
  # # With a block
233
322
  # canvas.save_graphics_state do
234
- # canvas.line_width(10)
235
- # canvas.line(100, 100, 200, 200)
323
+ # canvas.stroke_color("red") # After the block the color is reset
324
+ # canvas.line(20, 20, 70, 180).stroke
236
325
  # end
326
+ # canvas.line(60, 20, 110, 180).stroke
237
327
  #
238
328
  # # Same without a block
239
- # canvas.save_graphics_state
240
- # canvas.line_width(10)
241
- # canvas.line(100, 100, 200, 200)
242
- # canvas.restore_graphics_state
329
+ # canvas.save_graphics_state.
330
+ # stroke_color("red").
331
+ # line(100, 20, 150, 180).stroke.
332
+ # restore_graphics_state
333
+ # canvas.line(140, 20, 190, 180).stroke
243
334
  #
244
335
  # See: PDF1.7 s8.4.2, #restore_graphics_state
245
336
  def save_graphics_state
@@ -286,10 +377,12 @@ module HexaPDF
286
377
  #
287
378
  # Examples:
288
379
  #
380
+ # #>pdf
289
381
  # canvas.transform(1, 0, 0, 1, 100, 100) do # Translate origin to (100, 100)
290
- # canvas.line(0, 0, 100, 100) # Actually from (100, 100) to (200, 200)
382
+ # canvas.stroke_color("red").
383
+ # line(0, 0, 100, 50).stroke # Actually from (100, 100) to (200, 150)
291
384
  # end
292
- # canvas.line(0, 0, 100, 100) # Again from (0, 0) to (100, 100)
385
+ # canvas.line(0, 0, 100, 50).stroke # Really from (0, 0) to (100, 50)
293
386
  #
294
387
  # See: PDF1.7 s8.3, s8.4.4
295
388
  def transform(a, b, c, d, e, f)
@@ -313,20 +406,25 @@ module HexaPDF
313
406
  # If invoked with a block, the rotation of the user space is only active during the block by
314
407
  # saving and restoring the graphics state.
315
408
  #
316
- # Note that the origin of the coordinate system itself doesn't change!
409
+ # Note that the origin of the coordinate system itself doesn't change even if the +origin+
410
+ # argument is given!
317
411
  #
318
412
  # origin::
319
413
  # The point around which the user space should be rotated.
320
414
  #
321
415
  # Examples:
322
416
  #
323
- # canvas.rotate(90) do # Positive x-axis is now pointing upwards
324
- # canvas.line(0, 0, 100, 0) # Actually from (0, 0) to (0, 100)
417
+ # #>pdf-center
418
+ # canvas.stroke_color("lightgrey").
419
+ # rectangle(0, 0, 60, 40).stroke
420
+ # canvas.rotate(45) do # Positive x-axis pointing to top-right corner
421
+ # canvas.stroke_color("red").
422
+ # rectangle(0, 0, 60, 40).stroke
325
423
  # end
326
- # canvas.line(0, 0, 100, 0) # Again from (0, 0) to (100, 0)
327
424
  #
328
- # canvas.rotate(90, origin: [100, 100]) do
329
- # canvas.line(100, 100, 200, 0) # Actually from (100, 100) to (100, 200)
425
+ # canvas.rotate(-45, origin: [-50, -50]) do # Rotate around (-50,-50)
426
+ # canvas.stroke_color("blue").
427
+ # rectangle(0, 0, 60, 40).stroke
330
428
  # end
331
429
  #
332
430
  # See: #transform
@@ -352,20 +450,25 @@ module HexaPDF
352
450
  # If invoked with a block, the scaling is only active during the block by saving and
353
451
  # restoring the graphics state.
354
452
  #
355
- # Note that the origin of the coordinate system itself doesn't change!
453
+ # Note that the origin of the coordinate system itself doesn't change even if the +origin+
454
+ # argument is given!
356
455
  #
357
456
  # origin::
358
457
  # The point from which the user space should be scaled.
359
458
  #
360
459
  # Examples:
361
460
  #
362
- # canvas.scale(2, 3) do # Point (1, 1) is now actually (2, 3)
363
- # canvas.line(50, 50, 100, 100) # Actually from (100, 150) to (200, 300)
461
+ # #>pdf-center
462
+ # canvas.stroke_color("lightgrey").
463
+ # rectangle(10, 10, 10, 10).stroke
464
+ # canvas.scale(4, 2) do # Scale from origin
465
+ # canvas.stroke_color("blue").
466
+ # rectangle(10, 10, 10, 10).stroke # Actually (40, 20) to (80, 40)
364
467
  # end
365
- # canvas.line(0, 0, 100, 0) # Again from (0, 0) to (100, 0)
366
468
  #
367
- # canvas.scale(2, 3, origin: [50, 50]) do
368
- # canvas.line(50, 50, 100, 100) # Actually from (50, 50) to (200, 300)
469
+ # canvas.scale(-2, 4, origin: [10, 10]) do # Scale from (10, 10)
470
+ # canvas.stroke_color("red").
471
+ # rectangle(10, 10, 10, 10).stroke # Actually (10, 10) to (-10, 40)
369
472
  # end
370
473
  #
371
474
  # See: #transform
@@ -389,10 +492,12 @@ module HexaPDF
389
492
  #
390
493
  # Examples:
391
494
  #
392
- # canvas.translate(100, 100) do # Origin is now at (100, 100)
393
- # canvas.line(0, 0, 100, 0) # Actually from (100, 100) to (200, 100)
495
+ # #>pdf-center
496
+ # canvas.rectangle(0, 0, 40, 20).stroke # Rectangle from (0, 0) to (40, 20)
497
+ # canvas.translate(50, 50) do # Origin is now at (50, 50)
498
+ # canvas.stroke_color("red").
499
+ # rectangle(0, 0, 40, 20).stroke # Actually (50, 50) to (90, 70)
394
500
  # end
395
- # canvas.line(0, 0, 100, 0) # Again from (0, 0) to (100, 0)
396
501
  #
397
502
  # See: #transform
398
503
  def translate(x, y, &block)
@@ -416,13 +521,17 @@ module HexaPDF
416
521
  #
417
522
  # Examples:
418
523
  #
419
- # canvas.skew(0, 45) do # Point (1, 1) is now actually (2, 1)
420
- # canvas.line(50, 50, 100, 100) # Actually from (100, 50) to (200, 100)
524
+ # #>pdf-center
525
+ # canvas.stroke_color("lightgrey").
526
+ # rectangle(10, 10, 40, 20).stroke
527
+ # canvas.skew(0, 30) do # Point (10, 10) is now actually (15, 10)
528
+ # canvas.stroke_color("blue").
529
+ # rectangle(10, 10, 40, 20).stroke # Now a parallelogram
421
530
  # end
422
- # canvas.line(0, 0, 100, 0) # Again from (0, 0) to (100, 0)
423
531
  #
424
- # canvas.skew(0, origin: [50, 50]) do
425
- # canvas.line(50, 50, 100, 100) # Actually from (50, 50) to (200, 300)
532
+ # canvas.skew(30, 30, origin: [-50, 50]) do # Skew from (-50, 50)
533
+ # canvas.stroke_color("red").
534
+ # rectangle(-50, 50, 20, 20).stroke
426
535
  # end
427
536
  #
428
537
  # See: #transform
@@ -453,14 +562,19 @@ module HexaPDF
453
562
  #
454
563
  # Examples:
455
564
  #
456
- # canvas.line_width(10)
565
+ # #>pdf
566
+ # canvas.line_width(10).
567
+ # line(10, 10, 10, 190).stroke
457
568
  # canvas.line_width # => 10
458
569
  # canvas.line_width = 5 # => 5
570
+ # canvas.line(60, 10, 60, 190).stroke
459
571
  #
460
572
  # canvas.line_width(10) do
461
573
  # canvas.line_width # => 10
574
+ # canvas.line(110, 10, 110, 190).stroke
462
575
  # end
463
576
  # canvas.line_width # => 5
577
+ # canvas.line(160, 10, 160, 190).stroke
464
578
  #
465
579
  # See: PDF1.7 s8.4.3.2
466
580
  def line_width(width = nil, &block)
@@ -473,10 +587,18 @@ module HexaPDF
473
587
  # canvas.line_cap_style(style) => canvas
474
588
  # canvas.line_cap_style(style) { block } => canvas
475
589
  #
476
- # The line cap style specifies how the ends of stroked open paths should look like. The
477
- # +style+ parameter can either be a valid integer or one of the symbols +:butt+, +:round+ or
478
- # +:projecting_square+ (see Content::LineCapStyle.normalize for details). Note that the return
479
- # value is always a normalized line cap style.
590
+ # The line cap style specifies how the ends of stroked open paths should look like.
591
+ #
592
+ # The +style+ parameter can be one of:
593
+ #
594
+ # :butt or 0::
595
+ # Stroke is squared off at the endpoint of a path.
596
+ # :round or 1::
597
+ # A semicircular arc is drawn at the endpoint of a path.
598
+ # :projecting_square or 2::
599
+ # The stroke continues half the line width beyond the endpoint of a path.
600
+ #
601
+ # Note that the return value is always a normalized line cap style.
480
602
  #
481
603
  # Returns the current line cap style (see Content::GraphicsState#line_cap_style) when no
482
604
  # argument is given. Otherwise sets the line cap style to the given +style+ and returns self.
@@ -487,6 +609,7 @@ module HexaPDF
487
609
  #
488
610
  # Examples:
489
611
  #
612
+ # #>pdf
490
613
  # canvas.line_cap_style(:butt)
491
614
  # canvas.line_cap_style # => #<NamedValue @name=:butt, @value=0>
492
615
  # canvas.line_cap_style = :round # => #<NamedValue @name=:round, @value=1>
@@ -496,7 +619,16 @@ module HexaPDF
496
619
  # end
497
620
  # canvas.line_cap_style # => #<NamedValue @name=:round, @value=1>
498
621
  #
499
- # See: PDF1.7 s8.4.3.3
622
+ # # visual example
623
+ # [:butt, :round, :projecting_square].each_with_index do |style, index|
624
+ # canvas.line_cap_style(style).
625
+ # line_width(10).stroke_color("black").
626
+ # line(50 + index * 50, 30, 50 + index * 50, 170).stroke
627
+ # canvas.stroke_color("white").line_width(1).line_cap_style(:butt).
628
+ # line(50 + index * 50, 30, 50 + index * 50, 170).stroke
629
+ # end
630
+ #
631
+ # See: PDF1.7 s8.4.3.3, Content::LineCapStyle
500
632
  def line_cap_style(style = nil, &block)
501
633
  gs_getter_setter(:line_cap_style, :J, style && LineCapStyle.normalize(style), &block)
502
634
  end
@@ -507,10 +639,19 @@ module HexaPDF
507
639
  # canvas.line_join_style(style) => canvas
508
640
  # canvas.line_join_style(style) { block } => canvas
509
641
  #
510
- # The line join style specifies the shape that is used at the corners of stroked paths. The
511
- # +style+ parameter can either be a valid integer or one of the symbols +:miter+, +:round+ or
512
- # +:bevel+ (see Content::LineJoinStyle.normalize for details). Note that the return value is
513
- # always a normalized line join style.
642
+ # The line join style specifies the shape that is used at the corners of stroked paths.
643
+ #
644
+ # The +style+ parameter can be one of:
645
+ #
646
+ # :miter or 0::
647
+ # The outer lines of the two segments continue until the meet at an angle.
648
+ # :round or 1::
649
+ # An arc of a circle is drawn around the point where the segments meet.
650
+ # :bevel or 2::
651
+ # The two segments are finished with butt caps and the space between the ends is filled
652
+ # with a triangle.
653
+ #
654
+ # Note that the return value is always a normalized line join style.
514
655
  #
515
656
  # Returns the current line join style (see Content::GraphicsState#line_join_style) when no
516
657
  # argument is given. Otherwise sets the line join style to the given +style+ and returns self.
@@ -521,6 +662,7 @@ module HexaPDF
521
662
  #
522
663
  # Examples:
523
664
  #
665
+ # #>pdf
524
666
  # canvas.line_join_style(:miter)
525
667
  # canvas.line_join_style # => #<NamedValue @name=:miter, @value=0>
526
668
  # canvas.line_join_style = :round # => #<NamedValue @name=:round, @value=1>
@@ -530,7 +672,16 @@ module HexaPDF
530
672
  # end
531
673
  # canvas.line_join_style # => #<NamedValue @name=:round, @value=1>
532
674
  #
533
- # See: PDF1.7 s8.4.3.4
675
+ # # visual example
676
+ # [:miter, :round, :bevel].each_with_index do |style, index|
677
+ # canvas.line_join_style(style).
678
+ # line_width(10).stroke_color("black").
679
+ # polyline(20 + index * 60, 30, 40 + index * 60, 170, 60 + index * 60, 30).stroke
680
+ # canvas.stroke_color("white").line_width(1).line_join_style(:bevel).
681
+ # polyline(20 + index * 60, 30, 40 + index * 60, 170, 60 + index * 60, 30).stroke
682
+ # end
683
+ #
684
+ # See: PDF1.7 s8.4.3.4, Content::LineJoinStyle
534
685
  def line_join_style(style = nil, &block)
535
686
  gs_getter_setter(:line_join_style, :j, style && LineJoinStyle.normalize(style), &block)
536
687
  end
@@ -554,6 +705,7 @@ module HexaPDF
554
705
  #
555
706
  # Examples:
556
707
  #
708
+ # #>pdf
557
709
  # canvas.miter_limit(10)
558
710
  # canvas.miter_limit # => 10
559
711
  # canvas.miter_limit = 5 # => 5
@@ -563,6 +715,13 @@ module HexaPDF
563
715
  # end
564
716
  # canvas.miter_limit # => 5
565
717
  #
718
+ # # visual example
719
+ # [10, 5].each_with_index do |limit, index|
720
+ # canvas.miter_limit(limit)
721
+ # canvas.line_width(10).polyline(20 + index * 80, 30, 40 + index * 80, 170,
722
+ # 60 + index * 80, 30).stroke
723
+ # end
724
+ #
566
725
  # See: PDF1.7 s8.4.3.5
567
726
  def miter_limit(limit = nil, &block)
568
727
  gs_getter_setter(:miter_limit, :M, limit, &block)
@@ -600,17 +759,25 @@ module HexaPDF
600
759
  #
601
760
  # Examples:
602
761
  #
762
+ # #>pdf
603
763
  # canvas.line_dash_pattern(10)
604
764
  # canvas.line_dash_pattern # => LineDashPattern.new([10], 0)
605
765
  # canvas.line_dash_pattern(10, 2)
606
766
  # canvas.line_dash_pattern([5, 3, 1], 2)
607
- # canvas.line_dash_pattern = LineDashPattern.new([5, 3, 1], 1)
767
+ # canvas.line_dash_pattern = HexaPDF::Content::LineDashPattern.new([5, 3, 1], 1)
608
768
  #
609
769
  # canvas.line_dash_pattern(10) do
610
770
  # canvas.line_dash_pattern # => LineDashPattern.new([10], 0)
611
771
  # end
612
772
  # canvas.line_dash_pattern # => LineDashPattern.new([5, 3, 1], 1)
613
773
  #
774
+ # # visual example
775
+ # [10, [10, 2], [[5, 3, 1], 2]].each_with_index do |pattern, index|
776
+ # canvas.line_dash_pattern(*pattern)
777
+ # canvas.line_width(10).line(50 + index * 50, 30, 50 + index * 50, 170).
778
+ # stroke
779
+ # end
780
+ #
614
781
  # See: PDF1.7 s8.4.3.5, LineDashPattern
615
782
  def line_dash_pattern(value = nil, phase = 0, &block)
616
783
  gs_getter_setter(:line_dash_pattern, :d, value && LineDashPattern.normalize(value, phase),
@@ -675,6 +842,10 @@ module HexaPDF
675
842
  # * Three numeric arguments specify an RGB color (see Content::ColorSpace::DeviceRGB::Color).
676
843
  # * A string in the format "RRGGBB" where "RR" is the hexadecimal number for the red, "GG"
677
844
  # for the green and "BB" for the blue color value also specifies an RGB color.
845
+ # * As does a string in the format "RGB" where "RR", "GG" and "BB" would be used as the
846
+ # hexadecimal numbers for the red, green and blue color values of an RGB color.
847
+ # * Any other string is treated as a CSS Color Module Level 3 color name, see
848
+ # https://www.w3.org/TR/css-color-3/#svg-color.
678
849
  # * Four numeric arguments specify a CMYK color (see Content::ColorSpace::DeviceCMYK::Color).
679
850
  # * A color object is used directly (normally used for color spaces other than DeviceRGB,
680
851
  # DeviceCMYK and DeviceGray).
@@ -689,28 +860,36 @@ module HexaPDF
689
860
  #
690
861
  # Examples:
691
862
  #
863
+ # #>pdf
864
+ # canvas.line_width(5)
865
+ #
692
866
  # # With no arguments just returns the current color
693
867
  # canvas.stroke_color # => DeviceGray.color(0.0)
694
868
  #
695
869
  # # Same gray color because integer values are normalized to the range of 0.0 to 1.0
696
- # canvas.stroke_color(102)
697
- # canvas.stroke_color(0.4)
870
+ # canvas.stroke_color(102).rectangle(10, 170, 20, 20).stroke
871
+ # canvas.stroke_color(0.4).rectangle(40, 170, 20, 20).stroke
698
872
  #
699
- # # Specifying RGB colors
700
- # canvas.stroke_color(255, 255, 0)
701
- # canvas.stroke_color("FFFF00")
873
+ # # Specifying RGB color yellow in all possible formats
874
+ # canvas.stroke_color(255, 255, 0).rectangle(10, 140, 20, 20).stroke
875
+ # canvas.stroke_color(1.0, 1.0, 0).rectangle(40, 140, 20, 20).stroke
876
+ # canvas.stroke_color("FFFF00").rectangle(70, 140, 20, 20).stroke
877
+ # canvas.stroke_color("FF0").rectangle(100, 140, 20, 20).stroke
878
+ # canvas.stroke_color("yellow").rectangle(130, 140, 20, 20).stroke
702
879
  #
703
880
  # # Specifying CMYK colors
704
- # canvas.stroke_color(255, 255, 0, 128)
881
+ # canvas.stroke_color(100, 100, 0, 60).rectangle(10, 110, 20, 20).stroke
882
+ # canvas.stroke_color(1.0, 1.0, 0, 0.6).rectangle(40, 110, 20, 20).stroke
705
883
  #
706
- # # Can use a color object directly
707
- # color = HexaPDF::Content::ColorSpace::DeviceRGB.color(255, 255, 0)
708
- # canvas.stroke_color(color)
884
+ # # Can use a color object directly, only numeric normalization is performed
885
+ # color = HexaPDF::Content::ColorSpace::DeviceRGB.new.color(0, 255, 0)
886
+ # canvas.stroke_color(color).rectangle(10, 80, 20, 20).stroke
709
887
  #
710
888
  # # An array argument is destructured - these calls are all equal
711
- # cnavas.stroke_color(255, 255, 0)
712
- # canvas.stroke_color([255, 255, 0])
713
- # canvas.stroke_color = [255, 255, 0]
889
+ # canvas.stroke_color(0, 255, 0).rectangle(40, 80, 20, 20).stroke
890
+ # canvas.stroke_color([0, 255, 0]).rectangle(70, 80, 20, 20).stroke
891
+ # canvas.stroke_color = [0, 255, 0]
892
+ # canvas.rectangle(100, 80, 20, 20).stroke
714
893
  #
715
894
  # # As usual, can be invoked with a block to limit the effects
716
895
  # canvas.stroke_color(102) do
@@ -725,7 +904,7 @@ module HexaPDF
725
904
 
726
905
  # The fill color defines the color used for non-stroking operations, i.e. for filling paths.
727
906
  #
728
- # Works exactly the same #stroke_color but for the fill color. See #stroke_color for
907
+ # Works exactly the same as #stroke_color but for the fill color. See #stroke_color for
729
908
  # details on invocation and use.
730
909
  def fill_color(*color, &block)
731
910
  color_getter_setter(:fill_color, color, :rg, :g, :k, :cs, :scn, &block)
@@ -753,6 +932,7 @@ module HexaPDF
753
932
  #
754
933
  # Examples:
755
934
  #
935
+ # #>pdf
756
936
  # canvas.opacity(fill_alpha: 0.5)
757
937
  # canvas.opacity # => {fill_alpha: 0.5, stroke_alpha: 1.0}
758
938
  # canvas.opacity(fill_alpha: 0.4, stroke_alpha: 0.9)
@@ -763,6 +943,15 @@ module HexaPDF
763
943
  # end
764
944
  # canvas.opacity # => {fill_alpha: 0.4, stroke_alpha: 0.9}
765
945
  #
946
+ # # visual example
947
+ # canvas.opacity(fill_alpha: 1, stroke_alpha: 1) do # background rectangle on right side
948
+ # canvas.fill_color("lightgrey").rectangle(100, 0, 100, 200).fill
949
+ # end
950
+ # canvas.opacity(fill_alpha: 0.5, stroke_alpha: 0.8). # foreground rectangle, with a thick
951
+ # line_width(20). # stroke that also overlays the
952
+ # fill_color("red").stroke_color("blue"). # inside of the rectangle, creating
953
+ # rectangle(20, 20, 160, 160).fill_stroke # multiple shadings due to opacity
954
+ #
766
955
  # See: PDF1.7 s11.6.4.4
767
956
  def opacity(fill_alpha: nil, stroke_alpha: nil)
768
957
  if !fill_alpha.nil? || !stroke_alpha.nil?
@@ -796,7 +985,10 @@ module HexaPDF
796
985
  #
797
986
  # Examples:
798
987
  #
799
- # canvas.move_to(100, 50)
988
+ # canvas.move_to(10, 50)
989
+ # canvas.current_point # => [10, 50]
990
+ #
991
+ # See: PDF1.7 s8.5.2.1
800
992
  def move_to(x, y)
801
993
  raise_unless_at_page_description_level_or_in_path
802
994
  invoke2(:m, x, y)
@@ -813,7 +1005,13 @@ module HexaPDF
813
1005
  #
814
1006
  # Examples:
815
1007
  #
816
- # canvas.line_to(100, 100)
1008
+ # #>pdf-center
1009
+ # canvas.move_to(10, 50).
1010
+ # line_to(80, 80)
1011
+ # canvas.current_point # => [80, 80]
1012
+ # canvas.stroke
1013
+ #
1014
+ # See: PDF1.7 s8.5.2.1
817
1015
  def line_to(x, y)
818
1016
  raise_unless_in_path
819
1017
  invoke2(:l, x, y)
@@ -831,7 +1029,7 @@ module HexaPDF
831
1029
  # point becomes the new current point.
832
1030
  #
833
1031
  # A Bezier curve consists of the start point, the end point and the two control points +p1+
834
- # and +p2+. The start point is always the current point and the end point is specified as
1032
+ # and +p2+. The start point is always the current point and the end point is specified as the
835
1033
  # +x+ and +y+ arguments.
836
1034
  #
837
1035
  # Additionally, either the first control point +p1+ or the second control +p2+ or both
@@ -841,9 +1039,15 @@ module HexaPDF
841
1039
  #
842
1040
  # Examples:
843
1041
  #
844
- # canvas.curve_to(100, 100, p1: [100, 50], p2: [50, 100])
845
- # canvas.curve_to(100, 100, p1: [100, 50])
846
- # canvas.curve_to(100, 100, p2: [50, 100])
1042
+ # #>pdf-center
1043
+ # canvas.move_to(10, 50).
1044
+ # curve_to(80, 80, p1: [10, 70], p2: [50, 100]).
1045
+ # curve_to(90, -20, p1: [50, 50]).
1046
+ # curve_to(-30, 60, p2: [-20, -40])
1047
+ # canvas.current_point # => [-30, 60]
1048
+ # canvas.stroke
1049
+ #
1050
+ # See: PDF1.7 s8.5.2.2
847
1051
  def curve_to(x, y, p1: nil, p2: nil)
848
1052
  raise_unless_in_path
849
1053
  if p1 && p2
@@ -876,8 +1080,13 @@ module HexaPDF
876
1080
  #
877
1081
  # Examples:
878
1082
  #
879
- # canvas.rectangle(100, 100, 100, 50)
880
- # canvas.rectangle(100, 100, 100, 50, radius: 10)
1083
+ # #>pdf
1084
+ # canvas.rectangle(10, 110, 80, 50).stroke
1085
+ # canvas.rectangle(110, 110, 80, 50, radius: 10).stroke
1086
+ # canvas.rectangle(10, 10, 80, 0).stroke # Degraded: Just a line
1087
+ # canvas.rectangle(110, 10, 0, 0).stroke # Degraded: Draws nothing
1088
+ #
1089
+ # See: PDF1.7 s8.5.2.1
881
1090
  def rectangle(x, y, width, height, radius: 0)
882
1091
  raise_unless_at_page_description_level_or_in_path
883
1092
  if radius == 0
@@ -895,6 +1104,17 @@ module HexaPDF
895
1104
  #
896
1105
  # Closes the current subpath by appending a straight line from the current point to the
897
1106
  # start point of the subpath which also becomes the new current point.
1107
+ #
1108
+ # Examples:
1109
+ #
1110
+ # #>pdf
1111
+ # canvas.move_to(10, 10).
1112
+ # line_to(110, 10).
1113
+ # line_to(60, 60).
1114
+ # close_subpath. # Draws the line from (60, 60) to (10, 10)
1115
+ # stroke
1116
+ #
1117
+ # See: PDF1.7 s8.5.2.1
898
1118
  def close_subpath
899
1119
  raise_unless_in_path
900
1120
  invoke0(:h)
@@ -911,7 +1131,8 @@ module HexaPDF
911
1131
  #
912
1132
  # Examples:
913
1133
  #
914
- # canvas.line(10, 10, 100, 100)
1134
+ # #>pdf
1135
+ # canvas.line(10, 10, 100, 100).stroke
915
1136
  def line(x0, y0, x1, y1)
916
1137
  move_to(x0, y0)
917
1138
  line_to(x1, y1)
@@ -926,7 +1147,8 @@ module HexaPDF
926
1147
  #
927
1148
  # Examples:
928
1149
  #
929
- # canvas.polyline(0, 0, 100, 0, 100, 100, 0, 100, 0, 0)
1150
+ # #>pdf
1151
+ # canvas.polyline(50, 50, 150, 50, 150, 150, 50, 150, 50, 50).stroke
930
1152
  def polyline(*points)
931
1153
  check_poly_points(points)
932
1154
  move_to(points[0], points[1])
@@ -950,8 +1172,10 @@ module HexaPDF
950
1172
  #
951
1173
  # Examples:
952
1174
  #
953
- # canvas.polygon(0, 0, 100, 0, 100, 100, 0, 100)
954
- # canvas.polygon(0, 0, 100, 0, 100, 100, 0, 100, radius: 10)
1175
+ # #>pdf
1176
+ # canvas.polygon(10, 10, 90, 10, 70, 90, 20, 100).stroke
1177
+ # canvas.stroke_color("red").
1178
+ # polygon(130, 130, 150, 100, 170, 150, 130, 190, radius: 10).stroke
955
1179
  def polygon(*points, radius: 0)
956
1180
  if radius == 0
957
1181
  polyline(*points)
@@ -959,7 +1183,9 @@ module HexaPDF
959
1183
  check_poly_points(points)
960
1184
  move_to(*point_on_line(points[0], points[1], points[2], points[3], distance: radius))
961
1185
  points.concat(points[0, 4])
962
- 0.step(points.length - 6, 2) {|i| line_with_rounded_corner(*points[i, 6], radius) }
1186
+ 0.step(points.length - 6, 2) do |i|
1187
+ line_with_rounded_corner(*points[i, 6], in_radius: radius)
1188
+ end
963
1189
  end
964
1190
  close_subpath
965
1191
  end
@@ -975,7 +1201,8 @@ module HexaPDF
975
1201
  #
976
1202
  # Examples:
977
1203
  #
978
- # canvas.circle(100, 100, 10)
1204
+ # #>pdf
1205
+ # canvas.circle(100, 100, 30).stroke
979
1206
  #
980
1207
  # See: #arc (for approximation accuracy)
981
1208
  def circle(cx, cy, radius)
@@ -994,11 +1221,13 @@ module HexaPDF
994
1221
  #
995
1222
  # Examples:
996
1223
  #
1224
+ # #>pdf
997
1225
  # # Ellipse aligned to x-axis and y-axis
998
- # canvas.ellipse(100, 100, a: 10, b: 5)
1226
+ # canvas.ellipse(50, 50, a: 20, b: 10).stroke
999
1227
  #
1000
1228
  # # Inclined ellipse
1001
- # canvas.ellipse(100, 100, a: 10, b: 5, inclination: 45)
1229
+ # canvas.stroke_color("red").
1230
+ # ellipse(150, 150, a: 20, b: 10, inclination: 30).stroke
1002
1231
  #
1003
1232
  # See: #arc (for approximation accuracy)
1004
1233
  def ellipse(cx, cy, a:, b:, inclination: 0)
@@ -1032,7 +1261,7 @@ module HexaPDF
1032
1261
  #
1033
1262
  # +clockwise+::
1034
1263
  # If +true+ the arc is drawn in clockwise direction, otherwise in counterclockwise
1035
- # direction.
1264
+ # direction (default: false).
1036
1265
  #
1037
1266
  # +inclination+::
1038
1267
  # Angle in degrees between the x-axis and the semi-major axis (default: 0)
@@ -1048,18 +1277,24 @@ module HexaPDF
1048
1277
  #
1049
1278
  # Examples:
1050
1279
  #
1051
- # canvas.arc(0, 0, a: 10) # Circle at (0, 0) with radius 10
1052
- # canvas.arc(0, 0, a: 10, b: 5) # Ellipse at (0, 0) with radii 10 and 5
1053
- # canvas.arc(0, 0, a: 10, b: 5, inclination: 45) # The above ellipse inclined 45 degrees
1280
+ # #>pdf
1281
+ # canvas.arc(50, 150, a: 10) # Circle with radius 10
1282
+ # canvas.arc(100, 150, a: 10, b: 5) # Ellipse with radii 10 and 5
1283
+ # canvas.arc(150, 150, a: 10, b: 5, inclination: 45) # The above ellipse inclined 45 degrees
1284
+ # canvas.stroke
1054
1285
  #
1055
- # # Circular and elliptical arcs from 45 degrees to 135 degrees
1056
- # canvas.arc(0, 0, a: 10, start_angle: 45, end_angle: 135)
1057
- # canvas.arc(0, 0, a: 10, b: 5, start_angle: 45, end_angle: 135)
1286
+ # # Circular and elliptical arcs from 30 degrees to 160 degrees
1287
+ # canvas.stroke_color("red")
1288
+ # canvas.arc(50, 100, a: 10, start_angle: 30, end_angle: 160)
1289
+ # canvas.arc(100, 100, a: 10, b: 5, start_angle: 30, end_angle: 160)
1290
+ # canvas.stroke
1058
1291
  #
1059
- # # Arcs from 135 degrees to 15 degrees, the first in counterclockwise direction (i.e. the
1292
+ # # Arcs from 135 degrees to 30 degrees, the first in counterclockwise direction (i.e. the
1060
1293
  # # big arc), the other in clockwise direction (i.e. the small arc)
1061
- # canvas.arc(0, 0, a: 10, start_angle: 135, end_angle: 15)
1062
- # canvas.arc(0, 0, a: 10, start_angle: 135, end_angle: 15, clockwise: true)
1294
+ # canvas.stroke_color("blue")
1295
+ # canvas.arc(50, 50, a: 10, start_angle: 135, end_angle: 30)
1296
+ # canvas.arc(100, 50, a: 10, start_angle: 135, end_angle: 30, clockwise: true)
1297
+ # canvas.stroke
1063
1298
  #
1064
1299
  # See: Content::GraphicObject::Arc
1065
1300
  def arc(cx, cy, a:, b: a, start_angle: 0, end_angle: 360, clockwise: false, inclination: 0)
@@ -1070,6 +1305,62 @@ module HexaPDF
1070
1305
  self
1071
1306
  end
1072
1307
 
1308
+ # Used for calculating the optimal distance of the control points for
1309
+ # #line_with_rounded_corner.
1310
+ #
1311
+ # See: http://itc.ktu.lt/itc354/Riskus354.pdf, p373 right column
1312
+ KAPPA = 0.55191496 #:nodoc:
1313
+
1314
+ # :call-seq:
1315
+ # canvas.line_with_rounded_corner(x0 = current_point[0], y0 = current_point[1], x1, y1, x2, y2, in_radius:, out_radius: in_radius)
1316
+ #
1317
+ # Appends a line with a rounded corner at (x1, y1) from the current point. The end point of
1318
+ # the rounded corner (i.e. +out_radius+ units from (x1, y1) in the direction of (x2, y2))
1319
+ # becomes the current point. In degraded cases the corner point (x1, y1) becomes the current
1320
+ # point.
1321
+ #
1322
+ # The corner is specified by (x0, y0) which defaults to the #current_point of the path, (x1,
1323
+ # y1) and (x2, y2) - all of which need to be different points. The +in_radius+ specifies the
1324
+ # corner radius into the corner and the +out_radius+ the one out of the corner. Degraded
1325
+ # cases, like with (x0, y0) == (x1, y1), are handled gracefully.
1326
+ #
1327
+ # There has to be a current path when this method is invoked. For example, the current point
1328
+ # ould be estabilshed beforehand using #move_to.
1329
+ #
1330
+ # Examples:
1331
+ #
1332
+ # #>pdf
1333
+ # canvas.move_to(10, 180) # Both radii are the same
1334
+ # canvas.line_with_rounded_corner(180, 180, 180, 100, in_radius: 20)
1335
+ # canvas.move_to(10, 150) # Different radii
1336
+ # canvas.line_with_rounded_corner(180, 150, 180, 100, in_radius: 50, out_radius: 20)
1337
+ # canvas.move_to(10, 120) # One radius is zero, making it just a line
1338
+ # canvas.line_with_rounded_corner(180, 120, 150, 100, in_radius: 0, out_radius: 10)
1339
+ # canvas.stroke
1340
+ #
1341
+ # # Special effects when (x0, y0) is not the current point, like when the current point
1342
+ # # would be equal to the corner point
1343
+ # canvas.rectangle(10, 10, 60, 60, radius: 60).stroke
1344
+ # canvas.rectangle(110, 10, 60, 60, radius: 70).stroke
1345
+ def line_with_rounded_corner(x0 = current_point[0], y0 = current_point[1], x1, y1, x2, y2,
1346
+ in_radius:, out_radius: in_radius)
1347
+ if in_radius == 0 || out_radius == 0
1348
+ line_to(x1, y1)
1349
+ else
1350
+ p0 = point_on_line(x1, y1, x0, y0, distance: in_radius)
1351
+ p3 = point_on_line(x1, y1, x2, y2, distance: out_radius)
1352
+ p1 = point_on_line(p0[0], p0[1], x1, y1, distance: KAPPA * in_radius)
1353
+ p2 = point_on_line(p3[0], p3[1], x1, y1, distance: KAPPA * out_radius)
1354
+ if p0[0].finite? && p3[0].finite?
1355
+ line_to(*p0)
1356
+ curve_to(p3[0], p3[1], p1: p1, p2: p2)
1357
+ else
1358
+ line_to(x1, y1)
1359
+ end
1360
+ end
1361
+ self
1362
+ end
1363
+
1073
1364
  # :call-seq:
1074
1365
  # canvas.graphic_object(obj, **options) => obj
1075
1366
  # canvas.graphic_object(name, **options) => graphic_object
@@ -1082,8 +1373,12 @@ module HexaPDF
1082
1373
  #
1083
1374
  # Examples:
1084
1375
  #
1085
- # obj = canvas.graphic_object(:arc, cx: 10, cy: 10)
1086
- # canvas.draw(obj)
1376
+ # #>pdf
1377
+ # obj = canvas.graphic_object(:solid_arc, cx: 100, cy: 100, inner_a: 20, inner_b: 10,
1378
+ # outer_a: 50, outer_b: 40, end_angle: 135)
1379
+ # canvas.draw(obj).stroke
1380
+ #
1381
+ # See: Content::GraphicObject
1087
1382
  def graphic_object(obj, **options)
1088
1383
  unless obj.respond_to?(:configure)
1089
1384
  obj = context.document.config.constantize('graphic_object.map', obj)
@@ -1098,11 +1393,9 @@ module HexaPDF
1098
1393
  #
1099
1394
  # Draws the given graphic object on the canvas.
1100
1395
  #
1101
- # See #graphic_object for information on the arguments.
1102
- #
1103
- # Examples:
1396
+ # This is the same as "graphic_object(obj_or_name, **options).draw(self)".
1104
1397
  #
1105
- # canvas.draw(:arc, cx: 10, cy: 10)
1398
+ # See #graphic_object for details on the arguments and invocation.
1106
1399
  def draw(name, **options)
1107
1400
  graphic_object(name, **options).draw(self)
1108
1401
  self
@@ -1113,6 +1406,12 @@ module HexaPDF
1113
1406
  #
1114
1407
  # Strokes the path.
1115
1408
  #
1409
+ # Examples:
1410
+ #
1411
+ # #>pdf
1412
+ # canvas.polyline(10, 10, 120, 40, 50, 160)
1413
+ # canvas.stroke
1414
+ #
1116
1415
  # See: PDF1.7 s8.5.3.1, s8.5.3.2
1117
1416
  def stroke
1118
1417
  raise_unless_in_path_or_clipping_path
@@ -1125,6 +1424,12 @@ module HexaPDF
1125
1424
  #
1126
1425
  # Closes the last subpath and then strokes the path.
1127
1426
  #
1427
+ # Examples:
1428
+ #
1429
+ # #>pdf
1430
+ # canvas.polyline(10, 10, 120, 40, 50, 160) # No line from the top to the left
1431
+ # canvas.close_stroke
1432
+ #
1128
1433
  # See: PDF1.7 s8.5.3.1, s8.5.3.2
1129
1434
  def close_stroke
1130
1435
  raise_unless_in_path_or_clipping_path
@@ -1138,10 +1443,21 @@ module HexaPDF
1138
1443
  # Fills the path using the given rule.
1139
1444
  #
1140
1445
  # The argument +rule+ may either be +:nonzero+ to use the nonzero winding number rule or
1141
- # +:even_odd+ to use the even-odd rule for determining which regions to fill in.
1446
+ # +: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 1.7 spec section 8.5.3.3 or via Internet search.
1142
1448
  #
1143
1449
  # Any open subpaths are implicitly closed before being filled.
1144
1450
  #
1451
+ # Examples:
1452
+ #
1453
+ # #>pdf
1454
+ # canvas.polyline(20, 10, 90, 60, 10, 60, 80, 10, 50, 90)
1455
+ # canvas.fill
1456
+ #
1457
+ # canvas.fill_color("red")
1458
+ # canvas.polyline(120, 110, 190, 160, 110, 160, 180, 110, 150, 190)
1459
+ # canvas.fill(:even_odd)
1460
+ #
1145
1461
  # See: PDF1.7 s8.5.3.1, s8.5.3.3
1146
1462
  def fill(rule = :nonzero)
1147
1463
  raise_unless_in_path_or_clipping_path
@@ -1155,9 +1471,23 @@ module HexaPDF
1155
1471
  # Fills and then strokes the path using the given rule.
1156
1472
  #
1157
1473
  # The argument +rule+ may either be +:nonzero+ to use the nonzero winding number rule or
1158
- # +:even_odd+ to use the even-odd rule for determining which regions to fill in.
1474
+ # +: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 1.7 spec section 8.5.3.3 or via Internet search.
1159
1476
  #
1160
- # See: PDF1.7 s8.5.3
1477
+ # Note that any open subpaths are *not* closed!
1478
+ #
1479
+ # Examples:
1480
+ #
1481
+ # #>pdf
1482
+ # canvas.stroke_color("green").line_width(3)
1483
+ # canvas.polyline(20, 10, 90, 60, 10, 60, 80, 10, 50, 90)
1484
+ # canvas.fill_stroke # Note the missing stroke from the top corner
1485
+ #
1486
+ # canvas.fill_color("red")
1487
+ # canvas.polyline(120, 110, 190, 160, 110, 160, 180, 110, 150, 190)
1488
+ # canvas.fill_stroke(:even_odd) # Note the missing stroke from the top corner
1489
+ #
1490
+ # See: PDF1.7 s8.5.3.1, s8.5.3.3
1161
1491
  def fill_stroke(rule = :nonzero)
1162
1492
  raise_unless_in_path_or_clipping_path
1163
1493
  invoke0(rule == :nonzero ? :B : :'B*')
@@ -1170,7 +1500,19 @@ module HexaPDF
1170
1500
  # Closes the last subpath and then fills and strokes the path using the given rule.
1171
1501
  #
1172
1502
  # The argument +rule+ may either be +:nonzero+ to use the nonzero winding number rule or
1173
- # +:even_odd+ to use the even-odd rule for determining which regions to fill in.
1503
+ # +: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 1.7 spec section 8.5.3.3 or via Internet search.
1505
+ #
1506
+ # Examples:
1507
+ #
1508
+ # #>pdf
1509
+ # canvas.stroke_color("green").line_width(3)
1510
+ # canvas.polyline(20, 10, 90, 60, 10, 60, 80, 10, 50, 90)
1511
+ # canvas.close_fill_stroke
1512
+ #
1513
+ # canvas.fill_color("red")
1514
+ # canvas.polyline(120, 110, 190, 160, 110, 160, 180, 110, 150, 190)
1515
+ # canvas.close_fill_stroke(:even_odd)
1174
1516
  #
1175
1517
  # See: PDF1.7 s8.5.3
1176
1518
  def close_fill_stroke(rule = :nonzero)
@@ -1187,7 +1529,12 @@ module HexaPDF
1187
1529
  # This method is normally used in conjunction with the clipping path methods to define the
1188
1530
  # clipping.
1189
1531
  #
1190
- # See: PDF1.7 s8.5.3.1 #clip
1532
+ # Examples:
1533
+ #
1534
+ # canvas.line(10, 10, 100, 100)
1535
+ # canvas.end_path # Nothing to see here!
1536
+ #
1537
+ # See: PDF1.7 s8.5.3.1, #clip_path
1191
1538
  def end_path
1192
1539
  raise_unless_in_path_or_clipping_path
1193
1540
  invoke0(:n)
@@ -1201,11 +1548,24 @@ module HexaPDF
1201
1548
  #
1202
1549
  # The argument +rule+ may either be +:nonzero+ to use the nonzero winding number rule or
1203
1550
  # +:even_odd+ to use the even-odd rule for determining which regions lie inside the clipping
1204
- # path.
1551
+ # path. Details on how these rules work are found in the PDF 1.7 spec section 8.5.3.3 or via
1552
+ # Internet search.
1553
+ #
1554
+ # The initial clipping path includes the entire canvas. Once the clipping path is reduced to a
1555
+ # subset of the canvas, there is no way to enlarge it. To restrict the effect of this method,
1556
+ # use #save_graphics_state before modifying the clipping path.
1205
1557
  #
1206
1558
  # Note that the current path cannot be modified after invoking this method! This means that
1207
1559
  # one of the path painting methods or #end_path must be called immediately afterwards.
1208
1560
  #
1561
+ # Examples:
1562
+ #
1563
+ # #>pdf
1564
+ # canvas.ellipse(100, 100, a: 50, b: 30). # Restrict operations to this intersecting path
1565
+ # ellipse(100, 100, a: 30, b: 50). # where the inside is not part of it
1566
+ # clip_path(:even_odd).end_path
1567
+ # canvas.rectangle(0, 0, 200, 200).fill # Fills everything inside the clipping path
1568
+ #
1209
1569
  # See: PDF1.7 s8.5.4
1210
1570
  def clip_path(rule = :nonzero)
1211
1571
  raise_unless_in_path
@@ -1245,15 +1605,19 @@ module HexaPDF
1245
1605
  #
1246
1606
  # Examples:
1247
1607
  #
1248
- # canvas.xobject('test.png', at: [100, 100])
1249
- # canvas.xobject('test.pdf', at: [100, 100])
1608
+ # #>pdf
1609
+ # canvas.xobject(machu_picchu, at: [10, 10], width: 90) # bottom left
1250
1610
  #
1251
- # File.new('test.jpg', 'rb') do |io|
1252
- # canvas.xobject(io, at: [100, 200], width: 300)
1253
- # end
1611
+ # file = File.new(machu_picchu, 'rb') # top left
1612
+ # canvas.xobject(file, at: [10, 110], height: 50)
1254
1613
  #
1255
- # image = document.object(5) # Object with oid=5 is an image XObject in this example
1256
- # canvas.xobject(image, at: [100, 200], width: 200, height: 300)
1614
+ # image = doc.images.add(machu_picchu)
1615
+ # canvas.xobject(image, at: [110, 10], width: 50, height: 90) # bottom right
1616
+ #
1617
+ # form = doc.add({Type: :XObject, Subtype: :Form, BBox: [0, 0, 100, 100]})
1618
+ # form.canvas.line(10, 10, 90, 90).stroke
1619
+ # canvas.line_width = 20
1620
+ # canvas.xobject(form, at: [100, 100]) # top right
1257
1621
  #
1258
1622
  # See: PDF1.7 s8.8, s.8.10.1
1259
1623
  def xobject(obj, at:, width: nil, height: nil)
@@ -1298,6 +1662,7 @@ module HexaPDF
1298
1662
  #
1299
1663
  # Examples:
1300
1664
  #
1665
+ # #>pdf
1301
1666
  # canvas.character_spacing(0.25)
1302
1667
  # canvas.character_spacing # => 0.25
1303
1668
  # canvas.character_spacing = 0.5 # => 0.5
@@ -1307,6 +1672,13 @@ module HexaPDF
1307
1672
  # end
1308
1673
  # canvas.character_spacing # => 0.5
1309
1674
  #
1675
+ # # visual example
1676
+ # canvas.font("Helvetica", size: 10)
1677
+ # canvas.character_spacing = 0 # initial value
1678
+ # canvas.text("This is an example text.", at: [10, 150])
1679
+ # canvas.character_spacing = 3
1680
+ # canvas.text("This is an example text.", at: [10, 100])
1681
+ #
1310
1682
  # See: PDF1.7 s9.3.2
1311
1683
  def character_spacing(amount = nil, &bk)
1312
1684
  gs_getter_setter(:character_spacing, :Tc, amount, &bk)
@@ -1323,8 +1695,8 @@ module HexaPDF
1323
1695
  # writing positive values increase the distance between two words, whereas for vertical
1324
1696
  # writing negative values increase the distance.
1325
1697
  #
1326
- # Note that in HexaPDF only the standard 14 PDF Type1 fonts support this property! When using
1327
- # any other font, for example a TrueType font, this property has no effect.
1698
+ # *Important*: In HexaPDF only the standard 14 PDF Type1 fonts support this property! When
1699
+ # using any other font, for example a TrueType font, this property has no effect.
1328
1700
  #
1329
1701
  # Returns the current word spacing value (see Content::GraphicsState#word_spacing) when no
1330
1702
  # argument is given. Otherwise sets the word spacing using the +amount+ argument and returns
@@ -1335,6 +1707,7 @@ module HexaPDF
1335
1707
  #
1336
1708
  # Examples:
1337
1709
  #
1710
+ # #>pdf
1338
1711
  # canvas.word_spacing(0.25)
1339
1712
  # canvas.word_spacing # => 0.25
1340
1713
  # canvas.word_spacing = 0.5 # => 0.5
@@ -1344,6 +1717,13 @@ module HexaPDF
1344
1717
  # end
1345
1718
  # canvas.word_spacing # => 0.5
1346
1719
  #
1720
+ # # visual example
1721
+ # canvas.font("Helvetica", size: 10)
1722
+ # canvas.word_spacing = 0 # initial value
1723
+ # canvas.text("This is an example text.", at: [10, 150])
1724
+ # canvas.word_spacing = 10
1725
+ # canvas.text("This is an example text.", at: [10, 100])
1726
+ #
1347
1727
  # See: PDF1.7 s9.3.3
1348
1728
  def word_spacing(amount = nil, &bk)
1349
1729
  gs_getter_setter(:word_spacing, :Tw, amount, &bk)
@@ -1357,7 +1737,7 @@ module HexaPDF
1357
1737
  #
1358
1738
  # The horizontal scaling adjusts the width of text character glyphs by stretching or
1359
1739
  # compressing them in the horizontal direction. The value is specified as percent of the
1360
- # normal width.
1740
+ # normal width, so 100 means no scaling.
1361
1741
  #
1362
1742
  # Returns the current horizontal scaling value (see Content::GraphicsState#horizontal_scaling)
1363
1743
  # when no argument is given. Otherwise sets the horizontal scaling using the +percent+
@@ -1369,6 +1749,7 @@ module HexaPDF
1369
1749
  #
1370
1750
  # Examples:
1371
1751
  #
1752
+ # #>pdf
1372
1753
  # canvas.horizontal_scaling(50) # each glyph has only 50% width
1373
1754
  # canvas.horizontal_scaling # => 50
1374
1755
  # canvas.horizontal_scaling = 125 # => 125
@@ -1378,6 +1759,13 @@ module HexaPDF
1378
1759
  # end
1379
1760
  # canvas.horizontal_scaling # => 125
1380
1761
  #
1762
+ # # visual example
1763
+ # canvas.font("Helvetica", size: 10)
1764
+ # canvas.horizontal_scaling = 100 # initial value
1765
+ # canvas.text("This is an example text.", at: [10, 150])
1766
+ # canvas.horizontal_scaling = 50
1767
+ # canvas.text("This is an example text.", at: [10, 100])
1768
+ #
1381
1769
  # See: PDF1.7 s9.3.4
1382
1770
  def horizontal_scaling(amount = nil, &bk)
1383
1771
  gs_getter_setter(:horizontal_scaling, :Tz, amount, &bk)
@@ -1389,7 +1777,12 @@ module HexaPDF
1389
1777
  # canvas.leading(amount) => canvas
1390
1778
  # canvas.leading(amount) { block } => canvas
1391
1779
  #
1392
- # The leading specifies the vertical distance between the baselines of adjacent text lines.
1780
+ # The leading specifies the vertical distance between the baselines of adjacent text lines. It
1781
+ # defaults to 0 if not changed.
1782
+ #
1783
+ # It is *only* used by HexaPDF when invoking #move_text_cursor with +offset+ set to +nil+.
1784
+ # There are other PDF content stream operators that would be effected but those are not used
1785
+ # by the canvas.
1393
1786
  #
1394
1787
  # Returns the current leading value (see Content::GraphicsState#leading) when no argument is
1395
1788
  # given. Otherwise sets the leading using the +amount+ argument and returns self. The setter
@@ -1400,6 +1793,7 @@ module HexaPDF
1400
1793
  #
1401
1794
  # Examples:
1402
1795
  #
1796
+ # #>pdf
1403
1797
  # canvas.leading(14.5)
1404
1798
  # canvas.leading # => 14.5
1405
1799
  # canvas.leading = 10 # => 10
@@ -1409,7 +1803,12 @@ module HexaPDF
1409
1803
  # end
1410
1804
  # canvas.leading # => 10
1411
1805
  #
1412
- # See: PDF1.7 s9.3.5
1806
+ # # visual example
1807
+ # canvas.font("Helvetica", size: 10)
1808
+ # canvas.leading = 15
1809
+ # canvas.text("This is an example text.\nwith a second\nand thrid line", at: [10, 150])
1810
+ #
1811
+ # See: PDF1.7 s9.3.5, #move_text_cursor
1413
1812
  def leading(amount = nil, &bk)
1414
1813
  gs_getter_setter(:leading, :TL, amount, &bk)
1415
1814
  end
@@ -1436,6 +1835,7 @@ module HexaPDF
1436
1835
  #
1437
1836
  # Examples:
1438
1837
  #
1838
+ # #>pdf
1439
1839
  # canvas.text_rendering_mode(:fill)
1440
1840
  # canvas.text_rendering_mode # => #<NamedValue @name=:fill, @value = 0>
1441
1841
  # canvas.text_rendering_mode = :stroke # => #<NamedValue @name=:stroke, @value = 1>
@@ -1445,7 +1845,15 @@ module HexaPDF
1445
1845
  # end
1446
1846
  # canvas.text_rendering_mode # => #<NamedValue @name=:stroke, @value = 1>
1447
1847
  #
1448
- # See: PDF1.7 s9.3.6
1848
+ # # visual example
1849
+ # canvas.font("Helvetica", size: 25)
1850
+ # canvas.stroke_color("green")
1851
+ # [:fill, :stroke, :fill_stroke, :invisible].each_with_index do |trm, index|
1852
+ # canvas.text_rendering_mode = trm
1853
+ # canvas.text("#{trm} text.", at: [20, 150 - 30 * index])
1854
+ # end
1855
+ #
1856
+ # See: PDF1.7 s9.3.6, Content::GraphicsState::TextRenderingMode
1449
1857
  def text_rendering_mode(m = nil, &bk)
1450
1858
  gs_getter_setter(:text_rendering_mode, :Tr, m && TextRenderingMode.normalize(m), &bk)
1451
1859
  end
@@ -1468,6 +1876,7 @@ module HexaPDF
1468
1876
  #
1469
1877
  # Examples:
1470
1878
  #
1879
+ # #>pdf
1471
1880
  # canvas.text_rise(5)
1472
1881
  # canvas.text_rise # => 5
1473
1882
  # canvas.text_rise = 10 # => 10
@@ -1477,6 +1886,15 @@ module HexaPDF
1477
1886
  # end
1478
1887
  # canvas.text_rise # => 10
1479
1888
  #
1889
+ # # visual example
1890
+ # canvas.font("Helvetica", size: 10)
1891
+ # canvas.text_rise = 0 # Set the default value
1892
+ # canvas.text("Hello", at: [20, 150])
1893
+ # canvas.text_rise = 10
1894
+ # canvas.text("from up here")
1895
+ # canvas.text_rise = -10
1896
+ # canvas.text("and also down here")
1897
+ #
1480
1898
  # See: PDF1.7 s9.3.7
1481
1899
  def text_rise(amount = nil, &bk)
1482
1900
  gs_getter_setter(:text_rise, :Ts, amount, &bk)
@@ -1491,6 +1909,9 @@ module HexaPDF
1491
1909
  # If +force+ is +true+ and the current graphics object is already a text object, it is ended
1492
1910
  # and a new text object is begun.
1493
1911
  #
1912
+ # It is not necessary to invoke this method manually in most cases since it is automatically
1913
+ # called when needed by other methods, i.e. the #text method.
1914
+ #
1494
1915
  # See: PDF1.7 s9.4.1
1495
1916
  def begin_text(force_new: false)
1496
1917
  raise_unless_at_page_description_level_or_in_text
@@ -1504,6 +1925,9 @@ module HexaPDF
1504
1925
  #
1505
1926
  # Ends the current text object.
1506
1927
  #
1928
+ # It is not necessary to invoke this method manually in most cases since it is automatically
1929
+ # called when needed by other methods, i.e. when creating a new path.
1930
+ #
1507
1931
  # See: PDF1.7 s9.4.1
1508
1932
  def end_text
1509
1933
  raise_unless_at_page_description_level_or_in_text
@@ -1522,10 +1946,19 @@ module HexaPDF
1522
1946
  # c d 0
1523
1947
  # e f 1
1524
1948
  #
1949
+ # If the current graphics object is not a text object, #begin_text is automatically called
1950
+ # because the text matrix is only available within a text object.
1951
+ #
1525
1952
  # Examples:
1526
1953
  #
1527
- # canvas.begin_text
1528
- # canvas.text_matrix(1, 0, 0, 1, 100, 100)
1954
+ # #>pdf
1955
+ # canvas.font("Helvetica", size: 10)
1956
+ # canvas.begin_text # Not necessary
1957
+ # canvas.text_matrix(1, 0, 0, 1, 50, 100) # Translate text origin to (50, 100)
1958
+ # canvas.text("This is some text")
1959
+ #
1960
+ # canvas.text_matrix(2, 1, 3, 0.5, 50, 50)
1961
+ # canvas.text("This is some text")
1529
1962
  #
1530
1963
  # See: PDF1.7 s9.4.2
1531
1964
  def text_matrix(a, b, c, d, e, f)
@@ -1555,7 +1988,24 @@ module HexaPDF
1555
1988
  # offset from the start of the current line (the origin of the text line matrix) by
1556
1989
  # +offset+.
1557
1990
  #
1558
- # See: #show_glyphs
1991
+ # If the current graphics object is not a text object, #begin_text is automatically called
1992
+ # because the text matrix is only available within a text object.
1993
+ #
1994
+ # Examples:
1995
+ #
1996
+ # #>pdf
1997
+ # canvas.font("Helvetica", size: 10)
1998
+ # canvas.move_text_cursor(offset: [30, 150])
1999
+ # canvas.text("Absolutely positioned at (30, 150)")
2000
+ #
2001
+ # canvas.move_text_cursor(offset: [20, -15], absolute: false)
2002
+ # canvas.text("Relative offset (20, -15)")
2003
+ #
2004
+ # canvas.leading(30)
2005
+ # canvas.move_text_cursor
2006
+ # canvas.text("Text on next line with leading=30")
2007
+ #
2008
+ # See: PDF1.7 s9.4.2, #show_glyphs
1559
2009
  def move_text_cursor(offset: nil, absolute: true)
1560
2010
  begin_text
1561
2011
  if offset
@@ -1577,6 +2027,18 @@ module HexaPDF
1577
2027
  #
1578
2028
  # Note that this method can only be called while the current graphic object is a text object
1579
2029
  # since the text matrix is otherwise undefined.
2030
+ #
2031
+ # Examples:
2032
+ #
2033
+ # #>pdf
2034
+ # canvas.font("Helvetica", size: 10)
2035
+ # canvas.text("Some sample text", at: [30, 150])
2036
+ # pos = canvas.text_cursor # Cursor is directly after the text
2037
+ # canvas.line_width(0.5).stroke_color("red").
2038
+ # polyline(pos[0], pos[1] + 10, pos[0], pos[1], pos[0] + 10, pos[1]).stroke
2039
+ # canvas.text("Last cursor: #{pos.map! {|f| f.round(2)}.join(", ")}", at: [30, 100])
2040
+ #
2041
+ # See: #move_text_cursor
1580
2042
  def text_cursor
1581
2043
  raise_unless_in_text
1582
2044
  graphics_state.tm.evaluate(0, 0)
@@ -1586,26 +2048,34 @@ module HexaPDF
1586
2048
  # canvas.font => current_font
1587
2049
  # canvas.font(name, size: nil, **options) => canvas
1588
2050
  #
1589
- # Specifies the font that should be used when showing text.
2051
+ # Specifies the font and optional the font size that should be used when showing text.
1590
2052
  #
1591
- # A valid font size need to be provided on the first invocation, otherwise an error is raised.
2053
+ # A valid font size need to be provided on the first invocation, otherwise an error is raised
2054
+ # (this is due to how setting a font works with PDFs).
1592
2055
  #
1593
- # *Note* that this method returns the font object itself, not the PDF dictionary representing
1594
- # the font!
2056
+ # If +size+ is specified, the #font_size method is invoked with it as argument.
1595
2057
  #
1596
- # If +size+ is specified, the #font_size method is invoked with it as argument. All other
1597
- # options are passed on to the font loaders (see HexaPDF::FontLoader) that are used for
1598
- # loading the specified font.
2058
+ # All other options are passed on to the font loaders (see HexaPDF::FontLoader) that are used
2059
+ # for loading the specified font. One standard keyword argument for fonts is +:variant+ which
2060
+ # specifies the font variant to use, with standard values of :none, :italic, :bold and
2061
+ # :bold_italic.
1599
2062
  #
1600
- # Returns the current font object when no argument is given.
2063
+ # Returns the current font object when no argument is given. *Note* that this is the font
2064
+ # object itself, not the PDF dictionary representing the font.
1601
2065
  #
1602
2066
  # Examples:
1603
2067
  #
1604
- # canvas.font("Times", variant: :bold, size: 12)
2068
+ # #>pdf
2069
+ # canvas.font("Times", variant: :bold, size: 10)
1605
2070
  # canvas.font # => font object
1606
2071
  # canvas.font = "Times"
1607
2072
  #
1608
- # See: PDF1.7 s9.2.2
2073
+ # # visual example
2074
+ # canvas.text("Times at size 10", at: [10, 150])
2075
+ # canvas.font("Times", variant: :bold_italic, size: 15)
2076
+ # canvas.text("Times bold+italic at size 15", at: [10, 100])
2077
+ #
2078
+ # See: PDF1.7 s9.2.2, #font_size
1609
2079
  def font(name = nil, size: nil, **options)
1610
2080
  if name
1611
2081
  @font = (name.respond_to?(:pdf_object) ? name : context.document.fonts.add(name, **options))
@@ -1629,17 +2099,27 @@ module HexaPDF
1629
2099
  #
1630
2100
  # Specifies the font size.
1631
2101
  #
1632
- # Note that an error is raised if no font has been set before!
2102
+ # Note that an error is raised if no font has been set before via #font (this is due to how
2103
+ # setting font and font size works in PDF).
1633
2104
  #
1634
- # Returns the current font size when no argument is given.
2105
+ # Returns the current font size when no argument is given. The setter version can also
2106
+ # be called in the font_size= form.
1635
2107
  #
1636
2108
  # Examples:
1637
2109
  #
2110
+ # #>pdf
2111
+ # canvas.font("Helvetica", size: 10) # Necessary only the first time
1638
2112
  # canvas.font_size(12)
1639
2113
  # canvas.font_size # => 12
1640
- # canvas.font_size = 12
2114
+ # canvas.font_size = 10
2115
+ #
2116
+ # # visual example
2117
+ # 6.step(to: 20, by: 2).each_with_index do |size, index|
2118
+ # canvas.font_size(size)
2119
+ # canvas.text("Text in size #{size}", at: [15, 180 - index * 20])
2120
+ # end
1641
2121
  #
1642
- # See: PDF1.7 s9.2.2
2122
+ # See: PDF1.7 s9.2.2, #font
1643
2123
  def font_size(size = nil)
1644
2124
  if size
1645
2125
  unless @font
@@ -1657,26 +2137,30 @@ module HexaPDF
1657
2137
  # canvas.text(text) -> canvas
1658
2138
  # canvas.text(text, at: [x, y]) -> canvas
1659
2139
  #
1660
- # Shows the given text string.
2140
+ # Shows the given text string, either at the current or the provided position.
1661
2141
  #
1662
2142
  # If no position is provided, the text is positioned at the current position of the text
1663
- # cursor (the origin in case of a new text object or otherwise after the last shown text).
2143
+ # cursor (see #text_cursor).
1664
2144
  #
1665
2145
  # The text string may contain any valid Unicode newline separator and if so, multiple lines
1666
- # are shown, using #leading for offsetting the lines.
2146
+ # are shown, using #leading for offsetting the lines. If no leading has been set, a leading
2147
+ # equal to the font size will be set..
1667
2148
  #
1668
2149
  # Note that there are no provisions to make sure that all text is visible! So if the text
1669
2150
  # string is too long, it will just flow off the page and be cut off.
1670
2151
  #
1671
2152
  # Examples:
1672
2153
  #
2154
+ # #>pdf
1673
2155
  # canvas.font('Times', size: 12)
1674
- # canvas.text("This is a \n multiline text", at: [100, 100])
2156
+ # canvas.text("This is a \n multiline text", at: [15, 150]) # Sets leading=12
2157
+ # canvas.text(". Some more text\nafter the newline.") # Starts right after the last text
1675
2158
  #
1676
- # See: http://www.unicode.org/reports/tr18/#Line_Boundaries
2159
+ # See: #leading, http://www.unicode.org/reports/tr18/#Line_Boundaries
1677
2160
  def text(text, at: nil)
1678
2161
  raise_unless_font_set
1679
2162
  move_text_cursor(offset: at) if at
2163
+ leading(font_size) if leading == 0
1680
2164
  lines = text.split(/\u{D A}|(?!\u{D A})[\u{A}-\u{D}\u{85}\u{2028}\u{2029}]/, -1)
1681
2165
  lines.each_with_index do |str, index|
1682
2166
  show_glyphs(@font.decode_utf8(str))
@@ -1698,8 +2182,19 @@ module HexaPDF
1698
2182
  # method.
1699
2183
  #
1700
2184
  # The text matrix is updated to correctly represent the graphics state after the invocation.
2185
+ # Since this is a compute intensive operation, use #show_glyphs_only if you don't need a
2186
+ # correct text matrix.
1701
2187
  #
1702
2188
  # This method is usually not invoked directly but by higher level methods like #text.
2189
+ #
2190
+ # Examples:
2191
+ #
2192
+ # #>pdf
2193
+ # canvas.font("Helvetica", size: 10)
2194
+ # glyphs = canvas.font.decode_utf8("Some text here")
2195
+ # canvas.move_text_cursor(offset: [15, 100])
2196
+ # canvas.show_glyphs(glyphs)
2197
+ # canvas.text(canvas.text_cursor.map(&:to_i).join(", "), at: [15, 80])
1703
2198
  def show_glyphs(glyphs)
1704
2199
  return if glyphs.empty?
1705
2200
  raise_unless_font_set
@@ -1736,7 +2231,16 @@ module HexaPDF
1736
2231
  #
1737
2232
  # *Warning*: Since this method doesn't update the text matrix, all following results from
1738
2233
  # #text_cursor and other methods using the current text matrix are invalid until the next call
1739
- # to #text_matrix or #end_text.
2234
+ # that sets the text matrix.
2235
+ #
2236
+ # Examples:
2237
+ #
2238
+ # #>pdf
2239
+ # canvas.font("Helvetica", size: 10)
2240
+ # glyphs = canvas.font.decode_utf8("Some text here")
2241
+ # canvas.move_text_cursor(offset: [15, 100])
2242
+ # canvas.show_glyphs_only(glyphs)
2243
+ # canvas.text(canvas.text_cursor.map(&:to_i).join(", "), at: [15, 80])
1740
2244
  def show_glyphs_only(glyphs)
1741
2245
  return if glyphs.empty?
1742
2246
  raise_unless_font_set
@@ -1794,9 +2298,9 @@ module HexaPDF
1794
2298
  # Inserts a marked-content sequence, optionally associated with a property list.
1795
2299
  #
1796
2300
  # A marked-content sequence is used to identify a sequence of complete graphics objects in the
1797
- # content stream for later use by other applications. The symbol +tag+ is used to uniquely
1798
- # identify the role of the marked-content sequence and should be registered with ISO to avoid
1799
- # conflicts.
2301
+ # content stream for later use by other applications, e.g. for tagged PDF. The symbol +tag+ is
2302
+ # used to uniquely identify the role of the marked-content sequence and should be registered
2303
+ # with ISO to avoid conflicts.
1800
2304
  #
1801
2305
  # The optional +property_list+ argument can either be a valid PDF dictionary or a symbol
1802
2306
  # referencing an already used property list in the resource dictionary's /Properties
@@ -1806,7 +2310,7 @@ module HexaPDF
1806
2310
  # done. Otherwise the marked-content sequence automatically ends when the block is finished.
1807
2311
  #
1808
2312
  # Although the PDF specification would allow using marked-content sequences inside text
1809
- # objects, this is prohibited.
2313
+ # objects, this is prohibited in HexaPDF.
1810
2314
  #
1811
2315
  # Examples:
1812
2316
  #
@@ -1850,9 +2354,12 @@ module HexaPDF
1850
2354
 
1851
2355
  # Creates a color object from the given color specification. See #stroke_color for details
1852
2356
  # on the possible color specifications.
2357
+ #
2358
+ # This utility method is meant for use by higher-level methods that need to convert a color
2359
+ # specification into a color object for this Canvas object.
1853
2360
  def color_from_specification(spec)
1854
2361
  if spec.length == 1 && spec[0].kind_of?(String)
1855
- resources.color_space(:DeviceRGB).color(*spec[0].scan(/../).map!(&:hex))
2362
+ ColorSpace.device_color_from_specification(spec)
1856
2363
  elsif spec.length == 1 && spec[0].respond_to?(:color_space)
1857
2364
  spec[0]
1858
2365
  else
@@ -2040,22 +2547,6 @@ module HexaPDF
2040
2547
  end
2041
2548
  end
2042
2549
 
2043
- # Used for calculating the optimal distance of the control points.
2044
- #
2045
- # See: http://itc.ktu.lt/itc354/Riskus354.pdf, p373 right column
2046
- KAPPA = 0.55191496 #:nodoc:
2047
-
2048
- # Appends a line with a rounded corner from the current point. The corner is specified by
2049
- # the three points (x0, y0), (x1, y1) and (x2, y2) where (x1, y1) is the corner point.
2050
- def line_with_rounded_corner(x0, y0, x1, y1, x2, y2, radius)
2051
- p0 = point_on_line(x1, y1, x0, y0, distance: radius)
2052
- p3 = point_on_line(x1, y1, x2, y2, distance: radius)
2053
- p1 = point_on_line(p0[0], p0[1], x1, y1, distance: KAPPA * radius)
2054
- p2 = point_on_line(p3[0], p3[1], x1, y1, distance: KAPPA * radius)
2055
- line_to(p0[0], p0[1])
2056
- curve_to(p3[0], p3[1], p1: p1, p2: p2)
2057
- end
2058
-
2059
2550
  end
2060
2551
 
2061
2552
  end