hexapdf 0.1.0

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 (346) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTERS +3 -0
  3. data/LICENSE +26 -0
  4. data/README.md +88 -0
  5. data/Rakefile +121 -0
  6. data/VERSION +1 -0
  7. data/agpl-3.0.txt +661 -0
  8. data/bin/hexapdf +6 -0
  9. data/data/hexapdf/afm/Courier-Bold.afm +342 -0
  10. data/data/hexapdf/afm/Courier-BoldOblique.afm +342 -0
  11. data/data/hexapdf/afm/Courier-Oblique.afm +342 -0
  12. data/data/hexapdf/afm/Courier.afm +342 -0
  13. data/data/hexapdf/afm/Helvetica-Bold.afm +2827 -0
  14. data/data/hexapdf/afm/Helvetica-BoldOblique.afm +2827 -0
  15. data/data/hexapdf/afm/Helvetica-Oblique.afm +3051 -0
  16. data/data/hexapdf/afm/Helvetica.afm +3051 -0
  17. data/data/hexapdf/afm/MustRead.html +1 -0
  18. data/data/hexapdf/afm/Symbol.afm +213 -0
  19. data/data/hexapdf/afm/Times-Bold.afm +2588 -0
  20. data/data/hexapdf/afm/Times-BoldItalic.afm +2384 -0
  21. data/data/hexapdf/afm/Times-Italic.afm +2667 -0
  22. data/data/hexapdf/afm/Times-Roman.afm +2419 -0
  23. data/data/hexapdf/afm/ZapfDingbats.afm +225 -0
  24. data/data/hexapdf/encoding/glyphlist.txt +4305 -0
  25. data/data/hexapdf/encoding/zapfdingbats.txt +225 -0
  26. data/examples/arc.rb +50 -0
  27. data/examples/graphics.rb +274 -0
  28. data/examples/hello_world.rb +16 -0
  29. data/examples/machupicchu.jpg +0 -0
  30. data/examples/merging.rb +24 -0
  31. data/examples/optimizing.rb +20 -0
  32. data/examples/show_char_bboxes.rb +55 -0
  33. data/examples/standard_pdf_fonts.rb +72 -0
  34. data/examples/truetype.rb +45 -0
  35. data/lib/hexapdf/cli/extract.rb +128 -0
  36. data/lib/hexapdf/cli/info.rb +121 -0
  37. data/lib/hexapdf/cli/inspect.rb +157 -0
  38. data/lib/hexapdf/cli/modify.rb +218 -0
  39. data/lib/hexapdf/cli.rb +121 -0
  40. data/lib/hexapdf/configuration.rb +392 -0
  41. data/lib/hexapdf/content/canvas.rb +1974 -0
  42. data/lib/hexapdf/content/color_space.rb +364 -0
  43. data/lib/hexapdf/content/graphic_object/arc.rb +267 -0
  44. data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +208 -0
  45. data/lib/hexapdf/content/graphic_object/solid_arc.rb +173 -0
  46. data/lib/hexapdf/content/graphic_object.rb +81 -0
  47. data/lib/hexapdf/content/graphics_state.rb +579 -0
  48. data/lib/hexapdf/content/operator.rb +1072 -0
  49. data/lib/hexapdf/content/parser.rb +204 -0
  50. data/lib/hexapdf/content/processor.rb +451 -0
  51. data/lib/hexapdf/content/transformation_matrix.rb +172 -0
  52. data/lib/hexapdf/content.rb +47 -0
  53. data/lib/hexapdf/data_dir.rb +51 -0
  54. data/lib/hexapdf/dictionary.rb +303 -0
  55. data/lib/hexapdf/dictionary_fields.rb +382 -0
  56. data/lib/hexapdf/document.rb +589 -0
  57. data/lib/hexapdf/document_utils.rb +209 -0
  58. data/lib/hexapdf/encryption/aes.rb +206 -0
  59. data/lib/hexapdf/encryption/arc4.rb +93 -0
  60. data/lib/hexapdf/encryption/fast_aes.rb +79 -0
  61. data/lib/hexapdf/encryption/fast_arc4.rb +67 -0
  62. data/lib/hexapdf/encryption/identity.rb +63 -0
  63. data/lib/hexapdf/encryption/ruby_aes.rb +447 -0
  64. data/lib/hexapdf/encryption/ruby_arc4.rb +96 -0
  65. data/lib/hexapdf/encryption/security_handler.rb +494 -0
  66. data/lib/hexapdf/encryption/standard_security_handler.rb +616 -0
  67. data/lib/hexapdf/encryption.rb +94 -0
  68. data/lib/hexapdf/error.rb +73 -0
  69. data/lib/hexapdf/filter/ascii85_decode.rb +160 -0
  70. data/lib/hexapdf/filter/ascii_hex_decode.rb +87 -0
  71. data/lib/hexapdf/filter/dct_decode.rb +57 -0
  72. data/lib/hexapdf/filter/encryption.rb +59 -0
  73. data/lib/hexapdf/filter/flate_decode.rb +93 -0
  74. data/lib/hexapdf/filter/jpx_decode.rb +56 -0
  75. data/lib/hexapdf/filter/lzw_decode.rb +191 -0
  76. data/lib/hexapdf/filter/predictor.rb +266 -0
  77. data/lib/hexapdf/filter/run_length_decode.rb +108 -0
  78. data/lib/hexapdf/filter.rb +176 -0
  79. data/lib/hexapdf/font/cmap/parser.rb +146 -0
  80. data/lib/hexapdf/font/cmap/writer.rb +176 -0
  81. data/lib/hexapdf/font/cmap.rb +90 -0
  82. data/lib/hexapdf/font/encoding/base.rb +77 -0
  83. data/lib/hexapdf/font/encoding/difference_encoding.rb +64 -0
  84. data/lib/hexapdf/font/encoding/glyph_list.rb +150 -0
  85. data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +221 -0
  86. data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +265 -0
  87. data/lib/hexapdf/font/encoding/standard_encoding.rb +205 -0
  88. data/lib/hexapdf/font/encoding/symbol_encoding.rb +244 -0
  89. data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +280 -0
  90. data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +250 -0
  91. data/lib/hexapdf/font/encoding.rb +68 -0
  92. data/lib/hexapdf/font/true_type/font.rb +179 -0
  93. data/lib/hexapdf/font/true_type/table/cmap.rb +103 -0
  94. data/lib/hexapdf/font/true_type/table/cmap_subtable.rb +384 -0
  95. data/lib/hexapdf/font/true_type/table/directory.rb +92 -0
  96. data/lib/hexapdf/font/true_type/table/glyf.rb +166 -0
  97. data/lib/hexapdf/font/true_type/table/head.rb +143 -0
  98. data/lib/hexapdf/font/true_type/table/hhea.rb +109 -0
  99. data/lib/hexapdf/font/true_type/table/hmtx.rb +79 -0
  100. data/lib/hexapdf/font/true_type/table/loca.rb +79 -0
  101. data/lib/hexapdf/font/true_type/table/maxp.rb +112 -0
  102. data/lib/hexapdf/font/true_type/table/name.rb +218 -0
  103. data/lib/hexapdf/font/true_type/table/os2.rb +200 -0
  104. data/lib/hexapdf/font/true_type/table/post.rb +230 -0
  105. data/lib/hexapdf/font/true_type/table.rb +155 -0
  106. data/lib/hexapdf/font/true_type.rb +48 -0
  107. data/lib/hexapdf/font/true_type_wrapper.rb +240 -0
  108. data/lib/hexapdf/font/type1/afm_parser.rb +230 -0
  109. data/lib/hexapdf/font/type1/character_metrics.rb +67 -0
  110. data/lib/hexapdf/font/type1/font.rb +123 -0
  111. data/lib/hexapdf/font/type1/font_metrics.rb +117 -0
  112. data/lib/hexapdf/font/type1/pfb_parser.rb +71 -0
  113. data/lib/hexapdf/font/type1.rb +52 -0
  114. data/lib/hexapdf/font/type1_wrapper.rb +193 -0
  115. data/lib/hexapdf/font_loader/from_configuration.rb +70 -0
  116. data/lib/hexapdf/font_loader/standard14.rb +98 -0
  117. data/lib/hexapdf/font_loader.rb +85 -0
  118. data/lib/hexapdf/font_utils.rb +89 -0
  119. data/lib/hexapdf/image_loader/jpeg.rb +166 -0
  120. data/lib/hexapdf/image_loader/pdf.rb +89 -0
  121. data/lib/hexapdf/image_loader/png.rb +410 -0
  122. data/lib/hexapdf/image_loader.rb +68 -0
  123. data/lib/hexapdf/importer.rb +139 -0
  124. data/lib/hexapdf/name_tree_node.rb +78 -0
  125. data/lib/hexapdf/number_tree_node.rb +67 -0
  126. data/lib/hexapdf/object.rb +363 -0
  127. data/lib/hexapdf/parser.rb +349 -0
  128. data/lib/hexapdf/rectangle.rb +99 -0
  129. data/lib/hexapdf/reference.rb +98 -0
  130. data/lib/hexapdf/revision.rb +206 -0
  131. data/lib/hexapdf/revisions.rb +194 -0
  132. data/lib/hexapdf/serializer.rb +326 -0
  133. data/lib/hexapdf/stream.rb +279 -0
  134. data/lib/hexapdf/task/dereference.rb +109 -0
  135. data/lib/hexapdf/task/optimize.rb +230 -0
  136. data/lib/hexapdf/task.rb +68 -0
  137. data/lib/hexapdf/tokenizer.rb +406 -0
  138. data/lib/hexapdf/type/catalog.rb +107 -0
  139. data/lib/hexapdf/type/embedded_file.rb +87 -0
  140. data/lib/hexapdf/type/file_specification.rb +232 -0
  141. data/lib/hexapdf/type/font.rb +81 -0
  142. data/lib/hexapdf/type/font_descriptor.rb +109 -0
  143. data/lib/hexapdf/type/font_simple.rb +190 -0
  144. data/lib/hexapdf/type/font_true_type.rb +47 -0
  145. data/lib/hexapdf/type/font_type1.rb +162 -0
  146. data/lib/hexapdf/type/form.rb +103 -0
  147. data/lib/hexapdf/type/graphics_state_parameter.rb +79 -0
  148. data/lib/hexapdf/type/image.rb +73 -0
  149. data/lib/hexapdf/type/info.rb +70 -0
  150. data/lib/hexapdf/type/names.rb +69 -0
  151. data/lib/hexapdf/type/object_stream.rb +224 -0
  152. data/lib/hexapdf/type/page.rb +355 -0
  153. data/lib/hexapdf/type/page_tree_node.rb +269 -0
  154. data/lib/hexapdf/type/resources.rb +212 -0
  155. data/lib/hexapdf/type/trailer.rb +128 -0
  156. data/lib/hexapdf/type/viewer_preferences.rb +73 -0
  157. data/lib/hexapdf/type/xref_stream.rb +204 -0
  158. data/lib/hexapdf/type.rb +67 -0
  159. data/lib/hexapdf/utils/bit_field.rb +87 -0
  160. data/lib/hexapdf/utils/bit_stream.rb +148 -0
  161. data/lib/hexapdf/utils/lru_cache.rb +65 -0
  162. data/lib/hexapdf/utils/math_helpers.rb +55 -0
  163. data/lib/hexapdf/utils/object_hash.rb +130 -0
  164. data/lib/hexapdf/utils/pdf_doc_encoding.rb +93 -0
  165. data/lib/hexapdf/utils/sorted_tree_node.rb +339 -0
  166. data/lib/hexapdf/version.rb +39 -0
  167. data/lib/hexapdf/writer.rb +199 -0
  168. data/lib/hexapdf/xref_section.rb +152 -0
  169. data/lib/hexapdf.rb +34 -0
  170. data/man/man1/hexapdf.1 +249 -0
  171. data/test/data/aes-test-vectors/CBCGFSbox-128-decrypt.data.gz +0 -0
  172. data/test/data/aes-test-vectors/CBCGFSbox-128-encrypt.data.gz +0 -0
  173. data/test/data/aes-test-vectors/CBCGFSbox-192-decrypt.data.gz +0 -0
  174. data/test/data/aes-test-vectors/CBCGFSbox-192-encrypt.data.gz +0 -0
  175. data/test/data/aes-test-vectors/CBCGFSbox-256-decrypt.data.gz +0 -0
  176. data/test/data/aes-test-vectors/CBCGFSbox-256-encrypt.data.gz +0 -0
  177. data/test/data/aes-test-vectors/CBCKeySbox-128-decrypt.data.gz +0 -0
  178. data/test/data/aes-test-vectors/CBCKeySbox-128-encrypt.data.gz +0 -0
  179. data/test/data/aes-test-vectors/CBCKeySbox-192-decrypt.data.gz +0 -0
  180. data/test/data/aes-test-vectors/CBCKeySbox-192-encrypt.data.gz +0 -0
  181. data/test/data/aes-test-vectors/CBCKeySbox-256-decrypt.data.gz +0 -0
  182. data/test/data/aes-test-vectors/CBCKeySbox-256-encrypt.data.gz +0 -0
  183. data/test/data/aes-test-vectors/CBCVarKey-128-decrypt.data.gz +0 -0
  184. data/test/data/aes-test-vectors/CBCVarKey-128-encrypt.data.gz +0 -0
  185. data/test/data/aes-test-vectors/CBCVarKey-192-decrypt.data.gz +0 -0
  186. data/test/data/aes-test-vectors/CBCVarKey-192-encrypt.data.gz +0 -0
  187. data/test/data/aes-test-vectors/CBCVarKey-256-decrypt.data.gz +0 -0
  188. data/test/data/aes-test-vectors/CBCVarKey-256-encrypt.data.gz +0 -0
  189. data/test/data/aes-test-vectors/CBCVarTxt-128-decrypt.data.gz +0 -0
  190. data/test/data/aes-test-vectors/CBCVarTxt-128-encrypt.data.gz +0 -0
  191. data/test/data/aes-test-vectors/CBCVarTxt-192-decrypt.data.gz +0 -0
  192. data/test/data/aes-test-vectors/CBCVarTxt-192-encrypt.data.gz +0 -0
  193. data/test/data/aes-test-vectors/CBCVarTxt-256-decrypt.data.gz +0 -0
  194. data/test/data/aes-test-vectors/CBCVarTxt-256-encrypt.data.gz +0 -0
  195. data/test/data/fonts/Ubuntu-Title.ttf +0 -0
  196. data/test/data/images/cmyk.jpg +0 -0
  197. data/test/data/images/fillbytes.jpg +0 -0
  198. data/test/data/images/gray.jpg +0 -0
  199. data/test/data/images/greyscale-1bit.png +0 -0
  200. data/test/data/images/greyscale-2bit.png +0 -0
  201. data/test/data/images/greyscale-4bit.png +0 -0
  202. data/test/data/images/greyscale-8bit.png +0 -0
  203. data/test/data/images/greyscale-alpha-8bit.png +0 -0
  204. data/test/data/images/greyscale-trns-8bit.png +0 -0
  205. data/test/data/images/greyscale-with-gamma1.0.png +0 -0
  206. data/test/data/images/greyscale-with-gamma1.5.png +0 -0
  207. data/test/data/images/indexed-1bit.png +0 -0
  208. data/test/data/images/indexed-2bit.png +0 -0
  209. data/test/data/images/indexed-4bit.png +0 -0
  210. data/test/data/images/indexed-8bit.png +0 -0
  211. data/test/data/images/indexed-alpha-4bit.png +0 -0
  212. data/test/data/images/indexed-alpha-8bit.png +0 -0
  213. data/test/data/images/rgb.jpg +0 -0
  214. data/test/data/images/truecolour-8bit.png +0 -0
  215. data/test/data/images/truecolour-alpha-8bit.png +0 -0
  216. data/test/data/images/truecolour-gama-chrm-8bit.png +0 -0
  217. data/test/data/images/truecolour-srgb-8bit.png +0 -0
  218. data/test/data/minimal.pdf +44 -0
  219. data/test/data/standard-security-handler/README +9 -0
  220. data/test/data/standard-security-handler/bothpwd-aes-128bit-V4.pdf +44 -0
  221. data/test/data/standard-security-handler/bothpwd-aes-256bit-V5.pdf +0 -0
  222. data/test/data/standard-security-handler/bothpwd-arc4-128bit-V2.pdf +43 -0
  223. data/test/data/standard-security-handler/bothpwd-arc4-128bit-V4.pdf +43 -0
  224. data/test/data/standard-security-handler/bothpwd-arc4-40bit-V1.pdf +0 -0
  225. data/test/data/standard-security-handler/nopwd-aes-128bit-V4.pdf +43 -0
  226. data/test/data/standard-security-handler/nopwd-aes-256bit-V5.pdf +0 -0
  227. data/test/data/standard-security-handler/nopwd-arc4-128bit-V2.pdf +43 -0
  228. data/test/data/standard-security-handler/nopwd-arc4-128bit-V4.pdf +43 -0
  229. data/test/data/standard-security-handler/nopwd-arc4-40bit-V1.pdf +43 -0
  230. data/test/data/standard-security-handler/ownerpwd-aes-128bit-V4.pdf +0 -0
  231. data/test/data/standard-security-handler/ownerpwd-aes-256bit-V5.pdf +43 -0
  232. data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V2.pdf +43 -0
  233. data/test/data/standard-security-handler/ownerpwd-arc4-128bit-V4.pdf +43 -0
  234. data/test/data/standard-security-handler/ownerpwd-arc4-40bit-V1.pdf +43 -0
  235. data/test/data/standard-security-handler/userpwd-aes-128bit-V4.pdf +43 -0
  236. data/test/data/standard-security-handler/userpwd-aes-256bit-V5.pdf +43 -0
  237. data/test/data/standard-security-handler/userpwd-arc4-128bit-V2.pdf +0 -0
  238. data/test/data/standard-security-handler/userpwd-arc4-128bit-V4.pdf +0 -0
  239. data/test/data/standard-security-handler/userpwd-arc4-40bit-V1.pdf +43 -0
  240. data/test/hexapdf/common_tokenizer_tests.rb +204 -0
  241. data/test/hexapdf/content/common.rb +31 -0
  242. data/test/hexapdf/content/graphic_object/test_arc.rb +93 -0
  243. data/test/hexapdf/content/graphic_object/test_endpoint_arc.rb +91 -0
  244. data/test/hexapdf/content/graphic_object/test_solid_arc.rb +86 -0
  245. data/test/hexapdf/content/test_canvas.rb +1113 -0
  246. data/test/hexapdf/content/test_color_space.rb +97 -0
  247. data/test/hexapdf/content/test_graphics_state.rb +138 -0
  248. data/test/hexapdf/content/test_operator.rb +619 -0
  249. data/test/hexapdf/content/test_parser.rb +66 -0
  250. data/test/hexapdf/content/test_processor.rb +156 -0
  251. data/test/hexapdf/content/test_transformation_matrix.rb +64 -0
  252. data/test/hexapdf/encryption/common.rb +87 -0
  253. data/test/hexapdf/encryption/test_aes.rb +121 -0
  254. data/test/hexapdf/encryption/test_arc4.rb +39 -0
  255. data/test/hexapdf/encryption/test_fast_aes.rb +17 -0
  256. data/test/hexapdf/encryption/test_fast_arc4.rb +12 -0
  257. data/test/hexapdf/encryption/test_identity.rb +21 -0
  258. data/test/hexapdf/encryption/test_ruby_aes.rb +23 -0
  259. data/test/hexapdf/encryption/test_ruby_arc4.rb +20 -0
  260. data/test/hexapdf/encryption/test_security_handler.rb +356 -0
  261. data/test/hexapdf/encryption/test_standard_security_handler.rb +274 -0
  262. data/test/hexapdf/filter/common.rb +53 -0
  263. data/test/hexapdf/filter/test_ascii85_decode.rb +60 -0
  264. data/test/hexapdf/filter/test_ascii_hex_decode.rb +33 -0
  265. data/test/hexapdf/filter/test_encryption.rb +24 -0
  266. data/test/hexapdf/filter/test_flate_decode.rb +35 -0
  267. data/test/hexapdf/filter/test_lzw_decode.rb +52 -0
  268. data/test/hexapdf/filter/test_predictor.rb +183 -0
  269. data/test/hexapdf/filter/test_run_length_decode.rb +32 -0
  270. data/test/hexapdf/font/cmap/test_parser.rb +67 -0
  271. data/test/hexapdf/font/cmap/test_writer.rb +58 -0
  272. data/test/hexapdf/font/encoding/test_base.rb +35 -0
  273. data/test/hexapdf/font/encoding/test_difference_encoding.rb +21 -0
  274. data/test/hexapdf/font/encoding/test_glyph_list.rb +59 -0
  275. data/test/hexapdf/font/encoding/test_zapf_dingbats_encoding.rb +16 -0
  276. data/test/hexapdf/font/test_encoding.rb +27 -0
  277. data/test/hexapdf/font/test_true_type_wrapper.rb +110 -0
  278. data/test/hexapdf/font/test_type1_wrapper.rb +66 -0
  279. data/test/hexapdf/font/true_type/common.rb +19 -0
  280. data/test/hexapdf/font/true_type/table/test_cmap.rb +59 -0
  281. data/test/hexapdf/font/true_type/table/test_cmap_subtable.rb +133 -0
  282. data/test/hexapdf/font/true_type/table/test_directory.rb +35 -0
  283. data/test/hexapdf/font/true_type/table/test_glyf.rb +58 -0
  284. data/test/hexapdf/font/true_type/table/test_head.rb +76 -0
  285. data/test/hexapdf/font/true_type/table/test_hhea.rb +40 -0
  286. data/test/hexapdf/font/true_type/table/test_hmtx.rb +38 -0
  287. data/test/hexapdf/font/true_type/table/test_loca.rb +43 -0
  288. data/test/hexapdf/font/true_type/table/test_maxp.rb +62 -0
  289. data/test/hexapdf/font/true_type/table/test_name.rb +95 -0
  290. data/test/hexapdf/font/true_type/table/test_os2.rb +65 -0
  291. data/test/hexapdf/font/true_type/table/test_post.rb +89 -0
  292. data/test/hexapdf/font/true_type/test_font.rb +120 -0
  293. data/test/hexapdf/font/true_type/test_table.rb +41 -0
  294. data/test/hexapdf/font/type1/test_afm_parser.rb +51 -0
  295. data/test/hexapdf/font/type1/test_font.rb +68 -0
  296. data/test/hexapdf/font/type1/test_pfb_parser.rb +37 -0
  297. data/test/hexapdf/font_loader/test_from_configuration.rb +28 -0
  298. data/test/hexapdf/font_loader/test_standard14.rb +22 -0
  299. data/test/hexapdf/image_loader/test_jpeg.rb +83 -0
  300. data/test/hexapdf/image_loader/test_pdf.rb +47 -0
  301. data/test/hexapdf/image_loader/test_png.rb +258 -0
  302. data/test/hexapdf/task/test_dereference.rb +46 -0
  303. data/test/hexapdf/task/test_optimize.rb +137 -0
  304. data/test/hexapdf/test_configuration.rb +82 -0
  305. data/test/hexapdf/test_data_dir.rb +32 -0
  306. data/test/hexapdf/test_dictionary.rb +284 -0
  307. data/test/hexapdf/test_dictionary_fields.rb +185 -0
  308. data/test/hexapdf/test_document.rb +574 -0
  309. data/test/hexapdf/test_document_utils.rb +144 -0
  310. data/test/hexapdf/test_filter.rb +96 -0
  311. data/test/hexapdf/test_font_utils.rb +47 -0
  312. data/test/hexapdf/test_importer.rb +78 -0
  313. data/test/hexapdf/test_object.rb +177 -0
  314. data/test/hexapdf/test_parser.rb +394 -0
  315. data/test/hexapdf/test_rectangle.rb +36 -0
  316. data/test/hexapdf/test_reference.rb +41 -0
  317. data/test/hexapdf/test_revision.rb +139 -0
  318. data/test/hexapdf/test_revisions.rb +93 -0
  319. data/test/hexapdf/test_serializer.rb +169 -0
  320. data/test/hexapdf/test_stream.rb +262 -0
  321. data/test/hexapdf/test_tokenizer.rb +30 -0
  322. data/test/hexapdf/test_writer.rb +120 -0
  323. data/test/hexapdf/test_xref_section.rb +35 -0
  324. data/test/hexapdf/type/test_catalog.rb +30 -0
  325. data/test/hexapdf/type/test_embedded_file.rb +16 -0
  326. data/test/hexapdf/type/test_file_specification.rb +148 -0
  327. data/test/hexapdf/type/test_font.rb +35 -0
  328. data/test/hexapdf/type/test_font_descriptor.rb +51 -0
  329. data/test/hexapdf/type/test_font_simple.rb +190 -0
  330. data/test/hexapdf/type/test_font_type1.rb +128 -0
  331. data/test/hexapdf/type/test_form.rb +60 -0
  332. data/test/hexapdf/type/test_info.rb +14 -0
  333. data/test/hexapdf/type/test_names.rb +9 -0
  334. data/test/hexapdf/type/test_object_stream.rb +84 -0
  335. data/test/hexapdf/type/test_page.rb +260 -0
  336. data/test/hexapdf/type/test_page_tree_node.rb +255 -0
  337. data/test/hexapdf/type/test_resources.rb +167 -0
  338. data/test/hexapdf/type/test_trailer.rb +109 -0
  339. data/test/hexapdf/type/test_xref_stream.rb +131 -0
  340. data/test/hexapdf/utils/test_bit_field.rb +47 -0
  341. data/test/hexapdf/utils/test_lru_cache.rb +22 -0
  342. data/test/hexapdf/utils/test_object_hash.rb +115 -0
  343. data/test/hexapdf/utils/test_pdf_doc_encoding.rb +18 -0
  344. data/test/hexapdf/utils/test_sorted_tree_node.rb +232 -0
  345. data/test/test_helper.rb +56 -0
  346. metadata +427 -0
@@ -0,0 +1,232 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ #--
4
+ # This file is part of HexaPDF.
5
+ #
6
+ # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
+ # Copyright (C) 2016 Thomas Leitner
8
+ #
9
+ # HexaPDF is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU Affero General Public License version 3 as
11
+ # published by the Free Software Foundation with the addition of the
12
+ # following permission added to Section 15 as permitted in Section 7(a):
13
+ # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
14
+ # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
15
+ # INFRINGEMENT OF THIRD PARTY RIGHTS.
16
+ #
17
+ # HexaPDF is distributed in the hope that it will be useful, but WITHOUT
18
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
20
+ # License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Affero General Public License
23
+ # along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
24
+ #
25
+ # The interactive user interfaces in modified source and object code
26
+ # versions of HexaPDF must display Appropriate Legal Notices, as required
27
+ # under Section 5 of the GNU Affero General Public License version 3.
28
+ #
29
+ # In accordance with Section 7(b) of the GNU Affero General Public
30
+ # License, a covered work must retain the producer line in every PDF that
31
+ # is created or manipulated using HexaPDF.
32
+ #++
33
+
34
+ require 'uri'
35
+ require 'hexapdf/dictionary'
36
+ require 'hexapdf/stream'
37
+
38
+ module HexaPDF
39
+ module Type
40
+
41
+ # Represents a file specification dictionary.
42
+ #
43
+ # File specifications are used to refer to other files or URLs from within a PDF file. Simple
44
+ # file specifications are just strings. However, the are automatically converted on access to
45
+ # a full file specification to provide a unified interface.
46
+ #
47
+ # == Working with File Specifications
48
+ #
49
+ # A file specification may refer to a file or an URL. This can easily be checked with #url?.
50
+ # Independent of whether the file specification referes to an URL or a file, the #path method
51
+ # returns the "best" useable path for it.
52
+ #
53
+ # Modifying a file specification should be done via the #path= and #url= methods as they
54
+ # ensure that no obsolescent entries are used and the file specification is consistent.
55
+ #
56
+ # Finally, since embedded files in a PDF document are always linked to a file specification it
57
+ # is useful to provide embedding/unembedding operations in this class, see #embed and
58
+ # #unembed.
59
+ #
60
+ # See: PDF1.7 s7.11
61
+ class FileSpecification < Dictionary
62
+
63
+ # The type used for the /EF field of a FileSpecification
64
+ class EFDictionary < Dictionary
65
+
66
+ define_field :F, type: :EmbeddedFile
67
+ define_field :UF, type: :EmbeddedFile
68
+ define_field :DOS, type: :EmbeddedFile
69
+ define_field :Mac, type: :EmbeddedFile
70
+ define_field :Unix, type: :EmbeddedFile
71
+
72
+ # Returns +:XXFilespecEFDictionary+
73
+ def type
74
+ :XXFilespecEFDictionary
75
+ end
76
+
77
+ end
78
+
79
+
80
+ define_field :Type, type: Symbol, default: :Filespec, required: true
81
+ define_field :FS, type: Symbol
82
+ define_field :F, type: PDFByteString
83
+ define_field :UF, type: String, version: '1.7'
84
+ define_field :DOS, type: PDFByteString
85
+ define_field :Mac, type: PDFByteString
86
+ define_field :Unix, type: PDFByteString
87
+ define_field :ID, type: Array
88
+ define_field :V, type: Boolean, version: '1.2'
89
+ define_field :EF, type: :XXFilespecEFDictionary, version: '1.7'
90
+ define_field :RF, type: Dictionary, version: '1.3'
91
+ define_field :Desc, type: String, version: '1.6'
92
+ define_field :CI, type: Dictionary, version: '1.7'
93
+
94
+
95
+ # Returns +true+ if this file specification references an URL and not a file.
96
+ def url?
97
+ self[:FS] == :URL
98
+ end
99
+
100
+ # Returns the path for the referenced file or URL. An empty string is returned if no file
101
+ # specification string is set.
102
+ #
103
+ # If multiple file specification strings are available, the fields are search in the
104
+ # following order and the first one with a value is used: /UF, /F, /Unix, /Mac, /DOS.
105
+ #
106
+ # The encoding of the returned path string is either UTF-8 (for /UF) or BINARY (for /F
107
+ # /Unix, /Mac and /DOS).
108
+ def path
109
+ tmp = (self[:UF] || self[:F] || self[:Unix] || self[:Mac] || self[:DOS] || '').dup
110
+ tmp.gsub!(/\\\//, "/") # PDF1.7 s7.11.2.1 but / in filename is interpreted as separator!
111
+ tmp.gsub!(/\\/, "/") # always use slashes instead of back-slashes!
112
+ tmp
113
+ end
114
+
115
+ # Sets the file specification string to the given filename.
116
+ #
117
+ # Since the /Unix, /Mac and /DOS fields are obsolescent, only the /F and /UF fields are set.
118
+ def path=(filename)
119
+ self[:UF] = self[:F] = filename
120
+ delete(:FS)
121
+ delete(:Unix)
122
+ delete(:Mac)
123
+ delete(:DOS)
124
+ end
125
+
126
+ # Sets the file specification string to the given URL and updates the file system entry
127
+ # appropriately.
128
+ #
129
+ # The provided URL needs to be in an RFC1738 compliant string representation. If not, an
130
+ # error is raised.
131
+ def url=(url)
132
+ begin
133
+ URI(url)
134
+ rescue URI::InvalidURIError => e
135
+ raise HexaPDF::Error.new(e)
136
+ end
137
+ self.path = url
138
+ self[:FS] = :URL
139
+ end
140
+
141
+ # Returns +true+ if this file specification contains an embedded file.
142
+ #
143
+ # See: #embedded_file_stream
144
+ def embedded_file?
145
+ key?(:EF) && !self[:EF].empty?
146
+ end
147
+
148
+ # Returns the embedded file associated with this file specification, or +nil+ if this file
149
+ # specification references no embedded file.
150
+ #
151
+ # If there are multiple possible embedded files, the /EF fields are searched in the following
152
+ # order and the first one with a value is used: /UF, /F, /Unix, /Mac, /DOS.
153
+ def embedded_file_stream
154
+ return unless key?(:EF)
155
+ ef = self[:EF]
156
+ ef[:UF] || ef[:F] || ef[:Unix] || ef[:Mac] || ef[:DOS]
157
+ end
158
+
159
+ # :call-seq:
160
+ # file_spec.embed(filename, name: File.basename(filename), register: true) -> ef_stream
161
+ # file_spec.embed(io, name:, register: true) -> ef_stream
162
+ #
163
+ # Embeds the given file or IO stream into the PDF file, sets the path accordingly and returns
164
+ # the created stream object.
165
+ #
166
+ # If a file is given, the +name+ option defaults to the basename of the file. However, if an
167
+ # IO object is given, the +name+ argument is mandatory.
168
+ #
169
+ # If there already was a file embedded for this file specification, it is unembedded first.
170
+ #
171
+ # The embedded file stream automatically uses the FlateEncode filter for compressing the
172
+ # embedded file.
173
+ #
174
+ # Options:
175
+ #
176
+ # name::
177
+ # The name that should be used as path value and when registering.
178
+ #
179
+ # register::
180
+ # Specifies whether the embedded file will be added to the EmbeddedFiles name tree under
181
+ # the +name+. If the name is already taken, it's value is overwritten.
182
+ #
183
+ # The file has to be available until the PDF document gets written because reading and
184
+ # writing is done lazily.
185
+ def embed(file_or_io, name: nil, register: true)
186
+ name ||= File.basename(file_or_io) if file_or_io.kind_of?(String)
187
+ if name.nil?
188
+ raise ArgumentError, "The name argument is mandatory when given an IO object"
189
+ end
190
+
191
+ unembed
192
+ self.path = name
193
+
194
+ self[:EF] ||= {}
195
+ ef_stream = self[:EF][:UF] = self[:EF][:F] = document.add(Type: :EmbeddedFile)
196
+ stat = if file_or_io.kind_of?(String)
197
+ File.stat(file_or_io)
198
+ elsif file_or_io.respond_to?(:stat)
199
+ file_or_io.stat
200
+ end
201
+ if stat
202
+ ef_stream[:Params] = {Size: stat.size, CreationDate: stat.ctime, ModDate: stat.mtime}
203
+ end
204
+ ef_stream.set_filter(:FlateDecode)
205
+ ef_stream.stream = HexaPDF::StreamData.new(file_or_io)
206
+
207
+ if register
208
+ (document.catalog[:Names] ||= {})[:EmbeddedFiles] ||= {}
209
+ document.catalog[:Names][:EmbeddedFiles].add_entry(name, self)
210
+ end
211
+
212
+ ef_stream
213
+ end
214
+
215
+ # Deletes any embedded file streams associated with this file specification. A possible entry
216
+ # in the EmbeddedFiles name tree is also deleted.
217
+ def unembed
218
+ return unless key?(:EF)
219
+ self[:EF].each {|_key, ef_stream| document.delete(ef_stream)}
220
+
221
+ if document.catalog.key?(:Names) && document.catalog[:Names].key?(:EmbeddedFiles)
222
+ tree = document.catalog[:Names][:EmbeddedFiles]
223
+ tree.each_entry.find_all {|_, spec| document.deref(spec) == self}.each do |name, _|
224
+ tree.delete_entry(name)
225
+ end
226
+ end
227
+ end
228
+
229
+ end
230
+
231
+ end
232
+ end
@@ -0,0 +1,81 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ #--
4
+ # This file is part of HexaPDF.
5
+ #
6
+ # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
+ # Copyright (C) 2016 Thomas Leitner
8
+ #
9
+ # HexaPDF is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU Affero General Public License version 3 as
11
+ # published by the Free Software Foundation with the addition of the
12
+ # following permission added to Section 15 as permitted in Section 7(a):
13
+ # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
14
+ # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
15
+ # INFRINGEMENT OF THIRD PARTY RIGHTS.
16
+ #
17
+ # HexaPDF is distributed in the hope that it will be useful, but WITHOUT
18
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
20
+ # License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Affero General Public License
23
+ # along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
24
+ #
25
+ # The interactive user interfaces in modified source and object code
26
+ # versions of HexaPDF must display Appropriate Legal Notices, as required
27
+ # under Section 5 of the GNU Affero General Public License version 3.
28
+ #
29
+ # In accordance with Section 7(b) of the GNU Affero General Public
30
+ # License, a covered work must retain the producer line in every PDF that
31
+ # is created or manipulated using HexaPDF.
32
+ #++
33
+
34
+ require 'hexapdf/stream'
35
+ require 'hexapdf/font/cmap'
36
+
37
+ module HexaPDF
38
+ module Type
39
+
40
+ # Represents a generic font object.
41
+ #
42
+ # This class is the base class for all font objects, be it simple fonts or composite fonts.
43
+ class Font < Dictionary
44
+
45
+ define_field :Type, type: Symbol, required: true, default: :Font
46
+ define_field :BaseFont, type: Symbol, required: true
47
+ define_field :ToUnicode, type: Stream, version: '1.2'
48
+
49
+ # Font objects must always be indirect.
50
+ def must_be_indirect?
51
+ true
52
+ end
53
+
54
+ # Returns the UTF-8 string for the given character code, or an empty string if no mapping was
55
+ # found.
56
+ def to_utf8(code)
57
+ if to_unicode_cmap
58
+ to_unicode_cmap.to_unicode(code)
59
+ else
60
+ ''.freeze
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ # Parses and caches the ToUnicode CMap.
67
+ def to_unicode_cmap
68
+ unless defined?(@to_unicode_cmap)
69
+ @to_unicode_cmap = if key?(:ToUnicode)
70
+ HexaPDF::Font::CMap.parse(self[:ToUnicode].stream)
71
+ else
72
+ nil
73
+ end
74
+ end
75
+ @to_unicode_cmap
76
+ end
77
+
78
+ end
79
+
80
+ end
81
+ end
@@ -0,0 +1,109 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ #--
4
+ # This file is part of HexaPDF.
5
+ #
6
+ # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
+ # Copyright (C) 2016 Thomas Leitner
8
+ #
9
+ # HexaPDF is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU Affero General Public License version 3 as
11
+ # published by the Free Software Foundation with the addition of the
12
+ # following permission added to Section 15 as permitted in Section 7(a):
13
+ # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
14
+ # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
15
+ # INFRINGEMENT OF THIRD PARTY RIGHTS.
16
+ #
17
+ # HexaPDF is distributed in the hope that it will be useful, but WITHOUT
18
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
20
+ # License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Affero General Public License
23
+ # along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
24
+ #
25
+ # The interactive user interfaces in modified source and object code
26
+ # versions of HexaPDF must display Appropriate Legal Notices, as required
27
+ # under Section 5 of the GNU Affero General Public License version 3.
28
+ #
29
+ # In accordance with Section 7(b) of the GNU Affero General Public
30
+ # License, a covered work must retain the producer line in every PDF that
31
+ # is created or manipulated using HexaPDF.
32
+ #++
33
+
34
+ require 'hexapdf/dictionary'
35
+ require 'hexapdf/stream'
36
+ require 'hexapdf/utils/bit_field'
37
+
38
+ module HexaPDF
39
+ module Type
40
+
41
+ # This class specifies metrics and other attributes of a simple font or a CID font as a
42
+ # whole.
43
+ #
44
+ # See: PDF1.7 s9.8
45
+ class FontDescriptor < Dictionary
46
+
47
+ extend Utils::BitField
48
+
49
+ define_field :Type, type: Symbol, required: true, default: :FontDescriptor
50
+ define_field :FontName, type: Symbol, required: true
51
+ define_field :FontFamily, type: PDFByteString, version: '1.5'
52
+ define_field :FontStretch, type: Symbol, version: '1.5'
53
+ define_field :FontWeight, type: Numeric, version: '1.5'
54
+ define_field :Flags, type: Integer, required: true
55
+ define_field :FontBBox, type: Rectangle
56
+ define_field :ItalicAngle, type: Numeric, required: true
57
+ define_field :Ascent, type: Numeric
58
+ define_field :Descent, type: Numeric
59
+ define_field :Leading, type: Numeric, default: 0
60
+ define_field :CapHeight, type: Numeric
61
+ define_field :XHeight, type: Numeric, default: 0
62
+ define_field :StemV, type: Numeric
63
+ define_field :StemH, type: Numeric, default: 0
64
+ define_field :AvgWidth, type: Numeric, default: 0
65
+ define_field :MaxWidth, type: Numeric, default: 0
66
+ define_field :MissingWidth, type: Numeric, default: 0
67
+ define_field :FontFile, type: Stream
68
+ define_field :FontFile2, type: Stream, version: '1.1'
69
+ define_field :FontFile3, type: Stream, version: '1.2'
70
+ define_field :CharSet, type: [String, PDFByteString], version: '1.1'
71
+
72
+ define_field :Style, type: Dictionary
73
+ define_field :Lang, type: Symbol, version: '1.5'
74
+ define_field :FD, type: Dictionary
75
+ define_field :CIDSet, type: Stream
76
+
77
+
78
+ bit_field(:raw_flags, {fixed_pitch: 0, serif: 1, symbolic: 2, script: 3, nonsymbolic: 5,
79
+ italic: 6, all_cap: 16, small_cap: 17, force_bold: 18},
80
+ lister: "flags", getter: "flagged?", setter: "flag")
81
+
82
+ private
83
+
84
+ # Helper method for bit field getter access.
85
+ def raw_flags
86
+ self[:Flags]
87
+ end
88
+
89
+ # Helper method for bit field setter access.
90
+ def raw_flags=(value)
91
+ self[:Flags] = value
92
+ end
93
+
94
+ def perform_validation #:nodoc:
95
+ super
96
+ if [self[:FontFile], self[:FontFile2], self[:FontFile3]].compact.size > 1
97
+ yield("Only one of /FontFile, /FontFile2 or /FontFile3 may be set", false)
98
+ end
99
+
100
+ descent = self[:Descent]
101
+ if descent && descent > 0
102
+ yield("The /Descent value needs to be a negative number", false)
103
+ end
104
+ end
105
+
106
+ end
107
+
108
+ end
109
+ end
@@ -0,0 +1,190 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ #--
4
+ # This file is part of HexaPDF.
5
+ #
6
+ # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
+ # Copyright (C) 2016 Thomas Leitner
8
+ #
9
+ # HexaPDF is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU Affero General Public License version 3 as
11
+ # published by the Free Software Foundation with the addition of the
12
+ # following permission added to Section 15 as permitted in Section 7(a):
13
+ # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
14
+ # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
15
+ # INFRINGEMENT OF THIRD PARTY RIGHTS.
16
+ #
17
+ # HexaPDF is distributed in the hope that it will be useful, but WITHOUT
18
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
20
+ # License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Affero General Public License
23
+ # along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
24
+ #
25
+ # The interactive user interfaces in modified source and object code
26
+ # versions of HexaPDF must display Appropriate Legal Notices, as required
27
+ # under Section 5 of the GNU Affero General Public License version 3.
28
+ #
29
+ # In accordance with Section 7(b) of the GNU Affero General Public
30
+ # License, a covered work must retain the producer line in every PDF that
31
+ # is created or manipulated using HexaPDF.
32
+ #++
33
+
34
+ require 'hexapdf/type/font'
35
+ require 'hexapdf/font/encoding'
36
+
37
+ module HexaPDF
38
+ module Type
39
+
40
+ # Represents a simple PDF font.
41
+ #
42
+ # A simple font has only single-byte character codes and only supports horizontal metrics.
43
+ #
44
+ # See: PDF1.7 s9.6
45
+ class FontSimple < Font
46
+
47
+ define_field :FirstChar, type: Integer
48
+ define_field :LastChar, type: Integer
49
+ define_field :Widths, type: Array
50
+ define_field :FontDescriptor, type: :FontDescriptor, indirect: true
51
+ define_field :Encoding, type: [Symbol, Dictionary, Hash]
52
+
53
+ # Returns the encoding object used for this font.
54
+ #
55
+ # Note that the encoding is cached internally when accessed the first time.
56
+ def encoding
57
+ @encoding ||=
58
+ begin
59
+ case (val = self[:Encoding])
60
+ when Symbol
61
+ encoding = HexaPDF::Font::Encoding.for_name(val)
62
+ encoding = encoding_from_font if encoding.nil?
63
+ encoding
64
+ when HexaPDF::Dictionary, Hash
65
+ encoding = val[:BaseEncoding]
66
+ encoding = HexaPDF::Font::Encoding.for_name(encoding) if encoding
67
+ unless encoding
68
+ if embedded? || symbolic?
69
+ encoding = encoding_from_font
70
+ else
71
+ encoding = HexaPDF::Font::Encoding.for_name(:StandardEncoding)
72
+ end
73
+ end
74
+ encoding = difference_encoding(encoding, val[:Differences]) if val.key?(:Differences)
75
+ encoding
76
+ when nil
77
+ encoding_from_font
78
+ else
79
+ raise HexaPDF::Error, "Unknown value for font's encoding: #{self[:Encoding]}"
80
+ end
81
+ end
82
+ end
83
+
84
+ # Decodes the given string into an array of character codes.
85
+ def decode(string)
86
+ string.bytes
87
+ end
88
+
89
+ # Returns the UTF-8 string for the given character code, or an empty string if no mapping was
90
+ # found.
91
+ def to_utf8(code)
92
+ str = super
93
+ str = encoding.unicode(code) if str.empty?
94
+ str
95
+ end
96
+
97
+ # Returns the unscaled width of the given code point in glyph units, or 0 if the width for
98
+ # the code point is missing.
99
+ def width(code)
100
+ widths = self[:Widths]
101
+ first_char = self[:FirstChar] || -1
102
+ last_char = self[:LastChar] || -1
103
+
104
+ if widths && code >= first_char && code <= last_char
105
+ widths[code - first_char]
106
+ elsif widths && key?(:FontDescriptor)
107
+ self[:FontDescriptor][:MissingWidth]
108
+ else
109
+ 0
110
+ end
111
+ end
112
+
113
+ # Returns the bounding box of the font or +nil+ if it is not found.
114
+ def bounding_box
115
+ if key?(:FontDescriptor) && self[:FontDescriptor].key?(:FontBBox)
116
+ self[:FontDescriptor][:FontBBox].value
117
+ else
118
+ nil
119
+ end
120
+ end
121
+
122
+ # Returns the writing mode which is always :horizontal for simple fonts like Type1.
123
+ def writing_mode
124
+ :horizontal
125
+ end
126
+
127
+ # Returns +true+ if the font is embedded.
128
+ def embedded?
129
+ dict = self[:FontDescriptor]
130
+ dict && (dict[:FontFile] || dict[:FontFile2] || dict[:FontFile3])
131
+ end
132
+
133
+ # Returns +true+ if the font is a symbolic font, +false+ if it is not, and +nil+ if it is
134
+ # not known.
135
+ def symbolic?
136
+ self[:FontDescriptor] && self[:FontDescriptor].flagged?(:symbolic) || nil
137
+ end
138
+
139
+ private
140
+
141
+ # Tries to read the encoding from the embedded font.
142
+ #
143
+ # This method has to be implemented in subclasses.
144
+ def encoding_from_font
145
+ raise NotImplementedError
146
+ end
147
+
148
+ # Uses the given base encoding and the differences array to create a DifferenceEncoding
149
+ # object.
150
+ def difference_encoding(base_encoding, differences)
151
+ unless differences[0].kind_of?(Integer)
152
+ raise HexaPDF::Error, "Invalid /Differences array in Encoding dict"
153
+ end
154
+
155
+ encoding = HexaPDF::Font::Encoding::DifferenceEncoding.new(base_encoding)
156
+ code = nil
157
+ differences.each do |entry|
158
+ case entry
159
+ when Symbol
160
+ encoding.code_to_name[code] = entry
161
+ code += 1
162
+ when Integer
163
+ code = entry
164
+ else
165
+ raise HexaPDF::Error, "Invalid /Differences array in Encoding dict"
166
+ end
167
+ end
168
+ encoding
169
+ end
170
+
171
+ # Validates the simple font dictionary.
172
+ #
173
+ # If +ignore_missing_font_fields+ is +true+, then missing fields are ignored (should only be
174
+ # used for backwards-compatibility regarding the Standard 14 Type1 fonts).
175
+ def perform_validation(ignore_missing_font_fields: false)
176
+ super()
177
+ return if ignore_missing_font_fields
178
+
179
+ [:FirstChar, :LastChar, :Widths, :FontDescriptor].each do |field|
180
+ yield("Required field #{field} is not set", false) if self[field].nil?
181
+ end
182
+ if self[:Widths].length != (self[:LastChar] - self[:FirstChar] + 1)
183
+ yield("Invalid number of entries in field Widths", false)
184
+ end
185
+ end
186
+
187
+ end
188
+
189
+ end
190
+ end
@@ -0,0 +1,47 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ #--
4
+ # This file is part of HexaPDF.
5
+ #
6
+ # HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
7
+ # Copyright (C) 2016 Thomas Leitner
8
+ #
9
+ # HexaPDF is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU Affero General Public License version 3 as
11
+ # published by the Free Software Foundation with the addition of the
12
+ # following permission added to Section 15 as permitted in Section 7(a):
13
+ # FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
14
+ # THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
15
+ # INFRINGEMENT OF THIRD PARTY RIGHTS.
16
+ #
17
+ # HexaPDF is distributed in the hope that it will be useful, but WITHOUT
18
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
20
+ # License for more details.
21
+ #
22
+ # You should have received a copy of the GNU Affero General Public License
23
+ # along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
24
+ #
25
+ # The interactive user interfaces in modified source and object code
26
+ # versions of HexaPDF must display Appropriate Legal Notices, as required
27
+ # under Section 5 of the GNU Affero General Public License version 3.
28
+ #
29
+ # In accordance with Section 7(b) of the GNU Affero General Public
30
+ # License, a covered work must retain the producer line in every PDF that
31
+ # is created or manipulated using HexaPDF.
32
+ #++
33
+
34
+ require 'hexapdf/type/font_simple'
35
+
36
+ module HexaPDF
37
+ module Type
38
+
39
+ # Represents a TrueType font.
40
+ class FontTrueType < FontSimple
41
+
42
+ define_field :Subtype, type: Symbol, required: true, default: :TrueType
43
+
44
+ end
45
+
46
+ end
47
+ end