diff --git a/wire/modules/Inputfield/InputfieldImage/InputfieldImage.module b/wire/modules/Inputfield/InputfieldImage/InputfieldImage.module
index 6358f0cc..16f4c15e 100755
--- a/wire/modules/Inputfield/InputfieldImage/InputfieldImage.module
+++ b/wire/modules/Inputfield/InputfieldImage/InputfieldImage.module
@@ -195,7 +195,7 @@ class InputfieldImage extends InputfieldFile implements InputfieldItemList, Inpu
if(!$this->resizeServer && ($this->maxWidth || $this->maxHeight || $this->maxSize)) {
$thisURL = $config->urls->InputfieldImage;
$jsExt = $config->debug ? "js" : "min.js";
- $config->scripts->add($thisURL . "exif.$jsExt");
+ $config->scripts->add($thisURL . "piexif.$jsExt");
$config->scripts->add($thisURL . "PWImageResizer.$jsExt");
$maxSize = str_replace(',', '.', $this->maxSize);
$quality = str_replace(',', '.', (float) ($this->clientQuality / 100));
diff --git a/wire/modules/Inputfield/InputfieldImage/PWImageResizer.js b/wire/modules/Inputfield/InputfieldImage/PWImageResizer.js
index 40061242..65f5d89b 100644
--- a/wire/modules/Inputfield/InputfieldImage/PWImageResizer.js
+++ b/wire/modules/Inputfield/InputfieldImage/PWImageResizer.js
@@ -3,8 +3,9 @@
*
* Code based on ImageUploader (c) Ross Turner (https://github.com/rossturner/HTML5-ImageUploader).
* Adapted for ProcessWire by Ryan as a resizer-only libary with different behavior and some fixes.
+ * Updates by Robin S. (https://github.com/toutouwai) to replace exif.js with piexif.js library.
*
- * Requires exif.js (https://github.com/exif-js/exif-js) for JPEG autoRotate functions.
+ * Requires piexif.js (https://github.com/hMatoba/piexifjs) to retain EXIF data in resized JPG.
*
* Config settings:
*
@@ -106,28 +107,7 @@ PWImageResizer.prototype.resize = function(file, completionCallback) {
completionCallback(false);
return;
}
-
- if(contentType == 'image/jpeg' && This.config.autoRotate) {
- // jpeg with autoRotate
- This.consoleLog('detecting JPEG image orientation...');
-
- if((typeof EXIF.getData === "function") && (typeof EXIF.getTag === "function")) {
- This.consoleLog('EXIF.getData starting');
- EXIF.getData(img, function() {
- This.consoleLog('EXIF.getData done, orientation:');
- var orientation = EXIF.getTag(this, "Orientation");
- This.consoleLog('image orientation from EXIF tag: ' + orientation);
- This.scaleImage(img, orientation, completionCallback);
- });
- } else {
- This.consoleLog("can't read EXIF data, the Exif.js library not found");
- This.scaleImage(img, 0, completionCallback);
- }
-
- } else {
- // png or gif (or jpeg with autoRotate==false)
- This.scaleImage(img, 0, completionCallback);
- }
+ This.scaleImage(img, completionCallback);
}
};
@@ -212,11 +192,10 @@ PWImageResizer.prototype.drawImage = function(context, img, x, y, width, height,
* Scale an image
*
* @param img The
element
- * @param orientation Orientation number from Exif.js or 0 bypass
* @param completionCallback Function to call upon completion
*
*/
-PWImageResizer.prototype.scaleImage = function(img, orientation, completionCallback) {
+PWImageResizer.prototype.scaleImage = function(img, completionCallback) {
var canvas = document.createElement('canvas');
canvas.width = img.width;
@@ -232,48 +211,7 @@ PWImageResizer.prototype.scaleImage = function(img, orientation, completionCallb
var styleWidth = canvas.style.width;
var height = canvas.height;
var styleHeight = canvas.style.height;
-
- if(typeof orientation === 'undefined') orientation = 1;
-
- if(orientation) {
- if(orientation > 4) {
- canvas.width = height;
- canvas.style.width = styleHeight;
- canvas.height = width;
- canvas.style.height = styleWidth;
- }
- switch(orientation) {
- case 2:
- ctx.translate(width, 0);
- ctx.scale(-1, 1);
- break;
- case 3:
- ctx.translate(width, height);
- ctx.rotate(Math.PI);
- break;
- case 4:
- ctx.translate(0, height);
- ctx.scale(1, -1);
- break;
- case 5:
- ctx.rotate(0.5 * Math.PI);
- ctx.scale(1, -1);
- break;
- case 6:
- ctx.rotate(0.5 * Math.PI);
- ctx.translate(0, -height);
- break;
- case 7:
- ctx.rotate(0.5 * Math.PI);
- ctx.translate(width, -height);
- ctx.scale(-1, 1);
- break;
- case 8:
- ctx.rotate(-0.5 * Math.PI);
- ctx.translate(-width, 0);
- break;
- }
- }
+
ctx.drawImage(img, 0, 0);
ctx.restore();
@@ -327,6 +265,32 @@ PWImageResizer.prototype.scaleImage = function(img, orientation, completionCallb
this.config.onScale(imageData);
}
+ /** Added by @Toutouwai for change to piexif **/
+ if(this.currentFile.type === 'image/jpeg') {
+ try {
+ var exifObj = piexif.load(img.src);
+ // Detect if there is a high likelihood this image has already been rotated according to its EXIF orientation
+ var orientation = exifObj['0th'][piexif.ImageIFD.Orientation];
+ if(orientation > 4 && img.height > img.width) {
+ // Set EXIF orientation to normal
+ exifObj['0th'][piexif.ImageIFD.Orientation] = 1;
+ }
+ try {
+ var exifStr = piexif.dump(exifObj);
+ try {
+ imageData = piexif.insert(exifStr, imageData);
+ } catch(error) {
+ console.error(error);
+ }
+ } catch(error) {
+ console.error(error);
+ }
+ } catch(error) {
+ console.error(error);
+ }
+ }
+ /** End added by @Toutouwai for piexif **/
+
completionCallback(this.imageDataToBlob(imageData));
};
diff --git a/wire/modules/Inputfield/InputfieldImage/PWImageResizer.min.js b/wire/modules/Inputfield/InputfieldImage/PWImageResizer.min.js
index 3115045b..0257ae6f 100644
--- a/wire/modules/Inputfield/InputfieldImage/PWImageResizer.min.js
+++ b/wire/modules/Inputfield/InputfieldImage/PWImageResizer.min.js
@@ -1 +1 @@
-var PWImageResizer=function(a){this.setConfig(a)};PWImageResizer.prototype.resize=function(c,d){var b=document.createElement("img");this.currentFile=c;var a=new FileReader();var e=this;var f=c.type.toString();a.onload=function(g){b.src=g.target.result;b.onload=function(){if(!e.needsResize(b,f)){d(false);return}if(f=="image/jpeg"&&e.config.autoRotate){e.consoleLog("detecting JPEG image orientation...");if((typeof EXIF.getData==="function")&&(typeof EXIF.getTag==="function")){e.consoleLog("EXIF.getData starting");EXIF.getData(b,function(){e.consoleLog("EXIF.getData done, orientation:");var h=EXIF.getTag(this,"Orientation");e.consoleLog("image orientation from EXIF tag: "+h);e.scaleImage(b,h,d)})}else{e.consoleLog("can't read EXIF data, the Exif.js library not found");e.scaleImage(b,0,d)}}else{e.scaleImage(b,0,d)}}};a.readAsDataURL(c)};PWImageResizer.prototype.needsResize=function(a,d){var c=false;var b="n/a";if(d!="image/jpeg"&&d!="image/png"&&d!="image/gif"){b="unsupported image content-type: "+d}else{if(this.config.scaleRatio>0){c=true;b="scaleRatio specified"}else{if(this.config.maxWidth>0||this.config.maxHeight>0){if(this.config.maxWidth>0&&a.width>this.config.maxWidth){c=true}if(this.config.maxHeight>0&&a.height>this.config.maxHeight){c=true}b=c?"dimensions exceed max allowed":"dimensions do not require resize"}}}if(!c&&this.config.maxSize>0){if(this.config.maxSize<(a.width*a.height)/1000000){c=true}b=(c?"megapixels exceeds ":"megapixels below ")+this.config.maxSize}if(this.config.debug){this.consoleLog("needsResize="+(c?"Yes":"No")+" ("+b+")")}return c};PWImageResizer.prototype.drawImage=function(d,f,j,i,c,k,b,g,e,a){d.save();if(typeof c==="undefined"){c=f.width}if(typeof k==="undefined"){k=f.height}if(typeof a==="undefined"){a=false}if(a){j-=c/2;i-=k/2}d.translate(j+c/2,i+k/2);var h=2*Math.PI-b*Math.PI/180;d.rotate(h);if(g){flipScale=-1}else{flipScale=1}if(e){flopScale=-1}else{flopScale=1}d.scale(flipScale,flopScale);d.drawImage(f,-c/2,-k/2,c,k);d.restore()};PWImageResizer.prototype.scaleImage=function(i,c,l){var d=document.createElement("canvas");d.width=i.width;d.height=i.height;var p=d.getContext("2d");p.save();var b=d.width;var f=d.style.width;var o=d.height;var e=d.style.height;if(typeof c==="undefined"){c=1}if(c){if(c>4){d.width=o;d.style.width=e;d.height=b;d.style.height=f}switch(c){case 2:p.translate(b,0);p.scale(-1,1);break;case 3:p.translate(b,o);p.rotate(Math.PI);break;case 4:p.translate(0,o);p.scale(1,-1);break;case 5:p.rotate(0.5*Math.PI);p.scale(1,-1);break;case 6:p.rotate(0.5*Math.PI);p.translate(0,-o);break;case 7:p.rotate(0.5*Math.PI);p.translate(b,-o);p.scale(-1,1);break;case 8:p.rotate(-0.5*Math.PI);p.translate(-b,0);break}}p.drawImage(i,0,0);p.restore();var k=d.width/d.height;var g=0;var h="";if(this.config.maxWidth>0||this.config.maxHeight>0){g=Math.min(this.config.maxWidth,k*this.config.maxHeight);h="max width/height of "+this.config.maxWidth+"x"+this.config.maxHeight}if(this.config.maxSize>0&&(this.config.maxSize<(d.width*d.height)/1000000)){var n=Math.floor(Math.sqrt(this.config.maxSize*k)*1000);g=g>0?Math.min(g,n):n;if(n===g){h="max megapixels of "+this.config.maxSize}}if(this.config.scaleRatio){var j=Math.floor(this.config.scaleRatio*d.width);g=g>0?Math.min(g,j):j;if(j==g){h="scale ratio of "+this.config.scaleRatio}}if(g<=0){this.consoleLog("image size is too small to resize");l(false);return}if(this.config.debug){this.consoleLog("original image size: "+d.width+"x"+d.height+" px");this.consoleLog("scaled image size: "+g+"x"+Math.floor(g/k)+" px via "+h)}while(d.width>=(2*g)){d=this.getHalfScaleCanvas(d)}if(d.width>g){d=this.scaleCanvasWithAlgorithm(d,g)}var m=this.config.quality;if(this.currentFile.type!="image/jpeg"){m=1}var a=d.toDataURL(this.currentFile.type,m);if(typeof this.config.onScale==="function"){this.config.onScale(a)}l(this.imageDataToBlob(a))};PWImageResizer.prototype.imageDataToBlob=function(h){var f=";base64,";if(h.indexOf(f)==-1){var e=h.split(",");var g=e[0].split(":")[1];var a=e[1];return new Blob([a],{type:g})}var e=h.split(f);var g=e[0].split(":")[1];var a=window.atob(e[1]);var d=a.length;var c=new Uint8Array(d);for(var b=0;b(y.height-1)?(y.height-1):Math.ceil(p));for(o=0;o(y.width-1)?(y.width-1):Math.ceil(f));e=(o+u.width*q)*4;n=(w+y.width*d)*4;C=(t+y.width*d)*4;m=(w+y.width*c)*4;B=(t+y.width*c)*4;k=f-w;h=p-d;l=z(y.data[n],y.data[C],y.data[m],y.data[B],k,h);u.data[e]=l;s=z(y.data[n+1],y.data[C+1],y.data[m+1],y.data[B+1],k,h);u.data[e+1]=s;v=z(y.data[n+2],y.data[C+2],y.data[m+2],y.data[B+2],k,h);u.data[e+2]=v;x=z(y.data[n+3],y.data[C+3],y.data[m+3],y.data[B+3],k,h);u.data[e+3]=x}}};PWImageResizer.prototype.setConfig=function(a){this.config=a;this.config.debug=this.config.debug||false;if(typeof a.quality=="undefined"){a.quality=1}if(a.quality<0.1){a.quality=0.1}if(a.quality>1){a.quality=1}this.config.quality=a.quality;if((!this.config.maxWidth)||(this.config.maxWidth<0)){this.config.maxWidth=0}if((!this.config.maxHeight)||(this.config.maxHeight<0)){this.config.maxHeight=0}if((!this.config.maxSize)||(this.config.maxSize<0)){this.config.maxSize=null}if((!this.config.scaleRatio)||(this.config.scaleRatio<=0)||(this.config.scaleRatio>=1)){this.config.scaleRatio=null}this.config.autoRotate=true;if(typeof a.autoRotate==="boolean"){this.config.autoRotate=a.autoRotate}if(this.config.maxWidth&&!this.config.maxHeight){this.config.maxHeight=this.config.maxWidth}else{if(this.config.maxHeight&&!this.config.maxWidth){this.config.maxWidth=this.config.maxHeight}else{if(!this.config.maxWidth&&!this.config.maxHeight){}}}};PWImageResizer.prototype.consoleLog=function(a){if(this.config.debug){console.log("PWImageResizer: "+a)}};
\ No newline at end of file
+var PWImageResizer=function(config){this.setConfig(config)};PWImageResizer.prototype.resize=function(file,completionCallback){var img=document.createElement("img");this.currentFile=file;var reader=new FileReader;var This=this;var contentType=file.type.toString();reader.onload=function(e){img.src=e.target.result;img.onload=function(){if(!This.needsResize(img,contentType)){completionCallback(false);return}This.scaleImage(img,completionCallback)}};reader.readAsDataURL(file)};PWImageResizer.prototype.needsResize=function(img,contentType){var needsResize=false;var why="n/a";if(contentType!="image/jpeg"&&contentType!="image/png"&&contentType!="image/gif"){why="unsupported image content-type: "+contentType}else if(this.config.scaleRatio>0){needsResize=true;why="scaleRatio specified"}else if(this.config.maxWidth>0||this.config.maxHeight>0){if(this.config.maxWidth>0&&img.width>this.config.maxWidth)needsResize=true;if(this.config.maxHeight>0&&img.height>this.config.maxHeight)needsResize=true;why=needsResize?"dimensions exceed max allowed":"dimensions do not require resize"}if(!needsResize&&this.config.maxSize>0){if(this.config.maxSize0||this.config.maxHeight>0){mWidth=Math.min(this.config.maxWidth,ratio*this.config.maxHeight);resizeType="max width/height of "+this.config.maxWidth+"x"+this.config.maxHeight}if(this.config.maxSize>0&&this.config.maxSize0?Math.min(mWidth,mSize):mSize;if(mSize===mWidth)resizeType="max megapixels of "+this.config.maxSize}if(this.config.scaleRatio){var mScale=Math.floor(this.config.scaleRatio*canvas.width);mWidth=mWidth>0?Math.min(mWidth,mScale):mScale;if(mScale==mWidth)resizeType="scale ratio of "+this.config.scaleRatio}if(mWidth<=0){this.consoleLog("image size is too small to resize");completionCallback(false);return}if(this.config.debug){this.consoleLog("original image size: "+canvas.width+"x"+canvas.height+" px");this.consoleLog("scaled image size: "+mWidth+"x"+Math.floor(mWidth/ratio)+" px via "+resizeType)}while(canvas.width>=2*mWidth){canvas=this.getHalfScaleCanvas(canvas)}if(canvas.width>mWidth){canvas=this.scaleCanvasWithAlgorithm(canvas,mWidth)}var quality=this.config.quality;if(this.currentFile.type!="image/jpeg")quality=1;var imageData=canvas.toDataURL(this.currentFile.type,quality);if(typeof this.config.onScale==="function"){this.config.onScale(imageData)}if(this.currentFile.type==="image/jpeg"){try{var exifObj=piexif.load(img.src);var orientation=exifObj["0th"][piexif.ImageIFD.Orientation];if(orientation>4&&img.height>img.width){exifObj["0th"][piexif.ImageIFD.Orientation]=1}try{var exifStr=piexif.dump(exifObj);try{imageData=piexif.insert(exifStr,imageData)}catch(error){console.error(error)}}catch(error){console.error(error)}}catch(error){console.error(error)}}completionCallback(this.imageDataToBlob(imageData))};PWImageResizer.prototype.imageDataToBlob=function(imageData){var base64Marker=";base64,";if(imageData.indexOf(base64Marker)==-1){var parts=imageData.split(",");var contentType=parts[0].split(":")[1];var raw=parts[1];return new Blob([raw],{type:contentType})}var parts=imageData.split(base64Marker);var contentType=parts[0].split(":")[1];var raw=window.atob(parts[1]);var rawLength=raw.length;var uInt8Array=new Uint8Array(rawLength);for(var i=0;isrcCanvasData.height-1?srcCanvasData.height-1:Math.ceil(iyv);for(j=0;jsrcCanvasData.width-1?srcCanvasData.width-1:Math.ceil(ixv);idxD=(j+destCanvasData.width*i)*4;idxS00=(ix0+srcCanvasData.width*iy0)*4;idxS10=(ix1+srcCanvasData.width*iy0)*4;idxS01=(ix0+srcCanvasData.width*iy1)*4;idxS11=(ix1+srcCanvasData.width*iy1)*4;dx=ixv-ix0;dy=iyv-iy0;r=inner(srcCanvasData.data[idxS00],srcCanvasData.data[idxS10],srcCanvasData.data[idxS01],srcCanvasData.data[idxS11],dx,dy);destCanvasData.data[idxD]=r;g=inner(srcCanvasData.data[idxS00+1],srcCanvasData.data[idxS10+1],srcCanvasData.data[idxS01+1],srcCanvasData.data[idxS11+1],dx,dy);destCanvasData.data[idxD+1]=g;b=inner(srcCanvasData.data[idxS00+2],srcCanvasData.data[idxS10+2],srcCanvasData.data[idxS01+2],srcCanvasData.data[idxS11+2],dx,dy);destCanvasData.data[idxD+2]=b;a=inner(srcCanvasData.data[idxS00+3],srcCanvasData.data[idxS10+3],srcCanvasData.data[idxS01+3],srcCanvasData.data[idxS11+3],dx,dy);destCanvasData.data[idxD+3]=a}}};PWImageResizer.prototype.setConfig=function(customConfig){this.config=customConfig;this.config.debug=this.config.debug||false;if(typeof customConfig.quality=="undefined")customConfig.quality=1;if(customConfig.quality<.1)customConfig.quality=.1;if(customConfig.quality>1)customConfig.quality=1;this.config.quality=customConfig.quality;if(!this.config.maxWidth||this.config.maxWidth<0){this.config.maxWidth=0}if(!this.config.maxHeight||this.config.maxHeight<0){this.config.maxHeight=0}if(!this.config.maxSize||this.config.maxSize<0){this.config.maxSize=null}if(!this.config.scaleRatio||this.config.scaleRatio<=0||this.config.scaleRatio>=1){this.config.scaleRatio=null}this.config.autoRotate=true;if(typeof customConfig.autoRotate==="boolean")this.config.autoRotate=customConfig.autoRotate;if(this.config.maxWidth&&!this.config.maxHeight){this.config.maxHeight=this.config.maxWidth}else if(this.config.maxHeight&&!this.config.maxWidth){this.config.maxWidth=this.config.maxHeight}else if(!this.config.maxWidth&&!this.config.maxHeight){}};PWImageResizer.prototype.consoleLog=function(msg){if(this.config.debug)console.log("PWImageResizer: "+msg)};
\ No newline at end of file
diff --git a/wire/modules/Inputfield/InputfieldImage/piexif.js b/wire/modules/Inputfield/InputfieldImage/piexif.js
new file mode 100755
index 00000000..3d0bd12d
--- /dev/null
+++ b/wire/modules/Inputfield/InputfieldImage/piexif.js
@@ -0,0 +1,2482 @@
+/* piexifjs
+
+The MIT License (MIT)
+
+Copyright (c) 2014, 2015 hMatoba(https://github.com/hMatoba)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+(function () {
+ "use strict";
+ var that = {};
+ that.version = "1.0.4";
+
+ that.remove = function (jpeg) {
+ var b64 = false;
+ if (jpeg.slice(0, 2) == "\xff\xd8") {
+ } else if (jpeg.slice(0, 23) == "data:image/jpeg;base64," || jpeg.slice(0, 22) == "data:image/jpg;base64,") {
+ jpeg = atob(jpeg.split(",")[1]);
+ b64 = true;
+ } else {
+ throw new Error("Given data is not jpeg.");
+ }
+
+ var segments = splitIntoSegments(jpeg);
+ var newSegments = segments.filter(function(seg){
+ return !(seg.slice(0, 2) == "\xff\xe1" &&
+ seg.slice(4, 10) == "Exif\x00\x00");
+ });
+
+ var new_data = newSegments.join("");
+ if (b64) {
+ new_data = "data:image/jpeg;base64," + btoa(new_data);
+ }
+
+ return new_data;
+ };
+
+
+ that.insert = function (exif, jpeg) {
+ var b64 = false;
+ if (exif.slice(0, 6) != "\x45\x78\x69\x66\x00\x00") {
+ throw new Error("Given data is not exif.");
+ }
+ if (jpeg.slice(0, 2) == "\xff\xd8") {
+ } else if (jpeg.slice(0, 23) == "data:image/jpeg;base64," || jpeg.slice(0, 22) == "data:image/jpg;base64,") {
+ jpeg = atob(jpeg.split(",")[1]);
+ b64 = true;
+ } else {
+ throw new Error("Given data is not jpeg.");
+ }
+
+ var exifStr = "\xff\xe1" + pack(">H", [exif.length + 2]) + exif;
+ var segments = splitIntoSegments(jpeg);
+ var new_data = mergeSegments(segments, exifStr);
+ if (b64) {
+ new_data = "data:image/jpeg;base64," + btoa(new_data);
+ }
+
+ return new_data;
+ };
+
+
+ that.load = function (data) {
+ var input_data;
+ if (typeof (data) == "string") {
+ if (data.slice(0, 2) == "\xff\xd8") {
+ input_data = data;
+ } else if (data.slice(0, 23) == "data:image/jpeg;base64," || data.slice(0, 22) == "data:image/jpg;base64,") {
+ input_data = atob(data.split(",")[1]);
+ } else if (data.slice(0, 4) == "Exif") {
+ input_data = data.slice(6);
+ } else {
+ throw new Error("'load' gots invalid file data.");
+ }
+ } else {
+ throw new Error("'load' gots invalid type argument.");
+ }
+
+ var exifDict = {};
+ var exif_dict = {
+ "0th": {},
+ "Exif": {},
+ "GPS": {},
+ "Interop": {},
+ "1st": {},
+ "thumbnail": null
+ };
+ var exifReader = new ExifReader(input_data);
+ if (exifReader.tiftag === null) {
+ return exif_dict;
+ }
+
+ if (exifReader.tiftag.slice(0, 2) == "\x49\x49") {
+ exifReader.endian_mark = "<";
+ } else {
+ exifReader.endian_mark = ">";
+ }
+
+ var pointer = unpack(exifReader.endian_mark + "L",
+ exifReader.tiftag.slice(4, 8))[0];
+ exif_dict["0th"] = exifReader.get_ifd(pointer, "0th");
+
+ var first_ifd_pointer = exif_dict["0th"]["first_ifd_pointer"];
+ delete exif_dict["0th"]["first_ifd_pointer"];
+
+ if (34665 in exif_dict["0th"]) {
+ pointer = exif_dict["0th"][34665];
+ exif_dict["Exif"] = exifReader.get_ifd(pointer, "Exif");
+ }
+ if (34853 in exif_dict["0th"]) {
+ pointer = exif_dict["0th"][34853];
+ exif_dict["GPS"] = exifReader.get_ifd(pointer, "GPS");
+ }
+ if (40965 in exif_dict["Exif"]) {
+ pointer = exif_dict["Exif"][40965];
+ exif_dict["Interop"] = exifReader.get_ifd(pointer, "Interop");
+ }
+ if (first_ifd_pointer != "\x00\x00\x00\x00") {
+ pointer = unpack(exifReader.endian_mark + "L",
+ first_ifd_pointer)[0];
+ exif_dict["1st"] = exifReader.get_ifd(pointer, "1st");
+ if ((513 in exif_dict["1st"]) && (514 in exif_dict["1st"])) {
+ var end = exif_dict["1st"][513] + exif_dict["1st"][514];
+ var thumb = exifReader.tiftag.slice(exif_dict["1st"][513], end);
+ exif_dict["thumbnail"] = thumb;
+ }
+ }
+
+ return exif_dict;
+ };
+
+
+ that.dump = function (exif_dict_original) {
+ var TIFF_HEADER_LENGTH = 8;
+
+ var exif_dict = copy(exif_dict_original);
+ var header = "Exif\x00\x00\x4d\x4d\x00\x2a\x00\x00\x00\x08";
+ var exif_is = false;
+ var gps_is = false;
+ var interop_is = false;
+ var first_is = false;
+
+ var zeroth_ifd,
+ exif_ifd,
+ interop_ifd,
+ gps_ifd,
+ first_ifd;
+
+ if ("0th" in exif_dict) {
+ zeroth_ifd = exif_dict["0th"];
+ } else {
+ zeroth_ifd = {};
+ }
+
+ if ((("Exif" in exif_dict) && (Object.keys(exif_dict["Exif"]).length)) ||
+ (("Interop" in exif_dict) && (Object.keys(exif_dict["Interop"]).length))) {
+ zeroth_ifd[34665] = 1;
+ exif_is = true;
+ exif_ifd = exif_dict["Exif"];
+ if (("Interop" in exif_dict) && Object.keys(exif_dict["Interop"]).length) {
+ exif_ifd[40965] = 1;
+ interop_is = true;
+ interop_ifd = exif_dict["Interop"];
+ } else if (Object.keys(exif_ifd).indexOf(that.ExifIFD.InteroperabilityTag.toString()) > -1) {
+ delete exif_ifd[40965];
+ }
+ } else if (Object.keys(zeroth_ifd).indexOf(that.ImageIFD.ExifTag.toString()) > -1) {
+ delete zeroth_ifd[34665];
+ }
+
+ if (("GPS" in exif_dict) && (Object.keys(exif_dict["GPS"]).length)) {
+ zeroth_ifd[that.ImageIFD.GPSTag] = 1;
+ gps_is = true;
+ gps_ifd = exif_dict["GPS"];
+ } else if (Object.keys(zeroth_ifd).indexOf(that.ImageIFD.GPSTag.toString()) > -1) {
+ delete zeroth_ifd[that.ImageIFD.GPSTag];
+ }
+
+ if (("1st" in exif_dict) &&
+ ("thumbnail" in exif_dict) &&
+ (exif_dict["thumbnail"] != null)) {
+ first_is = true;
+ exif_dict["1st"][513] = 1;
+ exif_dict["1st"][514] = 1;
+ first_ifd = exif_dict["1st"];
+ }
+
+ var zeroth_set = _dict_to_bytes(zeroth_ifd, "0th", 0);
+ var zeroth_length = (zeroth_set[0].length + exif_is * 12 + gps_is * 12 + 4 +
+ zeroth_set[1].length);
+
+ var exif_set,
+ exif_bytes = "",
+ exif_length = 0,
+ gps_set,
+ gps_bytes = "",
+ gps_length = 0,
+ interop_set,
+ interop_bytes = "",
+ interop_length = 0,
+ first_set,
+ first_bytes = "",
+ thumbnail;
+ if (exif_is) {
+ exif_set = _dict_to_bytes(exif_ifd, "Exif", zeroth_length);
+ exif_length = exif_set[0].length + interop_is * 12 + exif_set[1].length;
+ }
+ if (gps_is) {
+ gps_set = _dict_to_bytes(gps_ifd, "GPS", zeroth_length + exif_length);
+ gps_bytes = gps_set.join("");
+ gps_length = gps_bytes.length;
+ }
+ if (interop_is) {
+ var offset = zeroth_length + exif_length + gps_length;
+ interop_set = _dict_to_bytes(interop_ifd, "Interop", offset);
+ interop_bytes = interop_set.join("");
+ interop_length = interop_bytes.length;
+ }
+ if (first_is) {
+ var offset = zeroth_length + exif_length + gps_length + interop_length;
+ first_set = _dict_to_bytes(first_ifd, "1st", offset);
+ thumbnail = _get_thumbnail(exif_dict["thumbnail"]);
+ if (thumbnail.length > 64000) {
+ throw new Error("Given thumbnail is too large. max 64kB");
+ }
+ }
+
+ var exif_pointer = "",
+ gps_pointer = "",
+ interop_pointer = "",
+ first_ifd_pointer = "\x00\x00\x00\x00";
+ if (exif_is) {
+ var pointer_value = TIFF_HEADER_LENGTH + zeroth_length;
+ var pointer_str = pack(">L", [pointer_value]);
+ var key = 34665;
+ var key_str = pack(">H", [key]);
+ var type_str = pack(">H", [TYPES["Long"]]);
+ var length_str = pack(">L", [1]);
+ exif_pointer = key_str + type_str + length_str + pointer_str;
+ }
+ if (gps_is) {
+ var pointer_value = TIFF_HEADER_LENGTH + zeroth_length + exif_length;
+ var pointer_str = pack(">L", [pointer_value]);
+ var key = 34853;
+ var key_str = pack(">H", [key]);
+ var type_str = pack(">H", [TYPES["Long"]]);
+ var length_str = pack(">L", [1]);
+ gps_pointer = key_str + type_str + length_str + pointer_str;
+ }
+ if (interop_is) {
+ var pointer_value = (TIFF_HEADER_LENGTH +
+ zeroth_length + exif_length + gps_length);
+ var pointer_str = pack(">L", [pointer_value]);
+ var key = 40965;
+ var key_str = pack(">H", [key]);
+ var type_str = pack(">H", [TYPES["Long"]]);
+ var length_str = pack(">L", [1]);
+ interop_pointer = key_str + type_str + length_str + pointer_str;
+ }
+ if (first_is) {
+ var pointer_value = (TIFF_HEADER_LENGTH + zeroth_length +
+ exif_length + gps_length + interop_length);
+ first_ifd_pointer = pack(">L", [pointer_value]);
+ var thumbnail_pointer = (pointer_value + first_set[0].length + 24 +
+ 4 + first_set[1].length);
+ var thumbnail_p_bytes = ("\x02\x01\x00\x04\x00\x00\x00\x01" +
+ pack(">L", [thumbnail_pointer]));
+ var thumbnail_length_bytes = ("\x02\x02\x00\x04\x00\x00\x00\x01" +
+ pack(">L", [thumbnail.length]));
+ first_bytes = (first_set[0] + thumbnail_p_bytes +
+ thumbnail_length_bytes + "\x00\x00\x00\x00" +
+ first_set[1] + thumbnail);
+ }
+
+ var zeroth_bytes = (zeroth_set[0] + exif_pointer + gps_pointer +
+ first_ifd_pointer + zeroth_set[1]);
+ if (exif_is) {
+ exif_bytes = exif_set[0] + interop_pointer + exif_set[1];
+ }
+
+ return (header + zeroth_bytes + exif_bytes + gps_bytes +
+ interop_bytes + first_bytes);
+ };
+
+
+ function copy(obj) {
+ return JSON.parse(JSON.stringify(obj));
+ }
+
+
+ function _get_thumbnail(jpeg) {
+ var segments = splitIntoSegments(jpeg);
+ while (("\xff\xe0" <= segments[1].slice(0, 2)) && (segments[1].slice(0, 2) <= "\xff\xef")) {
+ segments = [segments[0]].concat(segments.slice(2));
+ }
+ return segments.join("");
+ }
+
+
+ function _pack_byte(array) {
+ return pack(">" + nStr("B", array.length), array);
+ }
+
+
+ function _pack_short(array) {
+ return pack(">" + nStr("H", array.length), array);
+ }
+
+
+ function _pack_long(array) {
+ return pack(">" + nStr("L", array.length), array);
+ }
+
+
+ function _value_to_bytes(raw_value, value_type, offset) {
+ var four_bytes_over = "";
+ var value_str = "";
+ var length,
+ new_value,
+ num,
+ den;
+
+ if (value_type == "Byte") {
+ length = raw_value.length;
+ if (length <= 4) {
+ value_str = (_pack_byte(raw_value) +
+ nStr("\x00", 4 - length));
+ } else {
+ value_str = pack(">L", [offset]);
+ four_bytes_over = _pack_byte(raw_value);
+ }
+ } else if (value_type == "Short") {
+ length = raw_value.length;
+ if (length <= 2) {
+ value_str = (_pack_short(raw_value) +
+ nStr("\x00\x00", 2 - length));
+ } else {
+ value_str = pack(">L", [offset]);
+ four_bytes_over = _pack_short(raw_value);
+ }
+ } else if (value_type == "Long") {
+ length = raw_value.length;
+ if (length <= 1) {
+ value_str = _pack_long(raw_value);
+ } else {
+ value_str = pack(">L", [offset]);
+ four_bytes_over = _pack_long(raw_value);
+ }
+ } else if (value_type == "Ascii") {
+ new_value = raw_value + "\x00";
+ length = new_value.length;
+ if (length > 4) {
+ value_str = pack(">L", [offset]);
+ four_bytes_over = new_value;
+ } else {
+ value_str = new_value + nStr("\x00", 4 - length);
+ }
+ } else if (value_type == "Rational") {
+ if (typeof (raw_value[0]) == "number") {
+ length = 1;
+ num = raw_value[0];
+ den = raw_value[1];
+ new_value = pack(">L", [num]) + pack(">L", [den]);
+ } else {
+ length = raw_value.length;
+ new_value = "";
+ for (var n = 0; n < length; n++) {
+ num = raw_value[n][0];
+ den = raw_value[n][1];
+ new_value += (pack(">L", [num]) +
+ pack(">L", [den]));
+ }
+ }
+ value_str = pack(">L", [offset]);
+ four_bytes_over = new_value;
+ } else if (value_type == "SRational") {
+ if (typeof (raw_value[0]) == "number") {
+ length = 1;
+ num = raw_value[0];
+ den = raw_value[1];
+ new_value = pack(">l", [num]) + pack(">l", [den]);
+ } else {
+ length = raw_value.length;
+ new_value = "";
+ for (var n = 0; n < length; n++) {
+ num = raw_value[n][0];
+ den = raw_value[n][1];
+ new_value += (pack(">l", [num]) +
+ pack(">l", [den]));
+ }
+ }
+ value_str = pack(">L", [offset]);
+ four_bytes_over = new_value;
+ } else if (value_type == "Undefined") {
+ length = raw_value.length;
+ if (length > 4) {
+ value_str = pack(">L", [offset]);
+ four_bytes_over = raw_value;
+ } else {
+ value_str = raw_value + nStr("\x00", 4 - length);
+ }
+ }
+
+ var length_str = pack(">L", [length]);
+
+ return [length_str, value_str, four_bytes_over];
+ }
+
+ function _dict_to_bytes(ifd_dict, ifd, ifd_offset) {
+ var TIFF_HEADER_LENGTH = 8;
+ var tag_count = Object.keys(ifd_dict).length;
+ var entry_header = pack(">H", [tag_count]);
+ var entries_length;
+ if (["0th", "1st"].indexOf(ifd) > -1) {
+ entries_length = 2 + tag_count * 12 + 4;
+ } else {
+ entries_length = 2 + tag_count * 12;
+ }
+ var entries = "";
+ var values = "";
+ var key;
+
+ for (var key in ifd_dict) {
+ if (typeof (key) == "string") {
+ key = parseInt(key);
+ }
+ if ((ifd == "0th") && ([34665, 34853].indexOf(key) > -1)) {
+ continue;
+ } else if ((ifd == "Exif") && (key == 40965)) {
+ continue;
+ } else if ((ifd == "1st") && ([513, 514].indexOf(key) > -1)) {
+ continue;
+ }
+
+ var raw_value = ifd_dict[key];
+ var key_str = pack(">H", [key]);
+ var value_type = TAGS[ifd][key]["type"];
+ var type_str = pack(">H", [TYPES[value_type]]);
+
+ if (typeof (raw_value) == "number") {
+ raw_value = [raw_value];
+ }
+ var offset = TIFF_HEADER_LENGTH + entries_length + ifd_offset + values.length;
+ var b = _value_to_bytes(raw_value, value_type, offset);
+ var length_str = b[0];
+ var value_str = b[1];
+ var four_bytes_over = b[2];
+
+ entries += key_str + type_str + length_str + value_str;
+ values += four_bytes_over;
+ }
+
+ return [entry_header + entries, values];
+ }
+
+
+
+ function ExifReader(data) {
+ var segments,
+ app1;
+ if (data.slice(0, 2) == "\xff\xd8") { // JPEG
+ segments = splitIntoSegments(data);
+ app1 = getExifSeg(segments);
+ if (app1) {
+ this.tiftag = app1.slice(10);
+ } else {
+ this.tiftag = null;
+ }
+ } else if (["\x49\x49", "\x4d\x4d"].indexOf(data.slice(0, 2)) > -1) { // TIFF
+ this.tiftag = data;
+ } else if (data.slice(0, 4) == "Exif") { // Exif
+ this.tiftag = data.slice(6);
+ } else {
+ throw new Error("Given file is neither JPEG nor TIFF.");
+ }
+ }
+
+ ExifReader.prototype = {
+ get_ifd: function (pointer, ifd_name) {
+ var ifd_dict = {};
+ var tag_count = unpack(this.endian_mark + "H",
+ this.tiftag.slice(pointer, pointer + 2))[0];
+ var offset = pointer + 2;
+ var t;
+ if (["0th", "1st"].indexOf(ifd_name) > -1) {
+ t = "Image";
+ } else {
+ t = ifd_name;
+ }
+
+ for (var x = 0; x < tag_count; x++) {
+ pointer = offset + 12 * x;
+ var tag = unpack(this.endian_mark + "H",
+ this.tiftag.slice(pointer, pointer + 2))[0];
+ var value_type = unpack(this.endian_mark + "H",
+ this.tiftag.slice(pointer + 2, pointer + 4))[0];
+ var value_num = unpack(this.endian_mark + "L",
+ this.tiftag.slice(pointer + 4, pointer + 8))[0];
+ var value = this.tiftag.slice(pointer + 8, pointer + 12);
+
+ var v_set = [value_type, value_num, value];
+ if (tag in TAGS[t]) {
+ ifd_dict[tag] = this.convert_value(v_set);
+ }
+ }
+
+ if (ifd_name == "0th") {
+ pointer = offset + 12 * tag_count;
+ ifd_dict["first_ifd_pointer"] = this.tiftag.slice(pointer, pointer + 4);
+ }
+
+ return ifd_dict;
+ },
+
+ convert_value: function (val) {
+ var data = null;
+ var t = val[0];
+ var length = val[1];
+ var value = val[2];
+ var pointer;
+
+ if (t == 1) { // BYTE
+ if (length > 4) {
+ pointer = unpack(this.endian_mark + "L", value)[0];
+ data = unpack(this.endian_mark + nStr("B", length),
+ this.tiftag.slice(pointer, pointer + length));
+ } else {
+ data = unpack(this.endian_mark + nStr("B", length), value.slice(0, length));
+ }
+ } else if (t == 2) { // ASCII
+ if (length > 4) {
+ pointer = unpack(this.endian_mark + "L", value)[0];
+ data = this.tiftag.slice(pointer, pointer + length - 1);
+ } else {
+ data = value.slice(0, length - 1);
+ }
+ } else if (t == 3) { // SHORT
+ if (length > 2) {
+ pointer = unpack(this.endian_mark + "L", value)[0];
+ data = unpack(this.endian_mark + nStr("H", length),
+ this.tiftag.slice(pointer, pointer + length * 2));
+ } else {
+ data = unpack(this.endian_mark + nStr("H", length),
+ value.slice(0, length * 2));
+ }
+ } else if (t == 4) { // LONG
+ if (length > 1) {
+ pointer = unpack(this.endian_mark + "L", value)[0];
+ data = unpack(this.endian_mark + nStr("L", length),
+ this.tiftag.slice(pointer, pointer + length * 4));
+ } else {
+ data = unpack(this.endian_mark + nStr("L", length),
+ value);
+ }
+ } else if (t == 5) { // RATIONAL
+ pointer = unpack(this.endian_mark + "L", value)[0];
+ if (length > 1) {
+ data = [];
+ for (var x = 0; x < length; x++) {
+ data.push([unpack(this.endian_mark + "L",
+ this.tiftag.slice(pointer + x * 8, pointer + 4 + x * 8))[0],
+ unpack(this.endian_mark + "L",
+ this.tiftag.slice(pointer + 4 + x * 8, pointer + 8 + x * 8))[0]
+ ]);
+ }
+ } else {
+ data = [unpack(this.endian_mark + "L",
+ this.tiftag.slice(pointer, pointer + 4))[0],
+ unpack(this.endian_mark + "L",
+ this.tiftag.slice(pointer + 4, pointer + 8))[0]
+ ];
+ }
+ } else if (t == 7) { // UNDEFINED BYTES
+ if (length > 4) {
+ pointer = unpack(this.endian_mark + "L", value)[0];
+ data = this.tiftag.slice(pointer, pointer + length);
+ } else {
+ data = value.slice(0, length);
+ }
+ } else if (t == 9) { // SLONG
+ if (length > 1) {
+ pointer = unpack(this.endian_mark + "L", value)[0];
+ data = unpack(this.endian_mark + nStr("l", length),
+ this.tiftag.slice(pointer, pointer + length * 4));
+ } else {
+ data = unpack(this.endian_mark + nStr("l", length),
+ value);
+ }
+ } else if (t == 10) { // SRATIONAL
+ pointer = unpack(this.endian_mark + "L", value)[0];
+ if (length > 1) {
+ data = [];
+ for (var x = 0; x < length; x++) {
+ data.push([unpack(this.endian_mark + "l",
+ this.tiftag.slice(pointer + x * 8, pointer + 4 + x * 8))[0],
+ unpack(this.endian_mark + "l",
+ this.tiftag.slice(pointer + 4 + x * 8, pointer + 8 + x * 8))[0]
+ ]);
+ }
+ } else {
+ data = [unpack(this.endian_mark + "l",
+ this.tiftag.slice(pointer, pointer + 4))[0],
+ unpack(this.endian_mark + "l",
+ this.tiftag.slice(pointer + 4, pointer + 8))[0]
+ ];
+ }
+ } else {
+ throw new Error("Exif might be wrong. Got incorrect value " +
+ "type to decode. type:" + t);
+ }
+
+ if ((data instanceof Array) && (data.length == 1)) {
+ return data[0];
+ } else {
+ return data;
+ }
+ },
+ };
+
+
+ if (typeof window !== "undefined" && typeof window.btoa === "function") {
+ var btoa = window.btoa;
+ }
+ if (typeof btoa === "undefined") {
+ var btoa = function (input) { var output = "";
+ var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
+ var i = 0;
+ var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+
+ while (i < input.length) {
+
+ chr1 = input.charCodeAt(i++);
+ chr2 = input.charCodeAt(i++);
+ chr3 = input.charCodeAt(i++);
+
+ enc1 = chr1 >> 2;
+ enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+ enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+ enc4 = chr3 & 63;
+
+ if (isNaN(chr2)) {
+ enc3 = enc4 = 64;
+ } else if (isNaN(chr3)) {
+ enc4 = 64;
+ }
+
+ output = output +
+ keyStr.charAt(enc1) + keyStr.charAt(enc2) +
+ keyStr.charAt(enc3) + keyStr.charAt(enc4);
+
+ }
+
+ return output;
+ };
+ }
+
+
+ if (typeof window !== "undefined" && typeof window.atob === "function") {
+ var atob = window.atob;
+ }
+ if (typeof atob === "undefined") {
+ var atob = function (input) {
+ var output = "";
+ var chr1, chr2, chr3;
+ var enc1, enc2, enc3, enc4;
+ var i = 0;
+ var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+
+ input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+
+ while (i < input.length) {
+
+ enc1 = keyStr.indexOf(input.charAt(i++));
+ enc2 = keyStr.indexOf(input.charAt(i++));
+ enc3 = keyStr.indexOf(input.charAt(i++));
+ enc4 = keyStr.indexOf(input.charAt(i++));
+
+ chr1 = (enc1 << 2) | (enc2 >> 4);
+ chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+ chr3 = ((enc3 & 3) << 6) | enc4;
+
+ output = output + String.fromCharCode(chr1);
+
+ if (enc3 != 64) {
+ output = output + String.fromCharCode(chr2);
+ }
+ if (enc4 != 64) {
+ output = output + String.fromCharCode(chr3);
+ }
+
+ }
+
+ return output;
+ };
+ }
+
+
+ function getImageSize(imageArray) {
+ var segments = slice2Segments(imageArray);
+ var seg,
+ width,
+ height,
+ SOF = [192, 193, 194, 195, 197, 198, 199, 201, 202, 203, 205, 206, 207];
+
+ for (var x = 0; x < segments.length; x++) {
+ seg = segments[x];
+ if (SOF.indexOf(seg[1]) >= 0) {
+ height = seg[5] * 256 + seg[6];
+ width = seg[7] * 256 + seg[8];
+ break;
+ }
+ }
+ return [width, height];
+ }
+
+
+ function pack(mark, array) {
+ if (!(array instanceof Array)) {
+ throw new Error("'pack' error. Got invalid type argument.");
+ }
+ if ((mark.length - 1) != array.length) {
+ throw new Error("'pack' error. " + (mark.length - 1) + " marks, " + array.length + " elements.");
+ }
+
+ var littleEndian;
+ if (mark[0] == "<") {
+ littleEndian = true;
+ } else if (mark[0] == ">") {
+ littleEndian = false;
+ } else {
+ throw new Error("");
+ }
+ var packed = "";
+ var p = 1;
+ var val = null;
+ var c = null;
+ var valStr = null;
+
+ while (c = mark[p]) {
+ if (c.toLowerCase() == "b") {
+ val = array[p - 1];
+ if ((c == "b") && (val < 0)) {
+ val += 0x100;
+ }
+ if ((val > 0xff) || (val < 0)) {
+ throw new Error("'pack' error.");
+ } else {
+ valStr = String.fromCharCode(val);
+ }
+ } else if (c == "H") {
+ val = array[p - 1];
+ if ((val > 0xffff) || (val < 0)) {
+ throw new Error("'pack' error.");
+ } else {
+ valStr = String.fromCharCode(Math.floor((val % 0x10000) / 0x100)) +
+ String.fromCharCode(val % 0x100);
+ if (littleEndian) {
+ valStr = valStr.split("").reverse().join("");
+ }
+ }
+ } else if (c.toLowerCase() == "l") {
+ val = array[p - 1];
+ if ((c == "l") && (val < 0)) {
+ val += 0x100000000;
+ }
+ if ((val > 0xffffffff) || (val < 0)) {
+ throw new Error("'pack' error.");
+ } else {
+ valStr = String.fromCharCode(Math.floor(val / 0x1000000)) +
+ String.fromCharCode(Math.floor((val % 0x1000000) / 0x10000)) +
+ String.fromCharCode(Math.floor((val % 0x10000) / 0x100)) +
+ String.fromCharCode(val % 0x100);
+ if (littleEndian) {
+ valStr = valStr.split("").reverse().join("");
+ }
+ }
+ } else {
+ throw new Error("'pack' error.");
+ }
+
+ packed += valStr;
+ p += 1;
+ }
+
+ return packed;
+ }
+
+ function unpack(mark, str) {
+ if (typeof (str) != "string") {
+ throw new Error("'unpack' error. Got invalid type argument.");
+ }
+ var l = 0;
+ for (var markPointer = 1; markPointer < mark.length; markPointer++) {
+ if (mark[markPointer].toLowerCase() == "b") {
+ l += 1;
+ } else if (mark[markPointer].toLowerCase() == "h") {
+ l += 2;
+ } else if (mark[markPointer].toLowerCase() == "l") {
+ l += 4;
+ } else {
+ throw new Error("'unpack' error. Got invalid mark.");
+ }
+ }
+
+ if (l != str.length) {
+ throw new Error("'unpack' error. Mismatch between symbol and string length. " + l + ":" + str.length);
+ }
+
+ var littleEndian;
+ if (mark[0] == "<") {
+ littleEndian = true;
+ } else if (mark[0] == ">") {
+ littleEndian = false;
+ } else {
+ throw new Error("'unpack' error.");
+ }
+ var unpacked = [];
+ var strPointer = 0;
+ var p = 1;
+ var val = null;
+ var c = null;
+ var length = null;
+ var sliced = "";
+
+ while (c = mark[p]) {
+ if (c.toLowerCase() == "b") {
+ length = 1;
+ sliced = str.slice(strPointer, strPointer + length);
+ val = sliced.charCodeAt(0);
+ if ((c == "b") && (val >= 0x80)) {
+ val -= 0x100;
+ }
+ } else if (c == "H") {
+ length = 2;
+ sliced = str.slice(strPointer, strPointer + length);
+ if (littleEndian) {
+ sliced = sliced.split("").reverse().join("");
+ }
+ val = sliced.charCodeAt(0) * 0x100 +
+ sliced.charCodeAt(1);
+ } else if (c.toLowerCase() == "l") {
+ length = 4;
+ sliced = str.slice(strPointer, strPointer + length);
+ if (littleEndian) {
+ sliced = sliced.split("").reverse().join("");
+ }
+ val = sliced.charCodeAt(0) * 0x1000000 +
+ sliced.charCodeAt(1) * 0x10000 +
+ sliced.charCodeAt(2) * 0x100 +
+ sliced.charCodeAt(3);
+ if ((c == "l") && (val >= 0x80000000)) {
+ val -= 0x100000000;
+ }
+ } else {
+ throw new Error("'unpack' error. " + c);
+ }
+
+ unpacked.push(val);
+ strPointer += length;
+ p += 1;
+ }
+
+ return unpacked;
+ }
+
+ function nStr(ch, num) {
+ var str = "";
+ for (var i = 0; i < num; i++) {
+ str += ch;
+ }
+ return str;
+ }
+
+ function splitIntoSegments(data) {
+ if (data.slice(0, 2) != "\xff\xd8") {
+ throw new Error("Given data isn't JPEG.");
+ }
+
+ var head = 2;
+ var segments = ["\xff\xd8"];
+ while (true) {
+ if (data.slice(head, head + 2) == "\xff\xda") {
+ segments.push(data.slice(head));
+ break;
+ } else {
+ var length = unpack(">H", data.slice(head + 2, head + 4))[0];
+ var endPoint = head + length + 2;
+ segments.push(data.slice(head, endPoint));
+ head = endPoint;
+ }
+
+ if (head >= data.length) {
+ throw new Error("Wrong JPEG data.");
+ }
+ }
+ return segments;
+ }
+
+
+ function getExifSeg(segments) {
+ var seg;
+ for (var i = 0; i < segments.length; i++) {
+ seg = segments[i];
+ if (seg.slice(0, 2) == "\xff\xe1" &&
+ seg.slice(4, 10) == "Exif\x00\x00") {
+ return seg;
+ }
+ }
+ return null;
+ }
+
+
+ function mergeSegments(segments, exif) {
+ var hasExifSegment = false;
+ var additionalAPP1ExifSegments = [];
+
+ segments.forEach(function(segment, i) {
+ // Replace first occurence of APP1:Exif segment
+ if (segment.slice(0, 2) == "\xff\xe1" &&
+ segment.slice(4, 10) == "Exif\x00\x00"
+ ) {
+ if (!hasExifSegment) {
+ segments[i] = exif;
+ hasExifSegment = true;
+ } else {
+ additionalAPP1ExifSegments.unshift(i);
+ }
+ }
+ });
+
+ // Remove additional occurences of APP1:Exif segment
+ additionalAPP1ExifSegments.forEach(function(segmentIndex) {
+ segments.splice(segmentIndex, 1);
+ });
+
+ if (!hasExifSegment && exif) {
+ segments = [segments[0], exif].concat(segments.slice(1));
+ }
+
+ return segments.join("");
+ }
+
+
+ function toHex(str) {
+ var hexStr = "";
+ for (var i = 0; i < str.length; i++) {
+ var h = str.charCodeAt(i);
+ var hex = ((h < 10) ? "0" : "") + h.toString(16);
+ hexStr += hex + " ";
+ }
+ return hexStr;
+ }
+
+
+ var TYPES = {
+ "Byte": 1,
+ "Ascii": 2,
+ "Short": 3,
+ "Long": 4,
+ "Rational": 5,
+ "Undefined": 7,
+ "SLong": 9,
+ "SRational": 10
+ };
+
+
+ var TAGS = {
+ 'Image': {
+ 11: {
+ 'name': 'ProcessingSoftware',
+ 'type': 'Ascii'
+ },
+ 254: {
+ 'name': 'NewSubfileType',
+ 'type': 'Long'
+ },
+ 255: {
+ 'name': 'SubfileType',
+ 'type': 'Short'
+ },
+ 256: {
+ 'name': 'ImageWidth',
+ 'type': 'Long'
+ },
+ 257: {
+ 'name': 'ImageLength',
+ 'type': 'Long'
+ },
+ 258: {
+ 'name': 'BitsPerSample',
+ 'type': 'Short'
+ },
+ 259: {
+ 'name': 'Compression',
+ 'type': 'Short'
+ },
+ 262: {
+ 'name': 'PhotometricInterpretation',
+ 'type': 'Short'
+ },
+ 263: {
+ 'name': 'Threshholding',
+ 'type': 'Short'
+ },
+ 264: {
+ 'name': 'CellWidth',
+ 'type': 'Short'
+ },
+ 265: {
+ 'name': 'CellLength',
+ 'type': 'Short'
+ },
+ 266: {
+ 'name': 'FillOrder',
+ 'type': 'Short'
+ },
+ 269: {
+ 'name': 'DocumentName',
+ 'type': 'Ascii'
+ },
+ 270: {
+ 'name': 'ImageDescription',
+ 'type': 'Ascii'
+ },
+ 271: {
+ 'name': 'Make',
+ 'type': 'Ascii'
+ },
+ 272: {
+ 'name': 'Model',
+ 'type': 'Ascii'
+ },
+ 273: {
+ 'name': 'StripOffsets',
+ 'type': 'Long'
+ },
+ 274: {
+ 'name': 'Orientation',
+ 'type': 'Short'
+ },
+ 277: {
+ 'name': 'SamplesPerPixel',
+ 'type': 'Short'
+ },
+ 278: {
+ 'name': 'RowsPerStrip',
+ 'type': 'Long'
+ },
+ 279: {
+ 'name': 'StripByteCounts',
+ 'type': 'Long'
+ },
+ 282: {
+ 'name': 'XResolution',
+ 'type': 'Rational'
+ },
+ 283: {
+ 'name': 'YResolution',
+ 'type': 'Rational'
+ },
+ 284: {
+ 'name': 'PlanarConfiguration',
+ 'type': 'Short'
+ },
+ 290: {
+ 'name': 'GrayResponseUnit',
+ 'type': 'Short'
+ },
+ 291: {
+ 'name': 'GrayResponseCurve',
+ 'type': 'Short'
+ },
+ 292: {
+ 'name': 'T4Options',
+ 'type': 'Long'
+ },
+ 293: {
+ 'name': 'T6Options',
+ 'type': 'Long'
+ },
+ 296: {
+ 'name': 'ResolutionUnit',
+ 'type': 'Short'
+ },
+ 301: {
+ 'name': 'TransferFunction',
+ 'type': 'Short'
+ },
+ 305: {
+ 'name': 'Software',
+ 'type': 'Ascii'
+ },
+ 306: {
+ 'name': 'DateTime',
+ 'type': 'Ascii'
+ },
+ 315: {
+ 'name': 'Artist',
+ 'type': 'Ascii'
+ },
+ 316: {
+ 'name': 'HostComputer',
+ 'type': 'Ascii'
+ },
+ 317: {
+ 'name': 'Predictor',
+ 'type': 'Short'
+ },
+ 318: {
+ 'name': 'WhitePoint',
+ 'type': 'Rational'
+ },
+ 319: {
+ 'name': 'PrimaryChromaticities',
+ 'type': 'Rational'
+ },
+ 320: {
+ 'name': 'ColorMap',
+ 'type': 'Short'
+ },
+ 321: {
+ 'name': 'HalftoneHints',
+ 'type': 'Short'
+ },
+ 322: {
+ 'name': 'TileWidth',
+ 'type': 'Short'
+ },
+ 323: {
+ 'name': 'TileLength',
+ 'type': 'Short'
+ },
+ 324: {
+ 'name': 'TileOffsets',
+ 'type': 'Short'
+ },
+ 325: {
+ 'name': 'TileByteCounts',
+ 'type': 'Short'
+ },
+ 330: {
+ 'name': 'SubIFDs',
+ 'type': 'Long'
+ },
+ 332: {
+ 'name': 'InkSet',
+ 'type': 'Short'
+ },
+ 333: {
+ 'name': 'InkNames',
+ 'type': 'Ascii'
+ },
+ 334: {
+ 'name': 'NumberOfInks',
+ 'type': 'Short'
+ },
+ 336: {
+ 'name': 'DotRange',
+ 'type': 'Byte'
+ },
+ 337: {
+ 'name': 'TargetPrinter',
+ 'type': 'Ascii'
+ },
+ 338: {
+ 'name': 'ExtraSamples',
+ 'type': 'Short'
+ },
+ 339: {
+ 'name': 'SampleFormat',
+ 'type': 'Short'
+ },
+ 340: {
+ 'name': 'SMinSampleValue',
+ 'type': 'Short'
+ },
+ 341: {
+ 'name': 'SMaxSampleValue',
+ 'type': 'Short'
+ },
+ 342: {
+ 'name': 'TransferRange',
+ 'type': 'Short'
+ },
+ 343: {
+ 'name': 'ClipPath',
+ 'type': 'Byte'
+ },
+ 344: {
+ 'name': 'XClipPathUnits',
+ 'type': 'Long'
+ },
+ 345: {
+ 'name': 'YClipPathUnits',
+ 'type': 'Long'
+ },
+ 346: {
+ 'name': 'Indexed',
+ 'type': 'Short'
+ },
+ 347: {
+ 'name': 'JPEGTables',
+ 'type': 'Undefined'
+ },
+ 351: {
+ 'name': 'OPIProxy',
+ 'type': 'Short'
+ },
+ 512: {
+ 'name': 'JPEGProc',
+ 'type': 'Long'
+ },
+ 513: {
+ 'name': 'JPEGInterchangeFormat',
+ 'type': 'Long'
+ },
+ 514: {
+ 'name': 'JPEGInterchangeFormatLength',
+ 'type': 'Long'
+ },
+ 515: {
+ 'name': 'JPEGRestartInterval',
+ 'type': 'Short'
+ },
+ 517: {
+ 'name': 'JPEGLosslessPredictors',
+ 'type': 'Short'
+ },
+ 518: {
+ 'name': 'JPEGPointTransforms',
+ 'type': 'Short'
+ },
+ 519: {
+ 'name': 'JPEGQTables',
+ 'type': 'Long'
+ },
+ 520: {
+ 'name': 'JPEGDCTables',
+ 'type': 'Long'
+ },
+ 521: {
+ 'name': 'JPEGACTables',
+ 'type': 'Long'
+ },
+ 529: {
+ 'name': 'YCbCrCoefficients',
+ 'type': 'Rational'
+ },
+ 530: {
+ 'name': 'YCbCrSubSampling',
+ 'type': 'Short'
+ },
+ 531: {
+ 'name': 'YCbCrPositioning',
+ 'type': 'Short'
+ },
+ 532: {
+ 'name': 'ReferenceBlackWhite',
+ 'type': 'Rational'
+ },
+ 700: {
+ 'name': 'XMLPacket',
+ 'type': 'Byte'
+ },
+ 18246: {
+ 'name': 'Rating',
+ 'type': 'Short'
+ },
+ 18249: {
+ 'name': 'RatingPercent',
+ 'type': 'Short'
+ },
+ 32781: {
+ 'name': 'ImageID',
+ 'type': 'Ascii'
+ },
+ 33421: {
+ 'name': 'CFARepeatPatternDim',
+ 'type': 'Short'
+ },
+ 33422: {
+ 'name': 'CFAPattern',
+ 'type': 'Byte'
+ },
+ 33423: {
+ 'name': 'BatteryLevel',
+ 'type': 'Rational'
+ },
+ 33432: {
+ 'name': 'Copyright',
+ 'type': 'Ascii'
+ },
+ 33434: {
+ 'name': 'ExposureTime',
+ 'type': 'Rational'
+ },
+ 34377: {
+ 'name': 'ImageResources',
+ 'type': 'Byte'
+ },
+ 34665: {
+ 'name': 'ExifTag',
+ 'type': 'Long'
+ },
+ 34675: {
+ 'name': 'InterColorProfile',
+ 'type': 'Undefined'
+ },
+ 34853: {
+ 'name': 'GPSTag',
+ 'type': 'Long'
+ },
+ 34857: {
+ 'name': 'Interlace',
+ 'type': 'Short'
+ },
+ 34858: {
+ 'name': 'TimeZoneOffset',
+ 'type': 'Long'
+ },
+ 34859: {
+ 'name': 'SelfTimerMode',
+ 'type': 'Short'
+ },
+ 37387: {
+ 'name': 'FlashEnergy',
+ 'type': 'Rational'
+ },
+ 37388: {
+ 'name': 'SpatialFrequencyResponse',
+ 'type': 'Undefined'
+ },
+ 37389: {
+ 'name': 'Noise',
+ 'type': 'Undefined'
+ },
+ 37390: {
+ 'name': 'FocalPlaneXResolution',
+ 'type': 'Rational'
+ },
+ 37391: {
+ 'name': 'FocalPlaneYResolution',
+ 'type': 'Rational'
+ },
+ 37392: {
+ 'name': 'FocalPlaneResolutionUnit',
+ 'type': 'Short'
+ },
+ 37393: {
+ 'name': 'ImageNumber',
+ 'type': 'Long'
+ },
+ 37394: {
+ 'name': 'SecurityClassification',
+ 'type': 'Ascii'
+ },
+ 37395: {
+ 'name': 'ImageHistory',
+ 'type': 'Ascii'
+ },
+ 37397: {
+ 'name': 'ExposureIndex',
+ 'type': 'Rational'
+ },
+ 37398: {
+ 'name': 'TIFFEPStandardID',
+ 'type': 'Byte'
+ },
+ 37399: {
+ 'name': 'SensingMethod',
+ 'type': 'Short'
+ },
+ 40091: {
+ 'name': 'XPTitle',
+ 'type': 'Byte'
+ },
+ 40092: {
+ 'name': 'XPComment',
+ 'type': 'Byte'
+ },
+ 40093: {
+ 'name': 'XPAuthor',
+ 'type': 'Byte'
+ },
+ 40094: {
+ 'name': 'XPKeywords',
+ 'type': 'Byte'
+ },
+ 40095: {
+ 'name': 'XPSubject',
+ 'type': 'Byte'
+ },
+ 50341: {
+ 'name': 'PrintImageMatching',
+ 'type': 'Undefined'
+ },
+ 50706: {
+ 'name': 'DNGVersion',
+ 'type': 'Byte'
+ },
+ 50707: {
+ 'name': 'DNGBackwardVersion',
+ 'type': 'Byte'
+ },
+ 50708: {
+ 'name': 'UniqueCameraModel',
+ 'type': 'Ascii'
+ },
+ 50709: {
+ 'name': 'LocalizedCameraModel',
+ 'type': 'Byte'
+ },
+ 50710: {
+ 'name': 'CFAPlaneColor',
+ 'type': 'Byte'
+ },
+ 50711: {
+ 'name': 'CFALayout',
+ 'type': 'Short'
+ },
+ 50712: {
+ 'name': 'LinearizationTable',
+ 'type': 'Short'
+ },
+ 50713: {
+ 'name': 'BlackLevelRepeatDim',
+ 'type': 'Short'
+ },
+ 50714: {
+ 'name': 'BlackLevel',
+ 'type': 'Rational'
+ },
+ 50715: {
+ 'name': 'BlackLevelDeltaH',
+ 'type': 'SRational'
+ },
+ 50716: {
+ 'name': 'BlackLevelDeltaV',
+ 'type': 'SRational'
+ },
+ 50717: {
+ 'name': 'WhiteLevel',
+ 'type': 'Short'
+ },
+ 50718: {
+ 'name': 'DefaultScale',
+ 'type': 'Rational'
+ },
+ 50719: {
+ 'name': 'DefaultCropOrigin',
+ 'type': 'Short'
+ },
+ 50720: {
+ 'name': 'DefaultCropSize',
+ 'type': 'Short'
+ },
+ 50721: {
+ 'name': 'ColorMatrix1',
+ 'type': 'SRational'
+ },
+ 50722: {
+ 'name': 'ColorMatrix2',
+ 'type': 'SRational'
+ },
+ 50723: {
+ 'name': 'CameraCalibration1',
+ 'type': 'SRational'
+ },
+ 50724: {
+ 'name': 'CameraCalibration2',
+ 'type': 'SRational'
+ },
+ 50725: {
+ 'name': 'ReductionMatrix1',
+ 'type': 'SRational'
+ },
+ 50726: {
+ 'name': 'ReductionMatrix2',
+ 'type': 'SRational'
+ },
+ 50727: {
+ 'name': 'AnalogBalance',
+ 'type': 'Rational'
+ },
+ 50728: {
+ 'name': 'AsShotNeutral',
+ 'type': 'Short'
+ },
+ 50729: {
+ 'name': 'AsShotWhiteXY',
+ 'type': 'Rational'
+ },
+ 50730: {
+ 'name': 'BaselineExposure',
+ 'type': 'SRational'
+ },
+ 50731: {
+ 'name': 'BaselineNoise',
+ 'type': 'Rational'
+ },
+ 50732: {
+ 'name': 'BaselineSharpness',
+ 'type': 'Rational'
+ },
+ 50733: {
+ 'name': 'BayerGreenSplit',
+ 'type': 'Long'
+ },
+ 50734: {
+ 'name': 'LinearResponseLimit',
+ 'type': 'Rational'
+ },
+ 50735: {
+ 'name': 'CameraSerialNumber',
+ 'type': 'Ascii'
+ },
+ 50736: {
+ 'name': 'LensInfo',
+ 'type': 'Rational'
+ },
+ 50737: {
+ 'name': 'ChromaBlurRadius',
+ 'type': 'Rational'
+ },
+ 50738: {
+ 'name': 'AntiAliasStrength',
+ 'type': 'Rational'
+ },
+ 50739: {
+ 'name': 'ShadowScale',
+ 'type': 'SRational'
+ },
+ 50740: {
+ 'name': 'DNGPrivateData',
+ 'type': 'Byte'
+ },
+ 50741: {
+ 'name': 'MakerNoteSafety',
+ 'type': 'Short'
+ },
+ 50778: {
+ 'name': 'CalibrationIlluminant1',
+ 'type': 'Short'
+ },
+ 50779: {
+ 'name': 'CalibrationIlluminant2',
+ 'type': 'Short'
+ },
+ 50780: {
+ 'name': 'BestQualityScale',
+ 'type': 'Rational'
+ },
+ 50781: {
+ 'name': 'RawDataUniqueID',
+ 'type': 'Byte'
+ },
+ 50827: {
+ 'name': 'OriginalRawFileName',
+ 'type': 'Byte'
+ },
+ 50828: {
+ 'name': 'OriginalRawFileData',
+ 'type': 'Undefined'
+ },
+ 50829: {
+ 'name': 'ActiveArea',
+ 'type': 'Short'
+ },
+ 50830: {
+ 'name': 'MaskedAreas',
+ 'type': 'Short'
+ },
+ 50831: {
+ 'name': 'AsShotICCProfile',
+ 'type': 'Undefined'
+ },
+ 50832: {
+ 'name': 'AsShotPreProfileMatrix',
+ 'type': 'SRational'
+ },
+ 50833: {
+ 'name': 'CurrentICCProfile',
+ 'type': 'Undefined'
+ },
+ 50834: {
+ 'name': 'CurrentPreProfileMatrix',
+ 'type': 'SRational'
+ },
+ 50879: {
+ 'name': 'ColorimetricReference',
+ 'type': 'Short'
+ },
+ 50931: {
+ 'name': 'CameraCalibrationSignature',
+ 'type': 'Byte'
+ },
+ 50932: {
+ 'name': 'ProfileCalibrationSignature',
+ 'type': 'Byte'
+ },
+ 50934: {
+ 'name': 'AsShotProfileName',
+ 'type': 'Byte'
+ },
+ 50935: {
+ 'name': 'NoiseReductionApplied',
+ 'type': 'Rational'
+ },
+ 50936: {
+ 'name': 'ProfileName',
+ 'type': 'Byte'
+ },
+ 50937: {
+ 'name': 'ProfileHueSatMapDims',
+ 'type': 'Long'
+ },
+ 50938: {
+ 'name': 'ProfileHueSatMapData1',
+ 'type': 'Float'
+ },
+ 50939: {
+ 'name': 'ProfileHueSatMapData2',
+ 'type': 'Float'
+ },
+ 50940: {
+ 'name': 'ProfileToneCurve',
+ 'type': 'Float'
+ },
+ 50941: {
+ 'name': 'ProfileEmbedPolicy',
+ 'type': 'Long'
+ },
+ 50942: {
+ 'name': 'ProfileCopyright',
+ 'type': 'Byte'
+ },
+ 50964: {
+ 'name': 'ForwardMatrix1',
+ 'type': 'SRational'
+ },
+ 50965: {
+ 'name': 'ForwardMatrix2',
+ 'type': 'SRational'
+ },
+ 50966: {
+ 'name': 'PreviewApplicationName',
+ 'type': 'Byte'
+ },
+ 50967: {
+ 'name': 'PreviewApplicationVersion',
+ 'type': 'Byte'
+ },
+ 50968: {
+ 'name': 'PreviewSettingsName',
+ 'type': 'Byte'
+ },
+ 50969: {
+ 'name': 'PreviewSettingsDigest',
+ 'type': 'Byte'
+ },
+ 50970: {
+ 'name': 'PreviewColorSpace',
+ 'type': 'Long'
+ },
+ 50971: {
+ 'name': 'PreviewDateTime',
+ 'type': 'Ascii'
+ },
+ 50972: {
+ 'name': 'RawImageDigest',
+ 'type': 'Undefined'
+ },
+ 50973: {
+ 'name': 'OriginalRawFileDigest',
+ 'type': 'Undefined'
+ },
+ 50974: {
+ 'name': 'SubTileBlockSize',
+ 'type': 'Long'
+ },
+ 50975: {
+ 'name': 'RowInterleaveFactor',
+ 'type': 'Long'
+ },
+ 50981: {
+ 'name': 'ProfileLookTableDims',
+ 'type': 'Long'
+ },
+ 50982: {
+ 'name': 'ProfileLookTableData',
+ 'type': 'Float'
+ },
+ 51008: {
+ 'name': 'OpcodeList1',
+ 'type': 'Undefined'
+ },
+ 51009: {
+ 'name': 'OpcodeList2',
+ 'type': 'Undefined'
+ },
+ 51022: {
+ 'name': 'OpcodeList3',
+ 'type': 'Undefined'
+ }
+ },
+ 'Exif': {
+ 33434: {
+ 'name': 'ExposureTime',
+ 'type': 'Rational'
+ },
+ 33437: {
+ 'name': 'FNumber',
+ 'type': 'Rational'
+ },
+ 34850: {
+ 'name': 'ExposureProgram',
+ 'type': 'Short'
+ },
+ 34852: {
+ 'name': 'SpectralSensitivity',
+ 'type': 'Ascii'
+ },
+ 34855: {
+ 'name': 'ISOSpeedRatings',
+ 'type': 'Short'
+ },
+ 34856: {
+ 'name': 'OECF',
+ 'type': 'Undefined'
+ },
+ 34864: {
+ 'name': 'SensitivityType',
+ 'type': 'Short'
+ },
+ 34865: {
+ 'name': 'StandardOutputSensitivity',
+ 'type': 'Long'
+ },
+ 34866: {
+ 'name': 'RecommendedExposureIndex',
+ 'type': 'Long'
+ },
+ 34867: {
+ 'name': 'ISOSpeed',
+ 'type': 'Long'
+ },
+ 34868: {
+ 'name': 'ISOSpeedLatitudeyyy',
+ 'type': 'Long'
+ },
+ 34869: {
+ 'name': 'ISOSpeedLatitudezzz',
+ 'type': 'Long'
+ },
+ 36864: {
+ 'name': 'ExifVersion',
+ 'type': 'Undefined'
+ },
+ 36867: {
+ 'name': 'DateTimeOriginal',
+ 'type': 'Ascii'
+ },
+ 36868: {
+ 'name': 'DateTimeDigitized',
+ 'type': 'Ascii'
+ },
+ 37121: {
+ 'name': 'ComponentsConfiguration',
+ 'type': 'Undefined'
+ },
+ 37122: {
+ 'name': 'CompressedBitsPerPixel',
+ 'type': 'Rational'
+ },
+ 37377: {
+ 'name': 'ShutterSpeedValue',
+ 'type': 'SRational'
+ },
+ 37378: {
+ 'name': 'ApertureValue',
+ 'type': 'Rational'
+ },
+ 37379: {
+ 'name': 'BrightnessValue',
+ 'type': 'SRational'
+ },
+ 37380: {
+ 'name': 'ExposureBiasValue',
+ 'type': 'SRational'
+ },
+ 37381: {
+ 'name': 'MaxApertureValue',
+ 'type': 'Rational'
+ },
+ 37382: {
+ 'name': 'SubjectDistance',
+ 'type': 'Rational'
+ },
+ 37383: {
+ 'name': 'MeteringMode',
+ 'type': 'Short'
+ },
+ 37384: {
+ 'name': 'LightSource',
+ 'type': 'Short'
+ },
+ 37385: {
+ 'name': 'Flash',
+ 'type': 'Short'
+ },
+ 37386: {
+ 'name': 'FocalLength',
+ 'type': 'Rational'
+ },
+ 37396: {
+ 'name': 'SubjectArea',
+ 'type': 'Short'
+ },
+ 37500: {
+ 'name': 'MakerNote',
+ 'type': 'Undefined'
+ },
+ 37510: {
+ 'name': 'UserComment',
+ 'type': 'Ascii'
+ },
+ 37520: {
+ 'name': 'SubSecTime',
+ 'type': 'Ascii'
+ },
+ 37521: {
+ 'name': 'SubSecTimeOriginal',
+ 'type': 'Ascii'
+ },
+ 37522: {
+ 'name': 'SubSecTimeDigitized',
+ 'type': 'Ascii'
+ },
+ 40960: {
+ 'name': 'FlashpixVersion',
+ 'type': 'Undefined'
+ },
+ 40961: {
+ 'name': 'ColorSpace',
+ 'type': 'Short'
+ },
+ 40962: {
+ 'name': 'PixelXDimension',
+ 'type': 'Long'
+ },
+ 40963: {
+ 'name': 'PixelYDimension',
+ 'type': 'Long'
+ },
+ 40964: {
+ 'name': 'RelatedSoundFile',
+ 'type': 'Ascii'
+ },
+ 40965: {
+ 'name': 'InteroperabilityTag',
+ 'type': 'Long'
+ },
+ 41483: {
+ 'name': 'FlashEnergy',
+ 'type': 'Rational'
+ },
+ 41484: {
+ 'name': 'SpatialFrequencyResponse',
+ 'type': 'Undefined'
+ },
+ 41486: {
+ 'name': 'FocalPlaneXResolution',
+ 'type': 'Rational'
+ },
+ 41487: {
+ 'name': 'FocalPlaneYResolution',
+ 'type': 'Rational'
+ },
+ 41488: {
+ 'name': 'FocalPlaneResolutionUnit',
+ 'type': 'Short'
+ },
+ 41492: {
+ 'name': 'SubjectLocation',
+ 'type': 'Short'
+ },
+ 41493: {
+ 'name': 'ExposureIndex',
+ 'type': 'Rational'
+ },
+ 41495: {
+ 'name': 'SensingMethod',
+ 'type': 'Short'
+ },
+ 41728: {
+ 'name': 'FileSource',
+ 'type': 'Undefined'
+ },
+ 41729: {
+ 'name': 'SceneType',
+ 'type': 'Undefined'
+ },
+ 41730: {
+ 'name': 'CFAPattern',
+ 'type': 'Undefined'
+ },
+ 41985: {
+ 'name': 'CustomRendered',
+ 'type': 'Short'
+ },
+ 41986: {
+ 'name': 'ExposureMode',
+ 'type': 'Short'
+ },
+ 41987: {
+ 'name': 'WhiteBalance',
+ 'type': 'Short'
+ },
+ 41988: {
+ 'name': 'DigitalZoomRatio',
+ 'type': 'Rational'
+ },
+ 41989: {
+ 'name': 'FocalLengthIn35mmFilm',
+ 'type': 'Short'
+ },
+ 41990: {
+ 'name': 'SceneCaptureType',
+ 'type': 'Short'
+ },
+ 41991: {
+ 'name': 'GainControl',
+ 'type': 'Short'
+ },
+ 41992: {
+ 'name': 'Contrast',
+ 'type': 'Short'
+ },
+ 41993: {
+ 'name': 'Saturation',
+ 'type': 'Short'
+ },
+ 41994: {
+ 'name': 'Sharpness',
+ 'type': 'Short'
+ },
+ 41995: {
+ 'name': 'DeviceSettingDescription',
+ 'type': 'Undefined'
+ },
+ 41996: {
+ 'name': 'SubjectDistanceRange',
+ 'type': 'Short'
+ },
+ 42016: {
+ 'name': 'ImageUniqueID',
+ 'type': 'Ascii'
+ },
+ 42032: {
+ 'name': 'CameraOwnerName',
+ 'type': 'Ascii'
+ },
+ 42033: {
+ 'name': 'BodySerialNumber',
+ 'type': 'Ascii'
+ },
+ 42034: {
+ 'name': 'LensSpecification',
+ 'type': 'Rational'
+ },
+ 42035: {
+ 'name': 'LensMake',
+ 'type': 'Ascii'
+ },
+ 42036: {
+ 'name': 'LensModel',
+ 'type': 'Ascii'
+ },
+ 42037: {
+ 'name': 'LensSerialNumber',
+ 'type': 'Ascii'
+ },
+ 42240: {
+ 'name': 'Gamma',
+ 'type': 'Rational'
+ }
+ },
+ 'GPS': {
+ 0: {
+ 'name': 'GPSVersionID',
+ 'type': 'Byte'
+ },
+ 1: {
+ 'name': 'GPSLatitudeRef',
+ 'type': 'Ascii'
+ },
+ 2: {
+ 'name': 'GPSLatitude',
+ 'type': 'Rational'
+ },
+ 3: {
+ 'name': 'GPSLongitudeRef',
+ 'type': 'Ascii'
+ },
+ 4: {
+ 'name': 'GPSLongitude',
+ 'type': 'Rational'
+ },
+ 5: {
+ 'name': 'GPSAltitudeRef',
+ 'type': 'Byte'
+ },
+ 6: {
+ 'name': 'GPSAltitude',
+ 'type': 'Rational'
+ },
+ 7: {
+ 'name': 'GPSTimeStamp',
+ 'type': 'Rational'
+ },
+ 8: {
+ 'name': 'GPSSatellites',
+ 'type': 'Ascii'
+ },
+ 9: {
+ 'name': 'GPSStatus',
+ 'type': 'Ascii'
+ },
+ 10: {
+ 'name': 'GPSMeasureMode',
+ 'type': 'Ascii'
+ },
+ 11: {
+ 'name': 'GPSDOP',
+ 'type': 'Rational'
+ },
+ 12: {
+ 'name': 'GPSSpeedRef',
+ 'type': 'Ascii'
+ },
+ 13: {
+ 'name': 'GPSSpeed',
+ 'type': 'Rational'
+ },
+ 14: {
+ 'name': 'GPSTrackRef',
+ 'type': 'Ascii'
+ },
+ 15: {
+ 'name': 'GPSTrack',
+ 'type': 'Rational'
+ },
+ 16: {
+ 'name': 'GPSImgDirectionRef',
+ 'type': 'Ascii'
+ },
+ 17: {
+ 'name': 'GPSImgDirection',
+ 'type': 'Rational'
+ },
+ 18: {
+ 'name': 'GPSMapDatum',
+ 'type': 'Ascii'
+ },
+ 19: {
+ 'name': 'GPSDestLatitudeRef',
+ 'type': 'Ascii'
+ },
+ 20: {
+ 'name': 'GPSDestLatitude',
+ 'type': 'Rational'
+ },
+ 21: {
+ 'name': 'GPSDestLongitudeRef',
+ 'type': 'Ascii'
+ },
+ 22: {
+ 'name': 'GPSDestLongitude',
+ 'type': 'Rational'
+ },
+ 23: {
+ 'name': 'GPSDestBearingRef',
+ 'type': 'Ascii'
+ },
+ 24: {
+ 'name': 'GPSDestBearing',
+ 'type': 'Rational'
+ },
+ 25: {
+ 'name': 'GPSDestDistanceRef',
+ 'type': 'Ascii'
+ },
+ 26: {
+ 'name': 'GPSDestDistance',
+ 'type': 'Rational'
+ },
+ 27: {
+ 'name': 'GPSProcessingMethod',
+ 'type': 'Undefined'
+ },
+ 28: {
+ 'name': 'GPSAreaInformation',
+ 'type': 'Undefined'
+ },
+ 29: {
+ 'name': 'GPSDateStamp',
+ 'type': 'Ascii'
+ },
+ 30: {
+ 'name': 'GPSDifferential',
+ 'type': 'Short'
+ },
+ 31: {
+ 'name': 'GPSHPositioningError',
+ 'type': 'Rational'
+ }
+ },
+ 'Interop': {
+ 1: {
+ 'name': 'InteroperabilityIndex',
+ 'type': 'Ascii'
+ }
+ },
+ };
+ TAGS["0th"] = TAGS["Image"];
+ TAGS["1st"] = TAGS["Image"];
+ that.TAGS = TAGS;
+
+
+ that.ImageIFD = {
+ ProcessingSoftware:11,
+ NewSubfileType:254,
+ SubfileType:255,
+ ImageWidth:256,
+ ImageLength:257,
+ BitsPerSample:258,
+ Compression:259,
+ PhotometricInterpretation:262,
+ Threshholding:263,
+ CellWidth:264,
+ CellLength:265,
+ FillOrder:266,
+ DocumentName:269,
+ ImageDescription:270,
+ Make:271,
+ Model:272,
+ StripOffsets:273,
+ Orientation:274,
+ SamplesPerPixel:277,
+ RowsPerStrip:278,
+ StripByteCounts:279,
+ XResolution:282,
+ YResolution:283,
+ PlanarConfiguration:284,
+ GrayResponseUnit:290,
+ GrayResponseCurve:291,
+ T4Options:292,
+ T6Options:293,
+ ResolutionUnit:296,
+ TransferFunction:301,
+ Software:305,
+ DateTime:306,
+ Artist:315,
+ HostComputer:316,
+ Predictor:317,
+ WhitePoint:318,
+ PrimaryChromaticities:319,
+ ColorMap:320,
+ HalftoneHints:321,
+ TileWidth:322,
+ TileLength:323,
+ TileOffsets:324,
+ TileByteCounts:325,
+ SubIFDs:330,
+ InkSet:332,
+ InkNames:333,
+ NumberOfInks:334,
+ DotRange:336,
+ TargetPrinter:337,
+ ExtraSamples:338,
+ SampleFormat:339,
+ SMinSampleValue:340,
+ SMaxSampleValue:341,
+ TransferRange:342,
+ ClipPath:343,
+ XClipPathUnits:344,
+ YClipPathUnits:345,
+ Indexed:346,
+ JPEGTables:347,
+ OPIProxy:351,
+ JPEGProc:512,
+ JPEGInterchangeFormat:513,
+ JPEGInterchangeFormatLength:514,
+ JPEGRestartInterval:515,
+ JPEGLosslessPredictors:517,
+ JPEGPointTransforms:518,
+ JPEGQTables:519,
+ JPEGDCTables:520,
+ JPEGACTables:521,
+ YCbCrCoefficients:529,
+ YCbCrSubSampling:530,
+ YCbCrPositioning:531,
+ ReferenceBlackWhite:532,
+ XMLPacket:700,
+ Rating:18246,
+ RatingPercent:18249,
+ ImageID:32781,
+ CFARepeatPatternDim:33421,
+ CFAPattern:33422,
+ BatteryLevel:33423,
+ Copyright:33432,
+ ExposureTime:33434,
+ ImageResources:34377,
+ ExifTag:34665,
+ InterColorProfile:34675,
+ GPSTag:34853,
+ Interlace:34857,
+ TimeZoneOffset:34858,
+ SelfTimerMode:34859,
+ FlashEnergy:37387,
+ SpatialFrequencyResponse:37388,
+ Noise:37389,
+ FocalPlaneXResolution:37390,
+ FocalPlaneYResolution:37391,
+ FocalPlaneResolutionUnit:37392,
+ ImageNumber:37393,
+ SecurityClassification:37394,
+ ImageHistory:37395,
+ ExposureIndex:37397,
+ TIFFEPStandardID:37398,
+ SensingMethod:37399,
+ XPTitle:40091,
+ XPComment:40092,
+ XPAuthor:40093,
+ XPKeywords:40094,
+ XPSubject:40095,
+ PrintImageMatching:50341,
+ DNGVersion:50706,
+ DNGBackwardVersion:50707,
+ UniqueCameraModel:50708,
+ LocalizedCameraModel:50709,
+ CFAPlaneColor:50710,
+ CFALayout:50711,
+ LinearizationTable:50712,
+ BlackLevelRepeatDim:50713,
+ BlackLevel:50714,
+ BlackLevelDeltaH:50715,
+ BlackLevelDeltaV:50716,
+ WhiteLevel:50717,
+ DefaultScale:50718,
+ DefaultCropOrigin:50719,
+ DefaultCropSize:50720,
+ ColorMatrix1:50721,
+ ColorMatrix2:50722,
+ CameraCalibration1:50723,
+ CameraCalibration2:50724,
+ ReductionMatrix1:50725,
+ ReductionMatrix2:50726,
+ AnalogBalance:50727,
+ AsShotNeutral:50728,
+ AsShotWhiteXY:50729,
+ BaselineExposure:50730,
+ BaselineNoise:50731,
+ BaselineSharpness:50732,
+ BayerGreenSplit:50733,
+ LinearResponseLimit:50734,
+ CameraSerialNumber:50735,
+ LensInfo:50736,
+ ChromaBlurRadius:50737,
+ AntiAliasStrength:50738,
+ ShadowScale:50739,
+ DNGPrivateData:50740,
+ MakerNoteSafety:50741,
+ CalibrationIlluminant1:50778,
+ CalibrationIlluminant2:50779,
+ BestQualityScale:50780,
+ RawDataUniqueID:50781,
+ OriginalRawFileName:50827,
+ OriginalRawFileData:50828,
+ ActiveArea:50829,
+ MaskedAreas:50830,
+ AsShotICCProfile:50831,
+ AsShotPreProfileMatrix:50832,
+ CurrentICCProfile:50833,
+ CurrentPreProfileMatrix:50834,
+ ColorimetricReference:50879,
+ CameraCalibrationSignature:50931,
+ ProfileCalibrationSignature:50932,
+ AsShotProfileName:50934,
+ NoiseReductionApplied:50935,
+ ProfileName:50936,
+ ProfileHueSatMapDims:50937,
+ ProfileHueSatMapData1:50938,
+ ProfileHueSatMapData2:50939,
+ ProfileToneCurve:50940,
+ ProfileEmbedPolicy:50941,
+ ProfileCopyright:50942,
+ ForwardMatrix1:50964,
+ ForwardMatrix2:50965,
+ PreviewApplicationName:50966,
+ PreviewApplicationVersion:50967,
+ PreviewSettingsName:50968,
+ PreviewSettingsDigest:50969,
+ PreviewColorSpace:50970,
+ PreviewDateTime:50971,
+ RawImageDigest:50972,
+ OriginalRawFileDigest:50973,
+ SubTileBlockSize:50974,
+ RowInterleaveFactor:50975,
+ ProfileLookTableDims:50981,
+ ProfileLookTableData:50982,
+ OpcodeList1:51008,
+ OpcodeList2:51009,
+ OpcodeList3:51022,
+ NoiseProfile:51041,
+ };
+
+
+ that.ExifIFD = {
+ ExposureTime:33434,
+ FNumber:33437,
+ ExposureProgram:34850,
+ SpectralSensitivity:34852,
+ ISOSpeedRatings:34855,
+ OECF:34856,
+ SensitivityType:34864,
+ StandardOutputSensitivity:34865,
+ RecommendedExposureIndex:34866,
+ ISOSpeed:34867,
+ ISOSpeedLatitudeyyy:34868,
+ ISOSpeedLatitudezzz:34869,
+ ExifVersion:36864,
+ DateTimeOriginal:36867,
+ DateTimeDigitized:36868,
+ ComponentsConfiguration:37121,
+ CompressedBitsPerPixel:37122,
+ ShutterSpeedValue:37377,
+ ApertureValue:37378,
+ BrightnessValue:37379,
+ ExposureBiasValue:37380,
+ MaxApertureValue:37381,
+ SubjectDistance:37382,
+ MeteringMode:37383,
+ LightSource:37384,
+ Flash:37385,
+ FocalLength:37386,
+ SubjectArea:37396,
+ MakerNote:37500,
+ UserComment:37510,
+ SubSecTime:37520,
+ SubSecTimeOriginal:37521,
+ SubSecTimeDigitized:37522,
+ FlashpixVersion:40960,
+ ColorSpace:40961,
+ PixelXDimension:40962,
+ PixelYDimension:40963,
+ RelatedSoundFile:40964,
+ InteroperabilityTag:40965,
+ FlashEnergy:41483,
+ SpatialFrequencyResponse:41484,
+ FocalPlaneXResolution:41486,
+ FocalPlaneYResolution:41487,
+ FocalPlaneResolutionUnit:41488,
+ SubjectLocation:41492,
+ ExposureIndex:41493,
+ SensingMethod:41495,
+ FileSource:41728,
+ SceneType:41729,
+ CFAPattern:41730,
+ CustomRendered:41985,
+ ExposureMode:41986,
+ WhiteBalance:41987,
+ DigitalZoomRatio:41988,
+ FocalLengthIn35mmFilm:41989,
+ SceneCaptureType:41990,
+ GainControl:41991,
+ Contrast:41992,
+ Saturation:41993,
+ Sharpness:41994,
+ DeviceSettingDescription:41995,
+ SubjectDistanceRange:41996,
+ ImageUniqueID:42016,
+ CameraOwnerName:42032,
+ BodySerialNumber:42033,
+ LensSpecification:42034,
+ LensMake:42035,
+ LensModel:42036,
+ LensSerialNumber:42037,
+ Gamma:42240,
+ };
+
+
+ that.GPSIFD = {
+ GPSVersionID:0,
+ GPSLatitudeRef:1,
+ GPSLatitude:2,
+ GPSLongitudeRef:3,
+ GPSLongitude:4,
+ GPSAltitudeRef:5,
+ GPSAltitude:6,
+ GPSTimeStamp:7,
+ GPSSatellites:8,
+ GPSStatus:9,
+ GPSMeasureMode:10,
+ GPSDOP:11,
+ GPSSpeedRef:12,
+ GPSSpeed:13,
+ GPSTrackRef:14,
+ GPSTrack:15,
+ GPSImgDirectionRef:16,
+ GPSImgDirection:17,
+ GPSMapDatum:18,
+ GPSDestLatitudeRef:19,
+ GPSDestLatitude:20,
+ GPSDestLongitudeRef:21,
+ GPSDestLongitude:22,
+ GPSDestBearingRef:23,
+ GPSDestBearing:24,
+ GPSDestDistanceRef:25,
+ GPSDestDistance:26,
+ GPSProcessingMethod:27,
+ GPSAreaInformation:28,
+ GPSDateStamp:29,
+ GPSDifferential:30,
+ GPSHPositioningError:31,
+ };
+
+
+ that.InteropIFD = {
+ InteroperabilityIndex:1,
+ };
+
+ that.GPSHelper = {
+ degToDmsRational:function (degFloat) {
+ var degAbs = Math.abs(degFloat);
+ var minFloat = degAbs % 1 * 60;
+ var secFloat = minFloat % 1 * 60;
+ var deg = Math.floor(degAbs);
+ var min = Math.floor(minFloat);
+ var sec = Math.round(secFloat * 100);
+
+ return [[deg, 1], [min, 1], [sec, 100]];
+ },
+
+ dmsRationalToDeg:function (dmsArray, ref) {
+ var sign = (ref === 'S' || ref === 'W') ? -1.0 : 1.0;
+ var deg = dmsArray[0][0] / dmsArray[0][1] +
+ dmsArray[1][0] / dmsArray[1][1] / 60.0 +
+ dmsArray[2][0] / dmsArray[2][1] / 3600.0;
+
+ return deg * sign;
+ }
+ };
+
+
+ if (typeof exports !== 'undefined') {
+ if (typeof module !== 'undefined' && module.exports) {
+ exports = module.exports = that;
+ }
+ exports.piexif = that;
+ } else {
+ window.piexif = that;
+ }
+
+})();
diff --git a/wire/modules/Inputfield/InputfieldImage/piexif.min.js b/wire/modules/Inputfield/InputfieldImage/piexif.min.js
new file mode 100644
index 00000000..eb016550
--- /dev/null
+++ b/wire/modules/Inputfield/InputfieldImage/piexif.min.js
@@ -0,0 +1 @@
+(function(){"use strict";var that={};that.version="1.0.4";that.remove=function(jpeg){var b64=false;if(jpeg.slice(0,2)=="ÿØ"){}else if(jpeg.slice(0,23)=="data:image/jpeg;base64,"||jpeg.slice(0,22)=="data:image/jpg;base64,"){jpeg=atob(jpeg.split(",")[1]);b64=true}else{throw new Error("Given data is not jpeg.")}var segments=splitIntoSegments(jpeg);var newSegments=segments.filter(function(seg){return!(seg.slice(0,2)=="ÿá"&&seg.slice(4,10)=="Exif\0\0")});var new_data=newSegments.join("");if(b64){new_data="data:image/jpeg;base64,"+btoa(new_data)}return new_data};that.insert=function(exif,jpeg){var b64=false;if(exif.slice(0,6)!="Exif\0\0"){throw new Error("Given data is not exif.")}if(jpeg.slice(0,2)=="ÿØ"){}else if(jpeg.slice(0,23)=="data:image/jpeg;base64,"||jpeg.slice(0,22)=="data:image/jpg;base64,"){jpeg=atob(jpeg.split(",")[1]);b64=true}else{throw new Error("Given data is not jpeg.")}var exifStr="ÿá"+pack(">H",[exif.length+2])+exif;var segments=splitIntoSegments(jpeg);var new_data=mergeSegments(segments,exifStr);if(b64){new_data="data:image/jpeg;base64,"+btoa(new_data)}return new_data};that.load=function(data){var input_data;if(typeof data=="string"){if(data.slice(0,2)=="ÿØ"){input_data=data}else if(data.slice(0,23)=="data:image/jpeg;base64,"||data.slice(0,22)=="data:image/jpg;base64,"){input_data=atob(data.split(",")[1])}else if(data.slice(0,4)=="Exif"){input_data=data.slice(6)}else{throw new Error("'load' gots invalid file data.")}}else{throw new Error("'load' gots invalid type argument.")}var exifDict={};var exif_dict={"0th":{},Exif:{},GPS:{},Interop:{},"1st":{},thumbnail:null};var exifReader=new ExifReader(input_data);if(exifReader.tiftag===null){return exif_dict}if(exifReader.tiftag.slice(0,2)=="II"){exifReader.endian_mark="<"}else{exifReader.endian_mark=">"}var pointer=unpack(exifReader.endian_mark+"L",exifReader.tiftag.slice(4,8))[0];exif_dict["0th"]=exifReader.get_ifd(pointer,"0th");var first_ifd_pointer=exif_dict["0th"]["first_ifd_pointer"];delete exif_dict["0th"]["first_ifd_pointer"];if(34665 in exif_dict["0th"]){pointer=exif_dict["0th"][34665];exif_dict["Exif"]=exifReader.get_ifd(pointer,"Exif")}if(34853 in exif_dict["0th"]){pointer=exif_dict["0th"][34853];exif_dict["GPS"]=exifReader.get_ifd(pointer,"GPS")}if(40965 in exif_dict["Exif"]){pointer=exif_dict["Exif"][40965];exif_dict["Interop"]=exifReader.get_ifd(pointer,"Interop")}if(first_ifd_pointer!="\0\0\0\0"){pointer=unpack(exifReader.endian_mark+"L",first_ifd_pointer)[0];exif_dict["1st"]=exifReader.get_ifd(pointer,"1st");if(513 in exif_dict["1st"]&&514 in exif_dict["1st"]){var end=exif_dict["1st"][513]+exif_dict["1st"][514];var thumb=exifReader.tiftag.slice(exif_dict["1st"][513],end);exif_dict["thumbnail"]=thumb}}return exif_dict};that.dump=function(exif_dict_original){var TIFF_HEADER_LENGTH=8;var exif_dict=copy(exif_dict_original);var header="Exif\0\0MM\0*\0\0\0\b";var exif_is=false;var gps_is=false;var interop_is=false;var first_is=false;var zeroth_ifd,exif_ifd,interop_ifd,gps_ifd,first_ifd;if("0th"in exif_dict){zeroth_ifd=exif_dict["0th"]}else{zeroth_ifd={}}if("Exif"in exif_dict&&Object.keys(exif_dict["Exif"]).length||"Interop"in exif_dict&&Object.keys(exif_dict["Interop"]).length){zeroth_ifd[34665]=1;exif_is=true;exif_ifd=exif_dict["Exif"];if("Interop"in exif_dict&&Object.keys(exif_dict["Interop"]).length){exif_ifd[40965]=1;interop_is=true;interop_ifd=exif_dict["Interop"]}else if(Object.keys(exif_ifd).indexOf(that.ExifIFD.InteroperabilityTag.toString())>-1){delete exif_ifd[40965]}}else if(Object.keys(zeroth_ifd).indexOf(that.ImageIFD.ExifTag.toString())>-1){delete zeroth_ifd[34665]}if("GPS"in exif_dict&&Object.keys(exif_dict["GPS"]).length){zeroth_ifd[that.ImageIFD.GPSTag]=1;gps_is=true;gps_ifd=exif_dict["GPS"]}else if(Object.keys(zeroth_ifd).indexOf(that.ImageIFD.GPSTag.toString())>-1){delete zeroth_ifd[that.ImageIFD.GPSTag]}if("1st"in exif_dict&&"thumbnail"in exif_dict&&exif_dict["thumbnail"]!=null){first_is=true;exif_dict["1st"][513]=1;exif_dict["1st"][514]=1;first_ifd=exif_dict["1st"]}var zeroth_set=_dict_to_bytes(zeroth_ifd,"0th",0);var zeroth_length=zeroth_set[0].length+exif_is*12+gps_is*12+4+zeroth_set[1].length;var exif_set,exif_bytes="",exif_length=0,gps_set,gps_bytes="",gps_length=0,interop_set,interop_bytes="",interop_length=0,first_set,first_bytes="",thumbnail;if(exif_is){exif_set=_dict_to_bytes(exif_ifd,"Exif",zeroth_length);exif_length=exif_set[0].length+interop_is*12+exif_set[1].length}if(gps_is){gps_set=_dict_to_bytes(gps_ifd,"GPS",zeroth_length+exif_length);gps_bytes=gps_set.join("");gps_length=gps_bytes.length}if(interop_is){var offset=zeroth_length+exif_length+gps_length;interop_set=_dict_to_bytes(interop_ifd,"Interop",offset);interop_bytes=interop_set.join("");interop_length=interop_bytes.length}if(first_is){var offset=zeroth_length+exif_length+gps_length+interop_length;first_set=_dict_to_bytes(first_ifd,"1st",offset);thumbnail=_get_thumbnail(exif_dict["thumbnail"]);if(thumbnail.length>64e3){throw new Error("Given thumbnail is too large. max 64kB")}}var exif_pointer="",gps_pointer="",interop_pointer="",first_ifd_pointer="\0\0\0\0";if(exif_is){var pointer_value=TIFF_HEADER_LENGTH+zeroth_length;var pointer_str=pack(">L",[pointer_value]);var key=34665;var key_str=pack(">H",[key]);var type_str=pack(">H",[TYPES["Long"]]);var length_str=pack(">L",[1]);exif_pointer=key_str+type_str+length_str+pointer_str}if(gps_is){var pointer_value=TIFF_HEADER_LENGTH+zeroth_length+exif_length;var pointer_str=pack(">L",[pointer_value]);var key=34853;var key_str=pack(">H",[key]);var type_str=pack(">H",[TYPES["Long"]]);var length_str=pack(">L",[1]);gps_pointer=key_str+type_str+length_str+pointer_str}if(interop_is){var pointer_value=TIFF_HEADER_LENGTH+zeroth_length+exif_length+gps_length;var pointer_str=pack(">L",[pointer_value]);var key=40965;var key_str=pack(">H",[key]);var type_str=pack(">H",[TYPES["Long"]]);var length_str=pack(">L",[1]);interop_pointer=key_str+type_str+length_str+pointer_str}if(first_is){var pointer_value=TIFF_HEADER_LENGTH+zeroth_length+exif_length+gps_length+interop_length;first_ifd_pointer=pack(">L",[pointer_value]);var thumbnail_pointer=pointer_value+first_set[0].length+24+4+first_set[1].length;var thumbnail_p_bytes="\0\0\0\0"+pack(">L",[thumbnail_pointer]);var thumbnail_length_bytes="\0\0\0\0"+pack(">L",[thumbnail.length]);first_bytes=first_set[0]+thumbnail_p_bytes+thumbnail_length_bytes+"\0\0\0\0"+first_set[1]+thumbnail}var zeroth_bytes=zeroth_set[0]+exif_pointer+gps_pointer+first_ifd_pointer+zeroth_set[1];if(exif_is){exif_bytes=exif_set[0]+interop_pointer+exif_set[1]}return header+zeroth_bytes+exif_bytes+gps_bytes+interop_bytes+first_bytes};function copy(obj){return JSON.parse(JSON.stringify(obj))}function _get_thumbnail(jpeg){var segments=splitIntoSegments(jpeg);while("ÿà"<=segments[1].slice(0,2)&&segments[1].slice(0,2)<="ÿï"){segments=[segments[0]].concat(segments.slice(2))}return segments.join("")}function _pack_byte(array){return pack(">"+nStr("B",array.length),array)}function _pack_short(array){return pack(">"+nStr("H",array.length),array)}function _pack_long(array){return pack(">"+nStr("L",array.length),array)}function _value_to_bytes(raw_value,value_type,offset){var four_bytes_over="";var value_str="";var length,new_value,num,den;if(value_type=="Byte"){length=raw_value.length;if(length<=4){value_str=_pack_byte(raw_value)+nStr("\0",4-length)}else{value_str=pack(">L",[offset]);four_bytes_over=_pack_byte(raw_value)}}else if(value_type=="Short"){length=raw_value.length;if(length<=2){value_str=_pack_short(raw_value)+nStr("\0\0",2-length)}else{value_str=pack(">L",[offset]);four_bytes_over=_pack_short(raw_value)}}else if(value_type=="Long"){length=raw_value.length;if(length<=1){value_str=_pack_long(raw_value)}else{value_str=pack(">L",[offset]);four_bytes_over=_pack_long(raw_value)}}else if(value_type=="Ascii"){new_value=raw_value+"\0";length=new_value.length;if(length>4){value_str=pack(">L",[offset]);four_bytes_over=new_value}else{value_str=new_value+nStr("\0",4-length)}}else if(value_type=="Rational"){if(typeof raw_value[0]=="number"){length=1;num=raw_value[0];den=raw_value[1];new_value=pack(">L",[num])+pack(">L",[den])}else{length=raw_value.length;new_value="";for(var n=0;nL",[num])+pack(">L",[den])}}value_str=pack(">L",[offset]);four_bytes_over=new_value}else if(value_type=="SRational"){if(typeof raw_value[0]=="number"){length=1;num=raw_value[0];den=raw_value[1];new_value=pack(">l",[num])+pack(">l",[den])}else{length=raw_value.length;new_value="";for(var n=0;nl",[num])+pack(">l",[den])}}value_str=pack(">L",[offset]);four_bytes_over=new_value}else if(value_type=="Undefined"){length=raw_value.length;if(length>4){value_str=pack(">L",[offset]);four_bytes_over=raw_value}else{value_str=raw_value+nStr("\0",4-length)}}var length_str=pack(">L",[length]);return[length_str,value_str,four_bytes_over]}function _dict_to_bytes(ifd_dict,ifd,ifd_offset){var TIFF_HEADER_LENGTH=8;var tag_count=Object.keys(ifd_dict).length;var entry_header=pack(">H",[tag_count]);var entries_length;if(["0th","1st"].indexOf(ifd)>-1){entries_length=2+tag_count*12+4}else{entries_length=2+tag_count*12}var entries="";var values="";var key;for(var key in ifd_dict){if(typeof key=="string"){key=parseInt(key)}if(ifd=="0th"&&[34665,34853].indexOf(key)>-1){continue}else if(ifd=="Exif"&&key==40965){continue}else if(ifd=="1st"&&[513,514].indexOf(key)>-1){continue}var raw_value=ifd_dict[key];var key_str=pack(">H",[key]);var value_type=TAGS[ifd][key]["type"];var type_str=pack(">H",[TYPES[value_type]]);if(typeof raw_value=="number"){raw_value=[raw_value]}var offset=TIFF_HEADER_LENGTH+entries_length+ifd_offset+values.length;var b=_value_to_bytes(raw_value,value_type,offset);var length_str=b[0];var value_str=b[1];var four_bytes_over=b[2];entries+=key_str+type_str+length_str+value_str;values+=four_bytes_over}return[entry_header+entries,values]}function ExifReader(data){var segments,app1;if(data.slice(0,2)=="ÿØ"){segments=splitIntoSegments(data);app1=getExifSeg(segments);if(app1){this.tiftag=app1.slice(10)}else{this.tiftag=null}}else if(["II","MM"].indexOf(data.slice(0,2))>-1){this.tiftag=data}else if(data.slice(0,4)=="Exif"){this.tiftag=data.slice(6)}else{throw new Error("Given file is neither JPEG nor TIFF.")}}ExifReader.prototype={get_ifd:function(pointer,ifd_name){var ifd_dict={};var tag_count=unpack(this.endian_mark+"H",this.tiftag.slice(pointer,pointer+2))[0];var offset=pointer+2;var t;if(["0th","1st"].indexOf(ifd_name)>-1){t="Image"}else{t=ifd_name}for(var x=0;x4){pointer=unpack(this.endian_mark+"L",value)[0];data=unpack(this.endian_mark+nStr("B",length),this.tiftag.slice(pointer,pointer+length))}else{data=unpack(this.endian_mark+nStr("B",length),value.slice(0,length))}}else if(t==2){if(length>4){pointer=unpack(this.endian_mark+"L",value)[0];data=this.tiftag.slice(pointer,pointer+length-1)}else{data=value.slice(0,length-1)}}else if(t==3){if(length>2){pointer=unpack(this.endian_mark+"L",value)[0];data=unpack(this.endian_mark+nStr("H",length),this.tiftag.slice(pointer,pointer+length*2))}else{data=unpack(this.endian_mark+nStr("H",length),value.slice(0,length*2))}}else if(t==4){if(length>1){pointer=unpack(this.endian_mark+"L",value)[0];data=unpack(this.endian_mark+nStr("L",length),this.tiftag.slice(pointer,pointer+length*4))}else{data=unpack(this.endian_mark+nStr("L",length),value)}}else if(t==5){pointer=unpack(this.endian_mark+"L",value)[0];if(length>1){data=[];for(var x=0;x4){pointer=unpack(this.endian_mark+"L",value)[0];data=this.tiftag.slice(pointer,pointer+length)}else{data=value.slice(0,length)}}else if(t==9){if(length>1){pointer=unpack(this.endian_mark+"L",value)[0];data=unpack(this.endian_mark+nStr("l",length),this.tiftag.slice(pointer,pointer+length*4))}else{data=unpack(this.endian_mark+nStr("l",length),value)}}else if(t==10){pointer=unpack(this.endian_mark+"L",value)[0];if(length>1){data=[];for(var x=0;x>2;enc2=(chr1&3)<<4|chr2>>4;enc3=(chr2&15)<<2|chr3>>6;enc4=chr3&63;if(isNaN(chr2)){enc3=enc4=64}else if(isNaN(chr3)){enc4=64}output=output+keyStr.charAt(enc1)+keyStr.charAt(enc2)+keyStr.charAt(enc3)+keyStr.charAt(enc4)}return output}}if(typeof window!=="undefined"&&typeof window.atob==="function"){var atob=window.atob}if(typeof atob==="undefined"){var atob=function(input){var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;var keyStr="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";input=input.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(i>4;chr2=(enc2&15)<<4|enc3>>2;chr3=(enc3&3)<<6|enc4;output=output+String.fromCharCode(chr1);if(enc3!=64){output=output+String.fromCharCode(chr2)}if(enc4!=64){output=output+String.fromCharCode(chr3)}}return output}}function getImageSize(imageArray){var segments=slice2Segments(imageArray);var seg,width,height,SOF=[192,193,194,195,197,198,199,201,202,203,205,206,207];for(var x=0;x=0){height=seg[5]*256+seg[6];width=seg[7]*256+seg[8];break}}return[width,height]}function pack(mark,array){if(!(array instanceof Array)){throw new Error("'pack' error. Got invalid type argument.")}if(mark.length-1!=array.length){throw new Error("'pack' error. "+(mark.length-1)+" marks, "+array.length+" elements.")}var littleEndian;if(mark[0]=="<"){littleEndian=true}else if(mark[0]==">"){littleEndian=false}else{throw new Error("")}var packed="";var p=1;var val=null;var c=null;var valStr=null;while(c=mark[p]){if(c.toLowerCase()=="b"){val=array[p-1];if(c=="b"&&val<0){val+=256}if(val>255||val<0){throw new Error("'pack' error.")}else{valStr=String.fromCharCode(val)}}else if(c=="H"){val=array[p-1];if(val>65535||val<0){throw new Error("'pack' error.")}else{valStr=String.fromCharCode(Math.floor(val%65536/256))+String.fromCharCode(val%256);if(littleEndian){valStr=valStr.split("").reverse().join("")}}}else if(c.toLowerCase()=="l"){val=array[p-1];if(c=="l"&&val<0){val+=4294967296}if(val>4294967295||val<0){throw new Error("'pack' error.")}else{valStr=String.fromCharCode(Math.floor(val/16777216))+String.fromCharCode(Math.floor(val%16777216/65536))+String.fromCharCode(Math.floor(val%65536/256))+String.fromCharCode(val%256);if(littleEndian){valStr=valStr.split("").reverse().join("")}}}else{throw new Error("'pack' error.")}packed+=valStr;p+=1}return packed}function unpack(mark,str){if(typeof str!="string"){throw new Error("'unpack' error. Got invalid type argument.")}var l=0;for(var markPointer=1;markPointer"){littleEndian=false}else{throw new Error("'unpack' error.")}var unpacked=[];var strPointer=0;var p=1;var val=null;var c=null;var length=null;var sliced="";while(c=mark[p]){if(c.toLowerCase()=="b"){length=1;sliced=str.slice(strPointer,strPointer+length);val=sliced.charCodeAt(0);if(c=="b"&&val>=128){val-=256}}else if(c=="H"){length=2;sliced=str.slice(strPointer,strPointer+length);if(littleEndian){sliced=sliced.split("").reverse().join("")}val=sliced.charCodeAt(0)*256+sliced.charCodeAt(1)}else if(c.toLowerCase()=="l"){length=4;sliced=str.slice(strPointer,strPointer+length);if(littleEndian){sliced=sliced.split("").reverse().join("")}val=sliced.charCodeAt(0)*16777216+sliced.charCodeAt(1)*65536+sliced.charCodeAt(2)*256+sliced.charCodeAt(3);if(c=="l"&&val>=2147483648){val-=4294967296}}else{throw new Error("'unpack' error. "+c)}unpacked.push(val);strPointer+=length;p+=1}return unpacked}function nStr(ch,num){var str="";for(var i=0;iH",data.slice(head+2,head+4))[0];var endPoint=head+length+2;segments.push(data.slice(head,endPoint));head=endPoint}if(head>=data.length){throw new Error("Wrong JPEG data.")}}return segments}function getExifSeg(segments){var seg;for(var i=0;i