html-to-markdown 2.24.6 → 2.25.1

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 (231) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +2 -2
  3. data/README.md +1 -1
  4. data/ext/html-to-markdown-rb/native/Cargo.lock +9 -32
  5. data/ext/html-to-markdown-rb/native/Cargo.toml +1 -1
  6. data/lib/html_to_markdown/version.rb +1 -1
  7. data/rust-vendor/html-to-markdown-rs/Cargo.toml +0 -1
  8. data/rust-vendor/html-to-markdown-rs/src/converter/main_helpers.rs +1 -1
  9. data/rust-vendor/html-to-markdown-rs/src/hocr/converter/hierarchy.rs +20 -5
  10. data/rust-vendor/html-to-markdown-rs/src/lib.rs +1 -0
  11. data/rust-vendor/{markup5ever_rcdom/lib.rs → html-to-markdown-rs/src/rcdom.rs} +56 -91
  12. data/rust-vendor/html-to-markdown-rs/tests/hocr_compliance_test.rs +157 -0
  13. data/rust-vendor/memmap2/.cargo-checksum.json +1 -1
  14. data/rust-vendor/memmap2/.cargo_vcs_info.json +1 -1
  15. data/rust-vendor/memmap2/CHANGELOG.md +8 -0
  16. data/rust-vendor/memmap2/Cargo.lock +1 -1
  17. data/rust-vendor/memmap2/Cargo.toml +2 -1
  18. data/rust-vendor/memmap2/Cargo.toml.orig +2 -1
  19. data/rust-vendor/memmap2/src/lib.rs +25 -1
  20. data/rust-vendor/memmap2/src/stub.rs +1 -4
  21. data/rust-vendor/memmap2/src/unix.rs +14 -1
  22. data/rust-vendor/png/.cargo-checksum.json +1 -1
  23. data/rust-vendor/png/.cargo_vcs_info.json +1 -1
  24. data/rust-vendor/png/CHANGES.md +44 -0
  25. data/rust-vendor/png/Cargo.lock +124 -171
  26. data/rust-vendor/png/Cargo.toml +1 -1
  27. data/rust-vendor/png/Cargo.toml.orig +1 -1
  28. data/rust-vendor/png/benches/expand_paletted.rs +5 -5
  29. data/rust-vendor/png/benches/unfilter.rs +3 -3
  30. data/rust-vendor/png/src/adam7.rs +17 -10
  31. data/rust-vendor/png/src/common.rs +8 -8
  32. data/rust-vendor/png/src/decoder/mod.rs +53 -20
  33. data/rust-vendor/png/src/decoder/stream.rs +263 -78
  34. data/rust-vendor/png/src/decoder/unfiltering_buffer.rs +210 -53
  35. data/rust-vendor/png/src/decoder/zlib.rs +130 -90
  36. data/rust-vendor/png/src/encoder.rs +4 -2
  37. data/rust-vendor/png/src/{filter.rs → filter/mod.rs} +100 -367
  38. data/rust-vendor/png/src/filter/optimization-notes.md +104 -0
  39. data/rust-vendor/png/src/filter/paeth.rs +398 -0
  40. data/rust-vendor/png/src/filter/simd.rs +308 -0
  41. data/rust-vendor/png/src/lib.rs +1 -0
  42. data/rust-vendor/syn/.cargo-checksum.json +1 -1
  43. data/rust-vendor/syn/.cargo_vcs_info.json +1 -1
  44. data/rust-vendor/syn/Cargo.lock +40 -41
  45. data/rust-vendor/syn/Cargo.toml +1 -1
  46. data/rust-vendor/syn/Cargo.toml.orig +1 -1
  47. data/rust-vendor/syn/src/item.rs +61 -40
  48. data/rust-vendor/syn/src/lib.rs +2 -1
  49. data/rust-vendor/syn/tests/test_item.rs +54 -0
  50. data/rust-vendor/unicode-ident/.cargo-checksum.json +1 -1
  51. data/rust-vendor/unicode-ident/.cargo_vcs_info.json +1 -1
  52. data/rust-vendor/unicode-ident/Cargo.lock +21 -21
  53. data/rust-vendor/unicode-ident/Cargo.toml +1 -1
  54. data/rust-vendor/unicode-ident/Cargo.toml.orig +1 -1
  55. data/rust-vendor/unicode-ident/src/lib.rs +1 -1
  56. data/rust-vendor/unicode-ident/src/tables.rs +87 -97
  57. data/rust-vendor/unicode-ident/tests/static_size.rs +1 -1
  58. metadata +7 -177
  59. data/rust-vendor/markup5ever_rcdom/.cargo-checksum.json +0 -1
  60. data/rust-vendor/markup5ever_rcdom/.cargo_vcs_info.json +0 -7
  61. data/rust-vendor/markup5ever_rcdom/Cargo.lock +0 -658
  62. data/rust-vendor/markup5ever_rcdom/Cargo.toml +0 -109
  63. data/rust-vendor/markup5ever_rcdom/Cargo.toml.orig +0 -42
  64. data/rust-vendor/markup5ever_rcdom/LICENSE-APACHE +0 -201
  65. data/rust-vendor/markup5ever_rcdom/LICENSE-MIT +0 -25
  66. data/rust-vendor/markup5ever_rcdom/README.md +0 -7
  67. data/rust-vendor/markup5ever_rcdom/custom-html5lib-tokenizer-tests/regression.test +0 -69
  68. data/rust-vendor/markup5ever_rcdom/data/test/ignore +0 -1
  69. data/rust-vendor/markup5ever_rcdom/examples/hello_xml.rs +0 -39
  70. data/rust-vendor/markup5ever_rcdom/examples/html2html.rs +0 -51
  71. data/rust-vendor/markup5ever_rcdom/examples/print-rcdom.rs +0 -78
  72. data/rust-vendor/markup5ever_rcdom/examples/xml_tree_printer.rs +0 -67
  73. data/rust-vendor/markup5ever_rcdom/html5lib-tests/.gitattributes +0 -2
  74. data/rust-vendor/markup5ever_rcdom/html5lib-tests/.github/workflows/downstream.yml +0 -76
  75. data/rust-vendor/markup5ever_rcdom/html5lib-tests/.github/workflows/lint.yml +0 -25
  76. data/rust-vendor/markup5ever_rcdom/html5lib-tests/.gitignore +0 -79
  77. data/rust-vendor/markup5ever_rcdom/html5lib-tests/AUTHORS.rst +0 -34
  78. data/rust-vendor/markup5ever_rcdom/html5lib-tests/LICENSE +0 -21
  79. data/rust-vendor/markup5ever_rcdom/html5lib-tests/encoding/chardet/test_big5.txt +0 -51
  80. data/rust-vendor/markup5ever_rcdom/html5lib-tests/encoding/scripted/tests1.dat +0 -5
  81. data/rust-vendor/markup5ever_rcdom/html5lib-tests/encoding/test-yahoo-jp.dat +0 -10
  82. data/rust-vendor/markup5ever_rcdom/html5lib-tests/encoding/tests1.dat +0 -388
  83. data/rust-vendor/markup5ever_rcdom/html5lib-tests/encoding/tests2.dat +0 -115
  84. data/rust-vendor/markup5ever_rcdom/html5lib-tests/lint +0 -6
  85. data/rust-vendor/markup5ever_rcdom/html5lib-tests/lint_lib/__init__.py +0 -0
  86. data/rust-vendor/markup5ever_rcdom/html5lib-tests/lint_lib/_vendor/__init__.py +0 -0
  87. data/rust-vendor/markup5ever_rcdom/html5lib-tests/lint_lib/_vendor/funcparserlib/LICENSE +0 -18
  88. data/rust-vendor/markup5ever_rcdom/html5lib-tests/lint_lib/_vendor/funcparserlib/__init__.py +0 -0
  89. data/rust-vendor/markup5ever_rcdom/html5lib-tests/lint_lib/_vendor/funcparserlib/lexer.py +0 -211
  90. data/rust-vendor/markup5ever_rcdom/html5lib-tests/lint_lib/_vendor/funcparserlib/lexer.pyi +0 -34
  91. data/rust-vendor/markup5ever_rcdom/html5lib-tests/lint_lib/_vendor/funcparserlib/parser.py +0 -872
  92. data/rust-vendor/markup5ever_rcdom/html5lib-tests/lint_lib/_vendor/funcparserlib/parser.pyi +0 -83
  93. data/rust-vendor/markup5ever_rcdom/html5lib-tests/lint_lib/_vendor/funcparserlib/py.typed +0 -0
  94. data/rust-vendor/markup5ever_rcdom/html5lib-tests/lint_lib/_vendor/funcparserlib/util.py +0 -72
  95. data/rust-vendor/markup5ever_rcdom/html5lib-tests/lint_lib/_vendor/funcparserlib/util.pyi +0 -7
  96. data/rust-vendor/markup5ever_rcdom/html5lib-tests/lint_lib/_vendor/vendor.txt +0 -1
  97. data/rust-vendor/markup5ever_rcdom/html5lib-tests/lint_lib/_vendor-patches/funcparserlib.patch +0 -24
  98. data/rust-vendor/markup5ever_rcdom/html5lib-tests/lint_lib/lint.py +0 -280
  99. data/rust-vendor/markup5ever_rcdom/html5lib-tests/lint_lib/parser.py +0 -177
  100. data/rust-vendor/markup5ever_rcdom/html5lib-tests/pyproject.toml +0 -7
  101. data/rust-vendor/markup5ever_rcdom/html5lib-tests/serializer/core.test +0 -125
  102. data/rust-vendor/markup5ever_rcdom/html5lib-tests/serializer/injectmeta.test +0 -66
  103. data/rust-vendor/markup5ever_rcdom/html5lib-tests/serializer/optionaltags.test +0 -965
  104. data/rust-vendor/markup5ever_rcdom/html5lib-tests/serializer/options.test +0 -60
  105. data/rust-vendor/markup5ever_rcdom/html5lib-tests/serializer/whitespace.test +0 -51
  106. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tokenizer/README.md +0 -107
  107. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tokenizer/contentModelFlags.test +0 -93
  108. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tokenizer/domjs.test +0 -335
  109. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tokenizer/entities.test +0 -542
  110. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tokenizer/escapeFlag.test +0 -36
  111. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tokenizer/namedEntities.test +0 -42422
  112. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tokenizer/numericEntities.test +0 -1677
  113. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tokenizer/pendingSpecChanges.test +0 -9
  114. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tokenizer/test1.test +0 -353
  115. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tokenizer/test2.test +0 -275
  116. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tokenizer/test3.test +0 -11233
  117. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tokenizer/test4.test +0 -532
  118. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tokenizer/unicodeChars.test +0 -1577
  119. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tokenizer/unicodeCharsProblematic.test +0 -41
  120. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tokenizer/xmlViolation.test +0 -20
  121. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/README.md +0 -108
  122. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/adoption01.dat +0 -354
  123. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/adoption02.dat +0 -39
  124. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/blocks.dat +0 -695
  125. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/comments01.dat +0 -217
  126. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/doctype01.dat +0 -474
  127. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/domjs-unsafe.dat +0 -0
  128. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/entities01.dat +0 -943
  129. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/entities02.dat +0 -309
  130. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/foreign-fragment.dat +0 -645
  131. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/html5test-com.dat +0 -301
  132. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/inbody01.dat +0 -54
  133. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/isindex.dat +0 -49
  134. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/main-element.dat +0 -46
  135. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/math.dat +0 -104
  136. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/menuitem-element.dat +0 -240
  137. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/namespace-sensitivity.dat +0 -22
  138. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/noscript01.dat +0 -237
  139. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/pending-spec-changes-plain-text-unsafe.dat +0 -0
  140. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/pending-spec-changes.dat +0 -46
  141. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/plain-text-unsafe.dat +0 -0
  142. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/quirks01.dat +0 -53
  143. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/ruby.dat +0 -302
  144. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/scriptdata01.dat +0 -372
  145. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/scripted/adoption01.dat +0 -16
  146. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/scripted/ark.dat +0 -27
  147. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/scripted/webkit01.dat +0 -30
  148. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/search-element.dat +0 -46
  149. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/svg.dat +0 -104
  150. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tables01.dat +0 -322
  151. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/template.dat +0 -1673
  152. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests1.dat +0 -1956
  153. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests10.dat +0 -849
  154. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests11.dat +0 -523
  155. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests12.dat +0 -62
  156. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests14.dat +0 -75
  157. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests15.dat +0 -216
  158. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests16.dat +0 -2602
  159. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests17.dat +0 -179
  160. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests18.dat +0 -558
  161. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests19.dat +0 -1398
  162. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests2.dat +0 -831
  163. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests20.dat +0 -842
  164. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests21.dat +0 -306
  165. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests22.dat +0 -190
  166. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests23.dat +0 -168
  167. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests24.dat +0 -79
  168. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests25.dat +0 -288
  169. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests26.dat +0 -453
  170. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests3.dat +0 -305
  171. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests4.dat +0 -74
  172. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests5.dat +0 -210
  173. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests6.dat +0 -663
  174. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests7.dat +0 -453
  175. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests8.dat +0 -165
  176. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests9.dat +0 -472
  177. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tests_innerHTML_1.dat +0 -843
  178. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/tricky01.dat +0 -336
  179. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/webkit01.dat +0 -785
  180. data/rust-vendor/markup5ever_rcdom/html5lib-tests/tree-construction/webkit02.dat +0 -554
  181. data/rust-vendor/markup5ever_rcdom/tests/foreach_html5lib_test/mod.rs +0 -41
  182. data/rust-vendor/markup5ever_rcdom/tests/html-driver.rs +0 -29
  183. data/rust-vendor/markup5ever_rcdom/tests/html-serializer.rs +0 -265
  184. data/rust-vendor/markup5ever_rcdom/tests/html-tokenizer.rs +0 -487
  185. data/rust-vendor/markup5ever_rcdom/tests/html-tree-builder.rs +0 -298
  186. data/rust-vendor/markup5ever_rcdom/tests/html-tree-sink.rs +0 -141
  187. data/rust-vendor/markup5ever_rcdom/tests/util/find_tests.rs +0 -34
  188. data/rust-vendor/markup5ever_rcdom/tests/util/runner.rs +0 -48
  189. data/rust-vendor/markup5ever_rcdom/tests/xml-driver.rs +0 -101
  190. data/rust-vendor/markup5ever_rcdom/tests/xml-tokenizer.rs +0 -374
  191. data/rust-vendor/markup5ever_rcdom/tests/xml-tree-builder.rs +0 -237
  192. data/rust-vendor/markup5ever_rcdom/xml5lib-tests/AUTHORS.rst +0 -9
  193. data/rust-vendor/markup5ever_rcdom/xml5lib-tests/LICENSE +0 -21
  194. data/rust-vendor/markup5ever_rcdom/xml5lib-tests/tokenizer/README.md +0 -92
  195. data/rust-vendor/markup5ever_rcdom/xml5lib-tests/tokenizer/comments.test +0 -274
  196. data/rust-vendor/markup5ever_rcdom/xml5lib-tests/tokenizer/doctype.test +0 -3232
  197. data/rust-vendor/markup5ever_rcdom/xml5lib-tests/tokenizer/entities.test +0 -283
  198. data/rust-vendor/markup5ever_rcdom/xml5lib-tests/tokenizer/eof.test +0 -113
  199. data/rust-vendor/markup5ever_rcdom/xml5lib-tests/tokenizer/namedEntities.test +0 -42210
  200. data/rust-vendor/markup5ever_rcdom/xml5lib-tests/tokenizer/numericEntities.test +0 -1349
  201. data/rust-vendor/markup5ever_rcdom/xml5lib-tests/tokenizer/test1.test +0 -162
  202. data/rust-vendor/markup5ever_rcdom/xml5lib-tests/tokenizer/test2.test +0 -64
  203. data/rust-vendor/markup5ever_rcdom/xml5lib-tests/tokenizer/unicodeChars.test +0 -1295
  204. data/rust-vendor/markup5ever_rcdom/xml5lib-tests/tree-construction/README.md +0 -104
  205. data/rust-vendor/markup5ever_rcdom/xml5lib-tests/tree-construction/namespace.dat +0 -119
  206. data/rust-vendor/markup5ever_rcdom/xml5lib-tests/tree-construction/test1.dat +0 -124
  207. data/rust-vendor/xml5ever/.cargo-checksum.json +0 -1
  208. data/rust-vendor/xml5ever/.cargo_vcs_info.json +0 -6
  209. data/rust-vendor/xml5ever/Cargo.lock +0 -752
  210. data/rust-vendor/xml5ever/Cargo.toml +0 -69
  211. data/rust-vendor/xml5ever/Cargo.toml.orig +0 -29
  212. data/rust-vendor/xml5ever/LICENSE-APACHE +0 -201
  213. data/rust-vendor/xml5ever/LICENSE-MIT +0 -25
  214. data/rust-vendor/xml5ever/README.md +0 -72
  215. data/rust-vendor/xml5ever/benches/xml5ever.rs +0 -77
  216. data/rust-vendor/xml5ever/data/bench/strong.xml +0 -1
  217. data/rust-vendor/xml5ever/examples/README.md +0 -223
  218. data/rust-vendor/xml5ever/examples/example.xml +0 -3
  219. data/rust-vendor/xml5ever/examples/simple_xml_tokenizer.rs +0 -81
  220. data/rust-vendor/xml5ever/examples/xml_tokenizer.rs +0 -115
  221. data/rust-vendor/xml5ever/src/driver.rs +0 -90
  222. data/rust-vendor/xml5ever/src/lib.rs +0 -47
  223. data/rust-vendor/xml5ever/src/macros.rs +0 -18
  224. data/rust-vendor/xml5ever/src/serialize/mod.rs +0 -216
  225. data/rust-vendor/xml5ever/src/tokenizer/char_ref/mod.rs +0 -456
  226. data/rust-vendor/xml5ever/src/tokenizer/interface.rs +0 -116
  227. data/rust-vendor/xml5ever/src/tokenizer/mod.rs +0 -1344
  228. data/rust-vendor/xml5ever/src/tokenizer/qname.rs +0 -84
  229. data/rust-vendor/xml5ever/src/tokenizer/states.rs +0 -167
  230. data/rust-vendor/xml5ever/src/tree_builder/mod.rs +0 -774
  231. data/rust-vendor/xml5ever/src/tree_builder/types.rs +0 -37
@@ -0,0 +1,398 @@
1
+ use crate::BytesPerPixel;
2
+
3
+ // This code path is used on non-x86_64 architectures but we allow dead code
4
+ // for the test module to be able to access it.
5
+ #[allow(dead_code)]
6
+ pub(super) fn filter_paeth(a: u8, b: u8, c: u8) -> u8 {
7
+ // On ARM this algorithm performs much better than the one above adapted from stb,
8
+ // and this is the better-studied algorithm we've always used here,
9
+ // so we default to it on all non-x86 platforms.
10
+ let pa = (i16::from(b) - i16::from(c)).abs();
11
+ let pb = (i16::from(a) - i16::from(c)).abs();
12
+ let pc = ((i16::from(a) - i16::from(c)) + (i16::from(b) - i16::from(c))).abs();
13
+
14
+ let mut out = a;
15
+ let mut min = pa;
16
+
17
+ if pb < min {
18
+ min = pb;
19
+ out = b;
20
+ }
21
+ if pc < min {
22
+ out = c;
23
+ }
24
+
25
+ out
26
+ }
27
+
28
+ pub(super) fn filter_paeth_stbi(a: i16, b: i16, c: i16) -> u8 {
29
+ // Decoding optimizes better with this algorithm than with `filter_paeth`
30
+ //
31
+ // This formulation looks very different from the reference in the PNG spec, but is
32
+ // actually equivalent and has favorable data dependencies and admits straightforward
33
+ // generation of branch-free code, which helps performance significantly.
34
+ //
35
+ // Adapted from public domain PNG implementation:
36
+ // https://github.com/nothings/stb/blob/5c205738c191bcb0abc65c4febfa9bd25ff35234/stb_image.h#L4657-L4668
37
+ let thresh = c * 3 - (a + b);
38
+ let lo = a.min(b);
39
+ let hi = a.max(b);
40
+ let t0 = if hi <= thresh { lo } else { c };
41
+ let t1 = if thresh <= lo { hi } else { t0 };
42
+ t1 as u8
43
+ }
44
+
45
+ pub(super) fn filter_paeth_fpnge(a: u8, b: u8, c: u8) -> u8 {
46
+ // This is an optimized version of the paeth filter from the PNG specification, proposed by
47
+ // Luca Versari for [FPNGE](https://www.lucaversari.it/FJXL_and_FPNGE.pdf). It operates
48
+ // entirely on unsigned 8-bit quantities, making it more conducive to vectorization.
49
+ //
50
+ // p = a + b - c
51
+ // pa = |p - a| = |a + b - c - a| = |b - c| = max(b, c) - min(b, c)
52
+ // pb = |p - b| = |a + b - c - b| = |a - c| = max(a, c) - min(a, c)
53
+ // pc = |p - c| = |a + b - c - c| = |(b - c) + (a - c)| = ...
54
+ //
55
+ // Further optimizing the calculation of `pc` a bit tricker. However, notice that:
56
+ //
57
+ // a > c && b > c
58
+ // ==> (a - c) > 0 && (b - c) > 0
59
+ // ==> pc > (a - c) && pc > (b - c)
60
+ // ==> pc > |a - c| && pc > |b - c|
61
+ // ==> pc > pb && pc > pa
62
+ //
63
+ // Meaning that if `c` is smaller than `a` and `b`, the value of `pc` is irrelevant. Similar
64
+ // reasoning applies if `c` is larger than the other two inputs. Assuming that `c >= b` and
65
+ // `c <= b` or vice versa:
66
+ //
67
+ // pc = ||b - c| - |a - c|| = |pa - pb| = max(pa, pb) - min(pa, pb)
68
+ //
69
+ let pa = b.max(c) - c.min(b);
70
+ let pb = a.max(c) - c.min(a);
71
+ let pc = if (a < c) == (c < b) {
72
+ pa.max(pb) - pa.min(pb)
73
+ } else {
74
+ 255
75
+ };
76
+
77
+ if pa <= pb && pa <= pc {
78
+ a
79
+ } else if pb <= pc {
80
+ b
81
+ } else {
82
+ c
83
+ }
84
+ }
85
+
86
+ #[allow(unreachable_code)]
87
+ #[cfg(not(target_arch = "x86_64"))]
88
+ pub(super) fn unfilter(tbpp: BytesPerPixel, previous: &[u8], current: &mut [u8]) {
89
+ // Paeth filter pixels:
90
+ // C B D
91
+ // A X
92
+ match tbpp {
93
+ BytesPerPixel::One => {
94
+ let mut a_bpp = [0; 1];
95
+ let mut c_bpp = [0; 1];
96
+ for (chunk, b_bpp) in current.chunks_exact_mut(1).zip(previous.chunks_exact(1)) {
97
+ let new_chunk = [chunk[0].wrapping_add(filter_paeth(a_bpp[0], b_bpp[0], c_bpp[0]))];
98
+ *TryInto::<&mut [u8; 1]>::try_into(chunk).unwrap() = new_chunk;
99
+ a_bpp = new_chunk;
100
+ c_bpp = b_bpp.try_into().unwrap();
101
+ }
102
+ }
103
+ BytesPerPixel::Two => {
104
+ let mut a_bpp = [0; 2];
105
+ let mut c_bpp = [0; 2];
106
+ for (chunk, b_bpp) in current.chunks_exact_mut(2).zip(previous.chunks_exact(2)) {
107
+ let new_chunk = [
108
+ chunk[0].wrapping_add(filter_paeth(a_bpp[0], b_bpp[0], c_bpp[0])),
109
+ chunk[1].wrapping_add(filter_paeth(a_bpp[1], b_bpp[1], c_bpp[1])),
110
+ ];
111
+ *TryInto::<&mut [u8; 2]>::try_into(chunk).unwrap() = new_chunk;
112
+ a_bpp = new_chunk;
113
+ c_bpp = b_bpp.try_into().unwrap();
114
+ }
115
+ }
116
+ BytesPerPixel::Three => {
117
+ #[cfg(all(feature = "unstable", not(target_vendor = "apple")))]
118
+ {
119
+ // Results in PR: https://github.com/image-rs/image-png/pull/632
120
+ // Approximately 30% better on Arm Cortex A520, 7%
121
+ // regression on Arm Cortex X4. Switched off on Apple
122
+ // Silicon due to 10-12% regression.
123
+ super::simd::paeth_unfilter_3bpp(current, previous);
124
+ return;
125
+ }
126
+ let mut a_bpp = [0; 3];
127
+ let mut c_bpp = [0; 3];
128
+
129
+ let mut previous = &previous[..previous.len() / 3 * 3];
130
+ let current_len = current.len();
131
+ let mut current = &mut current[..current_len / 3 * 3];
132
+
133
+ while let ([c0, c1, c2, c_rest @ ..], [p0, p1, p2, p_rest @ ..]) = (current, previous) {
134
+ current = c_rest;
135
+ previous = p_rest;
136
+
137
+ *c0 = c0.wrapping_add(filter_paeth(a_bpp[0], *p0, c_bpp[0]));
138
+ *c1 = c1.wrapping_add(filter_paeth(a_bpp[1], *p1, c_bpp[1]));
139
+ *c2 = c2.wrapping_add(filter_paeth(a_bpp[2], *p2, c_bpp[2]));
140
+
141
+ a_bpp = [*c0, *c1, *c2];
142
+ c_bpp = [*p0, *p1, *p2];
143
+ }
144
+ }
145
+ BytesPerPixel::Four => {
146
+ #[cfg(feature = "unstable")]
147
+ {
148
+ // Results in PR: https://github.com/image-rs/image-png/pull/633
149
+ // No change on Apple Silicon, 42% better on Arm Cortex A520,
150
+ // 10% better on Arm Cortex X4.
151
+ super::simd::paeth_unfilter_4bpp(current, previous);
152
+ return;
153
+ }
154
+
155
+ let mut a_bpp = [0; 4];
156
+ let mut c_bpp = [0; 4];
157
+
158
+ let mut previous = &previous[..previous.len() & !3];
159
+ let current_len = current.len();
160
+ let mut current = &mut current[..current_len & !3];
161
+
162
+ while let ([c0, c1, c2, c3, c_rest @ ..], [p0, p1, p2, p3, p_rest @ ..]) =
163
+ (current, previous)
164
+ {
165
+ current = c_rest;
166
+ previous = p_rest;
167
+
168
+ *c0 = c0.wrapping_add(filter_paeth(a_bpp[0], *p0, c_bpp[0]));
169
+ *c1 = c1.wrapping_add(filter_paeth(a_bpp[1], *p1, c_bpp[1]));
170
+ *c2 = c2.wrapping_add(filter_paeth(a_bpp[2], *p2, c_bpp[2]));
171
+ *c3 = c3.wrapping_add(filter_paeth(a_bpp[3], *p3, c_bpp[3]));
172
+
173
+ a_bpp = [*c0, *c1, *c2, *c3];
174
+ c_bpp = [*p0, *p1, *p2, *p3];
175
+ }
176
+ }
177
+ BytesPerPixel::Six => {
178
+ let mut a_bpp = [0; 6];
179
+ let mut c_bpp = [0; 6];
180
+ for (chunk, b_bpp) in current.chunks_exact_mut(6).zip(previous.chunks_exact(6)) {
181
+ let new_chunk = [
182
+ chunk[0].wrapping_add(filter_paeth(a_bpp[0], b_bpp[0], c_bpp[0])),
183
+ chunk[1].wrapping_add(filter_paeth(a_bpp[1], b_bpp[1], c_bpp[1])),
184
+ chunk[2].wrapping_add(filter_paeth(a_bpp[2], b_bpp[2], c_bpp[2])),
185
+ chunk[3].wrapping_add(filter_paeth(a_bpp[3], b_bpp[3], c_bpp[3])),
186
+ chunk[4].wrapping_add(filter_paeth(a_bpp[4], b_bpp[4], c_bpp[4])),
187
+ chunk[5].wrapping_add(filter_paeth(a_bpp[5], b_bpp[5], c_bpp[5])),
188
+ ];
189
+ *TryInto::<&mut [u8; 6]>::try_into(chunk).unwrap() = new_chunk;
190
+ a_bpp = new_chunk;
191
+ c_bpp = b_bpp.try_into().unwrap();
192
+ }
193
+ }
194
+ BytesPerPixel::Eight => {
195
+ let mut a_bpp = [0; 8];
196
+ let mut c_bpp = [0; 8];
197
+ for (chunk, b_bpp) in current.chunks_exact_mut(8).zip(previous.chunks_exact(8)) {
198
+ let new_chunk = [
199
+ chunk[0].wrapping_add(filter_paeth(a_bpp[0], b_bpp[0], c_bpp[0])),
200
+ chunk[1].wrapping_add(filter_paeth(a_bpp[1], b_bpp[1], c_bpp[1])),
201
+ chunk[2].wrapping_add(filter_paeth(a_bpp[2], b_bpp[2], c_bpp[2])),
202
+ chunk[3].wrapping_add(filter_paeth(a_bpp[3], b_bpp[3], c_bpp[3])),
203
+ chunk[4].wrapping_add(filter_paeth(a_bpp[4], b_bpp[4], c_bpp[4])),
204
+ chunk[5].wrapping_add(filter_paeth(a_bpp[5], b_bpp[5], c_bpp[5])),
205
+ chunk[6].wrapping_add(filter_paeth(a_bpp[6], b_bpp[6], c_bpp[6])),
206
+ chunk[7].wrapping_add(filter_paeth(a_bpp[7], b_bpp[7], c_bpp[7])),
207
+ ];
208
+ *TryInto::<&mut [u8; 8]>::try_into(chunk).unwrap() = new_chunk;
209
+ a_bpp = new_chunk;
210
+ c_bpp = b_bpp.try_into().unwrap();
211
+ }
212
+ }
213
+ }
214
+ }
215
+
216
+ /// The x86_64 functions avoid casting between u8xN and i16xN SIMD
217
+ /// representations when possible by maintaining [i16; BPP] arrays
218
+ /// between iterations instead of [u8; BPP].
219
+ #[allow(unreachable_code)]
220
+ #[cfg(target_arch = "x86_64")]
221
+ pub(super) fn unfilter(tbpp: BytesPerPixel, previous: &[u8], current: &mut [u8]) {
222
+ // Paeth filter pixels:
223
+ // C B D
224
+ // A X
225
+ match tbpp {
226
+ BytesPerPixel::One => {
227
+ const BPP: usize = 1;
228
+ let mut a_bpp = [0; BPP];
229
+ let mut c_bpp = [0; BPP];
230
+
231
+ for (c, p) in current
232
+ .chunks_exact_mut(BPP)
233
+ .zip(previous.chunks_exact(BPP))
234
+ {
235
+ for i in 0..BPP {
236
+ c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i]));
237
+ }
238
+
239
+ a_bpp = [c[0] as i16];
240
+ c_bpp = [p[0] as i16];
241
+ }
242
+ }
243
+ BytesPerPixel::Two => {
244
+ const BPP: usize = 2;
245
+ let mut a_bpp = [0; BPP];
246
+ let mut c_bpp = [0; BPP];
247
+
248
+ for (c, p) in current
249
+ .chunks_exact_mut(BPP)
250
+ .zip(previous.chunks_exact(BPP))
251
+ {
252
+ for i in 0..BPP {
253
+ c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i]));
254
+ }
255
+
256
+ a_bpp = [c[0] as i16, c[1] as i16];
257
+ c_bpp = [p[0] as i16, p[1] as i16];
258
+ }
259
+ }
260
+ BytesPerPixel::Three => {
261
+ #[cfg(feature = "unstable")]
262
+ {
263
+ // Results in PR: https://github.com/image-rs/image-png/pull/632
264
+ // 23% better on an Epyc 7B13, 10% on a Zen 3 part.
265
+ // ~30% when targeting x86-64-v2.
266
+ super::simd::paeth_unfilter_3bpp(current, previous);
267
+ return;
268
+ }
269
+ const BPP: usize = 3;
270
+ let mut a_bpp = [0; BPP];
271
+ let mut c_bpp = [0; BPP];
272
+
273
+ for (c, p) in current
274
+ .chunks_exact_mut(BPP)
275
+ .zip(previous.chunks_exact(BPP))
276
+ {
277
+ for i in 0..BPP {
278
+ c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i]));
279
+ }
280
+
281
+ a_bpp = [c[0] as i16, c[1] as i16, c[2] as i16];
282
+ c_bpp = [p[0] as i16, p[1] as i16, p[2] as i16];
283
+ }
284
+ }
285
+ BytesPerPixel::Four => {
286
+ #[cfg(feature = "unstable")]
287
+ {
288
+ // Results in PR: https://github.com/image-rs/image-png/pull/633
289
+ // May be slightly faster on AMD EPYC 7B13.
290
+ super::simd::paeth_unfilter_4bpp(current, previous);
291
+ return;
292
+ }
293
+ const BPP: usize = 4;
294
+ let mut a_bpp = [0; BPP];
295
+ let mut c_bpp = [0; BPP];
296
+
297
+ for (c, p) in current
298
+ .chunks_exact_mut(BPP)
299
+ .zip(previous.chunks_exact(BPP))
300
+ {
301
+ for i in 0..BPP {
302
+ c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i]));
303
+ }
304
+
305
+ a_bpp = [c[0] as i16, c[1] as i16, c[2] as i16, c[3] as i16];
306
+ c_bpp = [p[0] as i16, p[1] as i16, p[2] as i16, p[3] as i16];
307
+ }
308
+ }
309
+ BytesPerPixel::Six => {
310
+ const BPP: usize = 6;
311
+ let mut a_bpp = [0; BPP];
312
+ let mut c_bpp = [0; BPP];
313
+
314
+ for (c, p) in current
315
+ .chunks_exact_mut(BPP)
316
+ .zip(previous.chunks_exact(BPP))
317
+ {
318
+ for i in 0..BPP {
319
+ c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i]));
320
+ }
321
+
322
+ a_bpp = [
323
+ c[0] as i16,
324
+ c[1] as i16,
325
+ c[2] as i16,
326
+ c[3] as i16,
327
+ c[4] as i16,
328
+ c[5] as i16,
329
+ ];
330
+ c_bpp = [
331
+ p[0] as i16,
332
+ p[1] as i16,
333
+ p[2] as i16,
334
+ p[3] as i16,
335
+ p[4] as i16,
336
+ p[5] as i16,
337
+ ];
338
+ }
339
+ }
340
+ BytesPerPixel::Eight => {
341
+ const BPP: usize = 8;
342
+ let mut a_bpp = [0; BPP];
343
+ let mut c_bpp = [0; BPP];
344
+
345
+ for (c, p) in current
346
+ .chunks_exact_mut(BPP)
347
+ .zip(previous.chunks_exact(BPP))
348
+ {
349
+ for i in 0..BPP {
350
+ c[i] = c[i].wrapping_add(filter_paeth_stbi(a_bpp[i], p[i] as i16, c_bpp[i]));
351
+ }
352
+
353
+ a_bpp = [
354
+ c[0] as i16,
355
+ c[1] as i16,
356
+ c[2] as i16,
357
+ c[3] as i16,
358
+ c[4] as i16,
359
+ c[5] as i16,
360
+ c[6] as i16,
361
+ c[7] as i16,
362
+ ];
363
+ c_bpp = [
364
+ p[0] as i16,
365
+ p[1] as i16,
366
+ p[2] as i16,
367
+ p[3] as i16,
368
+ p[4] as i16,
369
+ p[5] as i16,
370
+ p[6] as i16,
371
+ p[7] as i16,
372
+ ];
373
+ }
374
+ }
375
+ }
376
+ }
377
+
378
+ #[cfg(test)]
379
+ mod tests {
380
+ use super::*;
381
+
382
+ #[test]
383
+ #[ignore] // takes ~20s without optimizations
384
+ fn paeth_impls_are_equivalent() {
385
+ for a in 0..=255 {
386
+ for b in 0..=255 {
387
+ for c in 0..=255 {
388
+ let baseline = filter_paeth(a, b, c);
389
+ let fpnge = filter_paeth_fpnge(a, b, c);
390
+ let stbi = filter_paeth_stbi(a as i16, b as i16, c as i16);
391
+
392
+ assert_eq!(baseline, fpnge);
393
+ assert_eq!(baseline, stbi);
394
+ }
395
+ }
396
+ }
397
+ }
398
+ }