|
12 | 12 | } (function (loadImage) {
|
13 | 13 | 'use strict'
|
14 | 14 |
|
| 15 | + loadImage.XmpMap = function () { |
| 16 | + return this |
| 17 | + }; |
| 18 | + |
| 19 | + loadImage.XmpMap.prototype.get = function (id) { |
| 20 | + return this[id]; |
| 21 | + } |
| 22 | + |
15 | 23 | loadImage.parseXmpData = function (dataView, offset, length, data, options) {
|
16 | 24 | if (options.disableExif) {
|
17 | 25 | return;
|
18 | 26 | }
|
19 | 27 |
|
20 | 28 | // Check for the ASCII code for "http" (0x68747470). Note that the actual XMP identifier is quite long: "http://ns.adobe.com/xap/1.0/\x00"
|
21 |
| - var arrIdentifier = []; |
22 | 29 | var offsetNamespace = 4;
|
23 | 30 | var lengthNamespace = 29;
|
| 31 | + var arrNamespace = []; |
24 | 32 | for (var i = 0; i < lengthNamespace; i++) {
|
25 |
| - arrIdentifier[i] = String.fromCharCode(dataView.getInt8(offset + offsetNamespace + i)); |
| 33 | + arrNamespace.push(String.fromCharCode(dataView.getUint8(offset + offsetNamespace + i))); |
26 | 34 | }
|
27 | 35 |
|
28 |
| - var identifier = arrIdentifier.join(""); |
29 |
| - if (identifier !== "http://ns.adobe.com/xap/1.0//0") { |
| 36 | + var namespace = arrNamespace.join(""); |
| 37 | + if (namespace !== "http://ns.adobe.com/xap/1.0//0") { |
30 | 38 | // No XMP data.
|
31 | 39 | return;
|
32 | 40 | }
|
33 | 41 |
|
34 | 42 | var offsetLp = 2; // Offset to the packet length field.
|
35 |
| - var xmpLength = dataView.getUint16(offset + offsetLp); |
| 43 | + var packetLength = dataView.getUint16(offset + offsetLp); |
36 | 44 |
|
37 | 45 | var lengthLp = 2;
|
38 |
| - xmpLength -= (lengthLp + lengthNamespace); // The packet length is a little misleading it includes the length of Lp and Namespace, remove those two to get the actual packet length. |
| 46 | + packetLength -= (lengthLp + lengthNamespace); // The packet length is a little misleading it includes the length of Lp and Namespace, remove those two to get the actual packet length. |
39 | 47 |
|
40 | 48 | var maxPacketLength = 65503;
|
41 |
| - if (maxPacketLength < xmpLength){ |
| 49 | + if (maxPacketLength < packetLength) { |
| 50 | + // The length of the packet is not valid. Note that XMP does allow multiple packets but they are unlikely and NOT currently supported |
| 51 | + return; |
| 52 | + } |
| 53 | + |
| 54 | + // According to Adobe's document |
| 55 | + // (http://www.adobe.com/content/dam/Adobe/en/devnet/xmp/pdfs/XMPSpecificationPart3.pdf) |
| 56 | + // an EXIF encoding of XMP will always be UTF-8. No need to check for |
| 57 | + // bytes per character or endianness. |
| 58 | + |
| 59 | + // Find the start of packet data. |
| 60 | + var offsetPacket = offsetNamespace + lengthNamespace; |
| 61 | + var arrPacketData = []; |
| 62 | + for (var j = 0; j < packetLength; j++) { |
| 63 | + arrPacketData.push(String.fromCharCode(dataView.getUint8(offset + offsetPacket + j))); |
| 64 | + } |
| 65 | + var xml = arrPacketData.join(""); |
| 66 | + |
| 67 | + data.xmp = new loadImage.XmpMap(); |
| 68 | + |
| 69 | + // Create an XMLDocument and extract the attributes from the |
| 70 | + // Description element. |
| 71 | + var xmlDocument = new DOMParser().parseFromString(xml, "application/xml"); |
| 72 | + |
| 73 | + var document = xmlDocument.documentElement; |
| 74 | + if (!document) { |
| 75 | + return; |
| 76 | + } |
| 77 | + |
| 78 | + var xpath = "/*[namespace-uri()='adobe:ns:meta/' and local-name()='xmpmeta']/*[namespace-uri()='http://www.w3.org/1999/02/22-rdf-syntax-ns#' and local-name()='RDF']/*[namespace-uri()='http://www.w3.org/1999/02/22-rdf-syntax-ns#' and local-name()='Description']"; |
| 79 | + var xpathResult; |
| 80 | + try { |
| 81 | + xpathResult = xmlDocument.evaluate(xpath, document, xmlDocument.createNSResolver(document), XPathResult.FIRST_ORDERED_NODE_TYPE, null); |
| 82 | + } catch (err) { |
| 83 | + console.log("Error selecting Description node: '" + err.message || JSON.stringify(err) + "'."); |
| 84 | + } |
| 85 | + |
| 86 | + if (!xpathResult) { |
42 | 87 | return;
|
43 | 88 | }
|
| 89 | + |
| 90 | + if (xpathResult.resultType !== XPathResult.FIRST_ORDERED_NODE_TYPE) { |
| 91 | + console.log("xpathResult type " + xpathResult.resultType + " is not supported."); |
| 92 | + return; |
| 93 | + } |
| 94 | + |
| 95 | + var node = xpathResult.singleNodeValue; |
| 96 | + var attr; |
| 97 | + for (var k = 0; k < node.attributes.length; k++) { |
| 98 | + attr = node.attributes[k]; |
| 99 | + data.xmp[attr.localName] = attr.value; |
| 100 | + } |
44 | 101 | }
|
45 | 102 |
|
46 | 103 | loadImage.metaDataParsers.jpeg[0xffe1].push(loadImage.parseXmpData);
|
|
0 commit comments