hexapdf 0.21.1 → 0.24.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (253) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +137 -0
  3. data/LICENSE +1 -1
  4. data/Rakefile +1 -1
  5. data/examples/016-frame_automatic_box_placement.rb +7 -2
  6. data/examples/017-frame_text_flow.rb +10 -18
  7. data/examples/020-column_box.rb +20 -37
  8. data/examples/021-list_box.rb +26 -0
  9. data/lib/hexapdf/cli/batch.rb +1 -1
  10. data/lib/hexapdf/cli/command.rb +1 -1
  11. data/lib/hexapdf/cli/files.rb +1 -1
  12. data/lib/hexapdf/cli/fonts.rb +1 -1
  13. data/lib/hexapdf/cli/form.rb +31 -4
  14. data/lib/hexapdf/cli/image2pdf.rb +1 -1
  15. data/lib/hexapdf/cli/images.rb +1 -1
  16. data/lib/hexapdf/cli/info.rb +2 -2
  17. data/lib/hexapdf/cli/inspect.rb +19 -6
  18. data/lib/hexapdf/cli/merge.rb +1 -1
  19. data/lib/hexapdf/cli/modify.rb +24 -4
  20. data/lib/hexapdf/cli/optimize.rb +1 -1
  21. data/lib/hexapdf/cli/split.rb +1 -1
  22. data/lib/hexapdf/cli/watermark.rb +1 -1
  23. data/lib/hexapdf/cli.rb +1 -1
  24. data/lib/hexapdf/composer.rb +66 -125
  25. data/lib/hexapdf/configuration.rb +17 -1
  26. data/lib/hexapdf/content/canvas.rb +1 -1
  27. data/lib/hexapdf/content/color_space.rb +1 -1
  28. data/lib/hexapdf/content/graphic_object/arc.rb +1 -1
  29. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +1 -1
  30. data/lib/hexapdf/content/graphic_object/geom2d.rb +2 -1
  31. data/lib/hexapdf/content/graphic_object/solid_arc.rb +1 -1
  32. data/lib/hexapdf/content/graphic_object.rb +1 -1
  33. data/lib/hexapdf/content/graphics_state.rb +1 -1
  34. data/lib/hexapdf/content/operator.rb +1 -1
  35. data/lib/hexapdf/content/parser.rb +1 -1
  36. data/lib/hexapdf/content/processor.rb +1 -1
  37. data/lib/hexapdf/content/transformation_matrix.rb +1 -1
  38. data/lib/hexapdf/content.rb +1 -1
  39. data/lib/hexapdf/data_dir.rb +1 -1
  40. data/lib/hexapdf/dictionary.rb +1 -1
  41. data/lib/hexapdf/dictionary_fields.rb +2 -2
  42. data/lib/hexapdf/document/destinations.rb +396 -0
  43. data/lib/hexapdf/document/files.rb +1 -1
  44. data/lib/hexapdf/document/fonts.rb +1 -1
  45. data/lib/hexapdf/document/images.rb +1 -1
  46. data/lib/hexapdf/document/layout.rb +397 -0
  47. data/lib/hexapdf/document/pages.rb +17 -1
  48. data/lib/hexapdf/document/signatures.rb +5 -4
  49. data/lib/hexapdf/document.rb +46 -90
  50. data/lib/hexapdf/encryption/aes.rb +1 -1
  51. data/lib/hexapdf/encryption/arc4.rb +1 -1
  52. data/lib/hexapdf/encryption/fast_aes.rb +1 -1
  53. data/lib/hexapdf/encryption/fast_arc4.rb +30 -21
  54. data/lib/hexapdf/encryption/identity.rb +1 -1
  55. data/lib/hexapdf/encryption/ruby_aes.rb +1 -1
  56. data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
  57. data/lib/hexapdf/encryption/security_handler.rb +1 -1
  58. data/lib/hexapdf/encryption/standard_security_handler.rb +1 -1
  59. data/lib/hexapdf/encryption.rb +1 -1
  60. data/lib/hexapdf/error.rb +1 -1
  61. data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
  62. data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
  63. data/lib/hexapdf/filter/crypt.rb +1 -1
  64. data/lib/hexapdf/filter/encryption.rb +1 -1
  65. data/lib/hexapdf/filter/flate_decode.rb +1 -1
  66. data/lib/hexapdf/filter/lzw_decode.rb +1 -1
  67. data/lib/hexapdf/filter/pass_through.rb +1 -1
  68. data/lib/hexapdf/filter/predictor.rb +1 -1
  69. data/lib/hexapdf/filter/run_length_decode.rb +1 -1
  70. data/lib/hexapdf/filter.rb +1 -1
  71. data/lib/hexapdf/font/cmap/parser.rb +1 -1
  72. data/lib/hexapdf/font/cmap/writer.rb +1 -1
  73. data/lib/hexapdf/font/cmap.rb +1 -1
  74. data/lib/hexapdf/font/encoding/base.rb +1 -1
  75. data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
  76. data/lib/hexapdf/font/encoding/glyph_list.rb +2 -2
  77. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
  78. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +1 -1
  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 +1 -1
  82. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
  83. data/lib/hexapdf/font/encoding.rb +1 -1
  84. data/lib/hexapdf/font/invalid_glyph.rb +1 -1
  85. data/lib/hexapdf/font/true_type/builder.rb +1 -1
  86. data/lib/hexapdf/font/true_type/font.rb +1 -1
  87. data/lib/hexapdf/font/true_type/optimizer.rb +1 -1
  88. data/lib/hexapdf/font/true_type/subsetter.rb +1 -1
  89. data/lib/hexapdf/font/true_type/table/cmap.rb +1 -1
  90. data/lib/hexapdf/font/true_type/table/cmap_subtable.rb +1 -1
  91. data/lib/hexapdf/font/true_type/table/directory.rb +1 -1
  92. data/lib/hexapdf/font/true_type/table/glyf.rb +1 -1
  93. data/lib/hexapdf/font/true_type/table/head.rb +1 -1
  94. data/lib/hexapdf/font/true_type/table/hhea.rb +1 -1
  95. data/lib/hexapdf/font/true_type/table/hmtx.rb +1 -1
  96. data/lib/hexapdf/font/true_type/table/kern.rb +1 -1
  97. data/lib/hexapdf/font/true_type/table/loca.rb +1 -1
  98. data/lib/hexapdf/font/true_type/table/maxp.rb +1 -1
  99. data/lib/hexapdf/font/true_type/table/name.rb +1 -1
  100. data/lib/hexapdf/font/true_type/table/os2.rb +1 -1
  101. data/lib/hexapdf/font/true_type/table/post.rb +1 -1
  102. data/lib/hexapdf/font/true_type/table.rb +1 -1
  103. data/lib/hexapdf/font/true_type.rb +1 -1
  104. data/lib/hexapdf/font/true_type_wrapper.rb +1 -1
  105. data/lib/hexapdf/font/type1/afm_parser.rb +1 -1
  106. data/lib/hexapdf/font/type1/character_metrics.rb +1 -1
  107. data/lib/hexapdf/font/type1/font.rb +1 -1
  108. data/lib/hexapdf/font/type1/font_metrics.rb +1 -1
  109. data/lib/hexapdf/font/type1/pfb_parser.rb +1 -1
  110. data/lib/hexapdf/font/type1.rb +1 -1
  111. data/lib/hexapdf/font/type1_wrapper.rb +1 -1
  112. data/lib/hexapdf/font_loader/from_configuration.rb +1 -1
  113. data/lib/hexapdf/font_loader/from_file.rb +1 -1
  114. data/lib/hexapdf/font_loader/standard14.rb +1 -1
  115. data/lib/hexapdf/font_loader.rb +1 -1
  116. data/lib/hexapdf/image_loader/jpeg.rb +1 -1
  117. data/lib/hexapdf/image_loader/pdf.rb +1 -1
  118. data/lib/hexapdf/image_loader/png.rb +1 -1
  119. data/lib/hexapdf/image_loader.rb +1 -1
  120. data/lib/hexapdf/importer.rb +1 -1
  121. data/lib/hexapdf/layout/box.rb +121 -22
  122. data/lib/hexapdf/layout/box_fitter.rb +136 -0
  123. data/lib/hexapdf/layout/column_box.rb +168 -89
  124. data/lib/hexapdf/layout/frame.rb +155 -140
  125. data/lib/hexapdf/layout/image_box.rb +19 -4
  126. data/lib/hexapdf/layout/inline_box.rb +1 -1
  127. data/lib/hexapdf/layout/line.rb +1 -1
  128. data/lib/hexapdf/layout/list_box.rb +355 -0
  129. data/lib/hexapdf/layout/numeric_refinements.rb +1 -1
  130. data/lib/hexapdf/layout/style.rb +285 -8
  131. data/lib/hexapdf/layout/text_box.rb +30 -11
  132. data/lib/hexapdf/layout/text_fragment.rb +3 -2
  133. data/lib/hexapdf/layout/text_layouter.rb +23 -3
  134. data/lib/hexapdf/layout/text_shaper.rb +1 -1
  135. data/lib/hexapdf/layout/width_from_polygon.rb +12 -7
  136. data/lib/hexapdf/layout.rb +4 -1
  137. data/lib/hexapdf/name_tree_node.rb +1 -1
  138. data/lib/hexapdf/number_tree_node.rb +1 -1
  139. data/lib/hexapdf/object.rb +1 -1
  140. data/lib/hexapdf/parser.rb +1 -8
  141. data/lib/hexapdf/pdf_array.rb +1 -1
  142. data/lib/hexapdf/rectangle.rb +1 -1
  143. data/lib/hexapdf/reference.rb +1 -1
  144. data/lib/hexapdf/revision.rb +9 -2
  145. data/lib/hexapdf/revisions.rb +152 -51
  146. data/lib/hexapdf/serializer.rb +1 -1
  147. data/lib/hexapdf/stream.rb +1 -1
  148. data/lib/hexapdf/task/dereference.rb +1 -1
  149. data/lib/hexapdf/task/optimize.rb +22 -12
  150. data/lib/hexapdf/task.rb +1 -1
  151. data/lib/hexapdf/tokenizer.rb +1 -1
  152. data/lib/hexapdf/type/acro_form/appearance_generator.rb +1 -1
  153. data/lib/hexapdf/type/acro_form/button_field.rb +1 -1
  154. data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
  155. data/lib/hexapdf/type/acro_form/field.rb +1 -1
  156. data/lib/hexapdf/type/acro_form/form.rb +12 -6
  157. data/lib/hexapdf/type/acro_form/signature_field.rb +1 -1
  158. data/lib/hexapdf/type/acro_form/text_field.rb +9 -1
  159. data/lib/hexapdf/type/acro_form/variable_text_field.rb +1 -1
  160. data/lib/hexapdf/type/acro_form.rb +1 -1
  161. data/lib/hexapdf/type/action.rb +1 -1
  162. data/lib/hexapdf/type/actions/go_to.rb +1 -1
  163. data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
  164. data/lib/hexapdf/type/actions/launch.rb +1 -1
  165. data/lib/hexapdf/type/actions/uri.rb +1 -1
  166. data/lib/hexapdf/type/actions.rb +1 -1
  167. data/lib/hexapdf/type/annotation.rb +1 -1
  168. data/lib/hexapdf/type/annotations/link.rb +1 -1
  169. data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
  170. data/lib/hexapdf/type/annotations/text.rb +1 -1
  171. data/lib/hexapdf/type/annotations/widget.rb +1 -1
  172. data/lib/hexapdf/type/annotations.rb +1 -1
  173. data/lib/hexapdf/type/catalog.rb +10 -2
  174. data/lib/hexapdf/type/cid_font.rb +1 -1
  175. data/lib/hexapdf/type/embedded_file.rb +1 -1
  176. data/lib/hexapdf/type/file_specification.rb +1 -1
  177. data/lib/hexapdf/type/font.rb +1 -1
  178. data/lib/hexapdf/type/font_descriptor.rb +1 -1
  179. data/lib/hexapdf/type/font_simple.rb +1 -1
  180. data/lib/hexapdf/type/font_true_type.rb +1 -1
  181. data/lib/hexapdf/type/font_type0.rb +1 -1
  182. data/lib/hexapdf/type/font_type1.rb +1 -1
  183. data/lib/hexapdf/type/font_type3.rb +1 -1
  184. data/lib/hexapdf/type/form.rb +1 -1
  185. data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
  186. data/lib/hexapdf/type/icon_fit.rb +1 -1
  187. data/lib/hexapdf/type/image.rb +48 -4
  188. data/lib/hexapdf/type/info.rb +1 -1
  189. data/lib/hexapdf/type/names.rb +14 -1
  190. data/lib/hexapdf/type/object_stream.rb +1 -1
  191. data/lib/hexapdf/type/page.rb +1 -1
  192. data/lib/hexapdf/type/page_tree_node.rb +19 -2
  193. data/lib/hexapdf/type/resources.rb +1 -1
  194. data/lib/hexapdf/type/signature/adbe_pkcs7_detached.rb +1 -1
  195. data/lib/hexapdf/type/signature/adbe_x509_rsa_sha1.rb +1 -1
  196. data/lib/hexapdf/type/signature/handler.rb +1 -1
  197. data/lib/hexapdf/type/signature/verification_result.rb +1 -1
  198. data/lib/hexapdf/type/signature.rb +1 -1
  199. data/lib/hexapdf/type/trailer.rb +2 -2
  200. data/lib/hexapdf/type/viewer_preferences.rb +1 -1
  201. data/lib/hexapdf/type/xref_stream.rb +3 -2
  202. data/lib/hexapdf/type.rb +1 -1
  203. data/lib/hexapdf/utils/bit_field.rb +1 -1
  204. data/lib/hexapdf/utils/bit_stream.rb +1 -1
  205. data/lib/hexapdf/utils/graphics_helpers.rb +1 -1
  206. data/lib/hexapdf/utils/lru_cache.rb +1 -1
  207. data/lib/hexapdf/utils/math_helpers.rb +1 -1
  208. data/lib/hexapdf/utils/object_hash.rb +1 -1
  209. data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -1
  210. data/lib/hexapdf/utils/sorted_tree_node.rb +4 -2
  211. data/lib/hexapdf/version.rb +2 -2
  212. data/lib/hexapdf/writer.rb +23 -8
  213. data/lib/hexapdf/xref_section.rb +1 -1
  214. data/lib/hexapdf.rb +1 -1
  215. data/test/hexapdf/content/graphic_object/test_geom2d.rb +1 -1
  216. data/test/hexapdf/document/test_destinations.rb +338 -0
  217. data/test/hexapdf/document/test_images.rb +1 -1
  218. data/test/hexapdf/document/test_layout.rb +264 -0
  219. data/test/hexapdf/document/test_pages.rb +9 -0
  220. data/test/hexapdf/document/test_signatures.rb +10 -3
  221. data/test/hexapdf/encryption/test_security_handler.rb +3 -3
  222. data/test/hexapdf/font/encoding/test_glyph_list.rb +4 -0
  223. data/test/hexapdf/layout/test_box.rb +53 -3
  224. data/test/hexapdf/layout/test_box_fitter.rb +62 -0
  225. data/test/hexapdf/layout/test_column_box.rb +159 -0
  226. data/test/hexapdf/layout/test_frame.rb +114 -39
  227. data/test/hexapdf/layout/test_image_box.rb +1 -1
  228. data/test/hexapdf/layout/test_list_box.rb +249 -0
  229. data/test/hexapdf/layout/test_text_box.rb +33 -2
  230. data/test/hexapdf/layout/test_text_fragment.rb +1 -1
  231. data/test/hexapdf/layout/test_text_layouter.rb +49 -17
  232. data/test/hexapdf/layout/test_width_from_polygon.rb +13 -0
  233. data/test/hexapdf/task/test_optimize.rb +17 -4
  234. data/test/hexapdf/test_composer.rb +35 -1
  235. data/test/hexapdf/test_dictionary_fields.rb +10 -10
  236. data/test/hexapdf/test_document.rb +33 -136
  237. data/test/hexapdf/test_filter.rb +1 -1
  238. data/test/hexapdf/test_parser.rb +1 -3
  239. data/test/hexapdf/test_revision.rb +14 -0
  240. data/test/hexapdf/test_revisions.rb +137 -29
  241. data/test/hexapdf/test_serializer.rb +1 -5
  242. data/test/hexapdf/test_writer.rb +99 -15
  243. data/test/hexapdf/type/acro_form/test_form.rb +2 -1
  244. data/test/hexapdf/type/acro_form/test_text_field.rb +17 -0
  245. data/test/hexapdf/type/test_catalog.rb +8 -0
  246. data/test/hexapdf/type/test_image.rb +45 -9
  247. data/test/hexapdf/type/test_names.rb +20 -0
  248. data/test/hexapdf/type/test_page_tree_node.rb +21 -1
  249. data/test/hexapdf/type/test_trailer.rb +3 -3
  250. data/test/hexapdf/type/test_xref_stream.rb +2 -1
  251. data/test/hexapdf/utils/test_sorted_tree_node.rb +11 -1
  252. data/test/test_helper.rb +5 -1
  253. metadata +29 -3
@@ -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-2021 Thomas Leitner
7
+ # Copyright (C) 2014-2022 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
@@ -581,9 +581,22 @@ module HexaPDF
581
581
  #
582
582
  # The font to be used, must be set to a valid font wrapper object before it can be used.
583
583
  #
584
+ # HexaPDF::Composer handles this property specially in that it resolves a set string or array
585
+ # to a font wrapper object before doing else with the style object.
586
+ #
584
587
  # This is the only style property without a default value!
585
588
  #
586
589
  # See: HexaPDF::Content::Canvas#font
590
+ #
591
+ # Examples:
592
+ #
593
+ # #>pdf-composer100
594
+ # composer.text("Helvetica", font: composer.document.fonts.add("Helvetica"))
595
+ # composer.text("Courier", font: "Courier") # works only with composer
596
+ #
597
+ # helvetica_bold = composer.document.fonts.add("Helvetica", variant: :bold)
598
+ # composer.text("Helvetica Bold", font: helvetica_bold)
599
+ # composer.text("Courier Bold", font: ["Courier", variant: :bold]) # only composer
587
600
 
588
601
  ##
589
602
  # :method: font_size
@@ -593,6 +606,12 @@ module HexaPDF
593
606
  # The font size, defaults to 10.
594
607
  #
595
608
  # See: HexaPDF::Content::Canvas#font_size
609
+ #
610
+ # Examples:
611
+ #
612
+ # #>pdf-composer100
613
+ # composer.text("Default size")
614
+ # composer.text("Larger size", font_size: 20)
596
615
 
597
616
  ##
598
617
  # :method: character_spacing
@@ -602,6 +621,11 @@ module HexaPDF
602
621
  # The character spacing, defaults to 0 (i.e. no additional character spacing).
603
622
  #
604
623
  # See: HexaPDF::Content::Canvas#character_spacing
624
+ #
625
+ # Examples:
626
+ #
627
+ # #>pdf-composer100
628
+ # composer.text("More spacing between characters", character_spacing: 1)
605
629
 
606
630
  ##
607
631
  # :method: word_spacing
@@ -611,6 +635,11 @@ module HexaPDF
611
635
  # The word spacing, defaults to 0 (i.e. no additional word spacing).
612
636
  #
613
637
  # See: HexaPDF::Content::Canvas#word_spacing
638
+ #
639
+ # Examples:
640
+ #
641
+ # #>pdf-composer100
642
+ # composer.text("More word spacing", word_spacing: 20)
614
643
 
615
644
  ##
616
645
  # :method: horizontal_scaling
@@ -620,6 +649,11 @@ module HexaPDF
620
649
  # The horizontal scaling, defaults to 100 (in percent, i.e. normal scaling).
621
650
  #
622
651
  # See: HexaPDF::Content::Canvas#horizontal_scaling
652
+ #
653
+ # Examples:
654
+ #
655
+ # #>pdf-composer100
656
+ # composer.text("Horizontal scaling", horizontal_scaling: 150)
623
657
 
624
658
  ##
625
659
  # :method: text_rise
@@ -629,6 +663,11 @@ module HexaPDF
629
663
  # The text rise, i.e. the vertical offset from the baseline, defaults to 0.
630
664
  #
631
665
  # See: HexaPDF::Content::Canvas#text_rise
666
+ #
667
+ # Examples:
668
+ #
669
+ # #>pdf-composer100
670
+ # composer.formatted_text(["Normal", {text: "Up in the air", text_rise: 5}])
632
671
 
633
672
  ##
634
673
  # :method: font_features
@@ -641,6 +680,13 @@ module HexaPDF
641
680
  # Each feature to be applied is indicated by a key with a truthy value.
642
681
  #
643
682
  # See: HexaPDF::Layout::TextShaper#shape_text for available features.
683
+ #
684
+ # Examples:
685
+ #
686
+ # #>pdf-composer100
687
+ # composer.style(:base, font: ["Times", custom_encoding: true], font_size: 30)
688
+ # composer.text("Test flight")
689
+ # composer.text("Test flight", font_features: {kern: true, liga: true})
644
690
 
645
691
  ##
646
692
  # :method: text_rendering_mode
@@ -652,6 +698,11 @@ module HexaPDF
652
698
  # rendering mode value.
653
699
  #
654
700
  # See: HexaPDF::Content::Canvas#text_rendering_mode
701
+ #
702
+ # Examples:
703
+ #
704
+ # #>pdf-composer100
705
+ # composer.text("Test flight", font_size: 40, text_rendering_mode: :stroke)
655
706
 
656
707
  ##
657
708
  # :method: subscript
@@ -661,6 +712,11 @@ module HexaPDF
661
712
  # Render the text as subscript, i.e. lower and in a smaller font size; defaults to false.
662
713
  #
663
714
  # If superscript is set, it will be deactivated.
715
+ #
716
+ # Examples:
717
+ #
718
+ # #>pdf-composer100
719
+ # composer.formatted_text(["Some ", {text: "subscript text", subscript: true}])
664
720
 
665
721
  ##
666
722
  # :method: superscript
@@ -670,6 +726,11 @@ module HexaPDF
670
726
  # Render the text as superscript, i.e. higher and in a smaller font size; defaults to false.
671
727
  #
672
728
  # If subscript is set, it will be deactivated.
729
+ #
730
+ # Examples:
731
+ #
732
+ # #>pdf-composer100
733
+ # composer.formatted_text(["Some ", {text: "superscript text", superscript: true}])
673
734
 
674
735
  ##
675
736
  # :method: underline
@@ -677,6 +738,11 @@ module HexaPDF
677
738
  # underline(enable = false)
678
739
  #
679
740
  # Renders a line underneath the text; defaults to false.
741
+ #
742
+ # Examples:
743
+ #
744
+ # #>pdf-composer100
745
+ # composer.text("Underlined text", underline: true)
680
746
 
681
747
  ##
682
748
  # :method: strikeout
@@ -684,6 +750,11 @@ module HexaPDF
684
750
  # strikeout(enable = false)
685
751
  #
686
752
  # Renders a line through the text; defaults to false.
753
+ #
754
+ # Examples:
755
+ #
756
+ # #>pdf-composer100
757
+ # composer.text("Strikeout text", strikeout: true)
687
758
 
688
759
  ##
689
760
  # :method: fill_color
@@ -693,6 +764,11 @@ module HexaPDF
693
764
  # The color used for filling (e.g. text), defaults to black.
694
765
  #
695
766
  # See: HexaPDF::Content::Canvas#fill_color
767
+ #
768
+ # Examples:
769
+ #
770
+ # #>pdf-composer100
771
+ # composer.text("This is some red text", fill_color: "red")
696
772
 
697
773
  ##
698
774
  # :method: fill_alpha
@@ -703,6 +779,11 @@ module HexaPDF
703
779
  # opaque).
704
780
  #
705
781
  # See: HexaPDF::Content::Canvas#opacity
782
+ #
783
+ # Examples:
784
+ #
785
+ # #>pdf-composer100
786
+ # composer.text("This is some semi-transparent text", fill_alpha: 0.5)
706
787
 
707
788
  ##
708
789
  # :method: stroke_color
@@ -712,6 +793,12 @@ module HexaPDF
712
793
  # The color used for stroking (e.g. text outlines), defaults to black.
713
794
  #
714
795
  # See: HexaPDF::Content::Canvas#stroke_color
796
+ #
797
+ # Examples:
798
+ #
799
+ # #>pdf-composer100
800
+ # composer.text("Stroked text", font_size: 40, stroke_color: "red",
801
+ # text_rendering_mode: :stroke)
715
802
 
716
803
  ##
717
804
  # :method: stroke_alpha
@@ -722,6 +809,12 @@ module HexaPDF
722
809
  # 100% opaque).
723
810
  #
724
811
  # See: HexaPDF::Content::Canvas#opacity
812
+ #
813
+ # Examples:
814
+ #
815
+ # #>pdf-composer100
816
+ # composer.text("Stroked text", font_size: 40, stroke_alpha: 0.5,
817
+ # text_rendering_mode: :stroke)
725
818
 
726
819
  ##
727
820
  # :method: stroke_width
@@ -731,6 +824,12 @@ module HexaPDF
731
824
  # The line width used for stroking operations (e.g. text outlines), defaults to 1.
732
825
  #
733
826
  # See: HexaPDF::Content::Canvas#line_width
827
+ #
828
+ # Examples:
829
+ #
830
+ # #>pdf-composer100
831
+ # composer.text("Stroked text", font_size: 40, stroke_width: 2,
832
+ # text_rendering_mode: :stroke)
734
833
 
735
834
  ##
736
835
  # :method: stroke_cap_style
@@ -741,6 +840,12 @@ module HexaPDF
741
840
  # returned values is always a normalized line cap style value.
742
841
  #
743
842
  # See: HexaPDF::Content::Canvas#line_cap_style
843
+ #
844
+ # Examples:
845
+ #
846
+ # #>pdf-composer100
847
+ # composer.text("Stroked text", font_size: 40, stroke_cap_style: :round,
848
+ # text_rendering_mode: :stroke)
744
849
 
745
850
  ##
746
851
  # :method: stroke_join_style
@@ -751,6 +856,12 @@ module HexaPDF
751
856
  # The returned values is always a normalized line joine style value.
752
857
  #
753
858
  # See: HexaPDF::Content::Canvas#line_join_style
859
+ #
860
+ # Examples:
861
+ #
862
+ # #>pdf-composer100
863
+ # composer.text("Stroked text", font_size: 40, stroke_join_style: :bevel,
864
+ # text_rendering_mode: :stroke)
754
865
 
755
866
  ##
756
867
  # :method: stroke_miter_limit
@@ -761,6 +872,12 @@ module HexaPDF
761
872
  # :miter, defaults to 10.0.
762
873
  #
763
874
  # See: HexaPDF::Content::Canvas#miter_limit
875
+ #
876
+ # Examples:
877
+ #
878
+ # #>pdf-composer100
879
+ # composer.text("Stroked text", font_size: 40, stroke_join_style: :bevel,
880
+ # stroke_miter_limit: 1, text_rendering_mode: :stroke)
764
881
 
765
882
  ##
766
883
  # :method: stroke_dash_pattern
@@ -771,6 +888,12 @@ module HexaPDF
771
888
  # line.
772
889
  #
773
890
  # See: HexaPDF::Content::Canvas#line_dash_pattern
891
+ #
892
+ # Examples:
893
+ #
894
+ # #>pdf-composer100
895
+ # composer.text("Stroked text", font_size: 40, stroke_dash_pattern: [4, 2],
896
+ # text_rendering_mode: :stroke)
774
897
 
775
898
  ##
776
899
  # :method: align
@@ -785,19 +908,42 @@ module HexaPDF
785
908
  # :center:: Center the text horizontally.
786
909
  # :right:: Right-align the text, i.e. the left side is rugged.
787
910
  # :justify:: Justify the text, except for those lines that end in a hard line break.
911
+ #
912
+ # Examples:
913
+ #
914
+ # #>pdf-composer100
915
+ # text = "Lorem ipsum dolor sit amet. " * 2
916
+ # composer.style(:base, border: {width: 1})
917
+ # composer.text(text, align: :left)
918
+ # composer.text(text, align: :center)
919
+ # composer.text(text, align: :right)
920
+ # composer.text(text, align: :justify)
788
921
 
789
922
  ##
790
923
  # :method: valign
791
924
  # :call-seq:
792
925
  # valign(direction = nil)
793
926
  #
794
- # The vertical alignment of items (normally text) inside a box, defaults to :top.
927
+ # The vertical alignment of items (normally text) inside a text box, defaults to :top.
928
+ #
929
+ # For :center and :bottom alignment the box will fill the whole available height. If this is
930
+ # not wanted, an explicit height will need to be set for the box.
931
+ #
932
+ # This property is ignored when using position :flow for a text box.
795
933
  #
796
934
  # Possible values:
797
935
  #
798
936
  # :top:: Vertically align the items to the top of the box.
799
937
  # :center:: Vertically align the items in the center of the box.
800
938
  # :bottom:: Vertically align the items to the bottom of the box.
939
+ #
940
+ # Examples:
941
+ #
942
+ # #>pdf-composer100
943
+ # composer.style(:base, border: {width: 1})
944
+ # composer.text("Top aligned", height: 20, valign: :top)
945
+ # composer.text("Center aligned", height: 20, valign: :center)
946
+ # composer.text("Bottom aligned", valign: :bottom)
801
947
 
802
948
  ##
803
949
  # :method: text_indent
@@ -805,6 +951,12 @@ module HexaPDF
805
951
  # text_indent(amount = nil)
806
952
  #
807
953
  # The indentation to be used for the first line of a sequence of text lines, defaults to 0.
954
+ #
955
+ # Examples:
956
+ #
957
+ # #>pdf-composer100
958
+ # composer.text("This is some longer text that wraps around in two lines.",
959
+ # text_indent: 10)
808
960
 
809
961
  ##
810
962
  # :method: line_spacing
@@ -819,7 +971,20 @@ module HexaPDF
819
971
  # * Using two positional arguments +type+ and +value+.
820
972
  # * Or a hash with the keys +type+ and +value+.
821
973
  #
974
+ # Note that the last line has no additional spacing after it by default. Set #last_line_gap
975
+ # for adding such a spacing.
976
+ #
822
977
  # See LineSpacing for supported types of line spacing.
978
+ #
979
+ # Examples:
980
+ #
981
+ # #>pdf-composer100
982
+ # composer.text("This is some longer text that wraps around in two lines.",
983
+ # line_spacing: 1.5)
984
+ # composer.text("This is some longer text that wraps around in two lines.",
985
+ # line_spacing: :double)
986
+ # composer.text("This is some longer text that wraps around in two lines.",
987
+ # line_spacing: {type: :proportional, value: 1.2})
823
988
 
824
989
  ##
825
990
  # :method: last_line_gap
@@ -827,6 +992,13 @@ module HexaPDF
827
992
  # last_line_gap(enable = false)
828
993
  #
829
994
  # Add an appropriately sized gap after the last line of text if enabled, defaults to false.
995
+ #
996
+ # Examples:
997
+ #
998
+ # #>pdf-composer100
999
+ # composer.text("This is some longer text that wraps around in two lines.",
1000
+ # line_spacing: 1.5, last_line_gap: true)
1001
+ # composer.text("There is spacing above this line due to last_line_gap.")
830
1002
 
831
1003
  ##
832
1004
  # :method: background_color
@@ -834,6 +1006,11 @@ module HexaPDF
834
1006
  # background_color(color = nil)
835
1007
  #
836
1008
  # The color used for backgrounds, defaults to +nil+ (i.e. no background).
1009
+ #
1010
+ # Examples:
1011
+ #
1012
+ # #>pdf-composer100
1013
+ # composer.text("Some text here", background_color: "lightgrey")
837
1014
 
838
1015
  ##
839
1016
  # :method: background_alpha
@@ -844,6 +1021,11 @@ module HexaPDF
844
1021
  # opaque).
845
1022
  #
846
1023
  # See: HexaPDF::Content::Canvas#opacity
1024
+ #
1025
+ # Examples:
1026
+ #
1027
+ # #>pdf-composer100
1028
+ # composer.text("Some text here", background_color: "red", background_alpha: 0.5)
847
1029
 
848
1030
  ##
849
1031
  # :method: padding
@@ -851,6 +1033,13 @@ module HexaPDF
851
1033
  # padding(value = nil)
852
1034
  #
853
1035
  # The padding between the border and the contents, defaults to 0 for all four sides.
1036
+ #
1037
+ # See Style::Quad#set for information on how to set the values.
1038
+ #
1039
+ # Examples:
1040
+ #
1041
+ # #>pdf-composer100
1042
+ # composer.text("Some text here", padding: 10, border: {width: 1})
854
1043
 
855
1044
  ##
856
1045
  # :method: margin
@@ -858,29 +1047,83 @@ module HexaPDF
858
1047
  # margin(value = nil)
859
1048
  #
860
1049
  # The margin around a box, defaults to 0 for all four sides.
1050
+ #
1051
+ # See Style::Quad#set for information on how to set the values.
1052
+ #
1053
+ # Examples:
1054
+ #
1055
+ # #>pdf-composer100
1056
+ # composer.text("Some text here", margin: [5, 10], position: :float,
1057
+ # border: {width: 1})
1058
+ # composer.text("Text starts after floating box and continues below it, " \
1059
+ # "respecting the margin.", position: :flow)
861
1060
 
862
1061
  ##
863
1062
  # :method: border
864
1063
  # :call-seq:
865
1064
  # border(value = nil)
866
1065
  #
867
- # The border around the contents, defaults to no border.
1066
+ # The border around the contents, defaults to no border for all four sides.
1067
+ #
1068
+ # The value has to be a hash containing any of the keys :width, :color and :style. The width,
1069
+ # color and style of the border can be set independently for each side (see Style::Quad#set).
1070
+ #
1071
+ # See Border for more details.
1072
+ #
1073
+ # Examples:
1074
+ #
1075
+ # #>pdf-composer100
1076
+ # composer.text("Some text here", border: {
1077
+ # width: [6, 3],
1078
+ # color: ["green", "blue", "orange"],
1079
+ # style: [:solid, :dashed]
1080
+ # })
868
1081
 
869
1082
  ##
870
1083
  # :method: overlays
871
1084
  # :call-seq:
872
1085
  # overlays(layers = nil)
873
1086
  #
874
- # A Layers object containing all the layers that should be drawn over the box; defaults to no
875
- # layers being drawn.
1087
+ # A Style::Layers object containing all the layers that should be drawn over the box; defaults
1088
+ # to no layers being drawn.
1089
+ #
1090
+ # The +layers+ argument needs to be an array of layer objects. To define a layer either use a
1091
+ # callable object taking the canvas and the box as arguments; or use a pre-defined layer using
1092
+ # an array of the form [:layer_name, **options]. See Style::Layers for details.
1093
+ #
1094
+ # Examples:
1095
+ #
1096
+ # #>pdf-composer100
1097
+ # composer.text("Some text here", overlays: [
1098
+ # lambda do |canvas, box|
1099
+ # canvas.stroke_color("red").opacity(stroke_alpha: 0.5).
1100
+ # line_width(5).line(0, 0, box.width, box.height).stroke
1101
+ # end,
1102
+ # [:link, uri: "https://hexapdf.gettalong.org"]
1103
+ # ])
876
1104
 
877
1105
  ##
878
1106
  # :method: underlays
879
1107
  # :call-seq:
880
1108
  # underlays(layers = nil)
881
1109
  #
882
- # A Layers object containing all the layers that should be drawn under the box; defaults to no
883
- # layers being drawn.
1110
+ # A Style::Layers object containing all the layers that should be drawn under the box;
1111
+ # defaults to no layers being drawn.
1112
+ #
1113
+ # The +layers+ argument needs to be an array of layer objects. To define a layer either use a
1114
+ # callable object taking the canvas and the box as arguments; or use a pre-defined layer using
1115
+ # an array of the form [:layer_name, **options]. See Style::Layers for details.
1116
+ #
1117
+ # Examples:
1118
+ #
1119
+ # #>pdf-composer100
1120
+ # composer.text("Some text here", underlays: [
1121
+ # lambda do |canvas, box|
1122
+ # canvas.stroke_color("red").opacity(stroke_alpha: 0.5).
1123
+ # line_width(5).line(0, 0, box.width, box.height).stroke
1124
+ # end,
1125
+ # [:link, uri: "https://hexapdf.gettalong.org"]
1126
+ # ])
884
1127
 
885
1128
  ##
886
1129
  # :method: position
@@ -902,8 +1145,14 @@ module HexaPDF
902
1145
  #
903
1146
  # :flow:: Flows the content of the box inside the frame around objects.
904
1147
  #
1148
+ # A box needs to indicate whether it supports this value by implementing the
1149
+ # #supports_position_flow? method and returning +true+ if it does or +false+ if it
1150
+ # doesn't.
1151
+ #
905
1152
  # :absolute:: Position the box at an absolute position relative to the frame. The coordinates
906
1153
  # are given via the position hint.
1154
+ #
1155
+ # See #position_hint for examples
907
1156
 
908
1157
  ##
909
1158
  # :method: position_hint
@@ -918,19 +1167,47 @@ module HexaPDF
918
1167
  # :default::
919
1168
  #
920
1169
  # :left:: (default) Align the box to the left side of the available region.
921
- # :right:: Align the box to the right side of the available region.
922
1170
  # :center:: Horizontally center the box in the available region.
1171
+ # :right:: Align the box to the right side of the available region.
1172
+ #
1173
+ # Examples:
1174
+ #
1175
+ # #>pdf-composer100
1176
+ # composer.text("Left", border: {width: 1})
1177
+ # draw_current_frame_shape("red")
1178
+ # composer.text("Center", position_hint: :center, border: {width: 1})
1179
+ # draw_current_frame_shape("blue")
1180
+ # composer.text("Right", position_hint: :right, border: {width: 1})
1181
+ # draw_current_frame_shape("green")
923
1182
  #
924
1183
  # :float::
925
1184
  #
926
1185
  # :left:: (default) Float the box to the left side of the available region.
1186
+ # :center:: Float the box to the center of the available region.
927
1187
  # :right:: Float the box to the right side of the available region.
928
1188
  #
1189
+ # Examples:
1190
+ #
1191
+ # #>pdf-composer100
1192
+ # composer.style(:base, position: :float, border: {width: 1})
1193
+ # composer.text("Left", position_hint: :left)
1194
+ # draw_current_frame_shape("red")
1195
+ # composer.text("Center", position_hint: :center)
1196
+ # draw_current_frame_shape("blue")
1197
+ # composer.text("Right", position_hint: :right)
1198
+ # draw_current_frame_shape("green")
1199
+ #
929
1200
  # :absolute::
930
1201
  #
931
1202
  # An array with the x- and y-coordinates of the bottom left corner of the absolutely
932
1203
  # positioned box. The coordinates are taken as being relative to the bottom left corner of
933
1204
  # the frame into which the box is drawn.
1205
+ #
1206
+ # Examples:
1207
+ #
1208
+ # #>pdf-composer100
1209
+ # composer.text("Absolute", position: :absolute, position_hint: [30, 40])
1210
+ # draw_current_frame_shape("red")
934
1211
 
935
1212
  [
936
1213
  [:font, "raise HexaPDF::Error, 'No font set'"],
@@ -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-2021 Thomas Leitner
7
+ # Copyright (C) 2014-2022 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
@@ -47,18 +47,23 @@ module HexaPDF
47
47
 
48
48
  # Creates a new TextBox object with the given inline items (e.g. TextFragment and InlineBox
49
49
  # objects).
50
- def initialize(items, **kwargs)
50
+ def initialize(items:, **kwargs)
51
51
  super(**kwargs)
52
52
  @tl = TextLayouter.new(style)
53
53
  @items = items
54
54
  @result = nil
55
55
  end
56
56
 
57
+ # Returns +true+ as the 'position' style property value :flow is supported.
58
+ def supports_position_flow?
59
+ true
60
+ end
61
+
57
62
  # Fits the text box into the Frame.
58
63
  #
59
64
  # Depending on the 'position' style property, the text is either fit into the rectangular area
60
65
  # given by +available_width+ and +available_height+, or fit to the outline of the frame
61
- # starting from the top.
66
+ # starting from the top (when 'position' is set to :flow).
62
67
  #
63
68
  # The spacing after the last line can be controlled via the style property +last_line_gap+.
64
69
  #
@@ -69,7 +74,7 @@ module HexaPDF
69
74
 
70
75
  @width = @height = 0
71
76
  @result = if style.position == :flow
72
- @tl.fit(@items, frame.width_specification, frame.contour_line.bbox.height)
77
+ @tl.fit(@items, frame.width_specification, frame.shape.bbox.height)
73
78
  else
74
79
  @width = reserved_width
75
80
  @height = reserved_height
@@ -77,8 +82,16 @@ module HexaPDF
77
82
  height = (@initial_height > 0 ? @initial_height : available_height) - @height
78
83
  @tl.fit(@items, width, height)
79
84
  end
80
- @width += (@initial_width > 0 ? width : @result.lines.max_by(&:width)&.width || 0)
81
- @height += (@initial_height > 0 ? height : @result.height)
85
+ @width += if @initial_width > 0 || style.align == :center || style.align == :right
86
+ width
87
+ else
88
+ @result.lines.max_by(&:width)&.width || 0
89
+ end
90
+ @height += if @initial_height > 0 || style.valign == :center || style.valign == :bottom
91
+ height
92
+ else
93
+ @result.height
94
+ end
82
95
  if style.last_line_gap && @result.lines.last
83
96
  @height += style.line_spacing.gap(@result.lines.last, @result.lines.last)
84
97
  end
@@ -89,17 +102,15 @@ module HexaPDF
89
102
  # Splits the text box into two boxes if necessary and possible.
90
103
  def split(available_width, available_height, frame)
91
104
  fit(available_width, available_height, frame) unless @result
92
- if @width > available_width || @height > available_height
105
+
106
+ if style.position != :flow && (@width > available_width || @height > available_height)
93
107
  [nil, self]
94
108
  elsif @result.remaining_items.empty?
95
109
  [self]
96
110
  elsif @result.lines.empty?
97
111
  [nil, self]
98
112
  else
99
- box = clone
100
- box.instance_variable_set(:@result, nil)
101
- box.instance_variable_set(:@items, @result.remaining_items)
102
- [self, box]
113
+ [self, create_box_for_remaining_items]
103
114
  end
104
115
  end
105
116
 
@@ -116,6 +127,14 @@ module HexaPDF
116
127
  @result.draw(canvas, x, y + content_height)
117
128
  end
118
129
 
130
+ # Creates a new TextBox instance for the items remaining after fitting the box.
131
+ def create_box_for_remaining_items
132
+ box = create_split_box
133
+ box.instance_variable_set(:@result, nil)
134
+ box.instance_variable_set(:@items, @result.remaining_items)
135
+ box
136
+ end
137
+
119
138
  end
120
139
 
121
140
  end
@@ -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-2021 Thomas Leitner
7
+ # Copyright (C) 2014-2022 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
@@ -273,7 +273,8 @@ module HexaPDF
273
273
 
274
274
  # :nodoc:
275
275
  def inspect
276
- "#<#{self.class.name} #{items.inspect}>"
276
+ "#<#{self.class.name} #{items.reject {|i| i.kind_of?(Numeric) }.map(&:str).join.inspect} " \
277
+ "#{items.inspect}>"
277
278
  end
278
279
 
279
280
  private