@syzlm/ofdparser 0.0.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 (213) hide show
  1. package/.babelrc +14 -0
  2. package/.eslintignore +2 -0
  3. package/.eslintrc.json +18 -0
  4. package/.prettierrc.json +9 -0
  5. package/dist/OFD.d.ts +8 -0
  6. package/dist/Pages.d.ts +7 -0
  7. package/dist/RootDocumnet.d.ts +1 -0
  8. package/dist/bundle.cjs.js +64123 -0
  9. package/dist/bundle.esm.js +64115 -0
  10. package/dist/bundle.iife.js +14743 -0
  11. package/dist/bundle.umd.js +64045 -0
  12. package/dist/constant/index.d.ts +7 -0
  13. package/dist/constant.d.ts +6 -0
  14. package/dist/core/ofd-core/Annotations/AnnotationsXml.d.ts +16 -0
  15. package/dist/core/ofd-core/Asn.1Utils.d.ts +47 -0
  16. package/dist/core/ofd-core/Documents/DocumentResXml.d.ts +15 -0
  17. package/dist/core/ofd-core/Documents/DocumnetXml.d.ts +25 -0
  18. package/dist/core/ofd-core/Documents/PublicResXml.d.ts +15 -0
  19. package/dist/core/ofd-core/OFDElement.d.ts +232 -0
  20. package/dist/core/ofd-core/Ofd/OFDXml.d.ts +19 -0
  21. package/dist/core/ofd-core/Pages/PageXml.d.ts +20 -0
  22. package/dist/core/ofd-core/Signatures/Signatures.d.ts +20 -0
  23. package/dist/core/ofd-core/TemplatePages/TemplatePages.d.ts +20 -0
  24. package/dist/core/ofd-core/constant.d.ts +29 -0
  25. package/dist/core/ofd-core/utils.d.ts +21 -0
  26. package/dist/dicom/dicom.d.ts +15 -0
  27. package/dist/dicom/index.d.ts +1 -0
  28. package/dist/errors/ErrorHandle.d.ts +6 -0
  29. package/dist/errors/ErrorMsg.d.ts +16 -0
  30. package/dist/errors/FetchErrors.d.ts +4 -0
  31. package/dist/errors/MimeError.d.ts +4 -0
  32. package/dist/errors/OFDErrors.d.ts +4 -0
  33. package/dist/errors/UnzipErrors.d.ts +4 -0
  34. package/dist/errors/XmlErrors.d.ts +4 -0
  35. package/dist/errors/error-msg.d.ts +9 -0
  36. package/dist/es.d.ts +2 -0
  37. package/dist/index.d.ts +6 -0
  38. package/dist/lib/ParseFile.d.ts +7 -0
  39. package/dist/lib/UnitCoversion.d.ts +31 -0
  40. package/dist/lib/asn1/Asn.1.d.ts +34 -0
  41. package/dist/lib/asn1/Stream.d.ts +27 -0
  42. package/dist/lib/asn1/asn1.d.ts +4 -0
  43. package/dist/lib/asn1/base64.d.ts +4 -0
  44. package/dist/lib/asn1/hex.d.ts +5 -0
  45. package/dist/lib/asn1/index.d.ts +5 -0
  46. package/dist/lib/asn1/int10.d.ts +34 -0
  47. package/dist/lib/asn1/oids.d.ts +2 -0
  48. package/dist/lib/asn1/string-cut.d.ts +2 -0
  49. package/dist/lib/decode-html.d.ts +7 -0
  50. package/dist/lib/fetch.d.ts +17 -0
  51. package/dist/lib/is-element.d.ts +5 -0
  52. package/dist/lib/load-files.d.ts +3 -0
  53. package/dist/lib/load-opentype.d.ts +34 -0
  54. package/dist/lib/load-script.d.ts +1 -0
  55. package/dist/lib/mime.d.ts +8 -0
  56. package/dist/lib/read-buffer.d.ts +2 -0
  57. package/dist/lib/toFixeds.d.ts +7 -0
  58. package/dist/libs/Asn.1Utils.d.ts +47 -0
  59. package/dist/libs/asn1/Asn.1.d.ts +34 -0
  60. package/dist/libs/asn1/Stream.d.ts +27 -0
  61. package/dist/libs/asn1/asn1.d.ts +4 -0
  62. package/dist/libs/asn1/base64.d.ts +4 -0
  63. package/dist/libs/asn1/hex.d.ts +5 -0
  64. package/dist/libs/asn1/index.d.ts +5 -0
  65. package/dist/libs/asn1/int10.d.ts +34 -0
  66. package/dist/libs/asn1/oids.d.ts +2 -0
  67. package/dist/libs/asn1/string-cut.d.ts +2 -0
  68. package/dist/libs/decode-html.d.ts +7 -0
  69. package/dist/libs/fetch.d.ts +17 -0
  70. package/dist/libs/mime.d.ts +8 -0
  71. package/dist/libs/ofdArray.d.ts +10 -0
  72. package/dist/libs/ofdImageObject.d.ts +9 -0
  73. package/dist/libs/ofdLayer.d.ts +3 -0
  74. package/dist/libs/ofdName.d.ts +17 -0
  75. package/dist/libs/ofdPathObject.d.ts +11 -0
  76. package/dist/libs/ofdTextObject.d.ts +6 -0
  77. package/dist/libs/parseAnnotation.d.ts +5 -0
  78. package/dist/libs/parseColor.d.ts +5 -0
  79. package/dist/libs/parsePageArea.d.ts +17 -0
  80. package/dist/libs/parser-elements.d.ts +8 -0
  81. package/dist/libs/parserElements.d.ts +8 -0
  82. package/dist/libs/pipeExtensions.d.ts +4 -0
  83. package/dist/libs/read-buffer.d.ts +2 -0
  84. package/dist/main.d.ts +15 -0
  85. package/dist/ofd/ConverterDpi.d.ts +16 -0
  86. package/dist/ofd/index.d.ts +1 -0
  87. package/dist/ofd/ofd-utils.d.ts +137 -0
  88. package/dist/ofd/ofd.d.ts +35 -0
  89. package/dist/ofd/parse-ofd.d.ts +18 -0
  90. package/dist/ofd/render.d.ts +18 -0
  91. package/dist/ofd/svg-image.d.ts +12 -0
  92. package/dist/ofd/svg-path.d.ts +5 -0
  93. package/dist/ofd/svg-text.d.ts +8 -0
  94. package/dist/ofd.parse.d.ts +6 -0
  95. package/dist/ofd.xml.d.ts +1 -0
  96. package/dist/ofdParse.d.ts +6 -0
  97. package/dist/pipe/annotations.d.ts +13 -0
  98. package/dist/pipe/attachments.d.ts +13 -0
  99. package/dist/pipe/commonData.d.ts +18 -0
  100. package/dist/pipe/customTags.d.ts +14 -0
  101. package/dist/pipe/extensions.d.ts +14 -0
  102. package/dist/pipe/output.d.ts +7 -0
  103. package/dist/pipe/pages.d.ts +13 -0
  104. package/dist/pipe/permissions.d.ts +14 -0
  105. package/dist/pipe/pipeline.d.ts +63 -0
  106. package/dist/pipe/startPipe.d.ts +11 -0
  107. package/dist/xml/index.d.ts +2 -0
  108. package/dist/xml/render.d.ts +6 -0
  109. package/dist/xml/xml.d.ts +18 -0
  110. package/package.json +47 -0
  111. package/public/index.html +75 -0
  112. package/public/opentype.min.js +2 -0
  113. package/rollup.config.dev.mjs +47 -0
  114. package/rollup.config.mjs +70 -0
  115. package/src/constant/index.ts +13 -0
  116. package/src/core/ofd-core/Annotations/Annotation.km +206 -0
  117. package/src/core/ofd-core/Annotations/Annotations.km +59 -0
  118. package/src/core/ofd-core/Annotations/Annotations.md +13 -0
  119. package/src/core/ofd-core/Annotations/AnnotationsXml.ts +114 -0
  120. package/src/core/ofd-core/Asn.1Utils.ts +225 -0
  121. package/src/core/ofd-core/Documents/DocumentResXml.ts +55 -0
  122. package/src/core/ofd-core/Documents/Documnet.km +862 -0
  123. package/src/core/ofd-core/Documents/DocumnetXml.ts +118 -0
  124. package/src/core/ofd-core/Documents/Documnets.md +296 -0
  125. package/src/core/ofd-core/Documents/PublicResXml.ts +63 -0
  126. package/src/core/ofd-core/Documents//345/233/276/345/261/202/346/270/262/346/237/223/351/241/272/345/272/217.png +0 -0
  127. package/src/core/ofd-core/Documents//350/241/25022/347/272/277/346/235/241/350/277/236/346/216/245/346/240/267/345/274/217.png +0 -0
  128. package/src/core/ofd-core/Documents//350/241/25023/347/272/277/346/235/241/350/231/232/347/272/277/346/240/267/345/274/217.png +0 -0
  129. package/src/core/ofd-core/Documents//350/241/25023/347/273/223/345/220/210/347/202/271/351/225/277/345/272/246.png +0 -0
  130. package/src/core/ofd-core/Documents//350/241/25024/347/272/277/346/235/241/347/253/257/347/202/271/346/240/267/345/274/217.png +0 -0
  131. package/src/core/ofd-core/Documents//351/241/265/350/276/271/347/225/214/345/261/202/346/254/241/347/273/223/346/236/204.png +0 -0
  132. package/src/core/ofd-core/OFDElement.ts +724 -0
  133. package/src/core/ofd-core/Ofd/CT_DocInfo.km +197 -0
  134. package/src/core/ofd-core/Ofd/OFD.km +114 -0
  135. package/src/core/ofd-core/Ofd/OFD.md +99 -0
  136. package/src/core/ofd-core/Ofd/OFDXml.ts +69 -0
  137. package/src/core/ofd-core/Pages/PAGE.md +40 -0
  138. package/src/core/ofd-core/Pages/PageXml.ts +59 -0
  139. package/src/core/ofd-core/Signatures/Signature.km +308 -0
  140. package/src/core/ofd-core/Signatures/Signature.md +21 -0
  141. package/src/core/ofd-core/Signatures/Signatures.km +315 -0
  142. package/src/core/ofd-core/Signatures/Signatures.md +24 -0
  143. package/src/core/ofd-core/Signatures/Signatures.ts +247 -0
  144. package/src/core/ofd-core/TemplatePages/TemplatePages.ts +56 -0
  145. package/src/core/ofd-core/asn.md +60 -0
  146. package/src/core/ofd-core/constant.ts +35 -0
  147. package/src/core/ofd-core/index.d.ts +867 -0
  148. package/src/core/ofd-core/utils.ts +86 -0
  149. package/src/dicom/dicom.ts +42 -0
  150. package/src/dicom/index.ts +1 -0
  151. package/src/errors/ErrorHandle.ts +14 -0
  152. package/src/errors/FetchErrors.ts +8 -0
  153. package/src/errors/MimeError.ts +9 -0
  154. package/src/errors/OFDErrors.ts +11 -0
  155. package/src/errors/UnzipErrors.ts +9 -0
  156. package/src/errors/XmlErrors.ts +11 -0
  157. package/src/errors/error-msg.ts +17 -0
  158. package/src/es.ts +3 -0
  159. package/src/global.d.ts +7 -0
  160. package/src/index.ts +7 -0
  161. package/src/lib/ParseFile.ts +12 -0
  162. package/src/lib/README.md +69 -0
  163. package/src/lib/UnitCoversion.ts +55 -0
  164. package/src/lib/asn1/Asn.1.ts +284 -0
  165. package/src/lib/asn1/README.md +1 -0
  166. package/src/lib/asn1/Stream.ts +314 -0
  167. package/src/lib/asn1/asn1.ts +120 -0
  168. package/src/lib/asn1/base64.ts +97 -0
  169. package/src/lib/asn1/hex.ts +60 -0
  170. package/src/lib/asn1/index.ts +5 -0
  171. package/src/lib/asn1/int10.ts +103 -0
  172. package/src/lib/asn1/oids.ts +6164 -0
  173. package/src/lib/asn1/string-cut.ts +8 -0
  174. package/src/lib/decode-html.ts +37 -0
  175. package/src/lib/fetch.ts +70 -0
  176. package/src/lib/is-element.ts +13 -0
  177. package/src/lib/jbig/README.md +1 -0
  178. package/src/lib/jbig/arithmetic_decoder.js +184 -0
  179. package/src/lib/jbig/base_stream.js +117 -0
  180. package/src/lib/jbig/ccitt.js +1068 -0
  181. package/src/lib/jbig/ccitt_stream.js +60 -0
  182. package/src/lib/jbig/compatibility.js +108 -0
  183. package/src/lib/jbig/core_utils.js +591 -0
  184. package/src/lib/jbig/decode_stream.js +184 -0
  185. package/src/lib/jbig/is_node.js +28 -0
  186. package/src/lib/jbig/jbig2.js +2582 -0
  187. package/src/lib/jbig/jbig2_stream.js +78 -0
  188. package/src/lib/jbig/primitives.js +441 -0
  189. package/src/lib/jbig/stream.js +101 -0
  190. package/src/lib/jbig/util.js +1231 -0
  191. package/src/lib/load-files.ts +26 -0
  192. package/src/lib/load-opentype.ts +161 -0
  193. package/src/lib/load-script.ts +33 -0
  194. package/src/lib/mime.ts +97 -0
  195. package/src/lib/read-buffer.ts +19 -0
  196. package/src/lib/toFixeds.ts +56 -0
  197. package/src/ofd/ConverterDpi.ts +35 -0
  198. package/src/ofd/OFD.md +38 -0
  199. package/src/ofd/TODO.md +10 -0
  200. package/src/ofd/index.ts +1 -0
  201. package/src/ofd/ofd-utils.ts +627 -0
  202. package/src/ofd/ofd.demo.md +12 -0
  203. package/src/ofd/ofd.ts +200 -0
  204. package/src/ofd/ofdxml.km +162 -0
  205. package/src/ofd/parse-ofd.ts +103 -0
  206. package/src/ofd/render.ts +393 -0
  207. package/src/ofd/svg-image.ts +318 -0
  208. package/src/ofd/svg-path.ts +283 -0
  209. package/src/ofd/svg-text.ts +272 -0
  210. package/src/xml/index.ts +3 -0
  211. package/src/xml/render.ts +171 -0
  212. package/src/xml/xml.ts +136 -0
  213. package/tsconfig.json +21 -0
@@ -0,0 +1,2582 @@
1
+ /* Copyright 2012 Mozilla Foundation
2
+ *
3
+ * Licensed under the Apache License, Version 2.0 (the "License");
4
+ * you may not use this file except in compliance with the License.
5
+ * You may obtain a copy of the License at
6
+ *
7
+ * http://www.apache.org/licenses/LICENSE-2.0
8
+ *
9
+ * Unless required by applicable law or agreed to in writing, software
10
+ * distributed under the License is distributed on an "AS IS" BASIS,
11
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ * See the License for the specific language governing permissions and
13
+ * limitations under the License.
14
+ */
15
+
16
+ import { BaseException, shadow } from './util.js';
17
+ import { log2, readInt8, readUint16, readUint32 } from './core_utils.js';
18
+ import { ArithmeticDecoder } from './arithmetic_decoder.js';
19
+ import { CCITTFaxDecoder } from './ccitt.js';
20
+
21
+ class Jbig2Error extends BaseException {
22
+ constructor(msg) {
23
+ super(`JBIG2 error: ${msg}`, 'Jbig2Error');
24
+ }
25
+ }
26
+
27
+ // Utility data structures
28
+ class ContextCache {
29
+ getContexts(id) {
30
+ if (id in this) {
31
+ return this[id];
32
+ }
33
+ return (this[id] = new Int8Array(1 << 16));
34
+ }
35
+ }
36
+
37
+ class DecodingContext {
38
+ constructor(data, start, end) {
39
+ this.data = data;
40
+ this.start = start;
41
+ this.end = end;
42
+ }
43
+
44
+ get decoder() {
45
+ const decoder = new ArithmeticDecoder(this.data, this.start, this.end);
46
+ return shadow(this, 'decoder', decoder);
47
+ }
48
+
49
+ get contextCache() {
50
+ const cache = new ContextCache();
51
+ return shadow(this, 'contextCache', cache);
52
+ }
53
+ }
54
+
55
+ // Annex A. Arithmetic Integer Decoding Procedure
56
+ // A.2 Procedure for decoding values
57
+ function decodeInteger(contextCache, procedure, decoder) {
58
+ const contexts = contextCache.getContexts(procedure);
59
+ let prev = 1;
60
+
61
+ function readBits(length) {
62
+ let v = 0;
63
+ for (let i = 0; i < length; i++) {
64
+ const bit = decoder.readBit(contexts, prev);
65
+ prev = prev < 256 ? (prev << 1) | bit : (((prev << 1) | bit) & 511) | 256;
66
+ v = (v << 1) | bit;
67
+ }
68
+ return v >>> 0;
69
+ }
70
+
71
+ const sign = readBits(1);
72
+ // prettier-ignore
73
+ /* eslint-disable no-nested-ternary */
74
+ const value = readBits(1) ?
75
+ (readBits(1) ?
76
+ (readBits(1) ?
77
+ (readBits(1) ?
78
+ (readBits(1) ?
79
+ (readBits(32) + 4436) :
80
+ readBits(12) + 340) :
81
+ readBits(8) + 84) :
82
+ readBits(6) + 20) :
83
+ readBits(4) + 4) :
84
+ readBits(2);
85
+ /* eslint-enable no-nested-ternary */
86
+ if (sign === 0) {
87
+ return value;
88
+ } else if (value > 0) {
89
+ return -value;
90
+ }
91
+ return null;
92
+ }
93
+
94
+ // A.3 The IAID decoding procedure
95
+ function decodeIAID(contextCache, decoder, codeLength) {
96
+ const contexts = contextCache.getContexts('IAID');
97
+
98
+ let prev = 1;
99
+ for (let i = 0; i < codeLength; i++) {
100
+ const bit = decoder.readBit(contexts, prev);
101
+ prev = (prev << 1) | bit;
102
+ }
103
+ if (codeLength < 31) {
104
+ return prev & ((1 << codeLength) - 1);
105
+ }
106
+ return prev & 0x7fffffff;
107
+ }
108
+
109
+ // 7.3 Segment types
110
+ const SegmentTypes = [
111
+ 'SymbolDictionary',
112
+ null,
113
+ null,
114
+ null,
115
+ 'IntermediateTextRegion',
116
+ null,
117
+ 'ImmediateTextRegion',
118
+ 'ImmediateLosslessTextRegion',
119
+ null,
120
+ null,
121
+ null,
122
+ null,
123
+ null,
124
+ null,
125
+ null,
126
+ null,
127
+ 'PatternDictionary',
128
+ null,
129
+ null,
130
+ null,
131
+ 'IntermediateHalftoneRegion',
132
+ null,
133
+ 'ImmediateHalftoneRegion',
134
+ 'ImmediateLosslessHalftoneRegion',
135
+ null,
136
+ null,
137
+ null,
138
+ null,
139
+ null,
140
+ null,
141
+ null,
142
+ null,
143
+ null,
144
+ null,
145
+ null,
146
+ null,
147
+ 'IntermediateGenericRegion',
148
+ null,
149
+ 'ImmediateGenericRegion',
150
+ 'ImmediateLosslessGenericRegion',
151
+ 'IntermediateGenericRefinementRegion',
152
+ null,
153
+ 'ImmediateGenericRefinementRegion',
154
+ 'ImmediateLosslessGenericRefinementRegion',
155
+ null,
156
+ null,
157
+ null,
158
+ null,
159
+ 'PageInformation',
160
+ 'EndOfPage',
161
+ 'EndOfStripe',
162
+ 'EndOfFile',
163
+ 'Profiles',
164
+ 'Tables',
165
+ null,
166
+ null,
167
+ null,
168
+ null,
169
+ null,
170
+ null,
171
+ null,
172
+ null,
173
+ 'Extension'
174
+ ];
175
+
176
+ const CodingTemplates = [
177
+ [
178
+ { x: -1, y: -2 },
179
+ { x: 0, y: -2 },
180
+ { x: 1, y: -2 },
181
+ { x: -2, y: -1 },
182
+ { x: -1, y: -1 },
183
+ { x: 0, y: -1 },
184
+ { x: 1, y: -1 },
185
+ { x: 2, y: -1 },
186
+ { x: -4, y: 0 },
187
+ { x: -3, y: 0 },
188
+ { x: -2, y: 0 },
189
+ { x: -1, y: 0 }
190
+ ],
191
+ [
192
+ { x: -1, y: -2 },
193
+ { x: 0, y: -2 },
194
+ { x: 1, y: -2 },
195
+ { x: 2, y: -2 },
196
+ { x: -2, y: -1 },
197
+ { x: -1, y: -1 },
198
+ { x: 0, y: -1 },
199
+ { x: 1, y: -1 },
200
+ { x: 2, y: -1 },
201
+ { x: -3, y: 0 },
202
+ { x: -2, y: 0 },
203
+ { x: -1, y: 0 }
204
+ ],
205
+ [
206
+ { x: -1, y: -2 },
207
+ { x: 0, y: -2 },
208
+ { x: 1, y: -2 },
209
+ { x: -2, y: -1 },
210
+ { x: -1, y: -1 },
211
+ { x: 0, y: -1 },
212
+ { x: 1, y: -1 },
213
+ { x: -2, y: 0 },
214
+ { x: -1, y: 0 }
215
+ ],
216
+ [
217
+ { x: -3, y: -1 },
218
+ { x: -2, y: -1 },
219
+ { x: -1, y: -1 },
220
+ { x: 0, y: -1 },
221
+ { x: 1, y: -1 },
222
+ { x: -4, y: 0 },
223
+ { x: -3, y: 0 },
224
+ { x: -2, y: 0 },
225
+ { x: -1, y: 0 }
226
+ ]
227
+ ];
228
+
229
+ const RefinementTemplates = [
230
+ {
231
+ coding: [
232
+ { x: 0, y: -1 },
233
+ { x: 1, y: -1 },
234
+ { x: -1, y: 0 }
235
+ ],
236
+ reference: [
237
+ { x: 0, y: -1 },
238
+ { x: 1, y: -1 },
239
+ { x: -1, y: 0 },
240
+ { x: 0, y: 0 },
241
+ { x: 1, y: 0 },
242
+ { x: -1, y: 1 },
243
+ { x: 0, y: 1 },
244
+ { x: 1, y: 1 }
245
+ ]
246
+ },
247
+ {
248
+ coding: [
249
+ { x: -1, y: -1 },
250
+ { x: 0, y: -1 },
251
+ { x: 1, y: -1 },
252
+ { x: -1, y: 0 }
253
+ ],
254
+ reference: [
255
+ { x: 0, y: -1 },
256
+ { x: -1, y: 0 },
257
+ { x: 0, y: 0 },
258
+ { x: 1, y: 0 },
259
+ { x: 0, y: 1 },
260
+ { x: 1, y: 1 }
261
+ ]
262
+ }
263
+ ];
264
+
265
+ // See 6.2.5.7 Decoding the bitmap.
266
+ const ReusedContexts = [
267
+ 0x9b25, // 10011 0110010 0101
268
+ 0x0795, // 0011 110010 101
269
+ 0x00e5, // 001 11001 01
270
+ 0x0195 // 011001 0101
271
+ ];
272
+
273
+ const RefinementReusedContexts = [
274
+ 0x0020, // '000' + '0' (coding) + '00010000' + '0' (reference)
275
+ 0x0008 // '0000' + '001000'
276
+ ];
277
+
278
+ function decodeBitmapTemplate0(width, height, decodingContext) {
279
+ const decoder = decodingContext.decoder;
280
+ const contexts = decodingContext.contextCache.getContexts('GB');
281
+ const bitmap = [];
282
+ let contextLabel, i, j, pixel, row, row1, row2;
283
+
284
+ // ...ooooo....
285
+ // ..ooooooo... Context template for current pixel (X)
286
+ // .ooooX...... (concatenate values of 'o'-pixels to get contextLabel)
287
+ const OLD_PIXEL_MASK = 0x7bf7; // 01111 0111111 0111
288
+
289
+ for (i = 0; i < height; i++) {
290
+ row = bitmap[i] = new Uint8Array(width);
291
+ row1 = i < 1 ? row : bitmap[i - 1];
292
+ row2 = i < 2 ? row : bitmap[i - 2];
293
+
294
+ // At the beginning of each row:
295
+ // Fill contextLabel with pixels that are above/right of (X)
296
+ contextLabel =
297
+ (row2[0] << 13) |
298
+ (row2[1] << 12) |
299
+ (row2[2] << 11) |
300
+ (row1[0] << 7) |
301
+ (row1[1] << 6) |
302
+ (row1[2] << 5) |
303
+ (row1[3] << 4);
304
+
305
+ for (j = 0; j < width; j++) {
306
+ row[j] = pixel = decoder.readBit(contexts, contextLabel);
307
+
308
+ // At each pixel: Clear contextLabel pixels that are shifted
309
+ // out of the context, then add new ones.
310
+ contextLabel =
311
+ ((contextLabel & OLD_PIXEL_MASK) << 1) |
312
+ (j + 3 < width ? row2[j + 3] << 11 : 0) |
313
+ (j + 4 < width ? row1[j + 4] << 4 : 0) |
314
+ pixel;
315
+ }
316
+ }
317
+
318
+ return bitmap;
319
+ }
320
+
321
+ // 6.2 Generic Region Decoding Procedure
322
+ function decodeBitmap(
323
+ mmr,
324
+ width,
325
+ height,
326
+ templateIndex,
327
+ prediction,
328
+ skip,
329
+ at,
330
+ decodingContext
331
+ ) {
332
+ if (mmr) {
333
+ const input = new Reader(
334
+ decodingContext.data,
335
+ decodingContext.start,
336
+ decodingContext.end
337
+ );
338
+ return decodeMMRBitmap(input, width, height, false);
339
+ }
340
+
341
+ // Use optimized version for the most common case
342
+ if (
343
+ templateIndex === 0 &&
344
+ !skip &&
345
+ !prediction &&
346
+ at.length === 4 &&
347
+ at[0].x === 3 &&
348
+ at[0].y === -1 &&
349
+ at[1].x === -3 &&
350
+ at[1].y === -1 &&
351
+ at[2].x === 2 &&
352
+ at[2].y === -2 &&
353
+ at[3].x === -2 &&
354
+ at[3].y === -2
355
+ ) {
356
+ return decodeBitmapTemplate0(width, height, decodingContext);
357
+ }
358
+
359
+ const useskip = !!skip;
360
+ const template = CodingTemplates[templateIndex].concat(at);
361
+
362
+ // Sorting is non-standard, and it is not required. But sorting increases
363
+ // the number of template bits that can be reused from the previous
364
+ // contextLabel in the main loop.
365
+ template.sort(function (a, b) {
366
+ return a.y - b.y || a.x - b.x;
367
+ });
368
+
369
+ const templateLength = template.length;
370
+ const templateX = new Int8Array(templateLength);
371
+ const templateY = new Int8Array(templateLength);
372
+ const changingTemplateEntries = [];
373
+ let reuseMask = 0,
374
+ minX = 0,
375
+ maxX = 0,
376
+ minY = 0;
377
+ let c, k;
378
+
379
+ for (k = 0; k < templateLength; k++) {
380
+ templateX[k] = template[k].x;
381
+ templateY[k] = template[k].y;
382
+ minX = Math.min(minX, template[k].x);
383
+ maxX = Math.max(maxX, template[k].x);
384
+ minY = Math.min(minY, template[k].y);
385
+ // Check if the template pixel appears in two consecutive context labels,
386
+ // so it can be reused. Otherwise, we add it to the list of changing
387
+ // template entries.
388
+ if (
389
+ k < templateLength - 1 &&
390
+ template[k].y === template[k + 1].y &&
391
+ template[k].x === template[k + 1].x - 1
392
+ ) {
393
+ reuseMask |= 1 << (templateLength - 1 - k);
394
+ } else {
395
+ changingTemplateEntries.push(k);
396
+ }
397
+ }
398
+ const changingEntriesLength = changingTemplateEntries.length;
399
+
400
+ const changingTemplateX = new Int8Array(changingEntriesLength);
401
+ const changingTemplateY = new Int8Array(changingEntriesLength);
402
+ const changingTemplateBit = new Uint16Array(changingEntriesLength);
403
+ for (c = 0; c < changingEntriesLength; c++) {
404
+ k = changingTemplateEntries[c];
405
+ changingTemplateX[c] = template[k].x;
406
+ changingTemplateY[c] = template[k].y;
407
+ changingTemplateBit[c] = 1 << (templateLength - 1 - k);
408
+ }
409
+
410
+ // Get the safe bounding box edges from the width, height, minX, maxX, minY
411
+ const sbb_left = -minX;
412
+ const sbb_top = -minY;
413
+ const sbb_right = width - maxX;
414
+
415
+ const pseudoPixelContext = ReusedContexts[templateIndex];
416
+ let row = new Uint8Array(width);
417
+ const bitmap = [];
418
+
419
+ const decoder = decodingContext.decoder;
420
+ const contexts = decodingContext.contextCache.getContexts('GB');
421
+
422
+ let ltp = 0,
423
+ j,
424
+ i0,
425
+ j0,
426
+ contextLabel = 0,
427
+ bit,
428
+ shift;
429
+ for (let i = 0; i < height; i++) {
430
+ if (prediction) {
431
+ const sltp = decoder.readBit(contexts, pseudoPixelContext);
432
+ ltp ^= sltp;
433
+ if (ltp) {
434
+ bitmap.push(row); // duplicate previous row
435
+ continue;
436
+ }
437
+ }
438
+ row = new Uint8Array(row);
439
+ bitmap.push(row);
440
+ for (j = 0; j < width; j++) {
441
+ if (useskip && skip[i][j]) {
442
+ row[j] = 0;
443
+ continue;
444
+ }
445
+ // Are we in the middle of a scanline, so we can reuse contextLabel
446
+ // bits?
447
+ if (j >= sbb_left && j < sbb_right && i >= sbb_top) {
448
+ // If yes, we can just shift the bits that are reusable and only
449
+ // fetch the remaining ones.
450
+ contextLabel = (contextLabel << 1) & reuseMask;
451
+ for (k = 0; k < changingEntriesLength; k++) {
452
+ i0 = i + changingTemplateY[k];
453
+ j0 = j + changingTemplateX[k];
454
+ bit = bitmap[i0][j0];
455
+ if (bit) {
456
+ bit = changingTemplateBit[k];
457
+ contextLabel |= bit;
458
+ }
459
+ }
460
+ } else {
461
+ // compute the contextLabel from scratch
462
+ contextLabel = 0;
463
+ shift = templateLength - 1;
464
+ for (k = 0; k < templateLength; k++, shift--) {
465
+ j0 = j + templateX[k];
466
+ if (j0 >= 0 && j0 < width) {
467
+ i0 = i + templateY[k];
468
+ if (i0 >= 0) {
469
+ bit = bitmap[i0][j0];
470
+ if (bit) {
471
+ contextLabel |= bit << shift;
472
+ }
473
+ }
474
+ }
475
+ }
476
+ }
477
+ const pixel = decoder.readBit(contexts, contextLabel);
478
+ row[j] = pixel;
479
+ }
480
+ }
481
+ return bitmap;
482
+ }
483
+
484
+ // 6.3.2 Generic Refinement Region Decoding Procedure
485
+ function decodeRefinement(
486
+ width,
487
+ height,
488
+ templateIndex,
489
+ referenceBitmap,
490
+ offsetX,
491
+ offsetY,
492
+ prediction,
493
+ at,
494
+ decodingContext
495
+ ) {
496
+ let codingTemplate = RefinementTemplates[templateIndex].coding;
497
+ if (templateIndex === 0) {
498
+ codingTemplate = codingTemplate.concat([at[0]]);
499
+ }
500
+ const codingTemplateLength = codingTemplate.length;
501
+ const codingTemplateX = new Int32Array(codingTemplateLength);
502
+ const codingTemplateY = new Int32Array(codingTemplateLength);
503
+ let k;
504
+ for (k = 0; k < codingTemplateLength; k++) {
505
+ codingTemplateX[k] = codingTemplate[k].x;
506
+ codingTemplateY[k] = codingTemplate[k].y;
507
+ }
508
+
509
+ let referenceTemplate = RefinementTemplates[templateIndex].reference;
510
+ if (templateIndex === 0) {
511
+ referenceTemplate = referenceTemplate.concat([at[1]]);
512
+ }
513
+ const referenceTemplateLength = referenceTemplate.length;
514
+ const referenceTemplateX = new Int32Array(referenceTemplateLength);
515
+ const referenceTemplateY = new Int32Array(referenceTemplateLength);
516
+ for (k = 0; k < referenceTemplateLength; k++) {
517
+ referenceTemplateX[k] = referenceTemplate[k].x;
518
+ referenceTemplateY[k] = referenceTemplate[k].y;
519
+ }
520
+ const referenceWidth = referenceBitmap[0].length;
521
+ const referenceHeight = referenceBitmap.length;
522
+
523
+ const pseudoPixelContext = RefinementReusedContexts[templateIndex];
524
+ const bitmap = [];
525
+
526
+ const decoder = decodingContext.decoder;
527
+ const contexts = decodingContext.contextCache.getContexts('GR');
528
+
529
+ let ltp = 0;
530
+ for (let i = 0; i < height; i++) {
531
+ if (prediction) {
532
+ const sltp = decoder.readBit(contexts, pseudoPixelContext);
533
+ ltp ^= sltp;
534
+ if (ltp) {
535
+ throw new Jbig2Error('prediction is not supported');
536
+ }
537
+ }
538
+ const row = new Uint8Array(width);
539
+ bitmap.push(row);
540
+ for (let j = 0; j < width; j++) {
541
+ let i0, j0;
542
+ let contextLabel = 0;
543
+ for (k = 0; k < codingTemplateLength; k++) {
544
+ i0 = i + codingTemplateY[k];
545
+ j0 = j + codingTemplateX[k];
546
+ if (i0 < 0 || j0 < 0 || j0 >= width) {
547
+ contextLabel <<= 1; // out of bound pixel
548
+ } else {
549
+ contextLabel = (contextLabel << 1) | bitmap[i0][j0];
550
+ }
551
+ }
552
+ for (k = 0; k < referenceTemplateLength; k++) {
553
+ i0 = i + referenceTemplateY[k] - offsetY;
554
+ j0 = j + referenceTemplateX[k] - offsetX;
555
+ if (i0 < 0 || i0 >= referenceHeight || j0 < 0 || j0 >= referenceWidth) {
556
+ contextLabel <<= 1; // out of bound pixel
557
+ } else {
558
+ contextLabel = (contextLabel << 1) | referenceBitmap[i0][j0];
559
+ }
560
+ }
561
+ const pixel = decoder.readBit(contexts, contextLabel);
562
+ row[j] = pixel;
563
+ }
564
+ }
565
+
566
+ return bitmap;
567
+ }
568
+
569
+ // 6.5.5 Decoding the symbol dictionary
570
+ function decodeSymbolDictionary(
571
+ huffman,
572
+ refinement,
573
+ symbols,
574
+ numberOfNewSymbols,
575
+ numberOfExportedSymbols,
576
+ huffmanTables,
577
+ templateIndex,
578
+ at,
579
+ refinementTemplateIndex,
580
+ refinementAt,
581
+ decodingContext,
582
+ huffmanInput
583
+ ) {
584
+ if (huffman && refinement) {
585
+ throw new Jbig2Error('symbol refinement with Huffman is not supported');
586
+ }
587
+
588
+ const newSymbols = [];
589
+ let currentHeight = 0;
590
+ let symbolCodeLength = log2(symbols.length + numberOfNewSymbols);
591
+
592
+ const decoder = decodingContext.decoder;
593
+ const contextCache = decodingContext.contextCache;
594
+ let tableB1, symbolWidths;
595
+ if (huffman) {
596
+ tableB1 = getStandardTable(1); // standard table B.1
597
+ symbolWidths = [];
598
+ symbolCodeLength = Math.max(symbolCodeLength, 1); // 6.5.8.2.3
599
+ }
600
+
601
+ while (newSymbols.length < numberOfNewSymbols) {
602
+ const deltaHeight = huffman
603
+ ? huffmanTables.tableDeltaHeight.decode(huffmanInput)
604
+ : decodeInteger(contextCache, 'IADH', decoder); // 6.5.6
605
+ currentHeight += deltaHeight;
606
+ let currentWidth = 0,
607
+ totalWidth = 0;
608
+ // @ts-ignore
609
+ const firstSymbol = huffman ? symbolWidths.length : 0;
610
+ while (true) {
611
+ const deltaWidth = huffman
612
+ ? huffmanTables.tableDeltaWidth.decode(huffmanInput)
613
+ : decodeInteger(contextCache, 'IADW', decoder); // 6.5.7
614
+ if (deltaWidth === null) {
615
+ break; // OOB
616
+ }
617
+ currentWidth += deltaWidth;
618
+ totalWidth += currentWidth;
619
+ let bitmap;
620
+ if (refinement) {
621
+ // 6.5.8.2 Refinement/aggregate-coded symbol bitmap
622
+ const numberOfInstances = decodeInteger(contextCache, 'IAAI', decoder);
623
+ // @ts-ignore
624
+ if (numberOfInstances > 1) {
625
+ bitmap = decodeTextRegion(
626
+ huffman,
627
+ refinement,
628
+ currentWidth,
629
+ currentHeight,
630
+ 0,
631
+ numberOfInstances,
632
+ 1, // strip size
633
+ symbols.concat(newSymbols),
634
+ symbolCodeLength,
635
+ 0, // transposed
636
+ 0, // ds offset
637
+ 1, // top left 7.4.3.1.1
638
+ 0, // OR operator
639
+ huffmanTables,
640
+ refinementTemplateIndex,
641
+ refinementAt,
642
+ decodingContext,
643
+ 0,
644
+ huffmanInput
645
+ );
646
+ } else {
647
+ const symbolId = decodeIAID(contextCache, decoder, symbolCodeLength);
648
+ const rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3
649
+ const rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4
650
+ const symbol =
651
+ symbolId < symbols.length
652
+ ? symbols[symbolId]
653
+ : newSymbols[symbolId - symbols.length];
654
+ bitmap = decodeRefinement(
655
+ currentWidth,
656
+ currentHeight,
657
+ refinementTemplateIndex,
658
+ symbol,
659
+ rdx,
660
+ rdy,
661
+ false,
662
+ refinementAt,
663
+ decodingContext
664
+ );
665
+ }
666
+ newSymbols.push(bitmap);
667
+ } else if (huffman) {
668
+ // Store only symbol width and decode a collective bitmap when the
669
+ // height class is done.
670
+ // @ts-ignore
671
+ symbolWidths.push(currentWidth);
672
+ } else {
673
+ // 6.5.8.1 Direct-coded symbol bitmap
674
+ bitmap = decodeBitmap(
675
+ false,
676
+ currentWidth,
677
+ currentHeight,
678
+ templateIndex,
679
+ false,
680
+ null,
681
+ at,
682
+ decodingContext
683
+ );
684
+ newSymbols.push(bitmap);
685
+ }
686
+ }
687
+ if (huffman && !refinement) {
688
+ // 6.5.9 Height class collective bitmap
689
+ const bitmapSize = huffmanTables.tableBitmapSize.decode(huffmanInput);
690
+ huffmanInput.byteAlign();
691
+ let collectiveBitmap;
692
+ if (bitmapSize === 0) {
693
+ // Uncompressed collective bitmap
694
+ collectiveBitmap = readUncompressedBitmap(
695
+ huffmanInput,
696
+ totalWidth,
697
+ currentHeight
698
+ );
699
+ } else {
700
+ // MMR collective bitmap
701
+ const originalEnd = huffmanInput.end;
702
+ const bitmapEnd = huffmanInput.position + bitmapSize;
703
+ huffmanInput.end = bitmapEnd;
704
+ collectiveBitmap = decodeMMRBitmap(
705
+ huffmanInput,
706
+ totalWidth,
707
+ currentHeight,
708
+ false
709
+ );
710
+ huffmanInput.end = originalEnd;
711
+ huffmanInput.position = bitmapEnd;
712
+ }
713
+ // @ts-ignore
714
+ const numberOfSymbolsDecoded = symbolWidths.length;
715
+ if (firstSymbol === numberOfSymbolsDecoded - 1) {
716
+ // collectiveBitmap is a single symbol.
717
+ newSymbols.push(collectiveBitmap);
718
+ } else {
719
+ // Divide collectiveBitmap into symbols.
720
+ let i,
721
+ y,
722
+ xMin = 0,
723
+ xMax,
724
+ bitmapWidth,
725
+ symbolBitmap;
726
+ for (i = firstSymbol; i < numberOfSymbolsDecoded; i++) {
727
+ // @ts-ignore
728
+ bitmapWidth = symbolWidths[i];
729
+ xMax = xMin + bitmapWidth;
730
+ symbolBitmap = [];
731
+ for (y = 0; y < currentHeight; y++) {
732
+ symbolBitmap.push(collectiveBitmap[y].subarray(xMin, xMax));
733
+ }
734
+ newSymbols.push(symbolBitmap);
735
+ xMin = xMax;
736
+ }
737
+ }
738
+ }
739
+ }
740
+
741
+ // 6.5.10 Exported symbols
742
+ const exportedSymbols = [],
743
+ flags = [];
744
+ let currentFlag = false,
745
+ i,
746
+ ii;
747
+ const totalSymbolsLength = symbols.length + numberOfNewSymbols;
748
+ while (flags.length < totalSymbolsLength) {
749
+ let runLength = huffman
750
+ ? tableB1.decode(huffmanInput)
751
+ : decodeInteger(contextCache, 'IAEX', decoder);
752
+ while (runLength--) {
753
+ flags.push(currentFlag);
754
+ }
755
+ currentFlag = !currentFlag;
756
+ }
757
+ for (i = 0, ii = symbols.length; i < ii; i++) {
758
+ if (flags[i]) {
759
+ exportedSymbols.push(symbols[i]);
760
+ }
761
+ }
762
+ for (let j = 0; j < numberOfNewSymbols; i++, j++) {
763
+ if (flags[i]) {
764
+ exportedSymbols.push(newSymbols[j]);
765
+ }
766
+ }
767
+ return exportedSymbols;
768
+ }
769
+
770
+ function decodeTextRegion(
771
+ huffman,
772
+ refinement,
773
+ width,
774
+ height,
775
+ defaultPixelValue,
776
+ numberOfSymbolInstances,
777
+ stripSize,
778
+ inputSymbols,
779
+ symbolCodeLength,
780
+ transposed,
781
+ dsOffset,
782
+ referenceCorner,
783
+ combinationOperator,
784
+ huffmanTables,
785
+ refinementTemplateIndex,
786
+ refinementAt,
787
+ decodingContext,
788
+ logStripSize,
789
+ huffmanInput
790
+ ) {
791
+ if (huffman && refinement) {
792
+ throw new Jbig2Error('refinement with Huffman is not supported');
793
+ }
794
+
795
+ // Prepare bitmap
796
+ const bitmap = [];
797
+ let i, row;
798
+ for (i = 0; i < height; i++) {
799
+ row = new Uint8Array(width);
800
+ if (defaultPixelValue) {
801
+ for (let j = 0; j < width; j++) {
802
+ row[j] = defaultPixelValue;
803
+ }
804
+ }
805
+ bitmap.push(row);
806
+ }
807
+
808
+ const decoder = decodingContext.decoder;
809
+ const contextCache = decodingContext.contextCache;
810
+
811
+ let stripT = huffman
812
+ ? -huffmanTables.tableDeltaT.decode(huffmanInput)
813
+ : // @ts-ignore
814
+ -decodeInteger(contextCache, 'IADT', decoder); // 6.4.6
815
+ let firstS = 0;
816
+ i = 0;
817
+ while (i < numberOfSymbolInstances) {
818
+ const deltaT = huffman
819
+ ? huffmanTables.tableDeltaT.decode(huffmanInput)
820
+ : decodeInteger(contextCache, 'IADT', decoder); // 6.4.6
821
+ stripT += deltaT;
822
+
823
+ const deltaFirstS = huffman
824
+ ? huffmanTables.tableFirstS.decode(huffmanInput)
825
+ : decodeInteger(contextCache, 'IAFS', decoder); // 6.4.7
826
+ firstS += deltaFirstS;
827
+ let currentS = firstS;
828
+ do {
829
+ let currentT = 0; // 6.4.9
830
+ if (stripSize > 1) {
831
+ currentT = huffman
832
+ ? huffmanInput.readBits(logStripSize)
833
+ : decodeInteger(contextCache, 'IAIT', decoder);
834
+ }
835
+ const t = stripSize * stripT + currentT;
836
+ const symbolId = huffman
837
+ ? huffmanTables.symbolIDTable.decode(huffmanInput)
838
+ : decodeIAID(contextCache, decoder, symbolCodeLength);
839
+ const applyRefinement =
840
+ refinement &&
841
+ (huffman
842
+ ? huffmanInput.readBit()
843
+ : decodeInteger(contextCache, 'IARI', decoder));
844
+ let symbolBitmap = inputSymbols[symbolId];
845
+ let symbolWidth = symbolBitmap[0].length;
846
+ let symbolHeight = symbolBitmap.length;
847
+ if (applyRefinement) {
848
+ const rdw = decodeInteger(contextCache, 'IARDW', decoder); // 6.4.11.1
849
+ const rdh = decodeInteger(contextCache, 'IARDH', decoder); // 6.4.11.2
850
+ const rdx = decodeInteger(contextCache, 'IARDX', decoder); // 6.4.11.3
851
+ const rdy = decodeInteger(contextCache, 'IARDY', decoder); // 6.4.11.4
852
+ symbolWidth += rdw;
853
+ symbolHeight += rdh;
854
+ symbolBitmap = decodeRefinement(
855
+ symbolWidth,
856
+ symbolHeight,
857
+ refinementTemplateIndex,
858
+ symbolBitmap,
859
+ // @ts-ignore
860
+ (rdw >> 1) + rdx,
861
+ // @ts-ignore
862
+ (rdh >> 1) + rdy,
863
+ false,
864
+ refinementAt,
865
+ decodingContext
866
+ );
867
+ }
868
+ const offsetT = t - (referenceCorner & 1 ? 0 : symbolHeight - 1);
869
+ const offsetS = currentS - (referenceCorner & 2 ? symbolWidth - 1 : 0);
870
+ let s2, t2, symbolRow;
871
+ if (transposed) {
872
+ // Place Symbol Bitmap from T1,S1
873
+ for (s2 = 0; s2 < symbolHeight; s2++) {
874
+ row = bitmap[offsetS + s2];
875
+ if (!row) {
876
+ continue;
877
+ }
878
+ symbolRow = symbolBitmap[s2];
879
+ // To ignore Parts of Symbol bitmap which goes
880
+ // outside bitmap region
881
+ const maxWidth = Math.min(width - offsetT, symbolWidth);
882
+ switch (combinationOperator) {
883
+ case 0: // OR
884
+ for (t2 = 0; t2 < maxWidth; t2++) {
885
+ row[offsetT + t2] |= symbolRow[t2];
886
+ }
887
+ break;
888
+ case 2: // XOR
889
+ for (t2 = 0; t2 < maxWidth; t2++) {
890
+ row[offsetT + t2] ^= symbolRow[t2];
891
+ }
892
+ break;
893
+ default:
894
+ throw new Jbig2Error(
895
+ `operator ${combinationOperator} is not supported`
896
+ );
897
+ }
898
+ }
899
+ currentS += symbolHeight - 1;
900
+ } else {
901
+ for (t2 = 0; t2 < symbolHeight; t2++) {
902
+ row = bitmap[offsetT + t2];
903
+ if (!row) {
904
+ continue;
905
+ }
906
+ symbolRow = symbolBitmap[t2];
907
+ switch (combinationOperator) {
908
+ case 0: // OR
909
+ for (s2 = 0; s2 < symbolWidth; s2++) {
910
+ row[offsetS + s2] |= symbolRow[s2];
911
+ }
912
+ break;
913
+ case 2: // XOR
914
+ for (s2 = 0; s2 < symbolWidth; s2++) {
915
+ row[offsetS + s2] ^= symbolRow[s2];
916
+ }
917
+ break;
918
+ default:
919
+ throw new Jbig2Error(
920
+ `operator ${combinationOperator} is not supported`
921
+ );
922
+ }
923
+ }
924
+ currentS += symbolWidth - 1;
925
+ }
926
+ i++;
927
+ const deltaS = huffman
928
+ ? huffmanTables.tableDeltaS.decode(huffmanInput)
929
+ : decodeInteger(contextCache, 'IADS', decoder); // 6.4.8
930
+ if (deltaS === null) {
931
+ break; // OOB
932
+ }
933
+ currentS += deltaS + dsOffset;
934
+ } while (true);
935
+ }
936
+ return bitmap;
937
+ }
938
+
939
+ function decodePatternDictionary(
940
+ mmr,
941
+ patternWidth,
942
+ patternHeight,
943
+ maxPatternIndex,
944
+ template,
945
+ decodingContext
946
+ ) {
947
+ const at = [];
948
+ if (!mmr) {
949
+ at.push({
950
+ x: -patternWidth,
951
+ y: 0
952
+ });
953
+ if (template === 0) {
954
+ at.push(
955
+ {
956
+ x: -3,
957
+ y: -1
958
+ },
959
+ {
960
+ x: 2,
961
+ y: -2
962
+ },
963
+ {
964
+ x: -2,
965
+ y: -2
966
+ }
967
+ );
968
+ }
969
+ }
970
+ const collectiveWidth = (maxPatternIndex + 1) * patternWidth;
971
+ const collectiveBitmap = decodeBitmap(
972
+ mmr,
973
+ collectiveWidth,
974
+ patternHeight,
975
+ template,
976
+ false,
977
+ null,
978
+ at,
979
+ decodingContext
980
+ );
981
+ // Divide collective bitmap into patterns.
982
+ const patterns = [];
983
+ for (let i = 0; i <= maxPatternIndex; i++) {
984
+ const patternBitmap = [];
985
+ const xMin = patternWidth * i;
986
+ const xMax = xMin + patternWidth;
987
+ for (let y = 0; y < patternHeight; y++) {
988
+ patternBitmap.push(collectiveBitmap[y].subarray(xMin, xMax));
989
+ }
990
+ patterns.push(patternBitmap);
991
+ }
992
+ return patterns;
993
+ }
994
+
995
+ function decodeHalftoneRegion(
996
+ mmr,
997
+ patterns,
998
+ template,
999
+ regionWidth,
1000
+ regionHeight,
1001
+ defaultPixelValue,
1002
+ enableSkip,
1003
+ combinationOperator,
1004
+ gridWidth,
1005
+ gridHeight,
1006
+ gridOffsetX,
1007
+ gridOffsetY,
1008
+ gridVectorX,
1009
+ gridVectorY,
1010
+ decodingContext
1011
+ ) {
1012
+ const skip = null;
1013
+ if (enableSkip) {
1014
+ throw new Jbig2Error('skip is not supported');
1015
+ }
1016
+ if (combinationOperator !== 0) {
1017
+ throw new Jbig2Error(
1018
+ `operator "${combinationOperator}" is not supported in halftone region`
1019
+ );
1020
+ }
1021
+
1022
+ // Prepare bitmap.
1023
+ const regionBitmap = [];
1024
+ let i, j, row;
1025
+ for (i = 0; i < regionHeight; i++) {
1026
+ row = new Uint8Array(regionWidth);
1027
+ if (defaultPixelValue) {
1028
+ for (j = 0; j < regionWidth; j++) {
1029
+ row[j] = defaultPixelValue;
1030
+ }
1031
+ }
1032
+ regionBitmap.push(row);
1033
+ }
1034
+
1035
+ const numberOfPatterns = patterns.length;
1036
+ const pattern0 = patterns[0];
1037
+ const patternWidth = pattern0[0].length,
1038
+ patternHeight = pattern0.length;
1039
+ const bitsPerValue = log2(numberOfPatterns);
1040
+ const at = [];
1041
+ if (!mmr) {
1042
+ at.push({
1043
+ x: template <= 1 ? 3 : 2,
1044
+ y: -1
1045
+ });
1046
+ if (template === 0) {
1047
+ at.push(
1048
+ {
1049
+ x: -3,
1050
+ y: -1
1051
+ },
1052
+ {
1053
+ x: 2,
1054
+ y: -2
1055
+ },
1056
+ {
1057
+ x: -2,
1058
+ y: -2
1059
+ }
1060
+ );
1061
+ }
1062
+ }
1063
+ // Annex C. Gray-scale Image Decoding Procedure.
1064
+ const grayScaleBitPlanes = [];
1065
+ let mmrInput, bitmap;
1066
+ if (mmr) {
1067
+ // MMR bit planes are in one continuous stream. Only EOFB codes indicate
1068
+ // the end of each bitmap, so EOFBs must be decoded.
1069
+ mmrInput = new Reader(
1070
+ decodingContext.data,
1071
+ decodingContext.start,
1072
+ decodingContext.end
1073
+ );
1074
+ }
1075
+ for (i = bitsPerValue - 1; i >= 0; i--) {
1076
+ if (mmr) {
1077
+ bitmap = decodeMMRBitmap(mmrInput, gridWidth, gridHeight, true);
1078
+ } else {
1079
+ bitmap = decodeBitmap(
1080
+ false,
1081
+ gridWidth,
1082
+ gridHeight,
1083
+ template,
1084
+ false,
1085
+ skip,
1086
+ at,
1087
+ decodingContext
1088
+ );
1089
+ }
1090
+ grayScaleBitPlanes[i] = bitmap;
1091
+ }
1092
+ // 6.6.5.2 Rendering the patterns.
1093
+ let mg, ng, bit, patternIndex, patternBitmap, x, y, patternRow, regionRow;
1094
+ for (mg = 0; mg < gridHeight; mg++) {
1095
+ for (ng = 0; ng < gridWidth; ng++) {
1096
+ bit = 0;
1097
+ patternIndex = 0;
1098
+ for (j = bitsPerValue - 1; j >= 0; j--) {
1099
+ bit ^= grayScaleBitPlanes[j][mg][ng]; // Gray decoding
1100
+ patternIndex |= bit << j;
1101
+ }
1102
+ patternBitmap = patterns[patternIndex];
1103
+ x = (gridOffsetX + mg * gridVectorY + ng * gridVectorX) >> 8;
1104
+ y = (gridOffsetY + mg * gridVectorX - ng * gridVectorY) >> 8;
1105
+ // Draw patternBitmap at (x, y).
1106
+ if (
1107
+ x >= 0 &&
1108
+ x + patternWidth <= regionWidth &&
1109
+ y >= 0 &&
1110
+ y + patternHeight <= regionHeight
1111
+ ) {
1112
+ for (i = 0; i < patternHeight; i++) {
1113
+ regionRow = regionBitmap[y + i];
1114
+ patternRow = patternBitmap[i];
1115
+ for (j = 0; j < patternWidth; j++) {
1116
+ regionRow[x + j] |= patternRow[j];
1117
+ }
1118
+ }
1119
+ } else {
1120
+ let regionX, regionY;
1121
+ for (i = 0; i < patternHeight; i++) {
1122
+ regionY = y + i;
1123
+ if (regionY < 0 || regionY >= regionHeight) {
1124
+ continue;
1125
+ }
1126
+ regionRow = regionBitmap[regionY];
1127
+ patternRow = patternBitmap[i];
1128
+ for (j = 0; j < patternWidth; j++) {
1129
+ regionX = x + j;
1130
+ if (regionX >= 0 && regionX < regionWidth) {
1131
+ regionRow[regionX] |= patternRow[j];
1132
+ }
1133
+ }
1134
+ }
1135
+ }
1136
+ }
1137
+ }
1138
+ return regionBitmap;
1139
+ }
1140
+
1141
+ function readSegmentHeader(data, start) {
1142
+ const segmentHeader = {};
1143
+ segmentHeader.number = readUint32(data, start);
1144
+ const flags = data[start + 4];
1145
+ const segmentType = flags & 0x3f;
1146
+ if (!SegmentTypes[segmentType]) {
1147
+ throw new Jbig2Error('invalid segment type: ' + segmentType);
1148
+ }
1149
+ segmentHeader.type = segmentType;
1150
+ segmentHeader.typeName = SegmentTypes[segmentType];
1151
+ segmentHeader.deferredNonRetain = !!(flags & 0x80);
1152
+
1153
+ const pageAssociationFieldSize = !!(flags & 0x40);
1154
+ const referredFlags = data[start + 5];
1155
+ let referredToCount = (referredFlags >> 5) & 7;
1156
+ const retainBits = [referredFlags & 31];
1157
+ let position = start + 6;
1158
+ if (referredFlags === 7) {
1159
+ referredToCount = readUint32(data, position - 1) & 0x1fffffff;
1160
+ position += 3;
1161
+ let bytes = (referredToCount + 7) >> 3;
1162
+ retainBits[0] = data[position++];
1163
+ while (--bytes > 0) {
1164
+ retainBits.push(data[position++]);
1165
+ }
1166
+ } else if (referredFlags === 5 || referredFlags === 6) {
1167
+ throw new Jbig2Error('invalid referred-to flags');
1168
+ }
1169
+
1170
+ segmentHeader.retainBits = retainBits;
1171
+
1172
+ let referredToSegmentNumberSize = 4;
1173
+ if (segmentHeader.number <= 256) {
1174
+ referredToSegmentNumberSize = 1;
1175
+ } else if (segmentHeader.number <= 65536) {
1176
+ referredToSegmentNumberSize = 2;
1177
+ }
1178
+ const referredTo = [];
1179
+ let i, ii;
1180
+ for (i = 0; i < referredToCount; i++) {
1181
+ let number;
1182
+ if (referredToSegmentNumberSize === 1) {
1183
+ number = data[position];
1184
+ } else if (referredToSegmentNumberSize === 2) {
1185
+ number = readUint16(data, position);
1186
+ } else {
1187
+ number = readUint32(data, position);
1188
+ }
1189
+ referredTo.push(number);
1190
+ position += referredToSegmentNumberSize;
1191
+ }
1192
+ segmentHeader.referredTo = referredTo;
1193
+ if (!pageAssociationFieldSize) {
1194
+ segmentHeader.pageAssociation = data[position++];
1195
+ } else {
1196
+ segmentHeader.pageAssociation = readUint32(data, position);
1197
+ position += 4;
1198
+ }
1199
+ segmentHeader.length = readUint32(data, position);
1200
+ position += 4;
1201
+
1202
+ if (segmentHeader.length === 0xffffffff) {
1203
+ // 7.2.7 Segment data length, unknown segment length
1204
+ if (segmentType === 38) {
1205
+ // ImmediateGenericRegion
1206
+ const genericRegionInfo = readRegionSegmentInformation(data, position);
1207
+ const genericRegionSegmentFlags =
1208
+ data[position + RegionSegmentInformationFieldLength];
1209
+ const genericRegionMmr = !!(genericRegionSegmentFlags & 1);
1210
+ // searching for the segment end
1211
+ const searchPatternLength = 6;
1212
+ const searchPattern = new Uint8Array(searchPatternLength);
1213
+ if (!genericRegionMmr) {
1214
+ searchPattern[0] = 0xff;
1215
+ searchPattern[1] = 0xac;
1216
+ }
1217
+ searchPattern[2] = (genericRegionInfo.height >>> 24) & 0xff;
1218
+ searchPattern[3] = (genericRegionInfo.height >> 16) & 0xff;
1219
+ searchPattern[4] = (genericRegionInfo.height >> 8) & 0xff;
1220
+ searchPattern[5] = genericRegionInfo.height & 0xff;
1221
+ for (i = position, ii = data.length; i < ii; i++) {
1222
+ let j = 0;
1223
+ while (j < searchPatternLength && searchPattern[j] === data[i + j]) {
1224
+ j++;
1225
+ }
1226
+ if (j === searchPatternLength) {
1227
+ segmentHeader.length = i + searchPatternLength;
1228
+ break;
1229
+ }
1230
+ }
1231
+ if (segmentHeader.length === 0xffffffff) {
1232
+ throw new Jbig2Error('segment end was not found');
1233
+ }
1234
+ } else {
1235
+ throw new Jbig2Error('invalid unknown segment length');
1236
+ }
1237
+ }
1238
+ segmentHeader.headerEnd = position;
1239
+ return segmentHeader;
1240
+ }
1241
+
1242
+ function readSegments(header, data, start, end) {
1243
+ const segments = [];
1244
+ let position = start;
1245
+ while (position < end) {
1246
+ const segmentHeader = readSegmentHeader(data, position);
1247
+ position = segmentHeader.headerEnd;
1248
+ const segment = {
1249
+ header: segmentHeader,
1250
+ data
1251
+ };
1252
+ if (!header.randomAccess) {
1253
+ segment.start = position;
1254
+ position += segmentHeader.length;
1255
+ segment.end = position;
1256
+ }
1257
+ segments.push(segment);
1258
+ if (segmentHeader.type === 51) {
1259
+ break; // end of file is found
1260
+ }
1261
+ }
1262
+ if (header.randomAccess) {
1263
+ for (let i = 0, ii = segments.length; i < ii; i++) {
1264
+ segments[i].start = position;
1265
+ position += segments[i].header.length;
1266
+ segments[i].end = position;
1267
+ }
1268
+ }
1269
+ return segments;
1270
+ }
1271
+
1272
+ // 7.4.1 Region segment information field
1273
+ function readRegionSegmentInformation(data, start) {
1274
+ return {
1275
+ width: readUint32(data, start),
1276
+ height: readUint32(data, start + 4),
1277
+ x: readUint32(data, start + 8),
1278
+ y: readUint32(data, start + 12),
1279
+ combinationOperator: data[start + 16] & 7
1280
+ };
1281
+ }
1282
+ const RegionSegmentInformationFieldLength = 17;
1283
+
1284
+ function processSegment(segment, visitor) {
1285
+ const header = segment.header;
1286
+
1287
+ const data = segment.data,
1288
+ end = segment.end;
1289
+ let position = segment.start;
1290
+ let args, at, i, atLength;
1291
+ switch (header.type) {
1292
+ case 0: // SymbolDictionary
1293
+ // 7.4.2 Symbol dictionary segment syntax
1294
+ const dictionary = {};
1295
+ const dictionaryFlags = readUint16(data, position); // 7.4.2.1.1
1296
+ dictionary.huffman = !!(dictionaryFlags & 1);
1297
+ dictionary.refinement = !!(dictionaryFlags & 2);
1298
+ dictionary.huffmanDHSelector = (dictionaryFlags >> 2) & 3;
1299
+ dictionary.huffmanDWSelector = (dictionaryFlags >> 4) & 3;
1300
+ dictionary.bitmapSizeSelector = (dictionaryFlags >> 6) & 1;
1301
+ dictionary.aggregationInstancesSelector = (dictionaryFlags >> 7) & 1;
1302
+ dictionary.bitmapCodingContextUsed = !!(dictionaryFlags & 256);
1303
+ dictionary.bitmapCodingContextRetained = !!(dictionaryFlags & 512);
1304
+ dictionary.template = (dictionaryFlags >> 10) & 3;
1305
+ dictionary.refinementTemplate = (dictionaryFlags >> 12) & 1;
1306
+ position += 2;
1307
+ if (!dictionary.huffman) {
1308
+ atLength = dictionary.template === 0 ? 4 : 1;
1309
+ at = [];
1310
+ for (i = 0; i < atLength; i++) {
1311
+ at.push({
1312
+ x: readInt8(data, position),
1313
+ y: readInt8(data, position + 1)
1314
+ });
1315
+ position += 2;
1316
+ }
1317
+ dictionary.at = at;
1318
+ }
1319
+ if (dictionary.refinement && !dictionary.refinementTemplate) {
1320
+ at = [];
1321
+ for (i = 0; i < 2; i++) {
1322
+ at.push({
1323
+ x: readInt8(data, position),
1324
+ y: readInt8(data, position + 1)
1325
+ });
1326
+ position += 2;
1327
+ }
1328
+ dictionary.refinementAt = at;
1329
+ }
1330
+ dictionary.numberOfExportedSymbols = readUint32(data, position);
1331
+ position += 4;
1332
+ dictionary.numberOfNewSymbols = readUint32(data, position);
1333
+ position += 4;
1334
+ args = [
1335
+ dictionary,
1336
+ header.number,
1337
+ header.referredTo,
1338
+ data,
1339
+ position,
1340
+ end
1341
+ ];
1342
+ break;
1343
+ case 6: // ImmediateTextRegion
1344
+ case 7: // ImmediateLosslessTextRegion
1345
+ const textRegion = {};
1346
+ textRegion.info = readRegionSegmentInformation(data, position);
1347
+ position += RegionSegmentInformationFieldLength;
1348
+ const textRegionSegmentFlags = readUint16(data, position);
1349
+ position += 2;
1350
+ textRegion.huffman = !!(textRegionSegmentFlags & 1);
1351
+ textRegion.refinement = !!(textRegionSegmentFlags & 2);
1352
+ textRegion.logStripSize = (textRegionSegmentFlags >> 2) & 3;
1353
+ textRegion.stripSize = 1 << textRegion.logStripSize;
1354
+ textRegion.referenceCorner = (textRegionSegmentFlags >> 4) & 3;
1355
+ textRegion.transposed = !!(textRegionSegmentFlags & 64);
1356
+ textRegion.combinationOperator = (textRegionSegmentFlags >> 7) & 3;
1357
+ textRegion.defaultPixelValue = (textRegionSegmentFlags >> 9) & 1;
1358
+ textRegion.dsOffset = (textRegionSegmentFlags << 17) >> 27;
1359
+ textRegion.refinementTemplate = (textRegionSegmentFlags >> 15) & 1;
1360
+ if (textRegion.huffman) {
1361
+ const textRegionHuffmanFlags = readUint16(data, position);
1362
+ position += 2;
1363
+ textRegion.huffmanFS = textRegionHuffmanFlags & 3;
1364
+ textRegion.huffmanDS = (textRegionHuffmanFlags >> 2) & 3;
1365
+ textRegion.huffmanDT = (textRegionHuffmanFlags >> 4) & 3;
1366
+ textRegion.huffmanRefinementDW = (textRegionHuffmanFlags >> 6) & 3;
1367
+ textRegion.huffmanRefinementDH = (textRegionHuffmanFlags >> 8) & 3;
1368
+ textRegion.huffmanRefinementDX = (textRegionHuffmanFlags >> 10) & 3;
1369
+ textRegion.huffmanRefinementDY = (textRegionHuffmanFlags >> 12) & 3;
1370
+ textRegion.huffmanRefinementSizeSelector = !!(
1371
+ textRegionHuffmanFlags & 0x4000
1372
+ );
1373
+ }
1374
+ if (textRegion.refinement && !textRegion.refinementTemplate) {
1375
+ at = [];
1376
+ for (i = 0; i < 2; i++) {
1377
+ at.push({
1378
+ x: readInt8(data, position),
1379
+ y: readInt8(data, position + 1)
1380
+ });
1381
+ position += 2;
1382
+ }
1383
+ textRegion.refinementAt = at;
1384
+ }
1385
+ textRegion.numberOfSymbolInstances = readUint32(data, position);
1386
+ position += 4;
1387
+ args = [textRegion, header.referredTo, data, position, end];
1388
+ break;
1389
+ case 16: // PatternDictionary
1390
+ // 7.4.4. Pattern dictionary segment syntax
1391
+ const patternDictionary = {};
1392
+ const patternDictionaryFlags = data[position++];
1393
+ patternDictionary.mmr = !!(patternDictionaryFlags & 1);
1394
+ patternDictionary.template = (patternDictionaryFlags >> 1) & 3;
1395
+ patternDictionary.patternWidth = data[position++];
1396
+ patternDictionary.patternHeight = data[position++];
1397
+ patternDictionary.maxPatternIndex = readUint32(data, position);
1398
+ position += 4;
1399
+ args = [patternDictionary, header.number, data, position, end];
1400
+ break;
1401
+ case 22: // ImmediateHalftoneRegion
1402
+ case 23: // ImmediateLosslessHalftoneRegion
1403
+ // 7.4.5 Halftone region segment syntax
1404
+ const halftoneRegion = {};
1405
+ halftoneRegion.info = readRegionSegmentInformation(data, position);
1406
+ position += RegionSegmentInformationFieldLength;
1407
+ const halftoneRegionFlags = data[position++];
1408
+ halftoneRegion.mmr = !!(halftoneRegionFlags & 1);
1409
+ halftoneRegion.template = (halftoneRegionFlags >> 1) & 3;
1410
+ halftoneRegion.enableSkip = !!(halftoneRegionFlags & 8);
1411
+ halftoneRegion.combinationOperator = (halftoneRegionFlags >> 4) & 7;
1412
+ halftoneRegion.defaultPixelValue = (halftoneRegionFlags >> 7) & 1;
1413
+ halftoneRegion.gridWidth = readUint32(data, position);
1414
+ position += 4;
1415
+ halftoneRegion.gridHeight = readUint32(data, position);
1416
+ position += 4;
1417
+ halftoneRegion.gridOffsetX = readUint32(data, position) & 0xffffffff;
1418
+ position += 4;
1419
+ halftoneRegion.gridOffsetY = readUint32(data, position) & 0xffffffff;
1420
+ position += 4;
1421
+ halftoneRegion.gridVectorX = readUint16(data, position);
1422
+ position += 2;
1423
+ halftoneRegion.gridVectorY = readUint16(data, position);
1424
+ position += 2;
1425
+ args = [halftoneRegion, header.referredTo, data, position, end];
1426
+ break;
1427
+ case 38: // ImmediateGenericRegion
1428
+ case 39: // ImmediateLosslessGenericRegion
1429
+ const genericRegion = {};
1430
+ genericRegion.info = readRegionSegmentInformation(data, position);
1431
+ position += RegionSegmentInformationFieldLength;
1432
+ const genericRegionSegmentFlags = data[position++];
1433
+ genericRegion.mmr = !!(genericRegionSegmentFlags & 1);
1434
+ genericRegion.template = (genericRegionSegmentFlags >> 1) & 3;
1435
+ genericRegion.prediction = !!(genericRegionSegmentFlags & 8);
1436
+ if (!genericRegion.mmr) {
1437
+ atLength = genericRegion.template === 0 ? 4 : 1;
1438
+ at = [];
1439
+ for (i = 0; i < atLength; i++) {
1440
+ at.push({
1441
+ x: readInt8(data, position),
1442
+ y: readInt8(data, position + 1)
1443
+ });
1444
+ position += 2;
1445
+ }
1446
+ genericRegion.at = at;
1447
+ }
1448
+ args = [genericRegion, data, position, end];
1449
+ break;
1450
+ case 48: // PageInformation
1451
+ const pageInfo = {
1452
+ width: readUint32(data, position),
1453
+ height: readUint32(data, position + 4),
1454
+ resolutionX: readUint32(data, position + 8),
1455
+ resolutionY: readUint32(data, position + 12)
1456
+ };
1457
+ if (pageInfo.height === 0xffffffff) {
1458
+ // @ts-ignore
1459
+ delete pageInfo.height;
1460
+ }
1461
+ const pageSegmentFlags = data[position + 16];
1462
+ readUint16(data, position + 17); // pageStripingInformation
1463
+ pageInfo.lossless = !!(pageSegmentFlags & 1);
1464
+ pageInfo.refinement = !!(pageSegmentFlags & 2);
1465
+ pageInfo.defaultPixelValue = (pageSegmentFlags >> 2) & 1;
1466
+ pageInfo.combinationOperator = (pageSegmentFlags >> 3) & 3;
1467
+ pageInfo.requiresBuffer = !!(pageSegmentFlags & 32);
1468
+ pageInfo.combinationOperatorOverride = !!(pageSegmentFlags & 64);
1469
+ args = [pageInfo];
1470
+ break;
1471
+ case 49: // EndOfPage
1472
+ break;
1473
+ case 50: // EndOfStripe
1474
+ break;
1475
+ case 51: // EndOfFile
1476
+ break;
1477
+ case 53: // Tables
1478
+ args = [header.number, data, position, end];
1479
+ break;
1480
+ case 62: // 7.4.15 defines 2 extension types which
1481
+ // are comments and can be ignored.
1482
+ break;
1483
+ default:
1484
+ throw new Jbig2Error(
1485
+ `segment type ${header.typeName}(${header.type}) is not implemented`
1486
+ );
1487
+ }
1488
+ const callbackName = 'on' + header.typeName;
1489
+ if (callbackName in visitor) {
1490
+ // eslint-disable-next-line prefer-spread
1491
+ visitor[callbackName].apply(visitor, args);
1492
+ }
1493
+ }
1494
+
1495
+ function processSegments(segments, visitor) {
1496
+ for (let i = 0, ii = segments.length; i < ii; i++) {
1497
+ processSegment(segments[i], visitor);
1498
+ }
1499
+ }
1500
+
1501
+ function parseJbig2Chunks(chunks) {
1502
+ const visitor = new SimpleSegmentVisitor();
1503
+ for (let i = 0, ii = chunks.length; i < ii; i++) {
1504
+ const chunk = chunks[i];
1505
+ const segments = readSegments({}, chunk.data, chunk.start, chunk.end);
1506
+ processSegments(segments, visitor);
1507
+ }
1508
+ return visitor.buffer;
1509
+ }
1510
+
1511
+ function parseJbig2(data) {
1512
+ const end = data.length;
1513
+ let position = 0;
1514
+
1515
+ if (
1516
+ data[position] !== 0x97 ||
1517
+ data[position + 1] !== 0x4a ||
1518
+ data[position + 2] !== 0x42 ||
1519
+ data[position + 3] !== 0x32 ||
1520
+ data[position + 4] !== 0x0d ||
1521
+ data[position + 5] !== 0x0a ||
1522
+ data[position + 6] !== 0x1a ||
1523
+ data[position + 7] !== 0x0a
1524
+ ) {
1525
+ throw new Jbig2Error('parseJbig2 - invalid header.');
1526
+ }
1527
+
1528
+ const header = Object.create(null);
1529
+ position += 8;
1530
+ const flags = data[position++];
1531
+ header.randomAccess = !(flags & 1);
1532
+ if (!(flags & 2)) {
1533
+ header.numberOfPages = readUint32(data, position);
1534
+ position += 4;
1535
+ }
1536
+
1537
+ const segments = readSegments(header, data, position, end);
1538
+ const visitor = new SimpleSegmentVisitor();
1539
+ processSegments(segments, visitor);
1540
+
1541
+ const { width, height } = visitor.currentPageInfo;
1542
+ const bitPacked = visitor.buffer;
1543
+ const imgData = new Uint8ClampedArray(width * height);
1544
+ let q = 0,
1545
+ k = 0;
1546
+ for (let i = 0; i < height; i++) {
1547
+ let mask = 0,
1548
+ buffer;
1549
+ for (let j = 0; j < width; j++) {
1550
+ if (!mask) {
1551
+ mask = 128;
1552
+ // @ts-ignore
1553
+ buffer = bitPacked[k++];
1554
+ }
1555
+ // @ts-ignore
1556
+ imgData[q++] = buffer & mask ? 0 : 255;
1557
+ mask >>= 1;
1558
+ }
1559
+ }
1560
+
1561
+ return { imgData, width, height };
1562
+ }
1563
+
1564
+ class SimpleSegmentVisitor {
1565
+ onPageInformation(info) {
1566
+ this.currentPageInfo = info;
1567
+ const rowSize = (info.width + 7) >> 3;
1568
+ const buffer = new Uint8ClampedArray(rowSize * info.height);
1569
+ // The contents of ArrayBuffers are initialized to 0.
1570
+ // Fill the buffer with 0xFF only if info.defaultPixelValue is set
1571
+ if (info.defaultPixelValue) {
1572
+ buffer.fill(0xff);
1573
+ }
1574
+ this.buffer = buffer;
1575
+ }
1576
+
1577
+ drawBitmap(regionInfo, bitmap) {
1578
+ const pageInfo = this.currentPageInfo;
1579
+ const width = regionInfo.width,
1580
+ height = regionInfo.height;
1581
+ const rowSize = (pageInfo.width + 7) >> 3;
1582
+ const combinationOperator = pageInfo.combinationOperatorOverride
1583
+ ? regionInfo.combinationOperator
1584
+ : pageInfo.combinationOperator;
1585
+ const buffer = this.buffer;
1586
+ const mask0 = 128 >> (regionInfo.x & 7);
1587
+ let offset0 = regionInfo.y * rowSize + (regionInfo.x >> 3);
1588
+ let i, j, mask, offset;
1589
+ switch (combinationOperator) {
1590
+ case 0: // OR
1591
+ for (i = 0; i < height; i++) {
1592
+ mask = mask0;
1593
+ offset = offset0;
1594
+ for (j = 0; j < width; j++) {
1595
+ if (bitmap[i][j]) {
1596
+ // @ts-ignore
1597
+ buffer[offset] |= mask;
1598
+ }
1599
+ mask >>= 1;
1600
+ if (!mask) {
1601
+ mask = 128;
1602
+ offset++;
1603
+ }
1604
+ }
1605
+ offset0 += rowSize;
1606
+ }
1607
+ break;
1608
+ case 2: // XOR
1609
+ for (i = 0; i < height; i++) {
1610
+ mask = mask0;
1611
+ offset = offset0;
1612
+ for (j = 0; j < width; j++) {
1613
+ if (bitmap[i][j]) {
1614
+ // @ts-ignore
1615
+ buffer[offset] ^= mask;
1616
+ }
1617
+ mask >>= 1;
1618
+ if (!mask) {
1619
+ mask = 128;
1620
+ offset++;
1621
+ }
1622
+ }
1623
+ offset0 += rowSize;
1624
+ }
1625
+ break;
1626
+ default:
1627
+ throw new Jbig2Error(
1628
+ `operator ${combinationOperator} is not supported`
1629
+ );
1630
+ }
1631
+ }
1632
+
1633
+ onImmediateGenericRegion(region, data, start, end) {
1634
+ const regionInfo = region.info;
1635
+ const decodingContext = new DecodingContext(data, start, end);
1636
+ const bitmap = decodeBitmap(
1637
+ region.mmr,
1638
+ regionInfo.width,
1639
+ regionInfo.height,
1640
+ region.template,
1641
+ region.prediction,
1642
+ null,
1643
+ region.at,
1644
+ decodingContext
1645
+ );
1646
+ this.drawBitmap(regionInfo, bitmap);
1647
+ }
1648
+
1649
+ onImmediateLosslessGenericRegion() {
1650
+ this.onImmediateGenericRegion(...arguments);
1651
+ }
1652
+
1653
+ onSymbolDictionary(
1654
+ dictionary,
1655
+ currentSegment,
1656
+ referredSegments,
1657
+ data,
1658
+ start,
1659
+ end
1660
+ ) {
1661
+ let huffmanTables, huffmanInput;
1662
+ if (dictionary.huffman) {
1663
+ huffmanTables = getSymbolDictionaryHuffmanTables(
1664
+ dictionary,
1665
+ referredSegments,
1666
+ this.customTables
1667
+ );
1668
+ huffmanInput = new Reader(data, start, end);
1669
+ }
1670
+
1671
+ // Combines exported symbols from all referred segments
1672
+ let symbols = this.symbols;
1673
+ if (!symbols) {
1674
+ this.symbols = symbols = {};
1675
+ }
1676
+
1677
+ const inputSymbols = [];
1678
+ for (const referredSegment of referredSegments) {
1679
+ const referredSymbols = symbols[referredSegment];
1680
+ // referredSymbols is undefined when we have a reference to a Tables
1681
+ // segment instead of a SymbolDictionary.
1682
+ if (referredSymbols) {
1683
+ inputSymbols.push(...referredSymbols);
1684
+ }
1685
+ }
1686
+
1687
+ const decodingContext = new DecodingContext(data, start, end);
1688
+ symbols[currentSegment] = decodeSymbolDictionary(
1689
+ dictionary.huffman,
1690
+ dictionary.refinement,
1691
+ inputSymbols,
1692
+ dictionary.numberOfNewSymbols,
1693
+ dictionary.numberOfExportedSymbols,
1694
+ huffmanTables,
1695
+ dictionary.template,
1696
+ dictionary.at,
1697
+ dictionary.refinementTemplate,
1698
+ dictionary.refinementAt,
1699
+ decodingContext,
1700
+ huffmanInput
1701
+ );
1702
+ }
1703
+
1704
+ onImmediateTextRegion(region, referredSegments, data, start, end) {
1705
+ const regionInfo = region.info;
1706
+ let huffmanTables, huffmanInput;
1707
+
1708
+ // Combines exported symbols from all referred segments
1709
+ const symbols = this.symbols;
1710
+ const inputSymbols = [];
1711
+ for (const referredSegment of referredSegments) {
1712
+ const referredSymbols = symbols[referredSegment];
1713
+ // referredSymbols is undefined when we have a reference to a Tables
1714
+ // segment instead of a SymbolDictionary.
1715
+ if (referredSymbols) {
1716
+ inputSymbols.push(...referredSymbols);
1717
+ }
1718
+ }
1719
+ const symbolCodeLength = log2(inputSymbols.length);
1720
+ if (region.huffman) {
1721
+ huffmanInput = new Reader(data, start, end);
1722
+ huffmanTables = getTextRegionHuffmanTables(
1723
+ region,
1724
+ referredSegments,
1725
+ this.customTables,
1726
+ inputSymbols.length,
1727
+ huffmanInput
1728
+ );
1729
+ }
1730
+
1731
+ const decodingContext = new DecodingContext(data, start, end);
1732
+ const bitmap = decodeTextRegion(
1733
+ region.huffman,
1734
+ region.refinement,
1735
+ regionInfo.width,
1736
+ regionInfo.height,
1737
+ region.defaultPixelValue,
1738
+ region.numberOfSymbolInstances,
1739
+ region.stripSize,
1740
+ inputSymbols,
1741
+ symbolCodeLength,
1742
+ region.transposed,
1743
+ region.dsOffset,
1744
+ region.referenceCorner,
1745
+ region.combinationOperator,
1746
+ huffmanTables,
1747
+ region.refinementTemplate,
1748
+ region.refinementAt,
1749
+ decodingContext,
1750
+ region.logStripSize,
1751
+ huffmanInput
1752
+ );
1753
+ this.drawBitmap(regionInfo, bitmap);
1754
+ }
1755
+
1756
+ onImmediateLosslessTextRegion() {
1757
+ this.onImmediateTextRegion(...arguments);
1758
+ }
1759
+
1760
+ onPatternDictionary(dictionary, currentSegment, data, start, end) {
1761
+ let patterns = this.patterns;
1762
+ if (!patterns) {
1763
+ this.patterns = patterns = {};
1764
+ }
1765
+ const decodingContext = new DecodingContext(data, start, end);
1766
+ patterns[currentSegment] = decodePatternDictionary(
1767
+ dictionary.mmr,
1768
+ dictionary.patternWidth,
1769
+ dictionary.patternHeight,
1770
+ dictionary.maxPatternIndex,
1771
+ dictionary.template,
1772
+ decodingContext
1773
+ );
1774
+ }
1775
+
1776
+ onImmediateHalftoneRegion(region, referredSegments, data, start, end) {
1777
+ // HalftoneRegion refers to exactly one PatternDictionary.
1778
+ const patterns = this.patterns[referredSegments[0]];
1779
+ const regionInfo = region.info;
1780
+ const decodingContext = new DecodingContext(data, start, end);
1781
+ const bitmap = decodeHalftoneRegion(
1782
+ region.mmr,
1783
+ patterns,
1784
+ region.template,
1785
+ regionInfo.width,
1786
+ regionInfo.height,
1787
+ region.defaultPixelValue,
1788
+ region.enableSkip,
1789
+ region.combinationOperator,
1790
+ region.gridWidth,
1791
+ region.gridHeight,
1792
+ region.gridOffsetX,
1793
+ region.gridOffsetY,
1794
+ region.gridVectorX,
1795
+ region.gridVectorY,
1796
+ decodingContext
1797
+ );
1798
+ this.drawBitmap(regionInfo, bitmap);
1799
+ }
1800
+
1801
+ onImmediateLosslessHalftoneRegion() {
1802
+ this.onImmediateHalftoneRegion(...arguments);
1803
+ }
1804
+
1805
+ onTables(currentSegment, data, start, end) {
1806
+ let customTables = this.customTables;
1807
+ if (!customTables) {
1808
+ this.customTables = customTables = {};
1809
+ }
1810
+ customTables[currentSegment] = decodeTablesSegment(data, start, end);
1811
+ }
1812
+ }
1813
+
1814
+ class HuffmanLine {
1815
+ constructor(lineData) {
1816
+ if (lineData.length === 2) {
1817
+ // OOB line.
1818
+ this.isOOB = true;
1819
+ this.rangeLow = 0;
1820
+ this.prefixLength = lineData[0];
1821
+ this.rangeLength = 0;
1822
+ this.prefixCode = lineData[1];
1823
+ this.isLowerRange = false;
1824
+ } else {
1825
+ // Normal, upper range or lower range line.
1826
+ // Upper range lines are processed like normal lines.
1827
+ this.isOOB = false;
1828
+ this.rangeLow = lineData[0];
1829
+ this.prefixLength = lineData[1];
1830
+ this.rangeLength = lineData[2];
1831
+ this.prefixCode = lineData[3];
1832
+ this.isLowerRange = lineData[4] === 'lower';
1833
+ }
1834
+ }
1835
+ }
1836
+
1837
+ class HuffmanTreeNode {
1838
+ constructor(line) {
1839
+ this.children = [];
1840
+ if (line) {
1841
+ // Leaf node
1842
+ this.isLeaf = true;
1843
+ this.rangeLength = line.rangeLength;
1844
+ this.rangeLow = line.rangeLow;
1845
+ this.isLowerRange = line.isLowerRange;
1846
+ this.isOOB = line.isOOB;
1847
+ } else {
1848
+ // Intermediate or root node
1849
+ this.isLeaf = false;
1850
+ }
1851
+ }
1852
+
1853
+ buildTree(line, shift) {
1854
+ const bit = (line.prefixCode >> shift) & 1;
1855
+ if (shift <= 0) {
1856
+ // Create a leaf node.
1857
+ this.children[bit] = new HuffmanTreeNode(line);
1858
+ } else {
1859
+ // Create an intermediate node and continue recursively.
1860
+ let node = this.children[bit];
1861
+ if (!node) {
1862
+ this.children[bit] = node = new HuffmanTreeNode(null);
1863
+ }
1864
+ node.buildTree(line, shift - 1);
1865
+ }
1866
+ }
1867
+
1868
+ decodeNode(reader) {
1869
+ if (this.isLeaf) {
1870
+ if (this.isOOB) {
1871
+ return null;
1872
+ }
1873
+ const htOffset = reader.readBits(this.rangeLength);
1874
+ return this.rangeLow + (this.isLowerRange ? -htOffset : htOffset);
1875
+ }
1876
+ const node = this.children[reader.readBit()];
1877
+ if (!node) {
1878
+ throw new Jbig2Error('invalid Huffman data');
1879
+ }
1880
+ return node.decodeNode(reader);
1881
+ }
1882
+ }
1883
+
1884
+ class HuffmanTable {
1885
+ constructor(lines, prefixCodesDone) {
1886
+ if (!prefixCodesDone) {
1887
+ this.assignPrefixCodes(lines);
1888
+ }
1889
+ // Create Huffman tree.
1890
+ this.rootNode = new HuffmanTreeNode(null);
1891
+ for (let i = 0, ii = lines.length; i < ii; i++) {
1892
+ const line = lines[i];
1893
+ if (line.prefixLength > 0) {
1894
+ this.rootNode.buildTree(line, line.prefixLength - 1);
1895
+ }
1896
+ }
1897
+ }
1898
+
1899
+ decode(reader) {
1900
+ return this.rootNode.decodeNode(reader);
1901
+ }
1902
+
1903
+ assignPrefixCodes(lines) {
1904
+ // Annex B.3 Assigning the prefix codes.
1905
+ const linesLength = lines.length;
1906
+ let prefixLengthMax = 0;
1907
+ for (let i = 0; i < linesLength; i++) {
1908
+ prefixLengthMax = Math.max(prefixLengthMax, lines[i].prefixLength);
1909
+ }
1910
+
1911
+ const histogram = new Uint32Array(prefixLengthMax + 1);
1912
+ for (let i = 0; i < linesLength; i++) {
1913
+ histogram[lines[i].prefixLength]++;
1914
+ }
1915
+ let currentLength = 1,
1916
+ firstCode = 0,
1917
+ currentCode,
1918
+ currentTemp,
1919
+ line;
1920
+ histogram[0] = 0;
1921
+
1922
+ while (currentLength <= prefixLengthMax) {
1923
+ firstCode = (firstCode + histogram[currentLength - 1]) << 1;
1924
+ currentCode = firstCode;
1925
+ currentTemp = 0;
1926
+ while (currentTemp < linesLength) {
1927
+ line = lines[currentTemp];
1928
+ if (line.prefixLength === currentLength) {
1929
+ line.prefixCode = currentCode;
1930
+ currentCode++;
1931
+ }
1932
+ currentTemp++;
1933
+ }
1934
+ currentLength++;
1935
+ }
1936
+ }
1937
+ }
1938
+
1939
+ function decodeTablesSegment(data, start, end) {
1940
+ // Decodes a Tables segment, i.e., a custom Huffman table.
1941
+ // Annex B.2 Code table structure.
1942
+ const flags = data[start];
1943
+ const lowestValue = readUint32(data, start + 1) & 0xffffffff;
1944
+ const highestValue = readUint32(data, start + 5) & 0xffffffff;
1945
+ const reader = new Reader(data, start + 9, end);
1946
+
1947
+ const prefixSizeBits = ((flags >> 1) & 7) + 1;
1948
+ const rangeSizeBits = ((flags >> 4) & 7) + 1;
1949
+ const lines = [];
1950
+ let prefixLength,
1951
+ rangeLength,
1952
+ currentRangeLow = lowestValue;
1953
+
1954
+ // Normal table lines
1955
+ do {
1956
+ prefixLength = reader.readBits(prefixSizeBits);
1957
+ rangeLength = reader.readBits(rangeSizeBits);
1958
+ lines.push(
1959
+ new HuffmanLine([currentRangeLow, prefixLength, rangeLength, 0])
1960
+ );
1961
+ currentRangeLow += 1 << rangeLength;
1962
+ } while (currentRangeLow < highestValue);
1963
+
1964
+ // Lower range table line
1965
+ prefixLength = reader.readBits(prefixSizeBits);
1966
+ lines.push(new HuffmanLine([lowestValue - 1, prefixLength, 32, 0, 'lower']));
1967
+
1968
+ // Upper range table line
1969
+ prefixLength = reader.readBits(prefixSizeBits);
1970
+ lines.push(new HuffmanLine([highestValue, prefixLength, 32, 0]));
1971
+
1972
+ if (flags & 1) {
1973
+ // Out-of-band table line
1974
+ prefixLength = reader.readBits(prefixSizeBits);
1975
+ lines.push(new HuffmanLine([prefixLength, 0]));
1976
+ }
1977
+
1978
+ return new HuffmanTable(lines, false);
1979
+ }
1980
+
1981
+ const standardTablesCache = {};
1982
+
1983
+ function getStandardTable(number) {
1984
+ // Annex B.5 Standard Huffman tables.
1985
+ let table = standardTablesCache[number];
1986
+ if (table) {
1987
+ return table;
1988
+ }
1989
+ let lines;
1990
+ switch (number) {
1991
+ case 1:
1992
+ lines = [
1993
+ [0, 1, 4, 0x0],
1994
+ [16, 2, 8, 0x2],
1995
+ [272, 3, 16, 0x6],
1996
+ [65808, 3, 32, 0x7] // upper
1997
+ ];
1998
+ break;
1999
+ case 2:
2000
+ lines = [
2001
+ [0, 1, 0, 0x0],
2002
+ [1, 2, 0, 0x2],
2003
+ [2, 3, 0, 0x6],
2004
+ [3, 4, 3, 0xe],
2005
+ [11, 5, 6, 0x1e],
2006
+ [75, 6, 32, 0x3e], // upper
2007
+ [6, 0x3f] // OOB
2008
+ ];
2009
+ break;
2010
+ case 3:
2011
+ lines = [
2012
+ [-256, 8, 8, 0xfe],
2013
+ [0, 1, 0, 0x0],
2014
+ [1, 2, 0, 0x2],
2015
+ [2, 3, 0, 0x6],
2016
+ [3, 4, 3, 0xe],
2017
+ [11, 5, 6, 0x1e],
2018
+ [-257, 8, 32, 0xff, 'lower'],
2019
+ [75, 7, 32, 0x7e], // upper
2020
+ [6, 0x3e] // OOB
2021
+ ];
2022
+ break;
2023
+ case 4:
2024
+ lines = [
2025
+ [1, 1, 0, 0x0],
2026
+ [2, 2, 0, 0x2],
2027
+ [3, 3, 0, 0x6],
2028
+ [4, 4, 3, 0xe],
2029
+ [12, 5, 6, 0x1e],
2030
+ [76, 5, 32, 0x1f] // upper
2031
+ ];
2032
+ break;
2033
+ case 5:
2034
+ lines = [
2035
+ [-255, 7, 8, 0x7e],
2036
+ [1, 1, 0, 0x0],
2037
+ [2, 2, 0, 0x2],
2038
+ [3, 3, 0, 0x6],
2039
+ [4, 4, 3, 0xe],
2040
+ [12, 5, 6, 0x1e],
2041
+ [-256, 7, 32, 0x7f, 'lower'],
2042
+ [76, 6, 32, 0x3e] // upper
2043
+ ];
2044
+ break;
2045
+ case 6:
2046
+ lines = [
2047
+ [-2048, 5, 10, 0x1c],
2048
+ [-1024, 4, 9, 0x8],
2049
+ [-512, 4, 8, 0x9],
2050
+ [-256, 4, 7, 0xa],
2051
+ [-128, 5, 6, 0x1d],
2052
+ [-64, 5, 5, 0x1e],
2053
+ [-32, 4, 5, 0xb],
2054
+ [0, 2, 7, 0x0],
2055
+ [128, 3, 7, 0x2],
2056
+ [256, 3, 8, 0x3],
2057
+ [512, 4, 9, 0xc],
2058
+ [1024, 4, 10, 0xd],
2059
+ [-2049, 6, 32, 0x3e, 'lower'],
2060
+ [2048, 6, 32, 0x3f] // upper
2061
+ ];
2062
+ break;
2063
+ case 7:
2064
+ lines = [
2065
+ [-1024, 4, 9, 0x8],
2066
+ [-512, 3, 8, 0x0],
2067
+ [-256, 4, 7, 0x9],
2068
+ [-128, 5, 6, 0x1a],
2069
+ [-64, 5, 5, 0x1b],
2070
+ [-32, 4, 5, 0xa],
2071
+ [0, 4, 5, 0xb],
2072
+ [32, 5, 5, 0x1c],
2073
+ [64, 5, 6, 0x1d],
2074
+ [128, 4, 7, 0xc],
2075
+ [256, 3, 8, 0x1],
2076
+ [512, 3, 9, 0x2],
2077
+ [1024, 3, 10, 0x3],
2078
+ [-1025, 5, 32, 0x1e, 'lower'],
2079
+ [2048, 5, 32, 0x1f] // upper
2080
+ ];
2081
+ break;
2082
+ case 8:
2083
+ lines = [
2084
+ [-15, 8, 3, 0xfc],
2085
+ [-7, 9, 1, 0x1fc],
2086
+ [-5, 8, 1, 0xfd],
2087
+ [-3, 9, 0, 0x1fd],
2088
+ [-2, 7, 0, 0x7c],
2089
+ [-1, 4, 0, 0xa],
2090
+ [0, 2, 1, 0x0],
2091
+ [2, 5, 0, 0x1a],
2092
+ [3, 6, 0, 0x3a],
2093
+ [4, 3, 4, 0x4],
2094
+ [20, 6, 1, 0x3b],
2095
+ [22, 4, 4, 0xb],
2096
+ [38, 4, 5, 0xc],
2097
+ [70, 5, 6, 0x1b],
2098
+ [134, 5, 7, 0x1c],
2099
+ [262, 6, 7, 0x3c],
2100
+ [390, 7, 8, 0x7d],
2101
+ [646, 6, 10, 0x3d],
2102
+ [-16, 9, 32, 0x1fe, 'lower'],
2103
+ [1670, 9, 32, 0x1ff], // upper
2104
+ [2, 0x1] // OOB
2105
+ ];
2106
+ break;
2107
+ case 9:
2108
+ lines = [
2109
+ [-31, 8, 4, 0xfc],
2110
+ [-15, 9, 2, 0x1fc],
2111
+ [-11, 8, 2, 0xfd],
2112
+ [-7, 9, 1, 0x1fd],
2113
+ [-5, 7, 1, 0x7c],
2114
+ [-3, 4, 1, 0xa],
2115
+ [-1, 3, 1, 0x2],
2116
+ [1, 3, 1, 0x3],
2117
+ [3, 5, 1, 0x1a],
2118
+ [5, 6, 1, 0x3a],
2119
+ [7, 3, 5, 0x4],
2120
+ [39, 6, 2, 0x3b],
2121
+ [43, 4, 5, 0xb],
2122
+ [75, 4, 6, 0xc],
2123
+ [139, 5, 7, 0x1b],
2124
+ [267, 5, 8, 0x1c],
2125
+ [523, 6, 8, 0x3c],
2126
+ [779, 7, 9, 0x7d],
2127
+ [1291, 6, 11, 0x3d],
2128
+ [-32, 9, 32, 0x1fe, 'lower'],
2129
+ [3339, 9, 32, 0x1ff], // upper
2130
+ [2, 0x0] // OOB
2131
+ ];
2132
+ break;
2133
+ case 10:
2134
+ lines = [
2135
+ [-21, 7, 4, 0x7a],
2136
+ [-5, 8, 0, 0xfc],
2137
+ [-4, 7, 0, 0x7b],
2138
+ [-3, 5, 0, 0x18],
2139
+ [-2, 2, 2, 0x0],
2140
+ [2, 5, 0, 0x19],
2141
+ [3, 6, 0, 0x36],
2142
+ [4, 7, 0, 0x7c],
2143
+ [5, 8, 0, 0xfd],
2144
+ [6, 2, 6, 0x1],
2145
+ [70, 5, 5, 0x1a],
2146
+ [102, 6, 5, 0x37],
2147
+ [134, 6, 6, 0x38],
2148
+ [198, 6, 7, 0x39],
2149
+ [326, 6, 8, 0x3a],
2150
+ [582, 6, 9, 0x3b],
2151
+ [1094, 6, 10, 0x3c],
2152
+ [2118, 7, 11, 0x7d],
2153
+ [-22, 8, 32, 0xfe, 'lower'],
2154
+ [4166, 8, 32, 0xff], // upper
2155
+ [2, 0x2] // OOB
2156
+ ];
2157
+ break;
2158
+ case 11:
2159
+ lines = [
2160
+ [1, 1, 0, 0x0],
2161
+ [2, 2, 1, 0x2],
2162
+ [4, 4, 0, 0xc],
2163
+ [5, 4, 1, 0xd],
2164
+ [7, 5, 1, 0x1c],
2165
+ [9, 5, 2, 0x1d],
2166
+ [13, 6, 2, 0x3c],
2167
+ [17, 7, 2, 0x7a],
2168
+ [21, 7, 3, 0x7b],
2169
+ [29, 7, 4, 0x7c],
2170
+ [45, 7, 5, 0x7d],
2171
+ [77, 7, 6, 0x7e],
2172
+ [141, 7, 32, 0x7f] // upper
2173
+ ];
2174
+ break;
2175
+ case 12:
2176
+ lines = [
2177
+ [1, 1, 0, 0x0],
2178
+ [2, 2, 0, 0x2],
2179
+ [3, 3, 1, 0x6],
2180
+ [5, 5, 0, 0x1c],
2181
+ [6, 5, 1, 0x1d],
2182
+ [8, 6, 1, 0x3c],
2183
+ [10, 7, 0, 0x7a],
2184
+ [11, 7, 1, 0x7b],
2185
+ [13, 7, 2, 0x7c],
2186
+ [17, 7, 3, 0x7d],
2187
+ [25, 7, 4, 0x7e],
2188
+ [41, 8, 5, 0xfe],
2189
+ [73, 8, 32, 0xff] // upper
2190
+ ];
2191
+ break;
2192
+ case 13:
2193
+ lines = [
2194
+ [1, 1, 0, 0x0],
2195
+ [2, 3, 0, 0x4],
2196
+ [3, 4, 0, 0xc],
2197
+ [4, 5, 0, 0x1c],
2198
+ [5, 4, 1, 0xd],
2199
+ [7, 3, 3, 0x5],
2200
+ [15, 6, 1, 0x3a],
2201
+ [17, 6, 2, 0x3b],
2202
+ [21, 6, 3, 0x3c],
2203
+ [29, 6, 4, 0x3d],
2204
+ [45, 6, 5, 0x3e],
2205
+ [77, 7, 6, 0x7e],
2206
+ [141, 7, 32, 0x7f] // upper
2207
+ ];
2208
+ break;
2209
+ case 14:
2210
+ lines = [
2211
+ [-2, 3, 0, 0x4],
2212
+ [-1, 3, 0, 0x5],
2213
+ [0, 1, 0, 0x0],
2214
+ [1, 3, 0, 0x6],
2215
+ [2, 3, 0, 0x7]
2216
+ ];
2217
+ break;
2218
+ case 15:
2219
+ lines = [
2220
+ [-24, 7, 4, 0x7c],
2221
+ [-8, 6, 2, 0x3c],
2222
+ [-4, 5, 1, 0x1c],
2223
+ [-2, 4, 0, 0xc],
2224
+ [-1, 3, 0, 0x4],
2225
+ [0, 1, 0, 0x0],
2226
+ [1, 3, 0, 0x5],
2227
+ [2, 4, 0, 0xd],
2228
+ [3, 5, 1, 0x1d],
2229
+ [5, 6, 2, 0x3d],
2230
+ [9, 7, 4, 0x7d],
2231
+ [-25, 7, 32, 0x7e, 'lower'],
2232
+ [25, 7, 32, 0x7f] // upper
2233
+ ];
2234
+ break;
2235
+ default:
2236
+ throw new Jbig2Error(`standard table B.${number} does not exist`);
2237
+ }
2238
+
2239
+ for (let i = 0, ii = lines.length; i < ii; i++) {
2240
+ lines[i] = new HuffmanLine(lines[i]);
2241
+ }
2242
+ table = new HuffmanTable(lines, true);
2243
+ standardTablesCache[number] = table;
2244
+ return table;
2245
+ }
2246
+
2247
+ class Reader {
2248
+ constructor(data, start, end) {
2249
+ this.data = data;
2250
+ this.start = start;
2251
+ this.end = end;
2252
+ this.position = start;
2253
+ this.shift = -1;
2254
+ this.currentByte = 0;
2255
+ }
2256
+
2257
+ readBit() {
2258
+ if (this.shift < 0) {
2259
+ if (this.position >= this.end) {
2260
+ throw new Jbig2Error('end of data while reading bit');
2261
+ }
2262
+ this.currentByte = this.data[this.position++];
2263
+ this.shift = 7;
2264
+ }
2265
+ const bit = (this.currentByte >> this.shift) & 1;
2266
+ this.shift--;
2267
+ return bit;
2268
+ }
2269
+
2270
+ readBits(numBits) {
2271
+ let result = 0,
2272
+ i;
2273
+ for (i = numBits - 1; i >= 0; i--) {
2274
+ result |= this.readBit() << i;
2275
+ }
2276
+ return result;
2277
+ }
2278
+
2279
+ byteAlign() {
2280
+ this.shift = -1;
2281
+ }
2282
+
2283
+ next() {
2284
+ if (this.position >= this.end) {
2285
+ return -1;
2286
+ }
2287
+ return this.data[this.position++];
2288
+ }
2289
+ }
2290
+
2291
+ function getCustomHuffmanTable(index, referredTo, customTables) {
2292
+ // Returns a Tables segment that has been earlier decoded.
2293
+ // See 7.4.2.1.6 (symbol dictionary) or 7.4.3.1.6 (text region).
2294
+ let currentIndex = 0;
2295
+ for (let i = 0, ii = referredTo.length; i < ii; i++) {
2296
+ const table = customTables[referredTo[i]];
2297
+ if (table) {
2298
+ if (index === currentIndex) {
2299
+ return table;
2300
+ }
2301
+ currentIndex++;
2302
+ }
2303
+ }
2304
+ throw new Jbig2Error("can't find custom Huffman table");
2305
+ }
2306
+
2307
+ function getTextRegionHuffmanTables(
2308
+ textRegion,
2309
+ referredTo,
2310
+ customTables,
2311
+ numberOfSymbols,
2312
+ reader
2313
+ ) {
2314
+ // 7.4.3.1.7 Symbol ID Huffman table decoding
2315
+
2316
+ // Read code lengths for RUNCODEs 0...34.
2317
+ const codes = [];
2318
+ for (let i = 0; i <= 34; i++) {
2319
+ const codeLength = reader.readBits(4);
2320
+ codes.push(new HuffmanLine([i, codeLength, 0, 0]));
2321
+ }
2322
+ // Assign Huffman codes for RUNCODEs.
2323
+ const runCodesTable = new HuffmanTable(codes, false);
2324
+
2325
+ // Read a Huffman code using the assignment above.
2326
+ // Interpret the RUNCODE codes and the additional bits (if any).
2327
+ codes.length = 0;
2328
+ for (let i = 0; i < numberOfSymbols; ) {
2329
+ const codeLength = runCodesTable.decode(reader);
2330
+ if (codeLength >= 32) {
2331
+ let repeatedLength, numberOfRepeats, j;
2332
+ switch (codeLength) {
2333
+ case 32:
2334
+ if (i === 0) {
2335
+ throw new Jbig2Error('no previous value in symbol ID table');
2336
+ }
2337
+ numberOfRepeats = reader.readBits(2) + 3;
2338
+ repeatedLength = codes[i - 1].prefixLength;
2339
+ break;
2340
+ case 33:
2341
+ numberOfRepeats = reader.readBits(3) + 3;
2342
+ repeatedLength = 0;
2343
+ break;
2344
+ case 34:
2345
+ numberOfRepeats = reader.readBits(7) + 11;
2346
+ repeatedLength = 0;
2347
+ break;
2348
+ default:
2349
+ throw new Jbig2Error('invalid code length in symbol ID table');
2350
+ }
2351
+ for (j = 0; j < numberOfRepeats; j++) {
2352
+ codes.push(new HuffmanLine([i, repeatedLength, 0, 0]));
2353
+ i++;
2354
+ }
2355
+ } else {
2356
+ codes.push(new HuffmanLine([i, codeLength, 0, 0]));
2357
+ i++;
2358
+ }
2359
+ }
2360
+ reader.byteAlign();
2361
+ const symbolIDTable = new HuffmanTable(codes, false);
2362
+
2363
+ // 7.4.3.1.6 Text region segment Huffman table selection
2364
+
2365
+ let customIndex = 0,
2366
+ tableFirstS,
2367
+ tableDeltaS,
2368
+ tableDeltaT;
2369
+
2370
+ switch (textRegion.huffmanFS) {
2371
+ case 0:
2372
+ case 1:
2373
+ tableFirstS = getStandardTable(textRegion.huffmanFS + 6);
2374
+ break;
2375
+ case 3:
2376
+ tableFirstS = getCustomHuffmanTable(
2377
+ customIndex,
2378
+ referredTo,
2379
+ customTables
2380
+ );
2381
+ customIndex++;
2382
+ break;
2383
+ default:
2384
+ throw new Jbig2Error('invalid Huffman FS selector');
2385
+ }
2386
+
2387
+ switch (textRegion.huffmanDS) {
2388
+ case 0:
2389
+ case 1:
2390
+ case 2:
2391
+ tableDeltaS = getStandardTable(textRegion.huffmanDS + 8);
2392
+ break;
2393
+ case 3:
2394
+ tableDeltaS = getCustomHuffmanTable(
2395
+ customIndex,
2396
+ referredTo,
2397
+ customTables
2398
+ );
2399
+ customIndex++;
2400
+ break;
2401
+ default:
2402
+ throw new Jbig2Error('invalid Huffman DS selector');
2403
+ }
2404
+
2405
+ switch (textRegion.huffmanDT) {
2406
+ case 0:
2407
+ case 1:
2408
+ case 2:
2409
+ tableDeltaT = getStandardTable(textRegion.huffmanDT + 11);
2410
+ break;
2411
+ case 3:
2412
+ tableDeltaT = getCustomHuffmanTable(
2413
+ customIndex,
2414
+ referredTo,
2415
+ customTables
2416
+ );
2417
+ customIndex++;
2418
+ break;
2419
+ default:
2420
+ throw new Jbig2Error('invalid Huffman DT selector');
2421
+ }
2422
+
2423
+ if (textRegion.refinement) {
2424
+ // Load tables RDW, RDH, RDX and RDY.
2425
+ throw new Jbig2Error('refinement with Huffman is not supported');
2426
+ }
2427
+
2428
+ return {
2429
+ symbolIDTable,
2430
+ tableFirstS,
2431
+ tableDeltaS,
2432
+ tableDeltaT
2433
+ };
2434
+ }
2435
+
2436
+ function getSymbolDictionaryHuffmanTables(
2437
+ dictionary,
2438
+ referredTo,
2439
+ customTables
2440
+ ) {
2441
+ // 7.4.2.1.6 Symbol dictionary segment Huffman table selection
2442
+
2443
+ let customIndex = 0,
2444
+ tableDeltaHeight,
2445
+ tableDeltaWidth;
2446
+ switch (dictionary.huffmanDHSelector) {
2447
+ case 0:
2448
+ case 1:
2449
+ tableDeltaHeight = getStandardTable(dictionary.huffmanDHSelector + 4);
2450
+ break;
2451
+ case 3:
2452
+ tableDeltaHeight = getCustomHuffmanTable(
2453
+ customIndex,
2454
+ referredTo,
2455
+ customTables
2456
+ );
2457
+ customIndex++;
2458
+ break;
2459
+ default:
2460
+ throw new Jbig2Error('invalid Huffman DH selector');
2461
+ }
2462
+
2463
+ switch (dictionary.huffmanDWSelector) {
2464
+ case 0:
2465
+ case 1:
2466
+ tableDeltaWidth = getStandardTable(dictionary.huffmanDWSelector + 2);
2467
+ break;
2468
+ case 3:
2469
+ tableDeltaWidth = getCustomHuffmanTable(
2470
+ customIndex,
2471
+ referredTo,
2472
+ customTables
2473
+ );
2474
+ customIndex++;
2475
+ break;
2476
+ default:
2477
+ throw new Jbig2Error('invalid Huffman DW selector');
2478
+ }
2479
+
2480
+ let tableBitmapSize, tableAggregateInstances;
2481
+ if (dictionary.bitmapSizeSelector) {
2482
+ tableBitmapSize = getCustomHuffmanTable(
2483
+ customIndex,
2484
+ referredTo,
2485
+ customTables
2486
+ );
2487
+ customIndex++;
2488
+ } else {
2489
+ tableBitmapSize = getStandardTable(1);
2490
+ }
2491
+
2492
+ if (dictionary.aggregationInstancesSelector) {
2493
+ tableAggregateInstances = getCustomHuffmanTable(
2494
+ customIndex,
2495
+ referredTo,
2496
+ customTables
2497
+ );
2498
+ } else {
2499
+ tableAggregateInstances = getStandardTable(1);
2500
+ }
2501
+
2502
+ return {
2503
+ tableDeltaHeight,
2504
+ tableDeltaWidth,
2505
+ tableBitmapSize,
2506
+ tableAggregateInstances
2507
+ };
2508
+ }
2509
+
2510
+ function readUncompressedBitmap(reader, width, height) {
2511
+ const bitmap = [];
2512
+ for (let y = 0; y < height; y++) {
2513
+ const row = new Uint8Array(width);
2514
+ bitmap.push(row);
2515
+ for (let x = 0; x < width; x++) {
2516
+ row[x] = reader.readBit();
2517
+ }
2518
+ reader.byteAlign();
2519
+ }
2520
+ return bitmap;
2521
+ }
2522
+
2523
+ function decodeMMRBitmap(input, width, height, endOfBlock) {
2524
+ // MMR is the same compression algorithm as the PDF filter
2525
+ // CCITTFaxDecode with /K -1.
2526
+ const params = {
2527
+ K: -1,
2528
+ Columns: width,
2529
+ Rows: height,
2530
+ BlackIs1: true,
2531
+ EndOfBlock: endOfBlock
2532
+ };
2533
+ const decoder = new CCITTFaxDecoder(input, params);
2534
+ const bitmap = [];
2535
+ let currentByte,
2536
+ eof = false;
2537
+
2538
+ for (let y = 0; y < height; y++) {
2539
+ const row = new Uint8Array(width);
2540
+ bitmap.push(row);
2541
+ let shift = -1;
2542
+ for (let x = 0; x < width; x++) {
2543
+ if (shift < 0) {
2544
+ currentByte = decoder.readNextChar();
2545
+ if (currentByte === -1) {
2546
+ // Set the rest of the bits to zero.
2547
+ currentByte = 0;
2548
+ eof = true;
2549
+ }
2550
+ shift = 7;
2551
+ }
2552
+ // @ts-ignore
2553
+ row[x] = (currentByte >> shift) & 1;
2554
+ shift--;
2555
+ }
2556
+ }
2557
+
2558
+ if (endOfBlock && !eof) {
2559
+ // Read until EOFB has been consumed.
2560
+ const lookForEOFLimit = 5;
2561
+ for (let i = 0; i < lookForEOFLimit; i++) {
2562
+ if (decoder.readNextChar() === -1) {
2563
+ break;
2564
+ }
2565
+ }
2566
+ }
2567
+
2568
+ return bitmap;
2569
+ }
2570
+
2571
+ export class Jbig2Image {
2572
+ parseChunks(chunks) {
2573
+ return parseJbig2Chunks(chunks);
2574
+ }
2575
+
2576
+ parse(data) {
2577
+ const { imgData, width, height } = parseJbig2(data);
2578
+ this.width = width;
2579
+ this.height = height;
2580
+ return imgData;
2581
+ }
2582
+ }