@file-viewer/renderer-ofd 3.0.1 → 3.0.3
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.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@file-viewer/renderer-ofd",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Standalone OFD renderer plugin for File Viewer powered by DLTech21/ofd.js.",
|
|
@@ -54,10 +54,11 @@
|
|
|
54
54
|
"LICENSE"
|
|
55
55
|
],
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@file-viewer/core": "3.0.
|
|
58
|
-
"jszip": "
|
|
57
|
+
"@file-viewer/core": "3.0.3",
|
|
58
|
+
"jszip": "3.10.2"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
+
"@xmldom/xmldom": "0.9.12",
|
|
61
62
|
"linkedom": "^0.18.12",
|
|
62
63
|
"typescript": "^6.0.3"
|
|
63
64
|
},
|
|
@@ -43,6 +43,12 @@ const appendChildValue = function (target, key, value) {
|
|
|
43
43
|
target[key] = value;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
const xmlElementName = function (element) {
|
|
47
|
+
return element.namespaceURI === 'http://www.ofdspec.org/2016'
|
|
48
|
+
? `ofd:${element.localName}`
|
|
49
|
+
: element.nodeName;
|
|
50
|
+
}
|
|
51
|
+
|
|
46
52
|
const parseXmlElement = function (element, options, order) {
|
|
47
53
|
const attrPrefix = options.attributeNamePrefix ?? '@_';
|
|
48
54
|
const result = {};
|
|
@@ -64,7 +70,7 @@ const parseXmlElement = function (element, options, order) {
|
|
|
64
70
|
if (parsedChild && typeof parsedChild === 'object' && pfIndex !== undefined) {
|
|
65
71
|
parsedChild.pfIndex = pfIndex;
|
|
66
72
|
}
|
|
67
|
-
appendChildValue(result, child
|
|
73
|
+
appendChildValue(result, xmlElementName(child), parsedChild);
|
|
68
74
|
continue;
|
|
69
75
|
}
|
|
70
76
|
if (child.nodeType === 3 || child.nodeType === 4) {
|
|
@@ -103,7 +109,7 @@ const parseXmlToJson = function (xmlData, options = {}) {
|
|
|
103
109
|
return {};
|
|
104
110
|
}
|
|
105
111
|
return {
|
|
106
|
-
[root
|
|
112
|
+
[xmlElementName(root)]: parseXmlElement(root, options, { next: 0 })
|
|
107
113
|
};
|
|
108
114
|
}
|
|
109
115
|
|
|
@@ -159,18 +165,13 @@ const joinZipPath = function (...parts) {
|
|
|
159
165
|
}
|
|
160
166
|
|
|
161
167
|
const startsWithZipRoot = function (path, root) {
|
|
162
|
-
const normalizedPath = normalizeZipPath(path);
|
|
163
|
-
const normalizedRoot = normalizeZipPath(root);
|
|
168
|
+
const normalizedPath = normalizeZipPath(path).toLowerCase();
|
|
169
|
+
const normalizedRoot = normalizeZipPath(root).toLowerCase();
|
|
164
170
|
return normalizedPath === normalizedRoot || normalizedPath.startsWith(`${normalizedRoot}/`);
|
|
165
171
|
}
|
|
166
172
|
|
|
167
173
|
const getZipEntry = function (zip, candidates) {
|
|
168
174
|
const paths = asArray(candidates).map(normalizeZipPath).filter(Boolean);
|
|
169
|
-
for (const path of paths) {
|
|
170
|
-
if (zip.files[path]) {
|
|
171
|
-
return zip.files[path];
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
175
|
let lowerMap = zipEntryMapCache.get(zip);
|
|
175
176
|
if (!lowerMap) {
|
|
176
177
|
lowerMap = new Map();
|
|
@@ -180,7 +181,7 @@ const getZipEntry = function (zip, candidates) {
|
|
|
180
181
|
zipEntryMapCache.set(zip, lowerMap);
|
|
181
182
|
}
|
|
182
183
|
for (const path of paths) {
|
|
183
|
-
const entry = lowerMap.get(path.toLowerCase());
|
|
184
|
+
const entry = zip.files[path] || lowerMap.get(path.toLowerCase());
|
|
184
185
|
if (entry) {
|
|
185
186
|
return entry;
|
|
186
187
|
}
|
|
@@ -190,15 +191,22 @@ const getZipEntry = function (zip, candidates) {
|
|
|
190
191
|
|
|
191
192
|
const resolveDocumentPath = function (path, doc) {
|
|
192
193
|
const normalizedPath = normalizeZipPath(path);
|
|
193
|
-
if (!normalizedPath || startsWithZipRoot(normalizedPath, doc)) {
|
|
194
|
+
if (!normalizedPath || !doc || /^[\\/]/.test(String(path).trim()) || startsWithZipRoot(normalizedPath, doc)) {
|
|
194
195
|
return normalizedPath;
|
|
195
196
|
}
|
|
196
|
-
return joinZipPath(doc,
|
|
197
|
+
return joinZipPath(doc, path);
|
|
197
198
|
}
|
|
198
199
|
|
|
199
|
-
const resolveResourceCandidates = function (file, baseLoc, doc) {
|
|
200
|
+
const resolveResourceCandidates = function (file, baseLoc, doc, resourcePath) {
|
|
200
201
|
const mediaFile = normalizeZipPath(file);
|
|
201
202
|
const base = normalizeZipPath(baseLoc);
|
|
203
|
+
const rawFile = String(file || '').replace(/\\/g, '/').trim();
|
|
204
|
+
const rawBase = String(baseLoc || '').replace(/\\/g, '/').trim();
|
|
205
|
+
const resourceDirectory = normalizeZipPath(resourcePath).split('/').slice(0, -1).join('/');
|
|
206
|
+
const resourceBase = rawBase.startsWith('/') ? normalizeZipPath(rawBase) : joinZipPath(resourceDirectory, rawBase);
|
|
207
|
+
// Resolve relative components before normalizing '..'. Declared locations
|
|
208
|
+
// outrank compatibility fallbacks, including their case-insensitive matches.
|
|
209
|
+
const declaredPath = rawFile.startsWith('/') ? mediaFile : joinZipPath(resourceBase, rawFile);
|
|
202
210
|
const candidates = [mediaFile];
|
|
203
211
|
|
|
204
212
|
if (base && !startsWithZipRoot(mediaFile, base)) {
|
|
@@ -213,7 +221,7 @@ const resolveResourceCandidates = function (file, baseLoc, doc) {
|
|
|
213
221
|
}
|
|
214
222
|
}
|
|
215
223
|
|
|
216
|
-
return [...new Set(docCandidates.filter(Boolean))];
|
|
224
|
+
return [...new Set([declaredPath, ...docCandidates].filter(Boolean))];
|
|
217
225
|
}
|
|
218
226
|
|
|
219
227
|
const getImageMime = function (format) {
|
|
@@ -295,7 +303,7 @@ const sealImageMime = function (type) {
|
|
|
295
303
|
export const doGetDocRoot = async function (zip, docbody) {
|
|
296
304
|
let docRoot = docbody['ofd:DocRoot'];
|
|
297
305
|
docRoot = normalizeZipPath(replaceFirstSlash(docRoot));
|
|
298
|
-
const doc = docRoot.split('/')
|
|
306
|
+
const doc = docRoot.split('/').slice(0, -1).join('/');
|
|
299
307
|
const signatures = docbody['ofd:Signatures'];
|
|
300
308
|
const stampAnnot = await getSignature(zip, signatures, doc);
|
|
301
309
|
let stampAnnotArray = {};
|
|
@@ -422,7 +430,7 @@ export const getDocumentRes = async function ([zip, doc, Document, stampAnnot, a
|
|
|
422
430
|
const documentResObj = data['json']['ofd:Res'];
|
|
423
431
|
fontResObj = await getFont(documentResObj);
|
|
424
432
|
drawParamResObj = await getDrawParam(documentResObj);
|
|
425
|
-
multiMediaResObj = await getMultiMediaRes(zip, documentResObj, doc);
|
|
433
|
+
multiMediaResObj = await getMultiMediaRes(zip, documentResObj, doc, documentResPath);
|
|
426
434
|
}
|
|
427
435
|
}
|
|
428
436
|
return [zip, doc, Document, stampAnnot, annotationObjs, fontResObj, drawParamResObj, multiMediaResObj];
|
|
@@ -439,7 +447,7 @@ export const getPublicRes = async function ([zip, doc, Document, stampAnnot, ann
|
|
|
439
447
|
fontResObj = Object.assign(fontResObj, fontObj);
|
|
440
448
|
let drawParamObj = await getDrawParam(publicResObj);
|
|
441
449
|
drawParamResObj = Object.assign(drawParamResObj, drawParamObj);
|
|
442
|
-
let multiMediaObj = await getMultiMediaRes(zip, publicResObj, doc);
|
|
450
|
+
let multiMediaObj = await getMultiMediaRes(zip, publicResObj, doc, publicResPath);
|
|
443
451
|
multiMediaResObj = Object.assign(multiMediaResObj, multiMediaObj);
|
|
444
452
|
}
|
|
445
453
|
}
|
|
@@ -529,14 +537,14 @@ const getDrawParam = async function (res) {
|
|
|
529
537
|
return drawParamResObj;
|
|
530
538
|
}
|
|
531
539
|
|
|
532
|
-
const getMultiMediaRes = async function (zip, res, doc) {
|
|
540
|
+
const getMultiMediaRes = async function (zip, res, doc, resourcePath) {
|
|
533
541
|
const multiMedias = res['ofd:MultiMedias'];
|
|
534
542
|
let multiMediaResObj = {};
|
|
535
543
|
if (multiMedias) {
|
|
536
544
|
let array = collectGroupedItems(multiMedias, 'ofd:MultiMedia');
|
|
537
545
|
for (const item of array) {
|
|
538
546
|
if (item && item['ofd:MediaFile']) {
|
|
539
|
-
const candidates = resolveResourceCandidates(item['ofd:MediaFile'], res['@_BaseLoc'], doc);
|
|
547
|
+
const candidates = resolveResourceCandidates(item['ofd:MediaFile'], res['@_BaseLoc'], doc, resourcePath);
|
|
540
548
|
const file = getZipEntry(zip, candidates) ? candidates : null;
|
|
541
549
|
const type = item['@_Type'] ? item['@_Type'].toLowerCase() : '';
|
|
542
550
|
if (type === 'image') {
|
|
@@ -663,44 +671,32 @@ const getSealDocumentObj = function (stampAnnot) {
|
|
|
663
671
|
}
|
|
664
672
|
|
|
665
673
|
const getJsonFromXmlContent = async function (zip, xmlName) {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
}, function error(e) {
|
|
684
|
-
reject(e);
|
|
685
|
-
})
|
|
686
|
-
});
|
|
674
|
+
const entry = getZipEntry(zip, xmlName);
|
|
675
|
+
if (!entry) {
|
|
676
|
+
throw new Error(`OFD XML resource not found: ${normalizeZipPath(xmlName)}`);
|
|
677
|
+
}
|
|
678
|
+
const content = await entry.async('string');
|
|
679
|
+
ensureBrowserGlobal();
|
|
680
|
+
try {
|
|
681
|
+
const json = parseXmlToJson(content, {
|
|
682
|
+
attributeNamePrefix: "@_",
|
|
683
|
+
ignoreAttributes: false,
|
|
684
|
+
parseNodeValue: false,
|
|
685
|
+
trimValues: false
|
|
686
|
+
});
|
|
687
|
+
return {xml: content, json};
|
|
688
|
+
} catch (error) {
|
|
689
|
+
throw new Error(`OFD XML parse failed (${normalizeZipPath(xmlName)}): ${error.message}`);
|
|
690
|
+
}
|
|
687
691
|
}
|
|
688
692
|
|
|
689
693
|
const parseJbig2ImageFromZip = async function (zip, name) {
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
entry.async('uint8array').then(function (bytes) {
|
|
697
|
-
let jbig2 = new Jbig2Image();
|
|
698
|
-
const img = jbig2.parse(bytes);
|
|
699
|
-
resolve({img, width: jbig2.width, height: jbig2.height, format: 'gbig2'});
|
|
700
|
-
}, function error(e) {
|
|
701
|
-
reject(e);
|
|
702
|
-
})
|
|
703
|
-
});
|
|
694
|
+
const entry = getZipEntry(zip, name);
|
|
695
|
+
if (!entry) return null;
|
|
696
|
+
const bytes = await entry.async('uint8array');
|
|
697
|
+
const jbig2 = new Jbig2Image();
|
|
698
|
+
const img = jbig2.parse(bytes);
|
|
699
|
+
return {img, width: jbig2.width, height: jbig2.height, format: 'gbig2'};
|
|
704
700
|
}
|
|
705
701
|
|
|
706
702
|
const parseOtherImageFromZip = async function (zip, name, mime = 'image/png') {
|
|
@@ -311,6 +311,9 @@ let FONT_FAMILY = {
|
|
|
311
311
|
};
|
|
312
312
|
|
|
313
313
|
export const getFontFamily = function (font) {
|
|
314
|
+
if (typeof font !== 'string' || !font.trim()) {
|
|
315
|
+
return 'sans-serif';
|
|
316
|
+
}
|
|
314
317
|
if (FONT_FAMILY[font.toLowerCase()]) {
|
|
315
318
|
font = FONT_FAMILY[font.toLowerCase()];
|
|
316
319
|
}
|