hexapdf 0.17.1 → 0.17.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1024 -0
  3. data/LICENSE +29 -0
  4. data/README.md +129 -0
  5. data/Rakefile +109 -0
  6. data/agpl-3.0.txt +661 -0
  7. data/examples/001-hello_world.rb +16 -0
  8. data/examples/002-graphics.rb +275 -0
  9. data/examples/003-arcs.rb +50 -0
  10. data/examples/004-optimizing.rb +23 -0
  11. data/examples/005-merging.rb +27 -0
  12. data/examples/006-standard_pdf_fonts.rb +73 -0
  13. data/examples/007-truetype.rb +42 -0
  14. data/examples/008-show_char_bboxes.rb +55 -0
  15. data/examples/009-text_layouter_alignment.rb +47 -0
  16. data/examples/010-text_layouter_inline_boxes.rb +64 -0
  17. data/examples/011-text_layouter_line_wrapping.rb +57 -0
  18. data/examples/012-text_layouter_styling.rb +122 -0
  19. data/examples/013-text_layouter_shapes.rb +176 -0
  20. data/examples/014-text_in_polygon.rb +60 -0
  21. data/examples/015-boxes.rb +76 -0
  22. data/examples/016-frame_automatic_box_placement.rb +90 -0
  23. data/examples/017-frame_text_flow.rb +60 -0
  24. data/examples/018-composer.rb +44 -0
  25. data/examples/019-acro_form.rb +88 -0
  26. data/examples/emoji-smile.png +0 -0
  27. data/examples/emoji-wink.png +0 -0
  28. data/examples/machupicchu.jpg +0 -0
  29. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +66 -0
  30. data/lib/hexapdf/content/graphic_object/geom2d.rb +13 -0
  31. data/lib/hexapdf/version.rb +1 -1
  32. data/test/data/aes-test-vectors/CBCGFSbox-128-decrypt.data.gz +0 -0
  33. data/test/data/aes-test-vectors/CBCGFSbox-128-encrypt.data.gz +0 -0
  34. data/test/data/aes-test-vectors/CBCGFSbox-192-decrypt.data.gz +0 -0
  35. data/test/data/aes-test-vectors/CBCGFSbox-192-encrypt.data.gz +0 -0
  36. data/test/data/aes-test-vectors/CBCGFSbox-256-decrypt.data.gz +0 -0
  37. data/test/data/aes-test-vectors/CBCGFSbox-256-encrypt.data.gz +0 -0
  38. data/test/data/aes-test-vectors/CBCKeySbox-128-decrypt.data.gz +0 -0
  39. data/test/data/aes-test-vectors/CBCKeySbox-128-encrypt.data.gz +0 -0
  40. data/test/data/aes-test-vectors/CBCKeySbox-192-decrypt.data.gz +0 -0
  41. data/test/data/aes-test-vectors/CBCKeySbox-192-encrypt.data.gz +0 -0
  42. data/test/data/aes-test-vectors/CBCKeySbox-256-decrypt.data.gz +0 -0
  43. data/test/data/aes-test-vectors/CBCKeySbox-256-encrypt.data.gz +0 -0
  44. data/test/data/aes-test-vectors/CBCVarKey-128-decrypt.data.gz +0 -0
  45. data/test/data/aes-test-vectors/CBCVarKey-128-encrypt.data.gz +0 -0
  46. data/test/data/aes-test-vectors/CBCVarKey-192-decrypt.data.gz +0 -0
  47. data/test/data/aes-test-vectors/CBCVarKey-192-encrypt.data.gz +0 -0
  48. data/test/data/aes-test-vectors/CBCVarKey-256-decrypt.data.gz +0 -0
  49. data/test/data/aes-test-vectors/CBCVarKey-256-encrypt.data.gz +0 -0
  50. data/test/data/aes-test-vectors/CBCVarTxt-128-decrypt.data.gz +0 -0
  51. data/test/data/aes-test-vectors/CBCVarTxt-128-encrypt.data.gz +0 -0
  52. data/test/data/aes-test-vectors/CBCVarTxt-192-decrypt.data.gz +0 -0
  53. data/test/data/aes-test-vectors/CBCVarTxt-192-encrypt.data.gz +0 -0
  54. data/test/data/aes-test-vectors/CBCVarTxt-256-decrypt.data.gz +0 -0
  55. data/test/data/aes-test-vectors/CBCVarTxt-256-encrypt.data.gz +0 -0
  56. data/test/data/fonts/Ubuntu-Title.ttf +0 -0
  57. data/test/data/images/cmyk.jpg +0 -0
  58. data/test/data/images/fillbytes.jpg +0 -0
  59. data/test/data/images/gray.jpg +0 -0
  60. data/test/data/images/greyscale-1bit.png +0 -0
  61. data/test/data/images/greyscale-2bit.png +0 -0
  62. data/test/data/images/greyscale-4bit.png +0 -0
  63. data/test/data/images/greyscale-8bit.png +0 -0
  64. data/test/data/images/greyscale-alpha-8bit.png +0 -0
  65. data/test/data/images/greyscale-trns-8bit.png +0 -0
  66. data/test/data/images/greyscale-with-gamma1.0.png +0 -0
  67. data/test/data/images/greyscale-with-gamma1.5.png +0 -0
  68. data/test/data/images/indexed-1bit.png +0 -0
  69. data/test/data/images/indexed-2bit.png +0 -0
  70. data/test/data/images/indexed-4bit.png +0 -0
  71. data/test/data/images/indexed-8bit.png +0 -0
  72. data/test/data/images/indexed-alpha-4bit.png +0 -0
  73. data/test/data/images/indexed-alpha-8bit.png +0 -0
  74. data/test/data/images/rgb.jpg +0 -0
  75. data/test/data/images/truecolour-8bit.png +0 -0
  76. data/test/data/images/truecolour-alpha-8bit.png +0 -0
  77. data/test/data/images/truecolour-gama-chrm-8bit.png +0 -0
  78. data/test/data/images/truecolour-srgb-8bit.png +0 -0
  79. data/test/data/images/ycck.jpg +0 -0
  80. data/test/data/minimal.pdf +44 -0
  81. data/test/data/standard-security-handler/README +9 -0
  82. data/test/data/standard-security-handler/bothpwd-aes-128bit-V4.pdf +44 -0
  83. data/test/data/standard-security-handler/bothpwd-aes-256bit-V5.pdf +0 -0
  84. data/test/data/standard-security-handler/bothpwd-arc4-128bit-V2.pdf +43 -0
  85. data/test/data/standard-security-handler/bothpwd-arc4-128bit-V4.pdf +43 -0
  86. data/test/data/standard-security-handler/bothpwd-arc4-40bit-V1.pdf +0 -0
  87. data/test/data/standard-security-handler/nopwd-aes-128bit-V4.pdf +43 -0
  88. data/test/data/standard-security-handler/nopwd-aes-256bit-V5.pdf +0 -0
  89. data/test/data/standard-security-handler/nopwd-arc4-128bit-V2.pdf +43 -0
  90. data/test/data/standard-security-handler/nopwd-arc4-128bit-V4.pdf +43 -0
  91. data/test/data/standard-security-handler/nopwd-arc4-40bit-V1.pdf +43 -0
  92. data/test/data/standard-security-handler/ownerpwd-aes-128bit-V4.pdf +0 -0
  93. data/test/data/standard-security-handler/ownerpwd-aes-256bit-V5.pdf +43 -0
  94. data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V2.pdf +43 -0
  95. data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V4.pdf +43 -0
  96. data/test/data/standard-security-handler/ownerpwd-arc4-40bit-V1.pdf +43 -0
  97. data/test/data/standard-security-handler/userpwd-aes-128bit-V4.pdf +43 -0
  98. data/test/data/standard-security-handler/userpwd-aes-256bit-V5.pdf +43 -0
  99. data/test/data/standard-security-handler/userpwd-arc4-128bit-V2.pdf +0 -0
  100. data/test/data/standard-security-handler/userpwd-arc4-128bit-V4.pdf +0 -0
  101. data/test/data/standard-security-handler/userpwd-arc4-40bit-V1.pdf +43 -0
  102. data/test/hexapdf/common_tokenizer_tests.rb +236 -0
  103. data/test/hexapdf/content/common.rb +39 -0
  104. data/test/hexapdf/content/graphic_object/test_arc.rb +102 -0
  105. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +90 -0
  106. data/test/hexapdf/content/graphic_object/test_geom2d.rb +79 -0
  107. data/test/hexapdf/content/graphic_object/test_solid_arc.rb +86 -0
  108. data/test/hexapdf/content/test_canvas.rb +1279 -0
  109. data/test/hexapdf/content/test_color_space.rb +176 -0
  110. data/test/hexapdf/content/test_graphics_state.rb +151 -0
  111. data/test/hexapdf/content/test_operator.rb +619 -0
  112. data/test/hexapdf/content/test_parser.rb +99 -0
  113. data/test/hexapdf/content/test_processor.rb +163 -0
  114. data/test/hexapdf/content/test_transformation_matrix.rb +64 -0
  115. data/test/hexapdf/document/test_files.rb +72 -0
  116. data/test/hexapdf/document/test_fonts.rb +60 -0
  117. data/test/hexapdf/document/test_images.rb +72 -0
  118. data/test/hexapdf/document/test_pages.rb +130 -0
  119. data/test/hexapdf/encryption/common.rb +87 -0
  120. data/test/hexapdf/encryption/test_aes.rb +129 -0
  121. data/test/hexapdf/encryption/test_arc4.rb +39 -0
  122. data/test/hexapdf/encryption/test_fast_aes.rb +17 -0
  123. data/test/hexapdf/encryption/test_fast_arc4.rb +12 -0
  124. data/test/hexapdf/encryption/test_identity.rb +21 -0
  125. data/test/hexapdf/encryption/test_ruby_aes.rb +23 -0
  126. data/test/hexapdf/encryption/test_ruby_arc4.rb +20 -0
  127. data/test/hexapdf/encryption/test_security_handler.rb +380 -0
  128. data/test/hexapdf/encryption/test_standard_security_handler.rb +322 -0
  129. data/test/hexapdf/filter/common.rb +53 -0
  130. data/test/hexapdf/filter/test_ascii85_decode.rb +59 -0
  131. data/test/hexapdf/filter/test_ascii_hex_decode.rb +38 -0
  132. data/test/hexapdf/filter/test_crypt.rb +21 -0
  133. data/test/hexapdf/filter/test_encryption.rb +24 -0
  134. data/test/hexapdf/filter/test_flate_decode.rb +44 -0
  135. data/test/hexapdf/filter/test_lzw_decode.rb +52 -0
  136. data/test/hexapdf/filter/test_predictor.rb +219 -0
  137. data/test/hexapdf/filter/test_run_length_decode.rb +32 -0
  138. data/test/hexapdf/font/cmap/test_parser.rb +102 -0
  139. data/test/hexapdf/font/cmap/test_writer.rb +66 -0
  140. data/test/hexapdf/font/encoding/test_base.rb +45 -0
  141. data/test/hexapdf/font/encoding/test_difference_encoding.rb +29 -0
  142. data/test/hexapdf/font/encoding/test_glyph_list.rb +59 -0
  143. data/test/hexapdf/font/encoding/test_zapf_dingbats_encoding.rb +16 -0
  144. data/test/hexapdf/font/test_cmap.rb +104 -0
  145. data/test/hexapdf/font/test_encoding.rb +27 -0
  146. data/test/hexapdf/font/test_invalid_glyph.rb +34 -0
  147. data/test/hexapdf/font/test_true_type_wrapper.rb +186 -0
  148. data/test/hexapdf/font/test_type1_wrapper.rb +107 -0
  149. data/test/hexapdf/font/true_type/common.rb +17 -0
  150. data/test/hexapdf/font/true_type/table/common.rb +27 -0
  151. data/test/hexapdf/font/true_type/table/test_cmap.rb +47 -0
  152. data/test/hexapdf/font/true_type/table/test_cmap_subtable.rb +141 -0
  153. data/test/hexapdf/font/true_type/table/test_directory.rb +30 -0
  154. data/test/hexapdf/font/true_type/table/test_glyf.rb +58 -0
  155. data/test/hexapdf/font/true_type/table/test_head.rb +56 -0
  156. data/test/hexapdf/font/true_type/table/test_hhea.rb +26 -0
  157. data/test/hexapdf/font/true_type/table/test_hmtx.rb +30 -0
  158. data/test/hexapdf/font/true_type/table/test_kern.rb +61 -0
  159. data/test/hexapdf/font/true_type/table/test_loca.rb +33 -0
  160. data/test/hexapdf/font/true_type/table/test_maxp.rb +50 -0
  161. data/test/hexapdf/font/true_type/table/test_name.rb +76 -0
  162. data/test/hexapdf/font/true_type/table/test_os2.rb +55 -0
  163. data/test/hexapdf/font/true_type/table/test_post.rb +78 -0
  164. data/test/hexapdf/font/true_type/test_builder.rb +42 -0
  165. data/test/hexapdf/font/true_type/test_font.rb +116 -0
  166. data/test/hexapdf/font/true_type/test_optimizer.rb +26 -0
  167. data/test/hexapdf/font/true_type/test_subsetter.rb +73 -0
  168. data/test/hexapdf/font/true_type/test_table.rb +48 -0
  169. data/test/hexapdf/font/type1/common.rb +6 -0
  170. data/test/hexapdf/font/type1/test_afm_parser.rb +65 -0
  171. data/test/hexapdf/font/type1/test_font.rb +104 -0
  172. data/test/hexapdf/font/type1/test_font_metrics.rb +22 -0
  173. data/test/hexapdf/font/type1/test_pfb_parser.rb +37 -0
  174. data/test/hexapdf/font_loader/test_from_configuration.rb +43 -0
  175. data/test/hexapdf/font_loader/test_from_file.rb +36 -0
  176. data/test/hexapdf/font_loader/test_standard14.rb +33 -0
  177. data/test/hexapdf/image_loader/test_jpeg.rb +93 -0
  178. data/test/hexapdf/image_loader/test_pdf.rb +47 -0
  179. data/test/hexapdf/image_loader/test_png.rb +259 -0
  180. data/test/hexapdf/layout/test_box.rb +154 -0
  181. data/test/hexapdf/layout/test_frame.rb +350 -0
  182. data/test/hexapdf/layout/test_image_box.rb +73 -0
  183. data/test/hexapdf/layout/test_inline_box.rb +71 -0
  184. data/test/hexapdf/layout/test_line.rb +206 -0
  185. data/test/hexapdf/layout/test_style.rb +790 -0
  186. data/test/hexapdf/layout/test_text_box.rb +140 -0
  187. data/test/hexapdf/layout/test_text_fragment.rb +375 -0
  188. data/test/hexapdf/layout/test_text_layouter.rb +758 -0
  189. data/test/hexapdf/layout/test_text_shaper.rb +62 -0
  190. data/test/hexapdf/layout/test_width_from_polygon.rb +109 -0
  191. data/test/hexapdf/task/test_dereference.rb +51 -0
  192. data/test/hexapdf/task/test_optimize.rb +162 -0
  193. data/test/hexapdf/test_composer.rb +258 -0
  194. data/test/hexapdf/test_configuration.rb +93 -0
  195. data/test/hexapdf/test_data_dir.rb +32 -0
  196. data/test/hexapdf/test_dictionary.rb +340 -0
  197. data/test/hexapdf/test_dictionary_fields.rb +269 -0
  198. data/test/hexapdf/test_document.rb +641 -0
  199. data/test/hexapdf/test_filter.rb +100 -0
  200. data/test/hexapdf/test_importer.rb +106 -0
  201. data/test/hexapdf/test_object.rb +258 -0
  202. data/test/hexapdf/test_parser.rb +645 -0
  203. data/test/hexapdf/test_pdf_array.rb +169 -0
  204. data/test/hexapdf/test_rectangle.rb +73 -0
  205. data/test/hexapdf/test_reference.rb +50 -0
  206. data/test/hexapdf/test_revision.rb +188 -0
  207. data/test/hexapdf/test_revisions.rb +196 -0
  208. data/test/hexapdf/test_serializer.rb +195 -0
  209. data/test/hexapdf/test_stream.rb +274 -0
  210. data/test/hexapdf/test_tokenizer.rb +80 -0
  211. data/test/hexapdf/test_type.rb +18 -0
  212. data/test/hexapdf/test_writer.rb +140 -0
  213. data/test/hexapdf/test_xref_section.rb +61 -0
  214. data/test/hexapdf/type/acro_form/test_appearance_generator.rb +795 -0
  215. data/test/hexapdf/type/acro_form/test_button_field.rb +308 -0
  216. data/test/hexapdf/type/acro_form/test_choice_field.rb +220 -0
  217. data/test/hexapdf/type/acro_form/test_field.rb +259 -0
  218. data/test/hexapdf/type/acro_form/test_form.rb +357 -0
  219. data/test/hexapdf/type/acro_form/test_signature_field.rb +38 -0
  220. data/test/hexapdf/type/acro_form/test_text_field.rb +201 -0
  221. data/test/hexapdf/type/acro_form/test_variable_text_field.rb +88 -0
  222. data/test/hexapdf/type/actions/test_launch.rb +24 -0
  223. data/test/hexapdf/type/actions/test_uri.rb +23 -0
  224. data/test/hexapdf/type/annotations/test_markup_annotation.rb +22 -0
  225. data/test/hexapdf/type/annotations/test_text.rb +34 -0
  226. data/test/hexapdf/type/annotations/test_widget.rb +225 -0
  227. data/test/hexapdf/type/test_annotation.rb +97 -0
  228. data/test/hexapdf/type/test_catalog.rb +48 -0
  229. data/test/hexapdf/type/test_cid_font.rb +61 -0
  230. data/test/hexapdf/type/test_file_specification.rb +141 -0
  231. data/test/hexapdf/type/test_font.rb +67 -0
  232. data/test/hexapdf/type/test_font_descriptor.rb +61 -0
  233. data/test/hexapdf/type/test_font_simple.rb +176 -0
  234. data/test/hexapdf/type/test_font_true_type.rb +31 -0
  235. data/test/hexapdf/type/test_font_type0.rb +120 -0
  236. data/test/hexapdf/type/test_font_type1.rb +142 -0
  237. data/test/hexapdf/type/test_font_type3.rb +26 -0
  238. data/test/hexapdf/type/test_form.rb +120 -0
  239. data/test/hexapdf/type/test_image.rb +261 -0
  240. data/test/hexapdf/type/test_info.rb +9 -0
  241. data/test/hexapdf/type/test_object_stream.rb +117 -0
  242. data/test/hexapdf/type/test_page.rb +598 -0
  243. data/test/hexapdf/type/test_page_tree_node.rb +315 -0
  244. data/test/hexapdf/type/test_resources.rb +209 -0
  245. data/test/hexapdf/type/test_trailer.rb +116 -0
  246. data/test/hexapdf/type/test_xref_stream.rb +143 -0
  247. data/test/hexapdf/utils/test_bit_field.rb +63 -0
  248. data/test/hexapdf/utils/test_bit_stream.rb +69 -0
  249. data/test/hexapdf/utils/test_graphics_helpers.rb +37 -0
  250. data/test/hexapdf/utils/test_lru_cache.rb +22 -0
  251. data/test/hexapdf/utils/test_object_hash.rb +120 -0
  252. data/test/hexapdf/utils/test_pdf_doc_encoding.rb +18 -0
  253. data/test/hexapdf/utils/test_sorted_tree_node.rb +239 -0
  254. data/test/test_helper.rb +58 -0
  255. metadata +263 -3
@@ -0,0 +1,219 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require_relative 'common'
4
+ require 'hexapdf/filter/predictor'
5
+
6
+ describe HexaPDF::Filter::Predictor do
7
+ include TestHelper
8
+
9
+ module CommonPredictorTests
10
+ def test_decoding_through_decoder_method
11
+ @testcases.each do |name, data|
12
+ assert_equal(data[:source], collector(@obj.decoder(feeder(data[:result].dup), data)),
13
+ "test case: #{name}")
14
+ end
15
+ end
16
+
17
+ def test_encoding_through_encoder_method
18
+ @testcases.each do |name, data|
19
+ assert_equal(data[:result], collector(@obj.encoder(feeder(data[:source].dup), data)),
20
+ "test case: #{name}")
21
+ end
22
+ end
23
+ end
24
+
25
+ before do
26
+ @obj = HexaPDF::Filter::Predictor
27
+ end
28
+
29
+ it "encoder fails on invalid Predictor value" do
30
+ data = {Predictor: 5}
31
+ assert_raises(HexaPDF::InvalidPDFObjectError) do
32
+ @obj.encoder(feeder("test"), data)
33
+ end
34
+ end
35
+
36
+ it "just returns the source if no processing needs to be done" do
37
+ source = feeder("test")
38
+ assert_same(source, @obj.encoder(source, Predictor: 1))
39
+ assert_same(source, @obj.encoder(source, {}))
40
+ end
41
+
42
+ describe "png predictor" do
43
+ include CommonPredictorTests
44
+
45
+ before do
46
+ @testcases = {
47
+ 'none' => {
48
+ source: [110, 96].pack('C*'),
49
+ result: [0, 110, 96].pack('C*'),
50
+ Predictor: 10,
51
+ Colors: 1,
52
+ BitsPerComponent: 1,
53
+ Columns: 14,
54
+ },
55
+ 'sub' => {
56
+ source: [10, 20, 30, 40, 50, 10, 20, 30, 40, 50].pack('C*'),
57
+ result: [1, 10, 10, 10, 10, 10, 1, 10, 10, 10, 10, 10].pack('C*'),
58
+ Predictor: 11,
59
+ Colors: 2,
60
+ BitsPerComponent: 2,
61
+ Columns: 9,
62
+ },
63
+ 'up' => {
64
+ source: [10, 20, 30, 40, 50, 20, 30, 40, 50, 60].pack('C*'),
65
+ result: [2, 10, 20, 30, 40, 50, 2, 10, 10, 10, 10, 10].pack('C*'),
66
+ Predictor: 12,
67
+ Colors: 3,
68
+ BitsPerComponent: 4,
69
+ Columns: 3,
70
+ },
71
+ 'average' => {
72
+ source: [10, 20, 30, 40, 50, 60, 70, 80, 20, 30, 40, 50, 60, 70, 80, 90].pack('C*'),
73
+ result: [3, 10, 20, 25, 30, 35, 40, 45, 50, 3, 15, 20, 15, 15, 15, 15, 15, 15].pack('C*'),
74
+ Predictor: 13,
75
+ Colors: 4,
76
+ BitsPerComponent: 4,
77
+ Columns: 4,
78
+ },
79
+ 'paeth' => {
80
+ source: [10, 20, 30, 40, 50, 60, 70, 80, 20, 30, 40, 50, 60, 70, 80, 90].pack('C*'),
81
+ result: [4, 10, 20, 20, 20, 20, 20, 20, 20, 4, 10, 10, 10, 10, 10, 10, 10, 10].pack('C*'),
82
+ Predictor: 15,
83
+ Colors: 4,
84
+ BitsPerComponent: 4,
85
+ Columns: 4,
86
+ },
87
+ }
88
+ end
89
+
90
+ describe "encoder" do
91
+ it "works correctly" do
92
+ @testcases.each do |name, data|
93
+ encoder = @obj.png_execute(:encoder, feeder(data[:source].dup), data[:Predictor],
94
+ data[:Colors], data[:BitsPerComponent], data[:Columns])
95
+ assert_equal(data[:result], collector(encoder), "testcase #{name}")
96
+ end
97
+ end
98
+
99
+ it "handles a short last row if 'filter.predictor.strict' is false" do
100
+ data = @testcases['up']
101
+ encoder = @obj.png_execute(:encoder, feeder(data[:source][0..-3], 1), data[:Predictor],
102
+ data[:Colors], data[:BitsPerComponent], data[:Columns])
103
+ result = collector(encoder)
104
+ assert_equal(1 + 5 + 1 + 3, result.length)
105
+ assert_equal(data[:result][0..-3], result)
106
+ end
107
+
108
+ it "fails if the last row is missing data and 'filter.predictor.strict' is true " do
109
+ begin
110
+ HexaPDF::GlobalConfiguration['filter.predictor.strict'] = true
111
+ assert_raises(HexaPDF::FilterError) do
112
+ data = @testcases['up']
113
+ encoder = @obj.png_execute(:encoder, feeder(data[:source][0..-2], 1), data[:Predictor],
114
+ data[:Colors], data[:BitsPerComponent], data[:Columns])
115
+ collector(encoder)
116
+ end
117
+ ensure
118
+ HexaPDF::GlobalConfiguration['filter.predictor.strict'] = false
119
+ end
120
+ end
121
+ end
122
+
123
+ describe "decoder" do
124
+ it "works correctly" do
125
+ @testcases.each do |name, data|
126
+ encoder = @obj.png_execute(:decoder, feeder(data[:result].dup), data[:Predictor],
127
+ data[:Colors], data[:BitsPerComponent], data[:Columns])
128
+ assert_equal(data[:source], collector(encoder), "testcase #{name}")
129
+ end
130
+ end
131
+
132
+ it "handles a short last row if 'filter.predictor.strict' is false" do
133
+ data = @testcases['up']
134
+ encoder = @obj.png_execute(:decoder, feeder(data[:result][0..-3], 1), data[:Predictor],
135
+ data[:Colors], data[:BitsPerComponent], data[:Columns])
136
+ result = collector(encoder)
137
+ assert_equal(5 + 3, result.length)
138
+ assert_equal(data[:source][0..-3], result)
139
+ end
140
+
141
+ it "fails if the last row is missing data and 'filter.predictor.strict' is true " do
142
+ begin
143
+ HexaPDF::GlobalConfiguration['filter.predictor.strict'] = true
144
+ assert_raises(HexaPDF::FilterError) do
145
+ data = @testcases['up']
146
+ encoder = @obj.png_execute(:decoder, feeder(data[:result][0..-2], 1), data[:Predictor],
147
+ data[:Colors], data[:BitsPerComponent], data[:Columns])
148
+ collector(encoder)
149
+ end
150
+ ensure
151
+ HexaPDF::GlobalConfiguration['filter.predictor.strict'] = false
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+ describe "tiff predictor" do
158
+ include CommonPredictorTests
159
+
160
+ before do
161
+ @testcases = {
162
+ 'simple' => {
163
+ source: [0b10101010, 0b11111100].pack('C*'),
164
+ result: [0b11111111, 0b10000000].pack('C*'),
165
+ Predictor: 2,
166
+ Colors: 1,
167
+ BitsPerComponent: 1,
168
+ Columns: 14,
169
+ },
170
+ 'complex' => {
171
+ source: [0b10101010, 0b11110000, 0b10010100, 0b11010000].pack('C*'),
172
+ result: [0b10101000, 0b01010000, 0b10010110, 0b10000000].pack('C*'),
173
+ Predictor: 2,
174
+ Colors: 3,
175
+ BitsPerComponent: 2,
176
+ Columns: 2,
177
+ },
178
+ }
179
+ end
180
+
181
+ describe "encoder" do
182
+ it "works correctly" do
183
+ @testcases.each do |name, data|
184
+ encoder = @obj.tiff_execute(:encoder, feeder(data[:source].dup), data[:Colors],
185
+ data[:BitsPerComponent], data[:Columns])
186
+ assert_equal(data[:result], collector(encoder), "testcase #{name}")
187
+ end
188
+ end
189
+
190
+ it "fails if data is missing" do
191
+ assert_raises(HexaPDF::FilterError) do
192
+ data = @testcases['simple']
193
+ encoder = @obj.tiff_execute(:encoder, feeder(data[:source][0..-2], 1), data[:Colors],
194
+ data[:BitsPerComponent], data[:Columns])
195
+ collector(encoder)
196
+ end
197
+ end
198
+ end
199
+
200
+ describe "decoder" do
201
+ it "works correctly" do
202
+ @testcases.each do |name, data|
203
+ decoder = @obj.tiff_execute(:decoder, feeder(data[:result].dup), data[:Colors],
204
+ data[:BitsPerComponent], data[:Columns])
205
+ assert_equal(data[:source], collector(decoder), "testcase #{name}")
206
+ end
207
+ end
208
+
209
+ it "fails if data is missing" do
210
+ assert_raises(HexaPDF::FilterError) do
211
+ data = @testcases['simple']
212
+ decoder = @obj.tiff_execute(:decoder, feeder(data[:result][0..-2], 1), data[:Colors],
213
+ data[:BitsPerComponent], data[:Columns])
214
+ collector(decoder)
215
+ end
216
+ end
217
+ end
218
+ end
219
+ end
@@ -0,0 +1,32 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require_relative 'common'
4
+ require 'hexapdf/filter/run_length_decode'
5
+
6
+ describe HexaPDF::Filter::RunLengthDecode do
7
+ include CommonFilterTests
8
+
9
+ before do
10
+ @obj = HexaPDF::Filter::RunLengthDecode
11
+ @all_test_cases ||= [['abcabcaaaabbbcdeffffffagggggg'.b,
12
+ "\x05abcabc\xFDa\xFEb\x02cde\xFBf\x00a\xFBg\x80".b]]
13
+ @decoded = @all_test_cases[0][0]
14
+ @encoded = @all_test_cases[0][1]
15
+ end
16
+
17
+ describe "decoder" do
18
+ it "fails if data is missing from the source stream" do
19
+ assert_raises(HexaPDF::FilterError) { collector(@obj.decoder(feeder(@encoded.chop.chop))) }
20
+ end
21
+ end
22
+
23
+ # Won't work because the encoding is dependent on the length of the data that is passed in
24
+ undef_method :test_encoder_works_with_single_byte_input
25
+
26
+ describe "encoder" do
27
+ it "works with single byte input" do
28
+ assert_equal(@encoded.chars.map {|a| "\0#{a}" }.join << "\x80".b,
29
+ collector(@obj.encoder(feeder(@encoded.dup, 1))))
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,102 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/font/cmap/parser'
5
+
6
+ describe HexaPDF::Font::CMap::Parser do
7
+ describe "::parse" do
8
+ it "parses CMap data correctly" do
9
+ data = <<~EOF
10
+ /CIDInit /ProcSet findresource begin
11
+ 12 dict begin
12
+ begincmap
13
+ /H usecmap
14
+ /CIDSystemInfo
15
+ << /Registry (Adobe)
16
+ /Ordering (UCS)
17
+ /Supplement 0
18
+ >> def
19
+ /CMapName /Adobe-Identity-UCS def
20
+ /CMapType 2 def
21
+ /WMode 0 def
22
+ 4 begincodespacerange
23
+ <00> <20>
24
+ <8140> <9ffc>
25
+ <a0> <de>
26
+ <e040> <fbec>
27
+ endcodespacerange
28
+ 2 begincidchar
29
+ <8143> 8286
30
+ <8144> 8274
31
+ endcidchar
32
+ 2 begincidrange
33
+ <8145> <8145> 8123
34
+ <8146> <8148> 9000
35
+ endcidrange
36
+ 2 beginbfrange
37
+ <0000> <005E> <0020>
38
+ <1379> <137B> <90FE>
39
+ <005F> <0061> [ <00660066> <00660069> <00660066006C> ]
40
+ endbfrange
41
+ 1 beginbfchar
42
+ <3A51> <D840DC3E>
43
+ endbfchar
44
+ endcmap
45
+ CMapName currentdict /CMap defineresource pop
46
+ end
47
+ end
48
+ EOF
49
+ cmap = HexaPDF::Font::CMap.parse(data)
50
+ assert_equal("Adobe", cmap.registry)
51
+ assert_equal("UCS", cmap.ordering)
52
+ assert_equal(0, cmap.supplement)
53
+ assert_equal("Adobe-Identity-UCS", cmap.name)
54
+ assert_equal(0, cmap.wmode)
55
+
56
+ # Check mappings from used CMap
57
+ assert_equal([0x2121, 0x7e7e], cmap.read_codes("\x21\x21\x7e\x7e"))
58
+ assert_equal(633, cmap.to_cid(0x2121))
59
+ assert_equal(6455, cmap.to_cid(0x6930))
60
+
61
+ # Check codespace ranges
62
+ assert_equal([0, 0x10, 0x20, 33088, 34175, 40956, 160, 205, 222],
63
+ cmap.read_codes("\x00\x10\x20\x81\x40\x85\x7f\x9f\xfc\xa0\xcd\xde"))
64
+
65
+ # Check individual charater mappings
66
+ assert_equal(8286, cmap.to_cid(0x8143))
67
+ assert_equal(8274, cmap.to_cid(0x8144))
68
+
69
+ # Check CID ranges
70
+ assert_equal(8123, cmap.to_cid(0x8145))
71
+ assert_equal(9000, cmap.to_cid(0x8146))
72
+ assert_equal(9001, cmap.to_cid(0x8147))
73
+ assert_equal(9002, cmap.to_cid(0x8148))
74
+
75
+ # Check unicode mapping
76
+ ((0x20.chr)..(0x7e.chr)).each_with_index do |str, index|
77
+ assert_equal(str, cmap.to_unicode(index))
78
+ end
79
+ assert_equal("\u{90FE}", cmap.to_unicode(0x1379))
80
+ assert_equal("\u{90FF}", cmap.to_unicode(0x137A))
81
+ assert_equal("\u{9100}", cmap.to_unicode(0x137B))
82
+ assert_equal("ff", cmap.to_unicode(0x5F))
83
+ assert_equal("fi", cmap.to_unicode(0x60))
84
+ assert_equal("ffl", cmap.to_unicode(0x61))
85
+ assert_equal("\xD8\x40\xDC\x3E".encode("UTF-8", "UTF-16BE"),
86
+ cmap.to_unicode(0x3A51))
87
+ assert_nil(cmap.to_unicode(0xFF))
88
+ end
89
+
90
+ it "fails if there is an invalid token inside the bfrange operator" do
91
+ assert_raises(HexaPDF::Error) do
92
+ HexaPDF::Font::CMap.parse("1 beginbfrange <0000> <0001> 5 endbfrange")
93
+ end
94
+ end
95
+
96
+ it "fails if the CMap is not correctly structured" do
97
+ assert_raises(HexaPDF::Error) do
98
+ HexaPDF::Font::CMap.parse("1 beginbfchar <0000> <0001>")
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,66 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/font/cmap/writer'
5
+
6
+ describe HexaPDF::Font::CMap::Writer do
7
+ before do
8
+ @cmap_data = <<~EOF
9
+ /CIDInit /ProcSet findresource begin
10
+ 12 dict begin
11
+ begincmap
12
+ /CIDSystemInfo
13
+ << /Registry (Adobe)
14
+ /Ordering (UCS)
15
+ /Supplement 0
16
+ >> def
17
+ /CMapName /Adobe-Identity-UCS def
18
+ /CMapType 2 def
19
+ 1 begincodespacerange
20
+ <0000> <FFFF>
21
+ endcodespacerange
22
+ 2 beginbfchar
23
+ <0060><0090>
24
+ <3A51><d840dc3e>
25
+ endbfchar
26
+ 2 beginbfrange
27
+ <0000><005E><0020>
28
+ <1379><137B><90fe>
29
+ endbfrange
30
+ endcmap
31
+ CMapName currentdict /CMap defineresource pop
32
+ end
33
+ end
34
+ EOF
35
+ @mapping = []
36
+ 0x00.upto(0x5e) {|i| @mapping << [i, 0x20 + i] }
37
+ @mapping << [0x60, 0x90]
38
+ 0x1379.upto(0x137B) {|i| @mapping << [i, 0x90FE + i - 0x1379] }
39
+ @mapping << [0x3A51, 0x2003E]
40
+ end
41
+
42
+ describe "create_to_unicode_cmap" do
43
+ it "creates a correct CMap file" do
44
+ assert_equal(@cmap_data, HexaPDF::Font::CMap.create_to_unicode_cmap(@mapping))
45
+ end
46
+
47
+ it "works if the last item is a range" do
48
+ @mapping.pop
49
+ @cmap_data.sub!(/2 beginbfchar/, '1 beginbfchar')
50
+ @cmap_data.sub!(/<3A51><d840dc3e>\n/, '')
51
+ assert_equal(@cmap_data, HexaPDF::Font::CMap.create_to_unicode_cmap(@mapping))
52
+ end
53
+
54
+ it "works with only ranges" do
55
+ @mapping.delete_at(-1)
56
+ @mapping.delete_at(0x5f)
57
+ @cmap_data.sub!(/\n2 beginbfchar.*endbfchar/m, '')
58
+ assert_equal(@cmap_data, HexaPDF::Font::CMap.create_to_unicode_cmap(@mapping))
59
+ end
60
+
61
+ it "returns an empty CMap if the mapping is empty" do
62
+ assert_equal(@cmap_data.sub(/\d+ beginbfchar.*endbfrange/m, ''),
63
+ HexaPDF::Font::CMap.create_to_unicode_cmap([]))
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,45 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/font/encoding/base'
5
+
6
+ describe HexaPDF::Font::Encoding::Base do
7
+ before do
8
+ @base = HexaPDF::Font::Encoding::Base.new
9
+ @base.code_to_name[65] = :A
10
+ end
11
+
12
+ it "returns nil for the encoding_name" do
13
+ assert_nil(@base.encoding_name)
14
+ end
15
+
16
+ describe "name" do
17
+ it "returns a mapped code" do
18
+ assert_equal(:A, @base.name(65))
19
+ end
20
+
21
+ it "returns .notdef for an unmapped code" do
22
+ assert_equal(:'.notdef', @base.name(66))
23
+ end
24
+ end
25
+
26
+ describe "unicode" do
27
+ it "returns the unicode value of the code" do
28
+ assert_equal("A", @base.unicode(65))
29
+ end
30
+
31
+ it "returns an empty string for an unmapped code" do
32
+ assert_nil(@base.unicode(66))
33
+ end
34
+ end
35
+
36
+ describe "code" do
37
+ it "returns the code for an existing glyph name" do
38
+ assert_equal(65, @base.code(:A))
39
+ end
40
+
41
+ it "returns nil if the glyph name is not referenced" do
42
+ assert_nil(@base.code(:Unknown))
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/font/encoding/difference_encoding'
5
+ require 'hexapdf/font/encoding/win_ansi_encoding'
6
+
7
+ describe HexaPDF::Font::Encoding::DifferenceEncoding do
8
+ before do
9
+ base = HexaPDF::Font::Encoding::WinAnsiEncoding.new
10
+ @enc = HexaPDF::Font::Encoding::DifferenceEncoding.new(base)
11
+ end
12
+
13
+ describe "name" do
14
+ it "takes the encoding differences into account" do
15
+ assert_equal(:A, @enc.name(65))
16
+ @enc.code_to_name[65] = :B
17
+ assert_equal(:B, @enc.name(65))
18
+ assert_equal(:B, @enc.name(66))
19
+ end
20
+ end
21
+
22
+ describe "code" do
23
+ it "takes the encoding differences into account" do
24
+ assert_equal(65, @enc.code(:A))
25
+ @enc.code_to_name[65] = :Known
26
+ assert_equal(65, @enc.code(:Known))
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,59 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/font/encoding/glyph_list'
5
+
6
+ describe HexaPDF::Font::Encoding::GlyphList do
7
+ before do
8
+ @list = HexaPDF::Font::Encoding::GlyphList.new
9
+ end
10
+
11
+ describe ".new" do
12
+ it "only ever creates one instance" do
13
+ assert_same(@list, HexaPDF::Font::Encoding::GlyphList.new)
14
+ end
15
+ end
16
+
17
+ describe "name_to_unicode" do
18
+ it "maps known glyph names to their unicode equivalent" do
19
+ assert_equal("A", @list.name_to_unicode(:A))
20
+ assert_equal("9", HexaPDF::Font::Encoding::GlyphList.name_to_unicode(:nine))
21
+ assert_equal("\u05da\u05b8", @list.name_to_unicode(:finalkafqamats))
22
+ end
23
+
24
+ it "maps special uniXXXX names to unicode values" do
25
+ assert_equal("A", @list.name_to_unicode(:uni0041))
26
+ assert_equal("\u1234", @list.name_to_unicode(:uni1234))
27
+ end
28
+
29
+ it "maps special uXXXX[XX] names to unicode values" do
30
+ assert_equal("A", @list.name_to_unicode(:u0041))
31
+ assert_equal("" << "1F000".hex, @list.name_to_unicode(:u1F000))
32
+ end
33
+
34
+ it "maps Zapf Dingbats glyph names to their unicode" do
35
+ assert_equal("A", @list.name_to_unicode(:A, zapf_dingbats: true))
36
+ assert_equal("\u275e", @list.name_to_unicode(:a100, zapf_dingbats: true))
37
+ end
38
+
39
+ it "returns nil for unknown glyph names" do
40
+ assert_nil(@list.name_to_unicode(:MyUnknownGlyphName))
41
+ assert_nil(@list.name_to_unicode(:a100))
42
+ end
43
+ end
44
+
45
+ describe "unicode_to_name" do
46
+ it "maps codepoints to names" do
47
+ assert_equal(:space, @list.unicode_to_name(" "))
48
+ assert_equal(:A, HexaPDF::Font::Encoding::GlyphList.unicode_to_name("A"))
49
+ assert_equal(:odieresis, @list.unicode_to_name("ö"))
50
+ assert_equal(:finalkafqamats, @list.unicode_to_name("\u05da\u05b8"))
51
+ assert_equal(:'.notdef', @list.unicode_to_name("ABCDEFG"))
52
+ end
53
+
54
+ it "maps Zapf Dingbats codepoints to names" do
55
+ assert_equal(:'.notdef', @list.unicode_to_name("\u2710"))
56
+ assert_equal(:a105, @list.unicode_to_name("\u2710", zapf_dingbats: true))
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,16 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/font/encoding/zapf_dingbats_encoding'
5
+
6
+ describe HexaPDF::Font::Encoding::ZapfDingbatsEncoding do
7
+ before do
8
+ @enc = HexaPDF::Font::Encoding::ZapfDingbatsEncoding.new
9
+ end
10
+
11
+ describe "unicode" do
12
+ it "uses the special ZapfDingbats glyph list" do
13
+ assert_equal("\u2721", @enc.unicode(65))
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,104 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'test_helper'
4
+ require 'hexapdf/font/cmap'
5
+
6
+ describe HexaPDF::Font::CMap do
7
+ before do
8
+ @cmap = HexaPDF::Font::CMap.new
9
+ end
10
+
11
+ describe "using another CMap" do
12
+ it "uses all mappings of the other CMap" do
13
+ other = HexaPDF::Font::CMap.new
14
+ other.add_codespace_range(0x00..0x80)
15
+ other.add_codespace_range(0x81..0x9f, 0x40..0xfc)
16
+ other.add_cid_mapping(0x40, 2000)
17
+ other.add_cid_range(0x50, 0x60, 3000)
18
+ other.add_unicode_mapping(0x40, "A")
19
+ @cmap.use_cmap(other)
20
+
21
+ assert_equal([0, 0x80, 0x8140], @cmap.read_codes("\x0\x80\x81\x40"))
22
+ assert_equal(2000, @cmap.to_cid(0x40))
23
+ assert_equal(3000, @cmap.to_cid(0x50))
24
+ assert_equal(3016, @cmap.to_cid(0x60))
25
+ assert_equal("A", @cmap.to_unicode(0x40))
26
+ end
27
+ end
28
+
29
+ describe "predefined CMaps" do
30
+ it "can check if there is a predefined CMap for a certain name" do
31
+ assert(HexaPDF::Font::CMap.predefined?('H'))
32
+ refute(HexaPDF::Font::CMap.predefined?('Z'))
33
+ end
34
+
35
+ it "returns a predefined CMap using ::for_name" do
36
+ cmap = HexaPDF::Font::CMap.for_name('GB-EUC-H')
37
+ assert_equal("Adobe", cmap.registry)
38
+ assert_equal("GB1", cmap.ordering)
39
+ assert_equal(0, cmap.supplement)
40
+ assert_equal('GB-EUC-H', cmap.name)
41
+ end
42
+
43
+ it "fails in a non-existent CMap file should be parsed" do
44
+ assert_raises(HexaPDF::Error) { HexaPDF::Font::CMap.for_name('unknown') }
45
+ end
46
+ end
47
+
48
+ describe "add codespace ranges and read codes" do
49
+ before do
50
+ @cmap.add_codespace_range(0x00..0x80)
51
+ @cmap.add_codespace_range(0x81..0x9f, 0x40..0xfc)
52
+ @cmap.add_codespace_range(0xa0..0xde)
53
+ @cmap.add_codespace_range(0xe0..0xfb, 0x40..0xec)
54
+ end
55
+
56
+ it "can read valid character codes" do
57
+ assert_equal([0, 0x40, 0x80, 33088, 34175, 40956, 160, 205, 222],
58
+ @cmap.read_codes("\x00\x40\x80\x81\x40\x85\x7f\x9f\xfc\xa0\xcd\xde"))
59
+ end
60
+
61
+ it "fails if the first byte is not valid" do
62
+ assert_raises(HexaPDF::Error) { @cmap.read_codes("\xdf") }
63
+ end
64
+
65
+ it "fails if a byte following the first one is not valid" do
66
+ assert_raises(HexaPDF::Error) { @cmap.read_codes("\x82\x10") }
67
+ end
68
+
69
+ it "fails if too few bytes for a valid code are available" do
70
+ assert_raises(HexaPDF::Error) { @cmap.read_codes("\x82") }
71
+ end
72
+ end
73
+
74
+ describe "CID definition and retrieval" do
75
+ it "allows adding and retrieving mappings from individual codes to CIDs" do
76
+ @cmap.add_cid_mapping(57, 90)
77
+ assert_equal(90, @cmap.to_cid(57))
78
+ end
79
+
80
+ it "allows adding and retrieving mappings from code ranges to CIDs" do
81
+ @cmap.add_cid_range(20, 40, 100)
82
+ @cmap.add_cid_range(30, 35, 10)
83
+ assert_equal(100, @cmap.to_cid(20))
84
+ assert_equal(120, @cmap.to_cid(40))
85
+ assert_equal(10, @cmap.to_cid(30))
86
+ assert_equal(15, @cmap.to_cid(35))
87
+ end
88
+
89
+ it "returns 0 for unknown code-to-CID mappings" do
90
+ assert_equal(0, @cmap.to_cid(57))
91
+ end
92
+ end
93
+
94
+ describe "Unicode mapping and retrieval" do
95
+ it "allows adding and retrieving a code-to-unicode mapping" do
96
+ @cmap.add_unicode_mapping(20, "ABC")
97
+ assert_equal("ABC", @cmap.to_unicode(20))
98
+ end
99
+
100
+ it "returns nil for unknown mappings" do
101
+ assert_nil(@cmap.to_unicode(20))
102
+ end
103
+ end
104
+ end