exif
Advanced tools
Comparing version 0.4.0 to 0.5.0
@@ -1,5 +0,8 @@ | ||
var fs = require('fs'), | ||
util = require('util'), | ||
BufferExtender = require('./Buffer'); | ||
var fs = require('fs'); | ||
var util = require('util'); | ||
var BufferExtender = require('./Buffer'); // bad idea | ||
var debug = require('debug')('exif'); | ||
var DEFAULT_MAX_ENTRIES=128; | ||
/** | ||
@@ -13,3 +16,20 @@ * Represents an image with Exif information. When instantiating it you have to | ||
* a Buffer. | ||
* - tiffOffsets (boolean) an object named "offsets" is added to exifData | ||
* and contains lot of offsets needed to get thumbnail and other things. | ||
* - fixThumbnailOffset: node-exif corrects the thumbnail offset in order to have an offset from the start of the buffer/file. | ||
* - maxEntries: Specifies the maximum entries to be parsed | ||
* - ifd0MaxEntries | ||
* - ifd1MaxEntries | ||
* - maxGpsEntries | ||
* - maxInteroperabilityEntries | ||
* - agfaMaxEntries | ||
* - epsonMaxEntries | ||
* - fujifilmMaxEntries | ||
* - olympusMaxEntries | ||
* - panasonicMaxEntries | ||
* - sanyoMaxEntries | ||
* - noPadding | ||
* | ||
* If you unspecify the image, you might call exifImage.loadImage(image, callback) to get exif datas. | ||
* | ||
* @param options Configuration options as described above | ||
@@ -20,13 +40,17 @@ * @param callback Function to call when data is extracted or an error occured | ||
function ExifImage (options, callback) { | ||
if (!(this instanceof ExifImage)) { | ||
return new ExifImage(options, callback); | ||
} | ||
var self = this; | ||
options = options || {}; | ||
this.options=options; | ||
if (!options) | ||
var options = {}; | ||
// Default option values | ||
["ifd0MaxEntries", "ifd1MaxEntries", "maxGpsEntries", "maxInteroperabilityEntries", "agfaMaxEntries", "epsonMaxEntries", | ||
"fujifilmMaxEntries", "olympusMaxEntries", "panasonicMaxEntries", "sanyoMaxEntries"].forEach(function(p) { | ||
if (options[p]===undefined) { | ||
options[p]=DEFAULT_MAX_ENTRIES; | ||
} | ||
}); | ||
this.image; | ||
this.imageType; | ||
this.isBigEndian; | ||
this.makernoteOffset; | ||
this.exifData = { | ||
@@ -40,16 +64,30 @@ image : {}, // Information about the main image | ||
}; | ||
this.offsets={}; | ||
if (options.tiffOffsets) { | ||
exifData.offsets=offsets; | ||
} | ||
debug("New ExifImage options=",options); | ||
if (!options.image) { | ||
throw new Error('You have to provide an image, it is pretty hard to extract Exif data from nothing...'); | ||
} else if (typeof callback !== 'function') { | ||
// If options image is not specified, the developper must call loadImage() to parse the image. | ||
// callback(new Error('You have to provide an image, it is pretty hard to extract Exif data from nothing...')); | ||
return; | ||
} | ||
if (typeof callback !== 'function') { | ||
throw new Error('You have to provide a callback function.'); | ||
} else { | ||
this.loadImage(options.image, function (error, image) { | ||
if (error) | ||
callback(error); | ||
else | ||
callback(false, image); | ||
} | ||
var self=this; | ||
setImmediate(function() { | ||
self.loadImage(options.image, function (error, exifData) { | ||
if (error) { | ||
return callback(error); | ||
} | ||
callback(null, exifData); | ||
}); | ||
} | ||
}); | ||
} | ||
@@ -59,64 +97,82 @@ | ||
/** | ||
* Load image and parse exifDatas | ||
* | ||
* @param [String|Buffer] image the image | ||
* @param callback a callback which is called when exif datas are parsed. | ||
* @return Nothing | ||
*/ | ||
ExifImage.prototype.loadImage = function (image, callback) { | ||
var self = this; | ||
debug("loadImage image=", image); | ||
if (image.constructor.name === 'Buffer') { | ||
this.processImage(image, callback); | ||
} else if (image.constructor.name === 'String') { | ||
this.processImage("Buffer", image, callback); | ||
return; | ||
} | ||
if (image.constructor.name === 'String') { | ||
fs.readFile(image, function (error, data) { | ||
if (error) | ||
if (error) { | ||
callback(new Error('Encountered the following error while trying to read given image: '+error)); | ||
else | ||
self.processImage(data, callback); | ||
return; | ||
} | ||
self.processImage("File: "+image, data, options, callback); | ||
}); | ||
} else { | ||
callback(new Error('Given image is neither a buffer nor a file, please provide one of these.')); | ||
return; | ||
} | ||
callback(new Error('Given image is neither a buffer nor a file, please provide one of these.')); | ||
}; | ||
ExifImage.prototype.processImage = function (data, callback) { | ||
ExifImage.prototype.processImage = function (source, data, callback) { | ||
var self = this; | ||
var offset = 0; | ||
if (data[offset++] == 0xFF && data[offset++] == 0xD8) { | ||
self.imageType = 'JPEG'; | ||
} else { | ||
callback(new Error('The given image is not a JPEG and thus unsupported right now.')); | ||
if (data[offset++] != 0xFF || data[offset++] != 0xD8) { | ||
var e=new Error('The given image is not a JPEG and thus unsupported right now.'); | ||
e.source=source; | ||
e.code="NOT_A_JPEG"; | ||
callback(e); | ||
return; | ||
} | ||
try { | ||
this.imageType = 'JPEG'; | ||
while (offset < data.length) { | ||
while (offset < data.length) { | ||
if (data[offset++] != 0xFF) { | ||
callback(false, self.exifData); | ||
return; | ||
} | ||
if (data[offset++] != 0xFF) { | ||
break; | ||
} | ||
if (data[offset++] == 0xE1) { | ||
var exifData = self.extractExifData(data, offset + 2, data.getShort(offset, true) - 2); | ||
callback(false, exifData); | ||
if (data[offset++] == 0xE1) { | ||
try { | ||
this.extractExifData(data, offset + 2, data.getShort(offset, true) - 2); | ||
} catch (error) { | ||
error.code="PARSING_ERROR"; | ||
error.source=source; | ||
debug("Extract exif data error source=", source, "offset=", offset, "error=",error); | ||
callback(error); | ||
return; | ||
} else { | ||
offset += data.getShort(offset, true); | ||
} | ||
debug("Extract exif data success source=", source, "exifData=",this.exifData); | ||
callback(null, this.exifData); | ||
return; | ||
} | ||
} catch (error) { | ||
callback(error); | ||
offset += data.getShort(offset, true); | ||
} | ||
callback(new Error('No Exif segment found in the given image.')); | ||
var e2=new Error('No Exif segment found in the given image.'); | ||
e2.source=source; | ||
e2.code="NO_EXIF_SEGMENT"; | ||
callback(e2); | ||
}; | ||
@@ -126,5 +182,8 @@ | ||
var self = this; | ||
var exifData=this.exifData; | ||
var tiffOffset = start + 6; | ||
var ifdOffset, numberOfEntries; | ||
var noPadding = (this.options.noPadding!==false); | ||
this.offsets.tiff=tiffOffset; | ||
@@ -140,4 +199,6 @@ // Exif data always starts with Exif\0\0 | ||
this.isBigEndian = false; | ||
} else if (data.getShort(tiffOffset) == 0x4D4D) { | ||
this.isBigEndian = true; | ||
} else { | ||
@@ -147,2 +208,4 @@ throw new Error('Invalid TIFF data! Expected 0x4949 or 0x4D4D at offset '+(tiffOffset)+' but found 0x'+data[tiffOffset].toString(16).toUpperCase()+data[tiffOffset + 1].toString(16).toUpperCase()+"."); | ||
debug("BigEndian=",this.isBigEndian); | ||
// Valid TIFF headers always have 0x002A here | ||
@@ -159,11 +222,28 @@ if (data.getShort(tiffOffset + 2, this.isBigEndian) != 0x002A) { | ||
ifdOffset = tiffOffset + data.getLong(tiffOffset + 4, this.isBigEndian); | ||
this.offsets.ifd0=ifdOffset; | ||
numberOfEntries = data.getShort(ifdOffset, this.isBigEndian); | ||
if (this.options.ifd0MaxEntries) { | ||
numberOfEntries=Math.min(numberOfEntries, this.options.ifd0MaxEntries); | ||
} | ||
debug("IFD0 ifdOffset=",ifdOffset, "numberOfEntries=", numberOfEntries); | ||
// Each IFD entry consists of 12 bytes which we loop through and extract | ||
// the data from | ||
for (var i = 0; i < numberOfEntries; i++) { | ||
var exifEntry = self.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, ExifImage.TAGS.exif); | ||
if (exifEntry && exifEntry.tagName !== null) this.exifData.image[exifEntry.tagName] = exifEntry.value; | ||
var exifEntry = this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, ExifImage.TAGS.exif); | ||
if (!exifEntry) { | ||
continue; | ||
} | ||
if (exifEntry.tagId===0xEA1C && noPadding) { | ||
continue; | ||
} | ||
exifData.image[exifEntry.tagName] = exifEntry.value; | ||
} | ||
debug("IFD0 parsed", exifData.image); | ||
/********************************* IFD1 **********************************/ | ||
@@ -175,12 +255,36 @@ | ||
if (nextIfdOffset != 0x00000000) { | ||
ifdOffset = tiffOffset + nextIfdOffset; | ||
this.offsets.ifd1=ifdOffset; | ||
numberOfEntries = data.getShort(ifdOffset, this.isBigEndian); | ||
if (this.options.ifd1MaxEntries) { | ||
numberOfEntries=Math.min(numberOfEntries, this.options.ifd1MaxEntries); | ||
} | ||
debug("IFD1 ifdOffset=",ifdOffset, "numberOfEntries=", numberOfEntries); | ||
// Each IFD entry consists of 12 bytes which we loop through and extract | ||
// the data from | ||
for (var i = 0; i < numberOfEntries; i++) { | ||
var exifEntry = self.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, ExifImage.TAGS.exif); | ||
if (exifEntry && exifEntry.tagName !== null) this.exifData.thumbnail[exifEntry.tagName] = exifEntry.value; | ||
var exifEntry = this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, ExifImage.TAGS.exif); | ||
if (!exifEntry) { | ||
continue; | ||
} | ||
if (exifEntry.tagId===0xEA1C && noPadding) { | ||
continue; | ||
} | ||
exifData.thumbnail[exifEntry.tagName] = exifEntry.value; | ||
} | ||
if (this.options.fixThumbnailOffset) { | ||
var thumbnailOffset=exifData.thumbnail[ExifImage.TAGS.exif[0x0201]]; | ||
if (thumbnailOffset) { | ||
debug("IFD1 fix thumbnail offset, add=",this.offsets.tiff); | ||
exifData.thumbnail[ExifImage.TAGS.exif[0x0201]]+=this.offsets.tiff; | ||
} | ||
} | ||
debug("IFD1 parsed", exifData.thumbnail); | ||
} | ||
@@ -192,14 +296,30 @@ | ||
// it if available | ||
if (typeof this.exifData.image[ExifImage.TAGS.exif[0x8769]] != "undefined") { | ||
if (exifData.image[ExifImage.TAGS.exif[0x8769]]) { | ||
ifdOffset = tiffOffset + this.exifData.image[ExifImage.TAGS.exif[0x8769]]; | ||
ifdOffset = tiffOffset + exifData.image[ExifImage.TAGS.exif[0x8769]]; | ||
this.offsets.tags=ifdOffset; | ||
numberOfEntries = data.getShort(ifdOffset, this.isBigEndian); | ||
if (this.options.maxEntries) { | ||
numberOfEntries=Math.min(numberOfEntries, this.options.maxEntries); | ||
} | ||
debug("EXIF IFD ifdOffset=",ifdOffset, "numberOfEntries=", numberOfEntries); | ||
// Each IFD entry consists of 12 bytes which we loop through and extract | ||
// the data from | ||
for (var i = 0; i < numberOfEntries; i++) { | ||
var exifEntry = self.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, ExifImage.TAGS.exif); | ||
if (exifEntry && exifEntry.tagName !== null) this.exifData.exif[exifEntry.tagName] = exifEntry.value; | ||
var exifEntry = this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, ExifImage.TAGS.exif); | ||
if (!exifEntry) { | ||
continue; | ||
} | ||
if (exifEntry.tagId===0xEA1C && noPadding) { | ||
continue; | ||
} | ||
exifData.exif[exifEntry.tagName] = exifEntry.value; | ||
} | ||
debug("EXIF IFD parsed",exifData.exif); | ||
} | ||
@@ -211,6 +331,13 @@ | ||
// it if available | ||
if (typeof this.exifData.image[ExifImage.TAGS.exif[0x8825]] != "undefined") { | ||
if (exifData.image[ExifImage.TAGS.exif[0x8825]]) { | ||
ifdOffset = tiffOffset + this.exifData.image[ExifImage.TAGS.exif[0x8825]]; | ||
ifdOffset = tiffOffset + exifData.image[ExifImage.TAGS.exif[0x8825]]; | ||
this.offsets.gps=ifdOffset; | ||
numberOfEntries = data.getShort(ifdOffset, this.isBigEndian); | ||
if (this.options.maxGpsEntries) { | ||
numberOfEntries=Math.min(numberOfEntries, this.options.maxGpsEntries); | ||
} | ||
debug("GPS IFD ifdOffset=", ifdOffset, "numberOfEntries=", numberOfEntries); | ||
@@ -220,7 +347,16 @@ // Each IFD entry consists of 12 bytes which we loop through and extract | ||
for (var i = 0; i < numberOfEntries; i++) { | ||
var exifEntry = self.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, ExifImage.TAGS.gps); | ||
if (exifEntry && exifEntry.tagName !== null) this.exifData.gps[exifEntry.tagName] = exifEntry.value; | ||
var exifEntry = this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, ExifImage.TAGS.gps); | ||
if (!exifEntry) { | ||
continue; | ||
} | ||
if (exifEntry.tagId===0xEA1C && noPadding) { | ||
continue; | ||
} | ||
exifData.gps[exifEntry.tagName] = exifEntry.value; | ||
} | ||
} | ||
debug("GPS IFD parsed",exifData.gps); | ||
} | ||
@@ -231,6 +367,13 @@ /************************* Interoperability IFD **************************/ | ||
// extract information from it if available | ||
if (typeof this.exifData.exif[ExifImage.TAGS.exif[0xA005]] != "undefined") { | ||
if (exifData.exif[ExifImage.TAGS.exif[0xA005]]) { | ||
ifdOffset = tiffOffset + this.exifData.exif[ExifImage.TAGS.exif[0xA005]]; | ||
ifdOffset = tiffOffset + exifData.exif[ExifImage.TAGS.exif[0xA005]]; | ||
this.offsets.interoperability=ifdOffset; | ||
numberOfEntries = data.getShort(ifdOffset, this.isBigEndian); | ||
if (this.options.maxInteroperabilityEntries) { | ||
numberOfEntries=Math.min(numberOfEntries, this.options.maxInteroperabilityEntries); | ||
} | ||
debug("Interoperability IFD ifdOffset=", ifdOffset, "numberOfEntries=", numberOfEntries); | ||
@@ -240,6 +383,15 @@ // Each IFD entry consists of 12 bytes which we loop through and extract | ||
for (var i = 0; i < numberOfEntries; i++) { | ||
var exifEntry = self.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, ExifImage.TAGS.exif); | ||
if (exifEntry && exifEntry.tagName !== null) this.exifData.interoperability[exifEntry.tagName] = exifEntry.value; | ||
} | ||
var exifEntry = this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, ExifImage.TAGS.exif); | ||
if (!exifEntry) { | ||
break; | ||
} | ||
if (exifEntry.tagId===0xEA1C && noPadding) { | ||
continue; | ||
} | ||
exifData.interoperability[exifEntry.tagName] = exifEntry.value; | ||
} | ||
debug("Interoperability IFD parsed",exifData.gps); | ||
} | ||
@@ -252,32 +404,42 @@ | ||
// start the extraction | ||
if (typeof this.exifData.exif[ExifImage.TAGS.exif[0x927C]] != "undefined") { | ||
if (typeof exifData.exif[ExifImage.TAGS.exif[0x927C]] != "undefined") { | ||
var type; | ||
// Check the header to see what kind of Makernote we are dealing with | ||
if (this.exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 7) === "OLYMP\x00\x01" || this.exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 7) === "OLYMP\x00\x02") { | ||
this.extractMakernotes = require('./makernotes/olympus').extractMakernotes; | ||
} else if (this.exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 7) === "AGFA \x00\x01") { | ||
this.extractMakernotes = require('./makernotes/agfa').extractMakernotes; | ||
} else if (this.exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 8) === "EPSON\x00\x01\x00") { | ||
this.extractMakernotes = require('./makernotes/epson').extractMakernotes; | ||
} else if (this.exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 8) === "FUJIFILM") { | ||
this.extractMakernotes = require('./makernotes/fujifilm').extractMakernotes; | ||
} else if (this.exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 9) === "Panasonic") { | ||
this.extractMakernotes = require('./makernotes/panasonic').extractMakernotes; | ||
} else if (this.exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 5) === "SANYO") { | ||
this.extractMakernotes = require('./makernotes/sanyo').extractMakernotes; | ||
} else { | ||
if (exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 7) === "OLYMP\x00\x01" || exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 7) === "OLYMP\x00\x02") { | ||
type="olympus" | ||
} else if (exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 7) === "AGFA \x00\x01") { | ||
type="agfa"; | ||
} else if (exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 8) === "EPSON\x00\x01\x00") { | ||
type="epson"; | ||
} else if (exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 8) === "FUJIFILM") { | ||
type="fujifilm"; | ||
} else if (exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 9) === "Panasonic") { | ||
type="panasonic"; | ||
} else if (exifData.exif[ExifImage.TAGS.exif[0x927C]].getString(0, 5) === "SANYO") { | ||
type="sanyo"; | ||
} | ||
debug("Makernote IFD ifdOffset=", ifdOffset, "type=", type); | ||
if (type) { | ||
var extractMakernotes = require('./makernotes/'+type).extractMakernotes; | ||
exifData.makernote = extractMakernotes.call(this, data, this.makernoteOffset, tiffOffset); | ||
} else { | ||
// Makernotes are available but the format is not recognized so | ||
// an error message is pushed instead, this ain't the best | ||
// solution but should do for now | ||
this.exifData.makernote['error'] = 'Unable to extract Makernote information as it is in an unsupported or unrecognized format.'; | ||
exifData.makernote['error'] = 'Unable to extract Makernote information as it is in an unsupported or unrecognized format.'; | ||
} | ||
if (typeof this.exifData.makernote['error'] == "undefined") { | ||
this.exifData.makernote = this.extractMakernotes(data, self.makernoteOffset, tiffOffset); | ||
} | ||
debug("Makernote IFD parsed",exifData.makernote); | ||
} | ||
return this.exifData; | ||
}; | ||
@@ -287,5 +449,2 @@ | ||
var self = this; | ||
var tagName; | ||
var entry = { | ||
@@ -305,3 +464,4 @@ tag : data.slice(entryOffset, entryOffset + 2), | ||
if (tags && tags[entry.tagId] && typeof tags[entry.tagId] == "function") { | ||
if (!(entry.tagName = tags[entry.tagId](entry))) { | ||
entry.tagName = tags[entry.tagId].call(this, entry); | ||
if (!entry.tagName) { | ||
return false; | ||
@@ -313,2 +473,5 @@ } | ||
entry.tagName = tags[entry.tagId]; | ||
if (entry.tagName===undefined) { | ||
return false; | ||
} | ||
@@ -388,9 +551,12 @@ // The tagId is not recognized | ||
// If this is the Makernote tag save its offset for later use | ||
if (entry.tagName === "MakerNote") self.makernoteOffset = entry.valueOffset; | ||
if (entry.tagName === "MakerNote") { | ||
this.offsets.makernoteOffset = entry.valueOffset; | ||
} | ||
// If the value array has only one element we don't need an array | ||
if (entry.value.length == 1) entry.value = entry.value[0]; | ||
if (entry.value.length == 1) { | ||
entry.value = entry.value[0]; | ||
} | ||
return entry; | ||
}; | ||
@@ -397,0 +563,0 @@ |
@@ -6,4 +6,2 @@ /** | ||
var makernoteData = {}; | ||
// List of vendor specific Makernote tags found on | ||
@@ -137,7 +135,14 @@ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Olympus.html | ||
// Get the number of entries and extract them | ||
var numberOfEntries = data.getShort(ifdOffset, this.isBigEndian, tiffOffset); | ||
var numberOfEntries = data.getShort(ifdOffset, this.isBigEndian); | ||
if (this.options.agfaMaxEntries) { | ||
numberOfEntries=Math.min(numberOfEntries, this.options.agfaMaxEntries); | ||
} | ||
var makernoteData = {}; | ||
for (var i = 0; i < numberOfEntries; i++) { | ||
var exifEntry = this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, tags); | ||
if (exifEntry && exifEntry.tagName !== null) makernoteData[exifEntry.tagName] = exifEntry.value; | ||
if (exifEntry && exifEntry.tagName !== null) { | ||
makernoteData[exifEntry.tagName] = exifEntry.value; | ||
} | ||
} | ||
@@ -144,0 +149,0 @@ |
@@ -6,4 +6,2 @@ /** | ||
var makernoteData = {}; | ||
// List of vendor specific Makernote tags found on | ||
@@ -137,7 +135,14 @@ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Olympus.html | ||
// Get the number of entries and extract them | ||
var numberOfEntries = data.getShort(ifdOffset, this.isBigEndian, tiffOffset); | ||
var numberOfEntries = data.getShort(ifdOffset, this.isBigEndian); | ||
if (this.options.epsonMaxEntries) { | ||
numberOfEntries=Math.min(numberOfEntries, this.options.epsonMaxEntries); | ||
} | ||
var makernoteData = {}; | ||
for (var i = 0; i < numberOfEntries; i++) { | ||
var exifEntry = this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, tags); | ||
if (exifEntry && exifEntry.tagName !== null) makernoteData[exifEntry.tagName] = exifEntry.value; | ||
if (exifEntry && exifEntry.tagName !== null) { | ||
makernoteData[exifEntry.tagName] = exifEntry.value; | ||
} | ||
} | ||
@@ -144,0 +149,0 @@ |
@@ -9,4 +9,2 @@ /** | ||
var makernoteData = {}; | ||
// List of vendor specific Makernote tags found on | ||
@@ -66,4 +64,9 @@ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/FujiFilm.html | ||
// Get the number of entries and extract them | ||
var numberOfEntries = data.getShort(ifdOffset, false, tiffOffset); | ||
var numberOfEntries = data.getShort(ifdOffset, false); | ||
if (this.options.fujifilmMaxEntries) { | ||
numberOfEntries=Math.min(numberOfEntries, this.options.fujifilmMaxEntries); | ||
} | ||
var makernoteData = {}; | ||
for (var i = 0; i < numberOfEntries; i++) { | ||
@@ -70,0 +73,0 @@ var exifEntry = this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), makernoteOffset, false, tags); |
@@ -6,4 +6,2 @@ /** | ||
var makernoteData = {}; | ||
// List of vendor specific Makernote tags found on | ||
@@ -137,4 +135,9 @@ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Olympus.html | ||
// Get the number of entries and extract them | ||
var numberOfEntries = data.getShort(ifdOffset, this.isBigEndian, tiffOffset); | ||
var numberOfEntries = data.getShort(ifdOffset, this.isBigEndian); | ||
if (this.options.olympusMaxEntries) { | ||
numberOfEntries=Math.min(numberOfEntries, this.options.olympusMaxEntries); | ||
} | ||
var makernoteData = {}; | ||
for (var i = 0; i < numberOfEntries; i++) { | ||
@@ -141,0 +144,0 @@ var exifEntry = this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, tags); |
@@ -6,4 +6,2 @@ /** | ||
var makernoteData = {}; | ||
// List of vendor specific Makernote tags found on | ||
@@ -117,7 +115,15 @@ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Panasonic.html | ||
// Get the number of entries and extract them | ||
var numberOfEntries = data.getShort(ifdOffset, this.isBigEndian, tiffOffset); | ||
var numberOfEntries = data.getShort(ifdOffset, this.isBigEndian); | ||
if (this.options.panasonicMaxEntries) { | ||
numberOfEntries=Math.min(numberOfEntries, this.options.panasonicMaxEntries); | ||
} | ||
var makernoteData = {}; | ||
for (var i = 0; i < numberOfEntries; i++) { | ||
var exifEntry = this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), makernoteOffset, false, tags); | ||
if (exifEntry && exifEntry.tagName !== null) makernoteData[exifEntry.tagName] = exifEntry.value; | ||
if( ! exifEntry ) break; // stop if exifEntry starts to return false, prevents a process out of memory | ||
if (exifEntry && exifEntry.tagName) { | ||
makernoteData[exifEntry.tagName] = exifEntry.value; | ||
} | ||
} | ||
@@ -124,0 +130,0 @@ |
@@ -6,4 +6,2 @@ /** | ||
var makernoteData = {}; | ||
// List of vendor specific Makernote tags found on | ||
@@ -58,7 +56,14 @@ // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Sanyo.html | ||
// Get the number of entries and extract them | ||
var numberOfEntries = data.getShort(ifdOffset, this.isBigEndian, tiffOffset); | ||
var numberOfEntries = data.getShort(ifdOffset, this.isBigEndian); | ||
if (this.options.sanyoMaxEntries) { | ||
numberOfEntries=Math.min(numberOfEntries, this.options.sanyoMaxEntries); | ||
} | ||
var makernoteData = {}; | ||
for (var i = 0; i < numberOfEntries; i++) { | ||
var exifEntry = this.extractExifEntry(data, (ifdOffset + 2 + (i * 12)), tiffOffset, this.isBigEndian, tags); | ||
if (exifEntry && exifEntry.tagName !== null) makernoteData[exifEntry.tagName] = exifEntry.value; | ||
if (exifEntry && exifEntry.tagName) { | ||
makernoteData[exifEntry.tagName] = exifEntry.value; | ||
} | ||
} | ||
@@ -65,0 +70,0 @@ |
{ | ||
"name" : "exif", | ||
"version" : "0.4.0", | ||
"description" : "A node.js library to extract Exif metadata from images.", | ||
"author" : "Daniel Leinich <leinich@gmx.net>", | ||
"keywords" : ["exif", "image", "jpeg", "jpg", "tiff", "makernotes", "gps"], | ||
"main" : "./lib/exif", | ||
"repository" : { | ||
"type" : "git", | ||
"url" : "http://github.com/gomfunkel/node-exif.git" | ||
} | ||
"name" : "exif", | ||
"version" : "0.5.0", | ||
"description" : "A node.js library to extract Exif metadata from images.", | ||
"author" : "Daniel Leinich <leinich@gmx.net>", | ||
"keywords" : ["exif", "image", "jpeg", "jpg", "tiff", "makernotes", "gps"], | ||
"main" : "./lib/exif", | ||
"repository" : { | ||
"type" : "git", | ||
"url" : "http://github.com/gomfunkel/node-exif.git" | ||
}, | ||
"dependencies": { | ||
"debug": "2.2" | ||
} | ||
} |
@@ -5,2 +5,6 @@ # node-exif | ||
## node-exif CLI | ||
Rodrigo Espinosa proposes the npm package [exif-cli](https://github.com/RodrigoEspinosa/exif-cli) to execute node-exif from a shell. | ||
## Table of Contents | ||
@@ -18,3 +22,3 @@ | ||
npm install exif | ||
If you don't have npm installed or don't want to use it: | ||
@@ -31,3 +35,3 @@ | ||
var ExifImage = require('exif').ExifImage; | ||
try { | ||
@@ -59,4 +63,4 @@ new ExifImage({ image : 'myImage.jpg' }, function (error, exifData) { | ||
``` | ||
{ | ||
image: { | ||
{ | ||
image: { | ||
Make: 'FUJIFILM', | ||
@@ -72,5 +76,5 @@ Model: 'FinePix40i', | ||
Copyright: ' ', | ||
ExifOffset: 250 | ||
ExifOffset: 250 | ||
}, | ||
thumbnail: { | ||
thumbnail: { | ||
Compression: 6, | ||
@@ -83,5 +87,5 @@ Orientation: 1, | ||
ThumbnailLength: 8691, | ||
YCbCrPositioning: 2 | ||
YCbCrPositioning: 2 | ||
}, | ||
exif: { | ||
exif: { | ||
FNumber: 2.8, | ||
@@ -114,10 +118,10 @@ ExposureProgram: 2, | ||
FileSource: <Buffer 03>, | ||
SceneType: <Buffer 01> | ||
SceneType: <Buffer 01> | ||
}, | ||
gps: {}, | ||
interoperability: { | ||
InteropIndex: 'R98', | ||
InteropIndex: 'R98', | ||
InteropVersion: <Buffer 30 31 30 30> | ||
}, | ||
makernote: { | ||
makernote: { | ||
Version: <Buffer 30 31 33 30>, | ||
@@ -135,4 +139,4 @@ Quality: 'NORMAL ', | ||
FocusWarning: 0, | ||
ExposureWarning: 0 | ||
} | ||
ExposureWarning: 0 | ||
} | ||
} | ||
@@ -146,5 +150,5 @@ ``` | ||
There are a lot of things still to be done and to be made better. If you have any special requests please open an issue with a feature request. | ||
## License | ||
_node-exif_ is licensed under the MIT License. (See LICENSE) | ||
_node-exif_ is licensed under the MIT License. (See LICENSE) |
Sorry, the diff of this file is not supported yet
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
65760
1591
145
1
2
1
+ Addeddebug@2.2
+ Addeddebug@2.2.0(transitive)
+ Addedms@0.7.1(transitive)