Files
Chamilo/app/Resources/public/assets/blueimp-load-image/js/load-image-iptc.js
2025-08-14 22:33:03 +02:00

240 lines
6.9 KiB
JavaScript

/*
* 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(['./load-image', './load-image-meta'], factory)
} else if (typeof module === 'object' && module.exports) {
factory(require('./load-image'), require('./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.
})