Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for images with src of type "Data URI" (Base64) or "Object URL" (Blob). #6

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
115 changes: 85 additions & 30 deletions exif.js
Expand Up @@ -57,7 +57,7 @@ var EXIF = (function() {
0x9214 : "SubjectArea", // Location and area of main subject 0x9214 : "SubjectArea", // Location and area of main subject
0x920A : "FocalLength", // Focal length of the lens in mm 0x920A : "FocalLength", // Focal length of the lens in mm
0xA20B : "FlashEnergy", // Strobe energy in BCPS 0xA20B : "FlashEnergy", // Strobe energy in BCPS
0xA20C : "SpatialFrequencyResponse", // 0xA20C : "SpatialFrequencyResponse", //
0xA20E : "FocalPlaneXResolution", // Number of pixels in width direction per FocalPlaneResolutionUnit 0xA20E : "FocalPlaneXResolution", // Number of pixels in width direction per FocalPlaneResolutionUnit
0xA20F : "FocalPlaneYResolution", // Number of pixels in height direction per FocalPlaneResolutionUnit 0xA20F : "FocalPlaneYResolution", // Number of pixels in height direction per FocalPlaneResolutionUnit
0xA210 : "FocalPlaneResolutionUnit", // Unit for measuring FocalPlaneXResolution and FocalPlaneYResolution 0xA210 : "FocalPlaneResolutionUnit", // Unit for measuring FocalPlaneXResolution and FocalPlaneYResolution
Expand All @@ -77,7 +77,7 @@ var EXIF = (function() {
0xA408 : "Contrast", // Direction of contrast processing applied by camera 0xA408 : "Contrast", // Direction of contrast processing applied by camera
0xA409 : "Saturation", // Direction of saturation processing applied by camera 0xA409 : "Saturation", // Direction of saturation processing applied by camera
0xA40A : "Sharpness", // Direction of sharpness processing applied by camera 0xA40A : "Sharpness", // Direction of sharpness processing applied by camera
0xA40B : "DeviceSettingDescription", // 0xA40B : "DeviceSettingDescription", //
0xA40C : "SubjectDistanceRange", // Distance to subject 0xA40C : "SubjectDistanceRange", // Distance to subject


// other tags // other tags
Expand Down Expand Up @@ -294,17 +294,48 @@ var EXIF = (function() {
}; };


function addEvent(element, event, handler) { function addEvent(element, event, handler) {
if (element.addEventListener) { if (element.addEventListener) {
element.addEventListener(event, handler, false); element.addEventListener(event, handler, false);
} else if (element.attachEvent) { } else if (element.attachEvent) {
element.attachEvent("on" + event, handler); element.attachEvent("on" + event, handler);
} }
} }


function imageHasData(img) { function imageHasData(img) {
return !!(img.exifdata); return !!(img.exifdata);
} }


function base64ToBlob(base64, contentType) {
contentType = contentType || base64.match(/^data\:([^\;]+)\;base64,/mi)[1] || ''; // e.g. 'data:image/jpeg;base64,...' => 'image/jpeg'
base64 = base64.replace(/^data\:([^\;]+)\;base64,/gmi, '');

var binary = atob(base64);
var len = binary.length;
var buffer = new ArrayBuffer(len);
var view = new Uint8Array(buffer);

for (var i = 0; i < len; i++) {
view[i] = binary.charCodeAt(i);
}
var blob = new Blob([view], {type: contentType});

return blob;
}

function objectURLToBlob (object_url, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', object_url, true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
var blob;
if (this.status === 200) {
blob = this.response;
}
callback(blob);
};
xhr.send();
}

function getImageData(img, callback) { function getImageData(img, callback) {
function handleBinaryFile(binFile) { function handleBinaryFile(binFile) {
var data = findEXIFinJPEG(binFile); var data = findEXIFinJPEG(binFile);
Expand All @@ -315,10 +346,34 @@ var EXIF = (function() {
} }


if (img instanceof Image) { if (img instanceof Image) {
BinaryAjax(img.src, function(http) { if (/^data\:/i.test(img.src)) { // Data URI
handleBinaryFile(http.binaryResponse); var fileReader = new FileReader();
});
} else if (window.FileReader && img instanceof window.File) { fileReader.onload = function(e) {
handleBinaryFile(new BinaryFile(e.target.result));
};

var blob = base64ToBlob(img.src);

fileReader.readAsBinaryString(blob);

} else if (/^blob\:/i.test(img.src)) { // Object URL
var fileReader = new FileReader();

fileReader.onload = function(e) {
handleBinaryFile(new BinaryFile(e.target.result));
};

objectURLToBlob(img.src, function (blob) {
fileReader.readAsBinaryString(blob);
});

} else { // HTTP URL
BinaryAjax(img.src, function(http) {
handleBinaryFile(http.binaryResponse);
});
}
} else if (img instanceof Blob || (window.FileReader && img instanceof window.File)) {
var fileReader = new FileReader(); var fileReader = new FileReader();


fileReader.onload = function(e) { fileReader.onload = function(e) {
Expand Down Expand Up @@ -346,20 +401,20 @@ var EXIF = (function() {


marker = file.getByteAt(offset+1); marker = file.getByteAt(offset+1);


// we could implement handling for other markers here, // we could implement handling for other markers here,
// but we're only looking for 0xFFE1 for EXIF data // but we're only looking for 0xFFE1 for EXIF data


if (marker == 22400) { if (marker == 22400) {
if (debug) console.log("Found 0xFFE1 marker"); if (debug) console.log("Found 0xFFE1 marker");

return readEXIFData(file, offset + 4, file.getShortAt(offset+2, true)-2); return readEXIFData(file, offset + 4, file.getShortAt(offset+2, true)-2);

// offset += 2 + file.getShortAt(offset+2, true); // offset += 2 + file.getShortAt(offset+2, true);


} else if (marker == 225) { } else if (marker == 225) {
// 0xE1 = Application-specific 1 (for EXIF) // 0xE1 = Application-specific 1 (for EXIF)
if (debug) console.log("Found 0xFFE1 marker"); if (debug) console.log("Found 0xFFE1 marker");

return readEXIFData(file, offset + 4, file.getShortAt(offset+2, true)-2); return readEXIFData(file, offset + 4, file.getShortAt(offset+2, true)-2);


} else { } else {
Expand All @@ -373,10 +428,10 @@ var EXIF = (function() {


function readTags(file, tiffStart, dirStart, strings, bigEnd) { function readTags(file, tiffStart, dirStart, strings, bigEnd) {
var entries = file.getShortAt(dirStart, bigEnd), var entries = file.getShortAt(dirStart, bigEnd),
tags = {}, tags = {},
entryOffset, tag, entryOffset, tag,
i; i;

for (i=0;i<entries;i++) { for (i=0;i<entries;i++) {
entryOffset = dirStart + i*12 + 2; entryOffset = dirStart + i*12 + 2;
tag = strings[file.getShortAt(entryOffset, bigEnd)]; tag = strings[file.getShortAt(entryOffset, bigEnd)];
Expand Down Expand Up @@ -526,23 +581,23 @@ var EXIF = (function() {
case "SceneCaptureType" : case "SceneCaptureType" :
case "SceneType" : case "SceneType" :
case "CustomRendered" : case "CustomRendered" :
case "WhiteBalance" : case "WhiteBalance" :
case "GainControl" : case "GainControl" :
case "Contrast" : case "Contrast" :
case "Saturation" : case "Saturation" :
case "Sharpness" : case "Sharpness" :
case "SubjectDistanceRange" : case "SubjectDistanceRange" :
case "FileSource" : case "FileSource" :
exifData[tag] = StringValues[tag][exifData[tag]]; exifData[tag] = StringValues[tag][exifData[tag]];
break; break;

case "ExifVersion" : case "ExifVersion" :
case "FlashpixVersion" : case "FlashpixVersion" :
exifData[tag] = String.fromCharCode(exifData[tag][0], exifData[tag][1], exifData[tag][2], exifData[tag][3]); exifData[tag] = String.fromCharCode(exifData[tag][0], exifData[tag][1], exifData[tag][2], exifData[tag][3]);
break; break;

case "ComponentsConfiguration" : case "ComponentsConfiguration" :
exifData[tag] = exifData[tag] =
StringValues.Components[exifData[tag][0]] StringValues.Components[exifData[tag][0]]
+ StringValues.Components[exifData[tag][1]] + StringValues.Components[exifData[tag][1]]
+ StringValues.Components[exifData[tag][2]] + StringValues.Components[exifData[tag][2]]
Expand All @@ -557,10 +612,10 @@ var EXIF = (function() {
gpsData = readTags(file, tiffOffset, tiffOffset + tags.GPSInfoIFDPointer, GPSTags, bigEnd); gpsData = readTags(file, tiffOffset, tiffOffset + tags.GPSInfoIFDPointer, GPSTags, bigEnd);
for (tag in gpsData) { for (tag in gpsData) {
switch (tag) { switch (tag) {
case "GPSVersionID" : case "GPSVersionID" :
gpsData[tag] = gpsData[tag][0] gpsData[tag] = gpsData[tag][0]
+ "." + gpsData[tag][1] + "." + gpsData[tag][1]
+ "." + gpsData[tag][2] + "." + gpsData[tag][2]
+ "." + gpsData[tag][3]; + "." + gpsData[tag][3];
break; break;
} }
Expand Down Expand Up @@ -591,7 +646,7 @@ var EXIF = (function() {


function getAllTags(img) { function getAllTags(img) {
if (!imageHasData(img)) return {}; if (!imageHasData(img)) return {};
var a, var a,
data = img.exifdata, data = img.exifdata,
tags = {}; tags = {};
for (a in data) { for (a in data) {
Expand Down Expand Up @@ -627,14 +682,14 @@ var EXIF = (function() {
return findEXIFinJPEG(file); return findEXIFinJPEG(file);
} }



return { return {
readFromBinaryFile : readFromBinaryFile, readFromBinaryFile : readFromBinaryFile,
pretty : pretty, pretty : pretty,
getTag : getTag, getTag : getTag,
getAllTags : getAllTags, getAllTags : getAllTags,
getData : getData, getData : getData,

Tags : ExifTags, Tags : ExifTags,
TiffTags : TiffTags, TiffTags : TiffTags,
GPSTags : GPSTags, GPSTags : GPSTags,
Expand Down