hexapdf 0.17.1 → 0.17.2

Sign up to get free protection for your applications and to get access to all the features.
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