|
- /*
- * JavaScript Load Image IPTC Parser
- * https://github.com/blueimp/JavaScript-Load-Image
- *
- * Copyright 2013, Sebastian Tschan
- * Copyright 2018, Dave Bevan
- * https://blueimp.net
- *
- * Licensed under the MIT license:
- * https://opensource.org/licenses/MIT
- */
-
- /* global define, module, require, DataView */
-
- ;(function (factory) {
- 'use strict'
- if (typeof define === 'function' && define.amd) {
- // Register as an anonymous AMD module:
- define(['jquery/fileUploader/vendor/blueimp-load-image/js/load-image', 'jquery/fileUploader/vendor/blueimp-load-image/js/load-image-meta'], factory)
- } else if (typeof module === 'object' && module.exports) {
- factory(require('jquery/fileUploader/vendor/blueimp-load-image/js/load-image'), require('jquery/fileUploader/vendor/blueimp-load-image/js/load-image-meta'))
- } else {
- // Browser globals:
- factory(window.loadImage)
- }
- })(function (loadImage) {
- 'use strict'
-
- /**
- * IPTC tag map
- *
- * @name IptcMap
- * @class
- */
- function IptcMap() {}
-
- IptcMap.prototype.map = {
- ObjectName: 5
- }
-
- IptcMap.prototype.types = {
- 0: 'Uint16', // ApplicationRecordVersion
- 200: 'Uint16', // ObjectPreviewFileFormat
- 201: 'Uint16', // ObjectPreviewFileVersion
- 202: 'binary' // ObjectPreviewData
- }
-
- /**
- * Retrieves IPTC tag value
- *
- * @param {number|string} id IPTC tag code or name
- * @returns {object} IPTC tag value
- */
- IptcMap.prototype.get = function (id) {
- return this[id] || this[this.map[id]]
- }
-
- /**
- * Retrieves string for the given DataView and range
- *
- * @param {DataView} dataView Data view interface
- * @param {number} offset Offset start
- * @param {number} length Offset length
- * @returns {string} String value
- */
- function getStringValue(dataView, offset, length) {
- var outstr = ''
- var end = offset + length
- for (var n = offset; n < end; n += 1) {
- outstr += String.fromCharCode(dataView.getUint8(n))
- }
- return outstr
- }
-
- /**
- * Retrieves tag value for the given DataView and range
- *
- * @param {number} tagCode tag code
- * @param {IptcMap} map IPTC tag map
- * @param {DataView} dataView Data view interface
- * @param {number} offset Range start
- * @param {number} length Range length
- * @returns {object} Tag value
- */
- function getTagValue(tagCode, map, dataView, offset, length) {
- if (map.types[tagCode] === 'binary') {
- return new Blob([dataView.buffer.slice(offset, offset + length)])
- }
- if (map.types[tagCode] === 'Uint16') {
- return dataView.getUint16(offset)
- }
- return getStringValue(dataView, offset, length)
- }
-
- /**
- * Combines IPTC value with existing ones.
- *
- * @param {object} value Existing IPTC field value
- * @param {object} newValue New IPTC field value
- * @returns {object} Resulting IPTC field value
- */
- function combineTagValues(value, newValue) {
- if (value === undefined) return newValue
- if (value instanceof Array) {
- value.push(newValue)
- return value
- }
- return [value, newValue]
- }
-
- /**
- * Parses IPTC tags.
- *
- * @param {DataView} dataView Data view interface
- * @param {number} segmentOffset Segment offset
- * @param {number} segmentLength Segment length
- * @param {object} data Data export object
- * @param {object} includeTags Map of tags to include
- * @param {object} excludeTags Map of tags to exclude
- */
- function parseIptcTags(
- dataView,
- segmentOffset,
- segmentLength,
- data,
- includeTags,
- excludeTags
- ) {
- var value, tagSize, tagCode
- var segmentEnd = segmentOffset + segmentLength
- var offset = segmentOffset
- while (offset < segmentEnd) {
- if (
- dataView.getUint8(offset) === 0x1c && // tag marker
- dataView.getUint8(offset + 1) === 0x02 // record number, only handles v2
- ) {
- tagCode = dataView.getUint8(offset + 2)
- if (
- (!includeTags || includeTags[tagCode]) &&
- (!excludeTags || !excludeTags[tagCode])
- ) {
- tagSize = dataView.getInt16(offset + 3)
- value = getTagValue(tagCode, data.iptc, dataView, offset + 5, tagSize)
- data.iptc[tagCode] = combineTagValues(data.iptc[tagCode], value)
- if (data.iptcOffsets) {
- data.iptcOffsets[tagCode] = offset
- }
- }
- }
- offset += 1
- }
- }
-
- /**
- * Tests if field segment starts at offset.
- *
- * @param {DataView} dataView Data view interface
- * @param {number} offset Segment offset
- * @returns {boolean} True if '8BIM<EOT><EOT>' exists at offset
- */
- function isSegmentStart(dataView, offset) {
- return (
- dataView.getUint32(offset) === 0x3842494d && // Photoshop segment start
- dataView.getUint16(offset + 4) === 0x0404 // IPTC segment start
- )
- }
-
- /**
- * Returns header length.
- *
- * @param {DataView} dataView Data view interface
- * @param {number} offset Segment offset
- * @returns {number} Header length
- */
- function getHeaderLength(dataView, offset) {
- var length = dataView.getUint8(offset + 7)
- if (length % 2 !== 0) length += 1
- // Check for pre photoshop 6 format
- if (length === 0) {
- // Always 4
- length = 4
- }
- return length
- }
-
- loadImage.parseIptcData = function (dataView, offset, length, data, options) {
- if (options.disableIptc) {
- return
- }
- var markerLength = offset + length
- while (offset + 8 < markerLength) {
- if (isSegmentStart(dataView, offset)) {
- var headerLength = getHeaderLength(dataView, offset)
- var segmentOffset = offset + 8 + headerLength
- if (segmentOffset > markerLength) {
- // eslint-disable-next-line no-console
- console.log('Invalid IPTC data: Invalid segment offset.')
- break
- }
- var segmentLength = dataView.getUint16(offset + 6 + headerLength)
- if (offset + segmentLength > markerLength) {
- // eslint-disable-next-line no-console
- console.log('Invalid IPTC data: Invalid segment size.')
- break
- }
- // Create the iptc object to store the tags:
- data.iptc = new IptcMap()
- if (!options.disableIptcOffsets) {
- data.iptcOffsets = new IptcMap()
- }
- parseIptcTags(
- dataView,
- segmentOffset,
- segmentLength,
- data,
- options.includeIptcTags,
- options.excludeIptcTags || { 202: true } // ObjectPreviewData
- )
- return
- }
- // eslint-disable-next-line no-param-reassign
- offset += 1
- }
- }
-
- // Registers this IPTC parser for the APP13 JPEG metadata segment:
- loadImage.metaDataParsers.jpeg[0xffed].push(loadImage.parseIptcData)
-
- loadImage.IptcMap = IptcMap
-
- // Adds the following properties to the parseMetaData callback data:
- // - iptc: The iptc tags, parsed by the parseIptcData method
-
- // Adds the following options to the parseMetaData method:
- // - disableIptc: Disables IPTC parsing when true.
- // - disableIptcOffsets: Disables storing IPTC tag offsets when true.
- // - includeIptcTags: A map of IPTC tags to include for parsing.
- // - excludeIptcTags: A map of IPTC tags to exclude from parsing.
- })
|