hexapdf 0.32.1 → 0.33.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (205) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +76 -1
  3. data/README.md +9 -0
  4. data/examples/002-graphics.rb +15 -17
  5. data/examples/003-arcs.rb +9 -9
  6. data/examples/009-text_layouter_alignment.rb +1 -1
  7. data/examples/010-text_layouter_inline_boxes.rb +2 -2
  8. data/examples/011-text_layouter_line_wrapping.rb +1 -1
  9. data/examples/012-text_layouter_styling.rb +7 -7
  10. data/examples/013-text_layouter_shapes.rb +1 -1
  11. data/examples/014-text_in_polygon.rb +1 -1
  12. data/examples/015-boxes.rb +8 -7
  13. data/examples/016-frame_automatic_box_placement.rb +2 -2
  14. data/examples/017-frame_text_flow.rb +2 -1
  15. data/examples/018-composer.rb +1 -1
  16. data/examples/020-column_box.rb +2 -1
  17. data/examples/025-table_box.rb +46 -0
  18. data/lib/hexapdf/cli/command.rb +5 -2
  19. data/lib/hexapdf/cli/form.rb +5 -5
  20. data/lib/hexapdf/cli/inspect.rb +3 -3
  21. data/lib/hexapdf/cli.rb +4 -0
  22. data/lib/hexapdf/composer.rb +104 -52
  23. data/lib/hexapdf/configuration.rb +44 -39
  24. data/lib/hexapdf/content/canvas.rb +393 -267
  25. data/lib/hexapdf/content/color_space.rb +72 -25
  26. data/lib/hexapdf/content/graphic_object/arc.rb +57 -24
  27. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -23
  28. data/lib/hexapdf/content/graphic_object/geom2d.rb +47 -6
  29. data/lib/hexapdf/content/graphic_object/solid_arc.rb +58 -36
  30. data/lib/hexapdf/content/graphic_object.rb +6 -7
  31. data/lib/hexapdf/content/graphics_state.rb +54 -45
  32. data/lib/hexapdf/content/operator.rb +52 -54
  33. data/lib/hexapdf/content/parser.rb +2 -2
  34. data/lib/hexapdf/content/processor.rb +15 -15
  35. data/lib/hexapdf/content/transformation_matrix.rb +1 -1
  36. data/lib/hexapdf/content.rb +5 -0
  37. data/lib/hexapdf/dictionary.rb +6 -5
  38. data/lib/hexapdf/dictionary_fields.rb +42 -14
  39. data/lib/hexapdf/digital_signature/cms_handler.rb +2 -2
  40. data/lib/hexapdf/digital_signature/handler.rb +1 -1
  41. data/lib/hexapdf/digital_signature/pkcs1_handler.rb +2 -3
  42. data/lib/hexapdf/digital_signature/signature.rb +6 -6
  43. data/lib/hexapdf/digital_signature/signatures.rb +13 -12
  44. data/lib/hexapdf/digital_signature/signing/default_handler.rb +14 -5
  45. data/lib/hexapdf/digital_signature/signing/signed_data_creator.rb +2 -4
  46. data/lib/hexapdf/digital_signature/signing/timestamp_handler.rb +4 -4
  47. data/lib/hexapdf/digital_signature/signing.rb +4 -0
  48. data/lib/hexapdf/digital_signature/verification_result.rb +2 -2
  49. data/lib/hexapdf/digital_signature.rb +7 -2
  50. data/lib/hexapdf/document/destinations.rb +12 -11
  51. data/lib/hexapdf/document/files.rb +1 -1
  52. data/lib/hexapdf/document/fonts.rb +1 -1
  53. data/lib/hexapdf/document/layout.rb +167 -39
  54. data/lib/hexapdf/document/pages.rb +3 -2
  55. data/lib/hexapdf/document.rb +89 -55
  56. data/lib/hexapdf/encryption/aes.rb +5 -5
  57. data/lib/hexapdf/encryption/arc4.rb +1 -1
  58. data/lib/hexapdf/encryption/fast_aes.rb +2 -2
  59. data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
  60. data/lib/hexapdf/encryption/identity.rb +1 -1
  61. data/lib/hexapdf/encryption/ruby_aes.rb +1 -1
  62. data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
  63. data/lib/hexapdf/encryption/security_handler.rb +31 -24
  64. data/lib/hexapdf/encryption/standard_security_handler.rb +45 -36
  65. data/lib/hexapdf/encryption.rb +7 -2
  66. data/lib/hexapdf/error.rb +18 -0
  67. data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
  68. data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
  69. data/lib/hexapdf/filter/flate_decode.rb +1 -1
  70. data/lib/hexapdf/filter/lzw_decode.rb +1 -1
  71. data/lib/hexapdf/filter/pass_through.rb +1 -1
  72. data/lib/hexapdf/filter/predictor.rb +1 -1
  73. data/lib/hexapdf/filter/run_length_decode.rb +1 -1
  74. data/lib/hexapdf/filter.rb +55 -6
  75. data/lib/hexapdf/font/cmap/parser.rb +2 -2
  76. data/lib/hexapdf/font/cmap.rb +1 -1
  77. data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
  78. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
  79. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +2 -2
  80. data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
  81. data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
  82. data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +3 -3
  83. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
  84. data/lib/hexapdf/font/invalid_glyph.rb +3 -0
  85. data/lib/hexapdf/font/true_type_wrapper.rb +17 -4
  86. data/lib/hexapdf/font/type1_wrapper.rb +19 -4
  87. data/lib/hexapdf/font_loader/from_configuration.rb +5 -2
  88. data/lib/hexapdf/font_loader/from_file.rb +5 -5
  89. data/lib/hexapdf/font_loader/standard14.rb +3 -3
  90. data/lib/hexapdf/font_loader.rb +3 -0
  91. data/lib/hexapdf/image_loader/jpeg.rb +2 -2
  92. data/lib/hexapdf/image_loader/pdf.rb +1 -1
  93. data/lib/hexapdf/image_loader/png.rb +2 -2
  94. data/lib/hexapdf/image_loader.rb +1 -1
  95. data/lib/hexapdf/importer.rb +13 -0
  96. data/lib/hexapdf/layout/box.rb +9 -2
  97. data/lib/hexapdf/layout/box_fitter.rb +2 -2
  98. data/lib/hexapdf/layout/column_box.rb +18 -4
  99. data/lib/hexapdf/layout/frame.rb +30 -12
  100. data/lib/hexapdf/layout/image_box.rb +5 -0
  101. data/lib/hexapdf/layout/inline_box.rb +1 -0
  102. data/lib/hexapdf/layout/list_box.rb +17 -1
  103. data/lib/hexapdf/layout/page_style.rb +4 -4
  104. data/lib/hexapdf/layout/style.rb +18 -3
  105. data/lib/hexapdf/layout/table_box.rb +682 -0
  106. data/lib/hexapdf/layout/text_box.rb +5 -3
  107. data/lib/hexapdf/layout/text_fragment.rb +1 -1
  108. data/lib/hexapdf/layout/text_layouter.rb +12 -4
  109. data/lib/hexapdf/layout.rb +1 -0
  110. data/lib/hexapdf/name_tree_node.rb +1 -1
  111. data/lib/hexapdf/number_tree_node.rb +1 -1
  112. data/lib/hexapdf/object.rb +18 -7
  113. data/lib/hexapdf/parser.rb +8 -8
  114. data/lib/hexapdf/pdf_array.rb +1 -1
  115. data/lib/hexapdf/rectangle.rb +1 -1
  116. data/lib/hexapdf/reference.rb +1 -1
  117. data/lib/hexapdf/revision.rb +1 -1
  118. data/lib/hexapdf/revisions.rb +3 -3
  119. data/lib/hexapdf/serializer.rb +15 -15
  120. data/lib/hexapdf/stream.rb +4 -2
  121. data/lib/hexapdf/tokenizer.rb +14 -14
  122. data/lib/hexapdf/type/acro_form/appearance_generator.rb +22 -22
  123. data/lib/hexapdf/type/acro_form/button_field.rb +1 -1
  124. data/lib/hexapdf/type/acro_form/choice_field.rb +1 -1
  125. data/lib/hexapdf/type/acro_form/field.rb +2 -2
  126. data/lib/hexapdf/type/acro_form/form.rb +1 -1
  127. data/lib/hexapdf/type/acro_form/signature_field.rb +4 -4
  128. data/lib/hexapdf/type/acro_form/text_field.rb +1 -1
  129. data/lib/hexapdf/type/acro_form/variable_text_field.rb +1 -1
  130. data/lib/hexapdf/type/acro_form.rb +1 -1
  131. data/lib/hexapdf/type/action.rb +1 -1
  132. data/lib/hexapdf/type/actions/go_to.rb +1 -1
  133. data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
  134. data/lib/hexapdf/type/actions/launch.rb +1 -1
  135. data/lib/hexapdf/type/actions/uri.rb +1 -1
  136. data/lib/hexapdf/type/actions.rb +1 -1
  137. data/lib/hexapdf/type/annotation.rb +3 -3
  138. data/lib/hexapdf/type/annotations/link.rb +1 -1
  139. data/lib/hexapdf/type/annotations/markup_annotation.rb +1 -1
  140. data/lib/hexapdf/type/annotations/text.rb +1 -1
  141. data/lib/hexapdf/type/annotations/widget.rb +2 -2
  142. data/lib/hexapdf/type/annotations.rb +1 -1
  143. data/lib/hexapdf/type/catalog.rb +1 -1
  144. data/lib/hexapdf/type/cid_font.rb +3 -3
  145. data/lib/hexapdf/type/embedded_file.rb +1 -1
  146. data/lib/hexapdf/type/file_specification.rb +2 -2
  147. data/lib/hexapdf/type/font_descriptor.rb +1 -1
  148. data/lib/hexapdf/type/font_simple.rb +2 -2
  149. data/lib/hexapdf/type/font_type0.rb +3 -3
  150. data/lib/hexapdf/type/font_type3.rb +1 -1
  151. data/lib/hexapdf/type/form.rb +1 -1
  152. data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
  153. data/lib/hexapdf/type/icon_fit.rb +1 -1
  154. data/lib/hexapdf/type/image.rb +1 -1
  155. data/lib/hexapdf/type/info.rb +1 -1
  156. data/lib/hexapdf/type/mark_information.rb +1 -1
  157. data/lib/hexapdf/type/names.rb +2 -2
  158. data/lib/hexapdf/type/object_stream.rb +7 -3
  159. data/lib/hexapdf/type/outline.rb +1 -1
  160. data/lib/hexapdf/type/outline_item.rb +1 -1
  161. data/lib/hexapdf/type/page.rb +19 -10
  162. data/lib/hexapdf/type/page_label.rb +1 -1
  163. data/lib/hexapdf/type/page_tree_node.rb +1 -1
  164. data/lib/hexapdf/type/resources.rb +1 -1
  165. data/lib/hexapdf/type/trailer.rb +2 -2
  166. data/lib/hexapdf/type/viewer_preferences.rb +1 -1
  167. data/lib/hexapdf/type/xref_stream.rb +2 -2
  168. data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -1
  169. data/lib/hexapdf/version.rb +1 -1
  170. data/lib/hexapdf/writer.rb +4 -4
  171. data/lib/hexapdf/xref_section.rb +2 -2
  172. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +11 -1
  173. data/test/hexapdf/content/graphic_object/test_geom2d.rb +7 -0
  174. data/test/hexapdf/content/test_canvas.rb +0 -1
  175. data/test/hexapdf/digital_signature/test_signatures.rb +22 -0
  176. data/test/hexapdf/document/test_files.rb +2 -2
  177. data/test/hexapdf/document/test_layout.rb +98 -0
  178. data/test/hexapdf/encryption/test_security_handler.rb +12 -11
  179. data/test/hexapdf/encryption/test_standard_security_handler.rb +35 -23
  180. data/test/hexapdf/font/test_true_type_wrapper.rb +18 -1
  181. data/test/hexapdf/font/test_type1_wrapper.rb +15 -1
  182. data/test/hexapdf/layout/test_box.rb +1 -1
  183. data/test/hexapdf/layout/test_column_box.rb +65 -21
  184. data/test/hexapdf/layout/test_frame.rb +14 -14
  185. data/test/hexapdf/layout/test_image_box.rb +4 -0
  186. data/test/hexapdf/layout/test_inline_box.rb +5 -0
  187. data/test/hexapdf/layout/test_list_box.rb +40 -6
  188. data/test/hexapdf/layout/test_page_style.rb +3 -2
  189. data/test/hexapdf/layout/test_style.rb +50 -0
  190. data/test/hexapdf/layout/test_table_box.rb +722 -0
  191. data/test/hexapdf/layout/test_text_box.rb +18 -0
  192. data/test/hexapdf/layout/test_text_layouter.rb +4 -0
  193. data/test/hexapdf/test_dictionary_fields.rb +4 -1
  194. data/test/hexapdf/test_document.rb +1 -0
  195. data/test/hexapdf/test_filter.rb +8 -0
  196. data/test/hexapdf/test_importer.rb +9 -0
  197. data/test/hexapdf/test_object.rb +16 -5
  198. data/test/hexapdf/test_parser.rb +1 -1
  199. data/test/hexapdf/test_stream.rb +7 -0
  200. data/test/hexapdf/test_writer.rb +3 -3
  201. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +13 -5
  202. data/test/hexapdf/type/acro_form/test_form.rb +4 -3
  203. data/test/hexapdf/type/test_object_stream.rb +9 -3
  204. data/test/hexapdf/type/test_page.rb +18 -4
  205. metadata +17 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bee477049a8d45aa858093fa683fef19c4760626c3368bf782b74ca10c26d4e1
4
- data.tar.gz: e543e4d73eaf80d6f6e434e499715de454f43fb7dae789773282236c2154bc57
3
+ metadata.gz: 689e6d8b70951307055c635c744a85bcade50f7065af32b35bd5fd15230cdf4e
4
+ data.tar.gz: a4186126b30e18ad629db5e176be38f81b7367c72c369d8e715a1e952ad49298
5
5
  SHA512:
6
- metadata.gz: d2204bac09267cc3459511a4580480b6157dc5eceafd34c61881dbbcc5c52cc457e7862b3d888d0aa5b8260470b38febf2779ee442f697ce971f82044d81f7ee
7
- data.tar.gz: b77bbcb040ab16e98d3023447a96d7d942a8c80613969bece44ee96427d9235d6db25446dc1ddf6db6ba1f9d0010f4d4f076fdc7ee189947e7ab4cf94a871807
6
+ metadata.gz: 05ad5c0f6b7819499ef0f013d28c7ee821f94cdb02f3487d27bd91089c5238c3b5b91d25ed8be0dc9b548a1e3daae17dea96171f38522587afe6b0aed47d8585
7
+ data.tar.gz: 51119d2f079f827271378fc9a36310ff3abcda221113096cae0fe4abee42bf2421b6ac73232fe586d9cfcf0045b5f238bd8ff69491d6f6329decc77bba0285ff
data/CHANGELOG.md CHANGED
@@ -1,3 +1,75 @@
1
+ ## 0.33.0 - 2023-08-02
2
+
3
+ ### Added
4
+
5
+ * [HexaPDF::Layout::TableBox] for rendering tables
6
+ * [HexaPDF::Document::Layout#table_box] for easier table box creation
7
+ * [HexaPDF::Content::GraphicObject::EndpointArc#max_curves] for setting the
8
+ approximation accuracy
9
+ * [HexaPDF::Importer::copy] for completely copying (including referenced
10
+ indirect objects) a single PDF object (which may be from the same document)
11
+ * [HexaPDF::Layout::Style::Border#draw_on_bounds] for drawing the border on the
12
+ bounds instead of inside
13
+ * [HexaPDF::MissingGlyphError] for better error messages when a font is missing
14
+ a glyph
15
+ * [HexaPDF::Font::Type1Wrapper#custom_glyph] and
16
+ [HexaPDF::Font::TrueTypeWrapper#custom_glyph] for custom glyph creation
17
+ * [HexaPDF::FiberDoubleForString] to avoid creating real `Fiber` instances when
18
+ not necessary
19
+ * Support for drawing `Geom2D::Rectangle` instances via the :geom2d graphic
20
+ object
21
+ * Optional argument `apply_first_text_indent` to
22
+ [HexaPDF::Layout::TextLayouter#fit]
23
+
24
+ ### Changed
25
+
26
+ * [HexaPDF::Layout::Frame] to use more efficient `Geom2D::Rectangle` class
27
+ * Internal constant `HexaPDF::Content::ColorSpace::CSS_COLOR_NAMES` changed to
28
+ [HexaPDF::Content::ColorSpace::COLOR_NAMES]
29
+ * Constructor of [HexaPDF::Layout::PageStyle] to allow setting `next_style`
30
+ attribute
31
+ * The encryption dictionary is now validated before using it for decryption
32
+ * Changed encryption permissions to be compatible to PDF 2.0 by always
33
+ activating the "extract content" permission
34
+ * Digital signature creation in case of signature widgets containing images to
35
+ work around bug in Adobe Acrobat
36
+ * [HexaPDF::Type::Page#each_annotation] and
37
+ [HexaPDF::Type::Page#flatten_annotations] to process certain invalid /Annot
38
+ keys without errors
39
+
40
+ ### Fixed
41
+
42
+ **Breaking change**: [HexaPDF::Object::make_direct] now needs the document
43
+ instance as second argument to correctly resolve references
44
+ * [HexaPDF::Layout::ColumnBox], [HexaPDF::Layout::ListBox] and
45
+ [HexaPDF::Layout::ImageBox] to correctly respond to `#empty?`
46
+ * [HexaPDF::Layout::ColumnBox] and [HexaPDF::Layout::ListBox] to take different
47
+ final box positions into account
48
+ * [HexaPDF::Content::Canvas#text] to set the leading only when multiple lines
49
+ are drawn
50
+ * [HexaPDF::Layout::TextBox#split] to use float comparison
51
+ * Validation of standard encryption dictionary to auto-correct invalid /U and
52
+ /O fields in case they are padded with zeros
53
+ * [HexaPDF::Document#wrap] handling of sub-type mapping in case of missing type
54
+ * [HexaPDF::Type::AcroForm::AppearanceGenerator] to also take a text field
55
+ widget's width into account when auto-sizing
56
+ * [HexaPDF::Layout::TextBox] to correctly handle text indentation for split
57
+ boxes
58
+
59
+
60
+ ## 0.32.2 - 2023-05-06
61
+
62
+ ### Changed
63
+
64
+ * Cross-reference table reconstruction to be more relaxed concerning the
65
+ `endobj` keyword
66
+
67
+ ### Fixed
68
+
69
+ * [HexaPDF::Type::ObjectStream] to not compress any encryption dictionary
70
+ instead of only the current one
71
+
72
+
1
73
  ## 0.32.1 - 2023-04-20
2
74
 
3
75
  ### Added
@@ -25,7 +97,7 @@
25
97
  ### Added
26
98
 
27
99
  * [HexaPDF::Document::Layout#method_missing] for more convenient box creation
28
- * [HexaPDF::Document::Composer#method_missing] for more convenient box drawing
100
+ * [HexaPDF::Composer#method_missing] for more convenient box drawing
29
101
  * [HexaPDF::Document::Layout#inline_box] for easy creation of inline boxes
30
102
  * [HexaPDF::Type::OutlineItem#open?] for getting the open state of an outline
31
103
  item
@@ -52,6 +124,8 @@
52
124
 
53
125
  * [HexaPDF::Layout::PageStyle] for collecting all styling information for pages
54
126
  * [HexaPDF::Composer#page_style] for configuring different page styles
127
+ * Configuration option 'filter.flate.on_error' for handling potentially
128
+ recoverable flate errors
55
129
 
56
130
  ### Changed
57
131
 
@@ -71,6 +145,7 @@
71
145
  deleted
72
146
  * `HexaPDF::Type::Page#perform_validation` to set a /MediaBox for invalid pages
73
147
  that don't have one
148
+ * Parsing of invalid flate encoded streams that can potentially be recovered
74
149
 
75
150
 
76
151
  ## 0.30.0 - 2023-02-13
data/README.md CHANGED
@@ -13,6 +13,9 @@ In short, it allows
13
13
  * **securing** PDF files by encrypting or signing them and
14
14
  * **optimizing** PDF files for smaller file size or other criteria.
15
15
 
16
+ HexaPDF is available under two license, the AGPL and a commercial license, see the [License
17
+ section](#License) for details.
18
+
16
19
 
17
20
  ## Features
18
21
 
@@ -156,6 +159,12 @@ dependencies as well as make sure that all applications needed for the tests are
156
159
  AGPL - see the LICENSE file for licensing details. Commercial licenses are available at
157
160
  <https://gettalong.at/hexapdf/>.
158
161
 
162
+ A commercial license is needed as soon as HexaPDF is distributed with your software or remotely
163
+ accessed via a network and you don't provide the source code of your application under the AGPL. For
164
+ example, if you serve PDFs on the fly in a web application.
165
+
166
+ Contact <sales@gettalong.at> for more information!
167
+
159
168
  Some included files have a different license:
160
169
 
161
170
  * For the license of the included AFM files in the `data/hexapdf/afm` directory, see the file
@@ -29,8 +29,8 @@ end
29
29
 
30
30
  # Basic transformations: translate, scale, rotate, skew
31
31
  canvas.translate(0, 710) do
32
- normal_color = [0.7, 0.7, 0.3]
33
- transformed_color = [0.3, 0.7, 0.7]
32
+ normal_color = "black"
33
+ transformed_color = "hp-blue"
34
34
 
35
35
  canvas.translate(50, 0) do
36
36
  transformation_shape(canvas, normal_color)
@@ -134,7 +134,7 @@ canvas.translate(0, 320) do
134
134
  canvas.arc(180, 50, a: 40, b: 20, start_angle: -60, end_angle: 115, inclination: 45)
135
135
  canvas.stroke
136
136
 
137
- canvas.fill_color(0.4, 0.3, 0.4)
137
+ canvas.fill_color("hp-blue")
138
138
  canvas.arc(250, 50, a: 10, start_angle: -60, end_angle: 115)
139
139
  canvas.arc(300, 50, a: 40, b: 20, start_angle: -60, end_angle: 115)
140
140
  canvas.arc(380, 50, a: 40, b: 20, start_angle: -60, end_angle: 115, inclination: 45)
@@ -142,13 +142,13 @@ canvas.translate(0, 320) do
142
142
 
143
143
  arc = canvas.graphic_object(:arc, cx: 450, cy: 50, a: 30, b: 30,
144
144
  start_angle: -30, end_angle: 105)
145
- canvas.fill_color(0.4, 0.3, 0.4)
145
+ canvas.fill_color("hp-blue")
146
146
  canvas.move_to(450, 50)
147
147
  canvas.line_to(*arc.start_point)
148
148
  arc.curves.each {|x, y, hash| canvas.curve_to(x, y, **hash)}
149
149
  canvas.fill
150
150
  arc.configure(start_angle: 105, end_angle: -30)
151
- canvas.fill_color(0.3, 0.7, 0.7)
151
+ canvas.fill_color("hp-orange")
152
152
  canvas.move_to(450, 50)
153
153
  canvas.line_to(*arc.start_point)
154
154
  arc.curves.each {|x, y, hash| canvas.curve_to(x, y, **hash)}
@@ -156,13 +156,13 @@ canvas.translate(0, 320) do
156
156
 
157
157
  arc = canvas.graphic_object(:arc, cx: 530, cy: 50, a: 40, b: 20,
158
158
  start_angle: -30, end_angle: 105)
159
- canvas.fill_color(0.4, 0.3, 0.4)
159
+ canvas.fill_color("hp-blue")
160
160
  canvas.move_to(530, 50)
161
161
  canvas.line_to(*arc.start_point)
162
162
  arc.curves.each {|x, y, hash| canvas.curve_to(x, y, **hash)}
163
163
  canvas.fill
164
164
  arc.configure(start_angle: 105, end_angle: -30)
165
- canvas.fill_color(0.7, 0.7, 0.3)
165
+ canvas.fill_color("hp-orange")
166
166
  canvas.move_to(530, 50)
167
167
  canvas.line_to(*arc.start_point)
168
168
  arc.curves.each {|x, y, hash| canvas.curve_to(x, y, **hash)}
@@ -194,7 +194,7 @@ end
194
194
  # fill nonzero and stroke, close fill even-odd and stroke, clip even-odd, clip
195
195
  # nonzero
196
196
  canvas.translate(0, 190) do
197
- canvas.fill_color(0.3, 0.7, 0.7)
197
+ canvas.fill_color("hp-blue")
198
198
 
199
199
  [
200
200
  [:stroke], [:close_stroke], [:fill, :nonzero], [:fill, :even_odd],
@@ -212,8 +212,6 @@ canvas.translate(0, 190) do
212
212
  end
213
213
  end
214
214
 
215
- canvas.fill_color(0.7, 0.7, 0.3)
216
-
217
215
  [:even_odd, :nonzero].each_with_index do |op, index|
218
216
  canvas.translate(370 + 110 * index, 20) do
219
217
  canvas.circle(50, 50, 50)
@@ -228,7 +226,7 @@ end
228
226
 
229
227
  # Some composite shapes, an image and a form XObject
230
228
  canvas.translate(0, 80) do
231
- canvas.fill_color(0.3, 0.7, 0.7)
229
+ canvas.fill_color("hp-blue")
232
230
  canvas.rectangle(50, 0, 80, 80, radius: 80)
233
231
  canvas.fill
234
232
 
@@ -237,14 +235,14 @@ canvas.translate(0, 80) do
237
235
 
238
236
  canvas.line_width(0.5)
239
237
  canvas.opacity(fill_alpha: 0.5, stroke_alpha: 0.2) do
240
- canvas.fill_color('AA8888').draw(solid).fill_stroke
241
- canvas.fill_color('88AA88').draw(solid, start_angle: 130, end_angle: 220).fill_stroke
242
- canvas.fill_color('8888AA').draw(solid, start_angle: 220, end_angle: 10).fill_stroke
238
+ canvas.fill_color("hp-blue").draw(solid).fill_stroke
239
+ canvas.fill_color("hp-orange").draw(solid, start_angle: 130, end_angle: 220).fill_stroke
240
+ canvas.fill_color("hp-teal").draw(solid, start_angle: 220, end_angle: 10).fill_stroke
243
241
 
244
242
  solid.configure(inner_a: 0, inner_b: 0, outer_a: 40, outer_b: 40, cx: 290)
245
- canvas.fill_color('AA8888').draw(solid, start_angle: 10, end_angle: 130).fill_stroke
246
- canvas.fill_color('88AA88').draw(solid, start_angle: 130, end_angle: 220).fill_stroke
247
- canvas.fill_color('8888AA').draw(solid, start_angle: 220, end_angle: 10).fill_stroke
243
+ canvas.fill_color("hp-blue").draw(solid, start_angle: 10, end_angle: 130).fill_stroke
244
+ canvas.fill_color("hp-orange").draw(solid, start_angle: 130, end_angle: 220).fill_stroke
245
+ canvas.fill_color("hp-teal").draw(solid, start_angle: 220, end_angle: 10).fill_stroke
248
246
 
249
247
  canvas.image(File.join(__dir__, 'machupicchu.jpg'), at: [350, 0], height: 80)
250
248
  end
data/examples/003-arcs.rb CHANGED
@@ -19,20 +19,20 @@ radius = 75
19
19
  center = [page.box.width * 0.25, page.box.height * 0.85]
20
20
  pie = canvas.graphic_object(:solid_arc, cx: center[0], cy: center[1],
21
21
  outer_a: radius, outer_b: radius)
22
- canvas.fill_color('ddddff')
22
+ canvas.fill_color("hp-orange-light")
23
23
  canvas.draw(pie, start_angle: 30, end_angle: 110).fill
24
- canvas.fill_color('ffdddd')
24
+ canvas.fill_color("hp-teal-light")
25
25
  canvas.draw(pie, start_angle: 110, end_angle: 130).fill
26
- canvas.fill_color('ddffdd')
26
+ canvas.fill_color("hp-blue-light")
27
27
  canvas.draw(pie, start_angle: 130, end_angle: 30).fill
28
28
 
29
29
  arc = canvas.graphic_object(:arc, cx: center[0], cy: center[1],
30
30
  a: radius, b: radius)
31
- canvas.stroke_color('0000ff')
31
+ canvas.stroke_color("hp-orange")
32
32
  canvas.draw(arc, start_angle: 30, end_angle: 110).stroke
33
- canvas.stroke_color('ff0000')
33
+ canvas.stroke_color("hp-teal")
34
34
  canvas.draw(arc, start_angle: 110, end_angle: 130).stroke
35
- canvas.stroke_color('00ff00')
35
+ canvas.stroke_color("hp-blue-dark")
36
36
  canvas.draw(arc, start_angle: 130, end_angle: 30).stroke
37
37
 
38
38
  # Right pie chart
@@ -40,11 +40,11 @@ center = [page.box.width * 0.75, page.box.height * 0.85]
40
40
  canvas.stroke_color('777777')
41
41
  pie = canvas.graphic_object(:solid_arc, cx: center[0], cy: center[1],
42
42
  outer_a: radius, outer_b: radius)
43
- canvas.fill_color('ddddff')
43
+ canvas.fill_color("hp-orange-light")
44
44
  canvas.draw(pie, start_angle: 30, end_angle: 110).fill_stroke
45
- canvas.fill_color('ffdddd')
45
+ canvas.fill_color("hp-teal-light")
46
46
  canvas.draw(pie, start_angle: 110, end_angle: 130).fill_stroke
47
- canvas.fill_color('ddffdd')
47
+ canvas.fill_color("hp-blue-light")
48
48
  canvas.draw(pie, start_angle: 130, end_angle: 30).fill_stroke
49
49
 
50
50
  doc.write('arcs.pdf', optimize: true)
@@ -40,7 +40,7 @@ tl = HexaPDF::Layout::TextLayouter.new
40
40
 
41
41
  tl.style.align(align).valign(valign)
42
42
  tl.fit([tf], width, height).draw(canvas, x, y)
43
- canvas.stroke_color(128, 0, 0).rectangle(x, y, width, -height).stroke
43
+ canvas.stroke_color("hp-blue-dark").rectangle(x, y, width, -height).stroke
44
44
  end
45
45
  end
46
46
 
@@ -42,13 +42,13 @@ items = sample_text.split(/(:-\)|;-\))/).map do |part|
42
42
  case part
43
43
  when ':-)'
44
44
  InlineBox.create(width: size * 2, height: size * 2, content_box: true,
45
- background_color: [162, 234, 247], padding: 2) do |canvas, box|
45
+ background_color: "hp-blue-light", padding: 2) do |canvas, box|
46
46
  canvas.image(emoji_smile, at: [0, 0], width: box.content_width)
47
47
  end
48
48
  when ';-)'
49
49
  InlineBox.create(width: size, height: size, content_box: true,
50
50
  valign: :top, padding: 5, margin: [0, 10],
51
- border: {width: [1, 2], color: [200, 40]}) do |canvas, box|
51
+ border: {width: [1, 2], color: "hp-blue"}) do |canvas, box|
52
52
  canvas.image(emoji_wink, at: [0, 0], width: box.content_width)
53
53
  end
54
54
  else
@@ -49,7 +49,7 @@ layouter = HexaPDF::Layout::TextLayouter.new
49
49
  [30, 60, 100, 160].each do |width|
50
50
  result = layouter.fit([frag], width, 400)
51
51
  result.draw(canvas, x, y)
52
- canvas.stroke_color(255, 0, 0).line_width(0.2)
52
+ canvas.stroke_color("hp-blue-dark").line_width(0.2)
53
53
  canvas.rectangle(x, y, width, -result.height).stroke
54
54
  y -= result.height + 5
55
55
  end
@@ -44,9 +44,9 @@ base_style = {font: base_font, font_size: 12, text_indent: 20}
44
44
  styles = {
45
45
  "Fonts | Font Sizes | Colors" => [
46
46
  {font: doc.fonts.add("Times", variant: :italic),
47
- font_size: 12, fill_color: [0, 0, 255]},
47
+ font_size: 12, fill_color: "hp-blue-light"},
48
48
  {font: doc.fonts.add("Courier"), font_size: 14,
49
- fill_color: [0, 255, 0]},
49
+ fill_color: "hp-orange"},
50
50
  {font: doc.fonts.add("Helvetica", variant: :bold),
51
51
  font_size: 20, fill_alpha: 0.5},
52
52
  ],
@@ -72,16 +72,16 @@ styles = {
72
72
  {**base_style, text_rendering_mode: :stroke,
73
73
  stroke_width: 0.1},
74
74
  {**base_style, font_size: 20, text_rendering_mode: :fill_stroke,
75
- stroke_color: [0, 255, 0], stroke_width: 0.7,
75
+ stroke_color: "hp-orange-light", stroke_width: 0.7,
76
76
  stroke_dash_pattern: [0.5, 1, 1.5], stroke_cap_style: :round},
77
77
  ],
78
78
  "Underlays | Overlays" => [
79
79
  {**base_style, underlays: [lambda do |canv, box|
80
- canv.fill_color(240, 240, 0).opacity(fill_alpha: 0.5).
80
+ canv.fill_color("hp-orange-light2").opacity(fill_alpha: 0.5).
81
81
  rectangle(0, 0, box.width, box.height).fill
82
82
  end]},
83
83
  {**base_style, overlays: [lambda do |canv, box|
84
- canv.line_width(1).stroke_color([0, 255, 0]).
84
+ canv.line_width(1).stroke_color("hp-teal-light2").
85
85
  line(0, -box.y_min, box.width, box.y_max - box.y_min).stroke
86
86
  end]},
87
87
  ],
@@ -91,7 +91,7 @@ styles = {
91
91
  ]},
92
92
  {**base_style, overlays: [
93
93
  [:link, uri: "https://hexapdf.gettalong.org",
94
- border: [0, 0, 2, [3, 3]], border_color: [89, 150, 220]],
94
+ border: [0, 0, 2, [3, 3]], border_color: "hp-blue"],
95
95
  ]},
96
96
  {**base_style, overlays: [
97
97
  [:link, file: "text_layouter_styling.pdf", border: true],
@@ -115,7 +115,7 @@ styles.each do |desc, variations|
115
115
  fragment(str, base_style)
116
116
  end
117
117
  end
118
- items.unshift(fragment(desc + ": ", fill_color: [255, 0, 0], **base_style))
118
+ items.unshift(fragment(desc + ": ", fill_color: "hp-blue-dark", **base_style))
119
119
  y = draw_text(layouter.fit(items, width, 400), canvas, left, y) - 20
120
120
  end
121
121
 
@@ -31,7 +31,7 @@ doc = HexaPDF::Document.new
31
31
  page = doc.pages.add
32
32
  canvas = page.canvas
33
33
  canvas.font("Times", size: 10, variant: :bold)
34
- canvas.stroke_color(255, 0, 0).line_width(0.2)
34
+ canvas.stroke_color("hp-blue-dark").line_width(0.2)
35
35
  font = doc.fonts.add("Times")
36
36
 
37
37
  sample_text = "Lorem ipsum dolor sit amet, con\u{00AD}sectetur
@@ -53,7 +53,7 @@ width_spec = WidthFromPolygon.new(polygon)
53
53
  result = layouter.fit(items, width_spec, polygon.bbox.height)
54
54
  result.draw(canvas, 150, 550)
55
55
  canvas.translate(150, 100).
56
- stroke_color(255, 0, 0).opacity(stroke_alpha: 0.5).
56
+ stroke_color("hp-blue-dark").
57
57
  line_width(0.5).
58
58
  draw(:geom2d, object: polygon)
59
59
 
@@ -37,13 +37,14 @@ end
37
37
 
38
38
  canvas = doc.pages.add.canvas
39
39
 
40
- [[1, 140], [5, 190], [15, 240]].each_with_index do |(width, red), row|
41
- [[:solid, 140], [:dashed, 177], [:dashed_round, 207],
42
- [:dotted, 240]].each_with_index do |(style, green), column|
40
+ [[1, "hp-blue-light"], [5, "hp-teal-light"],
41
+ [15, "hp-orange-light"]].each_with_index do |(width, color), row|
42
+ color = canvas.color_from_specification([color])
43
+ [:solid, :dashed, :dashed_round, :dotted].each_with_index do |style, column|
43
44
  box = HexaPDF::Layout::Box.create(
44
45
  width: 100, height: 100, content_box: true,
45
46
  border: {width: width, style: style},
46
- background_color: [red, green, 0],
47
+ background_color: color.components.map {|c| c + 0.2 * column },
47
48
  &annotate_box)
48
49
  box.draw(canvas, 20 + 140 * column, 700 - 150 * row)
49
50
  end
@@ -54,9 +55,9 @@ box = HexaPDF::Layout::Box.create(
54
55
  width: 470, height: 200, content_box: true,
55
56
  padding: [20, 5, 10, 15],
56
57
  border: {width: [20, 40, 30, 15],
57
- color: [[46, 185, 206], [206, 199, 46], [188, 46, 206], [59, 206, 46]],
58
+ color: ["hp-blue", "hp-orange", "hp-teal", "hp-blue-light"],
58
59
  style: [:solid, :dashed, :dashed_round, :dotted]},
59
- background_color: [255, 255, 180],
60
+ background_color: "hp-orange-light2",
60
61
  underlays: [
61
62
  lambda do |canv, _|
62
63
  canv.stroke_color([255, 0, 0]).line_width(10).line_cap_style(:butt).
@@ -66,7 +67,7 @@ box = HexaPDF::Layout::Box.create(
66
67
  ],
67
68
  overlays: [
68
69
  lambda do |canv, _|
69
- canv.stroke_color([0, 0, 255]).line_width(5).
70
+ canv.stroke_color("hp-blue-dark").line_width(5).
70
71
  rectangle(10, 10, box.width - 20, box.height - 20).stroke
71
72
  end
72
73
  ],
@@ -28,9 +28,9 @@ frame = Frame.new(page_box.left + 20, page_box.bottom + 20,
28
28
 
29
29
  box_counter = 1
30
30
  draw_box = lambda do |**args|
31
- b = Box.create(**args, border: {width: 1, color: [[255, 0, 0]]}) do |canv, box|
31
+ b = Box.create(**args, border: {width: 1, color: "hp-blue-dark"}) do |canv, box|
32
32
  canv.save_graphics_state do
33
- canv.stroke_color(255, 0, 0)
33
+ canv.stroke_color("hp-blue-dark")
34
34
  canv.line(0, 0, box.content_width, box.content_height).
35
35
  line(0, box.content_height, box.content_width, 0).
36
36
  stroke
@@ -29,7 +29,8 @@ boxes << doc.layout.image_box(File.join(__dir__, 'machupicchu.jpg'),
29
29
  width: 100, margin: [10, 30], position: :float)
30
30
  boxes << Box.create(width: 50, height: 50, margin: 20,
31
31
  position: :float, position_hint: :right,
32
- border: {width: 1, color: [[255, 0, 0]]})
32
+ background_color: "hp-blue-light2",
33
+ border: {width: 1, color: "hp-blue-dark"})
33
34
  boxes << doc.layout.lorem_ipsum_box(count: 3, position: :flow, align: :justify)
34
35
 
35
36
  i = 0
@@ -27,7 +27,7 @@ ullamco laboris nisi ut aliquip ex ea commodo consequat. ".tr("\n", " ")
27
27
  HexaPDF::Composer.create('composer.pdf') do |pdf|
28
28
  pdf.style(:base, line_spacing: 1.5, last_line_gap: true, align: :justify)
29
29
  pdf.style(:image, border: {width: 1}, padding: 5, margin: 10)
30
- pdf.style(:link, fill_color: [6, 158, 224], underline: true)
30
+ pdf.style(:link, fill_color: "hp-blue-dark", underline: true)
31
31
  image = File.join(__dir__, 'machupicchu.jpg')
32
32
 
33
33
  pdf.text(lorem_ipsum * 2)
@@ -29,7 +29,8 @@ columns = doc.layout.column(columns: 2, style: {position: :flow}) do |column|
29
29
  style: {margin: [10, 30], position: :float})
30
30
  column.box(:base, width: 50, height: 50,
31
31
  style: {margin: 20, position: :float, position_hint: :right,
32
- border: {width: 1, color: [[255, 0, 0]]}})
32
+ background_color: "hp-blue-light2",
33
+ border: {width: 1, color: "hp-blue-dark"}})
33
34
  column.lorem_ipsum(count: 2, position: :flow, align: :justify)
34
35
  end
35
36
  end
@@ -0,0 +1,46 @@
1
+ # # Table Box
2
+ #
3
+ # This example shows how [HexaPDF::Layout::TableBox] can be used to
4
+ # create tables.
5
+ #
6
+ # Usage:
7
+ # : `ruby table_box.rb`
8
+ #
9
+
10
+ require 'hexapdf'
11
+
12
+ image = File.join(__dir__, 'machupicchu.jpg')
13
+
14
+ HexaPDF::Composer.create("table_box.pdf") do |composer|
15
+ # We start with the simplest table
16
+ data = [['Hello', 'World'], ['How', 'are you?']]
17
+ composer.table(data)
18
+
19
+ # The width of the columns can be specified
20
+ composer.table(data, column_widths: [100, 50])
21
+
22
+ # Besides text a table cell can contain any other element
23
+ l = composer.document.layout
24
+ data = [['Text', 'Just simple text'],
25
+ ['Image', l.image(image)],
26
+ ['List', l.list {|list| list.text('Hello'); list.text('List')}],
27
+ ['Columns', l.column {|c| c.lorem_ipsum(count: 4) }]]
28
+ composer.table(data, column_widths: [50])
29
+
30
+ # A table can be split if necessary
31
+ composer.table([[l.lorem_ipsum(sentences: 1), l.lorem_ipsum(sentences: 1)],
32
+ [l.lorem_ipsum, l.lorem_ipsum]])
33
+
34
+ # It is possible to specify headers and footers which all split parts
35
+ # will have
36
+ composer.column(height: 200) do |column|
37
+ header = lambda {|table| [[l.text('Header left'), l.text('Header right')]] }
38
+ footer = lambda {|table| [[l.text('Footer left'), l.text('Footer right')]] }
39
+ column.table([[l.lorem_ipsum(sentences: 1), l.lorem_ipsum(sentences: 1)],
40
+ [l.lorem_ipsum(sentences: 1), l.lorem_ipsum(sentences: 1)],
41
+ [l.lorem_ipsum(sentences: 1), l.lorem_ipsum(sentences: 1)],
42
+ [l.lorem_ipsum(sentences: 1), l.lorem_ipsum(sentences: 1)]],
43
+ header: header, footer: footer)
44
+
45
+ end
46
+ end
@@ -43,6 +43,9 @@ require 'hexapdf/font/true_type'
43
43
  module HexaPDF
44
44
  module CLI
45
45
 
46
+ # Raised when problems occur on the CLI side of things.
47
+ class Error < HexaPDF::Error; end
48
+
46
49
  # Base class for all hexapdf commands. It provides utility methods needed by the individual
47
50
  # commands.
48
51
  class Command < CmdParse::Command
@@ -134,7 +137,7 @@ module HexaPDF
134
137
  doc.trailer.update_id
135
138
  doc.validate(auto_correct: true) do |msg, correctable, object|
136
139
  if command_parser.strict && !correctable
137
- raise "Validation error for object (#{object.oid},#{object.gen}): #{msg}"
140
+ raise Error, "Validation error for object (#{object.oid},#{object.gen}): #{msg}"
138
141
  elsif command_parser.verbosity_info?
139
142
  $stderr.puts "#{correctable ? 'Corrected' : 'Ignored'} validation problem " \
140
143
  "for object (#{object.oid},#{object.gen}): #{msg}"
@@ -151,7 +154,7 @@ module HexaPDF
151
154
  # HexaPDF::CLI#force is not set.
152
155
  def maybe_raise_on_existing_file(filename)
153
156
  if !command_parser.force && File.exist?(filename)
154
- raise "Output file '#{filename}' already exists, not overwriting. Use --force to " \
157
+ raise Error, "Output file '#{filename}' already exists, not overwriting. Use --force to " \
155
158
  "force writing"
156
159
  end
157
160
  end
@@ -97,7 +97,7 @@ module HexaPDF
97
97
  def execute(in_file, out_file = nil) #:nodoc:
98
98
  maybe_raise_on_existing_file(out_file) if out_file
99
99
  if (@fill || @flatten) && !out_file
100
- raise "Output file missing"
100
+ raise Error, "Output file missing"
101
101
  end
102
102
  with_document(in_file, password: @password, out_file: out_file,
103
103
  incremental: @incremental) do |doc|
@@ -106,7 +106,7 @@ module HexaPDF
106
106
  end
107
107
 
108
108
  if !doc.acro_form
109
- raise "This PDF doesn't contain an interactive form"
109
+ raise Error, "This PDF doesn't contain an interactive form"
110
110
  elsif out_file
111
111
  doc.acro_form[:NeedAppearances] = @need_appearances unless @need_appearances.nil?
112
112
  if @fill || !@flatten
@@ -220,7 +220,7 @@ module HexaPDF
220
220
  form = doc.acro_form
221
221
  data.each do |name, value|
222
222
  field = form.field_by_name(name)
223
- raise "Field '#{name}' not found in input PDF" unless field
223
+ raise Error, "Field '#{name}' not found in input PDF" unless field
224
224
  apply_field_value(field, value)
225
225
  end
226
226
  end
@@ -268,10 +268,10 @@ module HexaPDF
268
268
  when :radio_button
269
269
  field.field_value = value.to_sym
270
270
  else
271
- raise "Field type #{field.concrete_field_type} not yet supported"
271
+ raise Error, "Field type #{field.concrete_field_type} not yet supported"
272
272
  end
273
273
  rescue StandardError
274
- raise "Error while setting '#{field.full_field_name}': #{$!.message}"
274
+ raise Error, "Error while setting '#{field.full_field_name}': #{$!.message}"
275
275
  end
276
276
 
277
277
  # Iterates over all non-push button fields in page order. If a field appears on multiple
@@ -266,11 +266,11 @@ module HexaPDF
266
266
  # Resolves the PDF object from the given string reference and returns it.
267
267
  def pdf_object_from_string_reference(str)
268
268
  if str.nil?
269
- raise "Error: Missing argument object identifier OID[,GEN]"
269
+ raise Error, "Error: Missing argument object identifier OID[,GEN]"
270
270
  elsif !str.match?(/^\d+(,\d+)?$/)
271
- raise "Error: Invalid argument: Must be of form OID[,GEN], not '#{str}'"
271
+ raise Error, "Error: Invalid argument: Must be of form OID[,GEN], not '#{str}'"
272
272
  elsif !(obj = @doc.object(pdf_reference_from_string(str)))
273
- raise "Error: No object with the given object identifier '#{str}' found"
273
+ raise Error, "Error: No object with the given object identifier '#{str}' found"
274
274
  else
275
275
  obj
276
276
  end
data/lib/hexapdf/cli.rb CHANGED
@@ -62,6 +62,10 @@ module HexaPDF
62
62
  Application.new.parse(args)
63
63
  rescue StandardError => e
64
64
  $stderr.puts "Problem encountered: #{e.message}"
65
+ unless e.kind_of?(HexaPDF::Error)
66
+ $stderr.puts "--> The problem might indicate a faulty PDF or a bug in HexaPDF."
67
+ $stderr.puts "--> Please report this at https://github.com/gettalong/hexapdf/issues - thanks!"
68
+ end
65
69
  exit(1)
66
70
  end
67
71