diff --git a/attributions.md b/attributions.md new file mode 100644 index 0000000000..581e681d73 --- /dev/null +++ b/attributions.md @@ -0,0 +1,43 @@ +## Frappe framework includes these public works + +### Javascript / CSS + +- Bootstrap: MIT License, (c) Twitter Inc, https://getbootstrap.com +- JQuery: MIT License, (c) JQuery Foundation, http://jquery.org/license +- JQuery UI: MIT License / GPL 2, (c) JQuery Foundation, https://jqueryui.com/about +- JQuery UI Bootstrap Theme: MIT / GPL 2, (c) Addy Osmani, http://addyosmani.github.com/jquery-ui-bootstrap +- QUnit: MIT License, (c) JQuery Foundation, http://jquery.org/license +- jquery.event.drag, MIT License, (c) 2010 Three Dub Media - http://threedubmedia.com +- JQuery Cookie Plugin, MIT / GPL 2, (c) 2011, Klaus Hartl +- JQuery Time Picker, MIT License, (c) 2013 Trent Richardson, http://trentrichardson.com/examples/timepicker +- JQuery Hotkeys Plugin, MIT License, (c) 2010, John Resig +- prettydate.js, MIT License, (c) 2011, John Resig +- jquery.flot.downsample, MIT License, (c) 2013, Sveinn Steinarsson +- JQuery Resize Event, MIT License, (c) 2010 "Cowboy" Ben Alman +- excanvas.js, Apache License Version 2.0, (c) 2006 Google Inc +- showdown.js - Javascript Markdown, BSD-style Open Source License, (c) 2007 John Fraser +- Beautify HTML - MIT License, (c) 2007-2013 Einar Lielmanis and contributors. +- JQuery Gantt - MIT License, http://taitems.github.com/jQuery.Gantt/ +- SlickGrid - MIT License, https://github.com/mleibman/SlickGrid +- MomentJS - MIT License, https://github.com/moment/moment +- JSColor - LGPL, (c) Jan Odvarko, http://jscolor.com +- FullCalendar - MIT License, (c) 2013 Adam Shaw, http://fullcalendar.io/license/ + +### Python + +- html2text.py - GNU GPL 3, (c) 2004-2008 Aaron Swartz +- minify.js - MIT License, (c) 2002 Douglas Crockford + +### Icon Fonts + +- Font Awesome - http://fontawesome.io/ + - Font License: SIL OFL 1.1 (http://scripts.sil.org/OFL) + - Code License: MIT (http://choosealicense.com/licenses/mit/) +- Octicons (c) GitHub Inc, https://octicons.github.com/ + - Font License: SIL OFL 1.1 (http://scripts.sil.org/OFL) + - Code License: MIT (http://choosealicense.com/licenses/mit/) +- Ionicons - MIT License, http://ionicons.com/ + +### IP Address Database + +- GeoIP: (c) 2014 MaxMind, http://dev.maxmind.com/geoip/geoip2/downloadable/ diff --git a/frappe/public/build.json b/frappe/public/build.json index 99edb0ec49..b349291821 100644 --- a/frappe/public/build.json +++ b/frappe/public/build.json @@ -16,10 +16,6 @@ "public/js/lib/highlight.pack.js", "website/js/website.js" ], - "js/canvasResize.min.js": [ - "website/js/jquery.exif.js", - "website/js/jquery.canvasResize.js" - ], "js/editor.min.js": [ "public/js/lib/jquery/jquery.hotkeys.js", "public/js/frappe/class.js", @@ -48,7 +44,6 @@ "public/js/lib/jquery/jquery.ui.min.js", "public/js/lib/tag-it.min.js", "public/js/lib/jquery/jquery.hotkeys.js", - "public/js/lib/center_image.js", "public/js/lib/bootstrap.min.js", "public/js/lib/nprogress.js", "public/js/lib/beautify-html.js", diff --git a/frappe/public/js/lib/center_image.js b/frappe/public/js/lib/center_image.js deleted file mode 100644 index 08b867e30b..0000000000 --- a/frappe/public/js/lib/center_image.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * bl-jquery-image-center jQuery Plugin - * - * @copyright Boxlight Media Ltd. 2012 - * @license MIT License - * @description Centers an image by moving, cropping and filling spaces inside it's parent container. Call - * this on a set of images to have them fill their parent whilst maintaining aspect ratio - * @author Robert Cambridge - * - * Usage: See documentation at http://boxlight.github.com/bl-jquery-image-center - */ -$.fn.centerImage = function(method, callback) { - callback = callback || function() {}; - var els = this; - var remaining = $(this).length; - method = method == 'inside'; - - // execute this on an individual image element once it's loaded - var fn = function(img) { - var $img = $(img); - var $div = $img.parent(); - // parent CSS should be in stylesheet, but to reinforce: - $div.css({ - overflow: 'hidden', - }); - - // temporarily set the image size naturally so we can get the aspect ratio - $img.css({ - 'position': 'static', - 'width': 'auto', - 'height': 'auto', - 'max-width': '100%', - 'max-height': '100%' - }); - - // now resize - var div = { w: $div.width(), h: $div.height(), r: $div.width() / $div.height() }; - var img = { w: $img.width(), h: $img.height(), r: $img.width() / $img.height() }; - var width = Math.round((div.r > img.r) ^ method ? '100%' : div.h / img.h * img.w); - var height = Math.round((div.r < img.r) ^ method ? '100%' : div.w / img.w * img.h); - - if(width) width++; - if(height) height++; - - $img.css({ - 'max-width': 'none', - 'max-height': 'none', - 'width': width, - 'height': height, - }); - - // now center - but portrait images need to be centered slightly above halfway (33%) - var div = { w: $div.width(), h: $div.height() }; - var img = { w: $img.width(), h: $img.height() }; - - var left = Math.round((div.w - img.w) / 2); - var top = Math.round((div.h - img.h) / 3); - - $img.css({ - 'margin-left': left, - 'margin-top': top - }); - - callbackWrapped(img) - }; - - var callbackWrapped = function(img) { - remaining--; - callback.apply(els, [ img, remaining ]); - }; - - // iterate through elements - return els.each(function(i) { - if (this.complete || this.readyState === 'complete') { - // loaded already? run fn - // when binding, we can tell whether image loaded or not. - // not if it's already failed though :( - (function(el) { - // use setTimeout to prevent browser locking up - setTimeout(function() { fn(el) }, 10); - })(this); - } else { - // not loaded? bind to load - (function(el) { - $(el) - .one('load', function() { - // use setTimeout to prevent browser locking up - setTimeout(function() { - fn(el); - }, 10); - }) - .one('error', function() { - // the image did not load - callbackWrapped(el) - }) - .end(); - - // IE9 won't always trigger the load event. fix it. - if (navigator.userAgent.indexOf("Trident/5") >= 0) { - el.src = el.src; - } - })(this); - } - }); -}; -// Alias functions which often better describe the use case -$.fn.imageCenterResize = function(callback) { - return $(this).centerImage('inside', callback); -}; -$.fn.imageCropFill = function(callback) { - return $(this).centerImage('outside', callback); -}; diff --git a/frappe/public/js/lib/sprintf.js b/frappe/public/js/lib/sprintf.js deleted file mode 100644 index 199ebfaea6..0000000000 --- a/frappe/public/js/lib/sprintf.js +++ /dev/null @@ -1,185 +0,0 @@ -/** -sprintf() for JavaScript 0.7-beta1 -http://www.diveintojavascript.com/projects/javascript-sprintf - -Copyright (c) Alexandru Marasteanu -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of sprintf() for JavaScript nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL Alexandru Marasteanu BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -Changelog: -2010.09.06 - 0.7-beta1 - - features: vsprintf, support for named placeholders - - enhancements: format cache, reduced global namespace pollution - -2010.05.22 - 0.6: - - reverted to 0.4 and fixed the bug regarding the sign of the number 0 - Note: - Thanks to Raphael Pigulla (http://www.n3rd.org/) - who warned me about a bug in 0.5, I discovered that the last update was - a regress. I appologize for that. - -2010.05.09 - 0.5: - - bug fix: 0 is now preceeded with a + sign - - bug fix: the sign was not at the right position on padded results (Kamal Abdali) - - switched from GPL to BSD license - -2007.10.21 - 0.4: - - unit test and patch (David Baird) - -2007.09.17 - 0.3: - - bug fix: no longer throws exception on empty paramenters (Hans Pufal) - -2007.09.11 - 0.2: - - feature: added argument swapping - -2007.04.03 - 0.1: - - initial release -**/ - -var sprintf = (function() { - function get_type(variable) { - return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase(); - } - function str_repeat(input, multiplier) { - for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */} - return output.join(''); - } - - var str_format = function() { - if (!str_format.cache.hasOwnProperty(arguments[0])) { - str_format.cache[arguments[0]] = str_format.parse(arguments[0]); - } - return str_format.format.call(null, str_format.cache[arguments[0]], arguments); - }; - - str_format.format = function(parse_tree, argv) { - var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length; - for (i = 0; i < tree_length; i++) { - node_type = get_type(parse_tree[i]); - if (node_type === 'string') { - output.push(parse_tree[i]); - } - else if (node_type === 'array') { - match = parse_tree[i]; // convenience purposes only - if (match[2]) { // keyword argument - arg = argv[cursor]; - for (k = 0; k < match[2].length; k++) { - if (!arg.hasOwnProperty(match[2][k])) { - //throw(sprintf('[sprintf] property "%s" does not exist', match[2][k])); - arg = ''; - } else { - arg = arg[match[2][k]]; - } - } - } - else if (match[1]) { // positional argument (explicit) - arg = argv[match[1]]; - } - else { // positional argument (implicit) - arg = argv[cursor++]; - } - - if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) { - throw(sprintf('[sprintf] expecting number but found %s', get_type(arg))); - } - switch (match[8]) { - case 'b': arg = arg.toString(2); break; - case 'c': arg = String.fromCharCode(arg); break; - case 'd': arg = parseInt(arg, 10); break; - case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break; - case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break; - case 'o': arg = arg.toString(8); break; - case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break; - case 'u': arg = Math.abs(arg); break; - case 'x': arg = arg.toString(16); break; - case 'X': arg = arg.toString(16).toUpperCase(); break; - } - arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg); - pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' '; - pad_length = match[6] - String(arg).length; - pad = match[6] ? str_repeat(pad_character, pad_length) : ''; - output.push(match[5] ? arg + pad : pad + arg); - } - } - return output.join(''); - }; - - str_format.cache = {}; - - str_format.parse = function(fmt) { - var _fmt = fmt, match = [], parse_tree = [], arg_names = 0; - while (_fmt) { - if ((match = /^[^\x25]+/.exec(_fmt)) !== null) { - parse_tree.push(match[0]); - } - else if ((match = /^\x25{2}/.exec(_fmt)) !== null) { - parse_tree.push('%'); - } - else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) { - if (match[2]) { - arg_names |= 1; - var field_list = [], replacement_field = match[2], field_match = []; - if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { - field_list.push(field_match[1]); - while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') { - if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) { - field_list.push(field_match[1]); - } - else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) { - field_list.push(field_match[1]); - } - else { - throw('[sprintf] huh?'); - } - } - } - else { - throw('[sprintf] huh?'); - } - match[2] = field_list; - } - else { - arg_names |= 2; - } - if (arg_names === 3) { - throw('[sprintf] mixing positional and named placeholders is not (yet) supported'); - } - parse_tree.push(match); - } - else { - throw('[sprintf] huh?'); - } - _fmt = _fmt.substring(match[0].length); - } - return parse_tree; - }; - - return str_format; -})(); - -var vsprintf = function(fmt, argv) { - argv.unshift(fmt); - return sprintf.apply(null, argv); -}; diff --git a/frappe/website/js/jquery.canvasResize.js b/frappe/website/js/jquery.canvasResize.js deleted file mode 100644 index 0f8a352b7b..0000000000 --- a/frappe/website/js/jquery.canvasResize.js +++ /dev/null @@ -1,313 +0,0 @@ -/* - * jQuery canvasResize plugin - * - * Version: 1.2.0 - * Date (d/m/y): 02/10/12 - * Update (d/m/y): 14/05/13 - * Original author: @gokercebeci - * Licensed under the MIT license - * - This plugin working with jquery.exif.js - * (It's under the MPL License http://www.nihilogic.dk/licenses/mpl-license.txt) - * Demo: http://ios6-image-resize.gokercebeci.com/ - * - * - I fixed iOS6 Safari's image file rendering issue for large size image (over mega-pixel) - * using few functions from https://github.com/stomita/ios-imagefile-megapixel - * (detectSubsampling, ) - * And fixed orientation issue by edited http://blog.nihilogic.dk/2008/05/jquery-exif-data-plugin.html - * Thanks, Shinichi Tomita and Jacob Seidelin - */ - -(function($) { - var pluginName = 'canvasResize', - methods = { - newsize: function(w, h, W, H, C) { - var c = C ? 'h' : ''; - if ((W && w > W) || (H && h > H)) { - var r = w / h; - if ((r >= 1 || H === 0) && W && !C) { - w = W; - h = (W / r) >> 0; - } else if (C && r <= (W / H)) { - w = W; - h = (W / r) >> 0; - c = 'w'; - } else { - w = (H * r) >> 0; - h = H; - } - } - return { - 'width': w, - 'height': h, - 'cropped': c - }; - }, - dataURLtoBlob: function(data) { - var mimeString = data.split(',')[0].split(':')[1].split(';')[0]; - var byteString = atob(data.split(',')[1]); - var ab = new ArrayBuffer(byteString.length); - var ia = new Uint8Array(ab); - for (var i = 0; i < byteString.length; i++) { - ia[i] = byteString.charCodeAt(i); - } - var bb = (window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder); - if (bb) { - // console.log('BlobBuilder'); - bb = new (window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder)(); - bb.append(ab); - return bb.getBlob(mimeString); - } else { - // console.log('Blob'); - bb = new Blob([ab], { - 'type': (mimeString) - }); - return bb; - } - }, - /** - * Detect subsampling in loaded image. - * In iOS, larger images than 2M pixels may be subsampled in rendering. - */ - detectSubsampling: function(img) { - var iw = img.width, ih = img.height; - if (iw * ih > 1048576) { // subsampling may happen over megapixel image - var canvas = document.createElement('canvas'); - canvas.width = canvas.height = 1; - var ctx = canvas.getContext('2d'); - ctx.drawImage(img, -iw + 1, 0); - // subsampled image becomes half smaller in rendering size. - // check alpha channel value to confirm image is covering edge pixel or not. - // if alpha value is 0 image is not covering, hence subsampled. - return ctx.getImageData(0, 0, 1, 1).data[3] === 0; - } else { - return false; - } - }, - /** - * Update the orientation according to the specified rotation angle - */ - rotate: function(orientation, angle) { - var o = { - // nothing - 1: {90: 6, 180: 3, 270: 8}, - // horizontal flip - 2: {90: 7, 180: 4, 270: 5}, - // 180 rotate left - 3: {90: 8, 180: 1, 270: 6}, - // vertical flip - 4: {90: 5, 180: 2, 270: 7}, - // vertical flip + 90 rotate right - 5: {90: 2, 180: 7, 270: 4}, - // 90 rotate right - 6: {90: 3, 180: 8, 270: 1}, - // horizontal flip + 90 rotate right - 7: {90: 4, 180: 5, 270: 2}, - // 90 rotate left - 8: {90: 1, 180: 6, 270: 3} - }; - return o[orientation][angle] ? o[orientation][angle] : orientation; - }, - /** - * Transform canvas coordination according to specified frame size and orientation - * Orientation value is from EXIF tag - */ - transformCoordinate: function(canvas, width, height, orientation) { - //console.log(width, height); - switch (orientation) { - case 5: - case 6: - case 7: - case 8: - canvas.width = height; - canvas.height = width; - break; - default: - canvas.width = width; - canvas.height = height; - } - var ctx = canvas.getContext('2d'); - switch (orientation) { - case 1: - // nothing - break; - case 2: - // horizontal flip - ctx.translate(width, 0); - ctx.scale(-1, 1); - break; - case 3: - // 180 rotate left - ctx.translate(width, height); - ctx.rotate(Math.PI); - break; - case 4: - // vertical flip - ctx.translate(0, height); - ctx.scale(1, -1); - break; - case 5: - // vertical flip + 90 rotate right - ctx.rotate(0.5 * Math.PI); - ctx.scale(1, -1); - break; - case 6: - // 90 rotate right - ctx.rotate(0.5 * Math.PI); - ctx.translate(0, -height); - break; - case 7: - // horizontal flip + 90 rotate right - ctx.rotate(0.5 * Math.PI); - ctx.translate(width, -height); - ctx.scale(-1, 1); - break; - case 8: - // 90 rotate left - ctx.rotate(-0.5 * Math.PI); - ctx.translate(-width, 0); - break; - default: - break; - } - }, - /** - * Detecting vertical squash in loaded image. - * Fixes a bug which squash image vertically while drawing into canvas for some images. - */ - detectVerticalSquash: function(img, iw, ih) { - var canvas = document.createElement('canvas'); - canvas.width = 1; - canvas.height = ih; - var ctx = canvas.getContext('2d'); - ctx.drawImage(img, 0, 0); - var data = ctx.getImageData(0, 0, 1, ih).data; - // search image edge pixel position in case it is squashed vertically. - var sy = 0; - var ey = ih; - var py = ih; - while (py > sy) { - var alpha = data[(py - 1) * 4 + 3]; - if (alpha === 0) { - ey = py; - } else { - sy = py; - } - py = (ey + sy) >> 1; - } - var ratio = py / ih; - return ratio === 0 ? 1 : ratio; - }, - callback: function(d) { - return d; - } - }, - defaults = { - width: 300, - height: 0, - crop: false, - quality: 80, - 'callback': methods.callback - }; - function Plugin(file, options) { - this.file = file; - this.options = $.extend({}, defaults, options); - this._defaults = defaults; - this._name = pluginName; - this.init(); - } - Plugin.prototype = { - init: function() { - //this.options.init(this); - var $this = this; - var file = this.file; - - var reader = new FileReader(); - reader.onloadend = function(e) { - var dataURL = e.target.result; - var img = new Image(); - img.onload = function(e) { - // Read Orientation Data in EXIF - $(img).exifLoadFromDataURL(function() { - var orientation = $(img).exif('Orientation')[0] || 1; - orientation = methods.rotate(orientation, $this.options.rotate); - - // CW or CCW ? replace width and height - var size = (orientation >= 5 && orientation <= 8) - ? methods.newsize(img.height, img.width, $this.options.width, $this.options.height, $this.options.crop) - : methods.newsize(img.width, img.height, $this.options.width, $this.options.height, $this.options.crop); - - var iw = img.width, ih = img.height; - var width = size.width, height = size.height; - - //console.log(iw, ih, size.width, size.height, orientation); - - var canvas = document.createElement("canvas"); - var ctx = canvas.getContext("2d"); - ctx.save(); - methods.transformCoordinate(canvas, width, height, orientation); - - // over image size - if (methods.detectSubsampling(img)) { - iw /= 2; - ih /= 2; - } - var d = 1024; // size of tiling canvas - var tmpCanvas = document.createElement('canvas'); - tmpCanvas.width = tmpCanvas.height = d; - var tmpCtx = tmpCanvas.getContext('2d'); - var vertSquashRatio = methods.detectVerticalSquash(img, iw, ih); - var sy = 0; - while (sy < ih) { - var sh = sy + d > ih ? ih - sy : d; - var sx = 0; - while (sx < iw) { - var sw = sx + d > iw ? iw - sx : d; - tmpCtx.clearRect(0, 0, d, d); - tmpCtx.drawImage(img, -sx, -sy); - var dx = Math.floor(sx * width / iw); - var dw = Math.ceil(sw * width / iw); - var dy = Math.floor(sy * height / ih / vertSquashRatio); - var dh = Math.ceil(sh * height / ih / vertSquashRatio); - ctx.drawImage(tmpCanvas, 0, 0, sw, sh, dx, dy, dw, dh); - sx += d; - } - sy += d; - } - ctx.restore(); - tmpCanvas = tmpCtx = null; - - // if cropped or rotated width and height data replacing issue - var newcanvas = document.createElement('canvas'); - newcanvas.width = size.cropped === 'h' ? height : width; - newcanvas.height = size.cropped === 'w' ? width : height; - var x = size.cropped === 'h' ? (height - width) * .5 : 0; - var y = size.cropped === 'w' ? (width - height) * .5 : 0; - newctx = newcanvas.getContext('2d'); - newctx.drawImage(canvas, x, y, width, height); - - if (file.type === "image/png") { - var data = newcanvas.toDataURL(file.type); - } else { - var data = newcanvas.toDataURL("image/jpeg", ($this.options.quality * .01)); - } - - // CALLBACK - $this.options.callback(data, width, height); - - }); - }; - img.src = dataURL; - // ===================================================== - }; - reader.readAsDataURL(file); - - } - }; - $[pluginName] = function(file, options) { - if (typeof file === 'string') - return methods[file](options); - else - new Plugin(file, options); - }; - -})(jQuery); \ No newline at end of file diff --git a/frappe/website/js/jquery.exif.js b/frappe/website/js/jquery.exif.js deleted file mode 100644 index 15b891bf3c..0000000000 --- a/frappe/website/js/jquery.exif.js +++ /dev/null @@ -1,957 +0,0 @@ - -/* - * Javascript EXIF Reader - jQuery plugin 0.1.3 - * Copyright (c) 2008 Jacob Seidelin, cupboy@gmail.com, http://blog.nihilogic.dk/ - * Licensed under the MPL License [http://www.nihilogic.dk/licenses/mpl-license.txt] - */ - -/* - * I added three functions for read EXIF from dataURL - * - getImageDataFromDataURL - * - getDataFromDataURL - * - jQuery.fn.exifLoadFromDataURL - * - * http://orientation.gokercebeci.com - * @gokercebeci - */ - -(function() { - - - var BinaryFile = function(strData, iDataOffset, iDataLength) { - var data = strData; - var dataOffset = iDataOffset || 0; - var dataLength = 0; - - this.getRawData = function() { - return data; - } - - if (typeof strData == "string") { - dataLength = iDataLength || data.length; - - this.getByteAt = function(iOffset) { - return data.charCodeAt(iOffset + dataOffset) & 0xFF; - } - } else if (typeof strData == "unknown") { - dataLength = iDataLength || IEBinary_getLength(data); - - this.getByteAt = function(iOffset) { - return IEBinary_getByteAt(data, iOffset + dataOffset); - } - } - - this.getLength = function() { - return dataLength; - } - - this.getSByteAt = function(iOffset) { - var iByte = this.getByteAt(iOffset); - if (iByte > 127) - return iByte - 256; - else - return iByte; - } - - this.getShortAt = function(iOffset, bBigEndian) { - var iShort = bBigEndian ? - (this.getByteAt(iOffset) << 8) + this.getByteAt(iOffset + 1) - : (this.getByteAt(iOffset + 1) << 8) + this.getByteAt(iOffset) - if (iShort < 0) - iShort += 65536; - return iShort; - } - this.getSShortAt = function(iOffset, bBigEndian) { - var iUShort = this.getShortAt(iOffset, bBigEndian); - if (iUShort > 32767) - return iUShort - 65536; - else - return iUShort; - } - this.getLongAt = function(iOffset, bBigEndian) { - var iByte1 = this.getByteAt(iOffset), - iByte2 = this.getByteAt(iOffset + 1), - iByte3 = this.getByteAt(iOffset + 2), - iByte4 = this.getByteAt(iOffset + 3); - - var iLong = bBigEndian ? - (((((iByte1 << 8) + iByte2) << 8) + iByte3) << 8) + iByte4 - : (((((iByte4 << 8) + iByte3) << 8) + iByte2) << 8) + iByte1; - if (iLong < 0) - iLong += 4294967296; - return iLong; - } - this.getSLongAt = function(iOffset, bBigEndian) { - var iULong = this.getLongAt(iOffset, bBigEndian); - if (iULong > 2147483647) - return iULong - 4294967296; - else - return iULong; - } - this.getStringAt = function(iOffset, iLength) { - var aStr = []; - for (var i = iOffset, j = 0; i < iOffset + iLength; i++, j++) { - aStr[j] = String.fromCharCode(this.getByteAt(i)); - } - return aStr.join(""); - } - - this.getCharAt = function(iOffset) { - return String.fromCharCode(this.getByteAt(iOffset)); - } - this.toBase64 = function() { - return window.btoa(data); - } - this.fromBase64 = function(strBase64) { - data = window.atob(strBase64); - } - } - - - var BinaryAjax = (function() { - - function createRequest() { - var oHTTP = null; - if (window.XMLHttpRequest) { - oHTTP = new XMLHttpRequest(); - } else if (window.ActiveXObject) { - oHTTP = new ActiveXObject("Microsoft.XMLHTTP"); - } - return oHTTP; - } - - function getHead(strURL, fncCallback, fncError) { - var oHTTP = createRequest(); - if (oHTTP) { - if (fncCallback) { - if (typeof(oHTTP.onload) != "undefined") { - oHTTP.onload = function() { - if (oHTTP.status == "200") { - fncCallback(this); - } else { - if (fncError) - fncError(); - } - oHTTP = null; - }; - } else { - oHTTP.onreadystatechange = function() { - if (oHTTP.readyState == 4) { - if (oHTTP.status == "200") { - fncCallback(this); - } else { - if (fncError) - fncError(); - } - oHTTP = null; - } - }; - } - } - oHTTP.open("HEAD", strURL, true); - oHTTP.send(null); - } else { - if (fncError) - fncError(); - } - } - - function sendRequest(strURL, fncCallback, fncError, aRange, bAcceptRanges, iFileSize) { - var oHTTP = createRequest(); - if (oHTTP) { - - var iDataOffset = 0; - if (aRange && !bAcceptRanges) { - iDataOffset = aRange[0]; - } - var iDataLen = 0; - if (aRange) { - iDataLen = aRange[1] - aRange[0] + 1; - } - - if (fncCallback) { - if (typeof(oHTTP.onload) != "undefined") { - oHTTP.onload = function() { - - if (oHTTP.status == "200" || oHTTP.status == "206" || oHTTP.status == "0") { - this.binaryResponse = new BinaryFile(this.responseText, iDataOffset, iDataLen); - this.fileSize = iFileSize || this.getResponseHeader("Content-Length"); - fncCallback(this); - } else { - if (fncError) - fncError(); - } - oHTTP = null; - }; - } else { - oHTTP.onreadystatechange = function() { - if (oHTTP.readyState == 4) { - if (oHTTP.status == "200" || oHTTP.status == "206" || oHTTP.status == "0") { - this.binaryResponse = new BinaryFile(oHTTP.responseBody, iDataOffset, iDataLen); - this.fileSize = iFileSize || this.getResponseHeader("Content-Length"); - fncCallback(this); - } else { - if (fncError) - fncError(); - } - oHTTP = null; - } - }; - } - } - oHTTP.open("GET", strURL, true); - - if (oHTTP.overrideMimeType) - oHTTP.overrideMimeType('text/plain; charset=x-user-defined'); - - if (aRange && bAcceptRanges) { - oHTTP.setRequestHeader("Range", "bytes=" + aRange[0] + "-" + aRange[1]); - } - - oHTTP.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 1970 00:00:00 GMT"); - - oHTTP.send(null); - } else { - if (fncError) - fncError(); - } - } - - return function(strURL, fncCallback, fncError, aRange) { - - if (aRange) { - getHead( - strURL, - function(oHTTP) { - var iLength = parseInt(oHTTP.getResponseHeader("Content-Length"), 10); - var strAcceptRanges = oHTTP.getResponseHeader("Accept-Ranges"); - - var iStart, iEnd; - iStart = aRange[0]; - if (aRange[0] < 0) - iStart += iLength; - iEnd = iStart + aRange[1] - 1; - - sendRequest(strURL, fncCallback, fncError, [iStart, iEnd], (strAcceptRanges == "bytes"), iLength); - } - ); - - } else { - sendRequest(strURL, fncCallback, fncError); - } - } - - }()); - - var script = document.createElement("script"); - script.type = 'text/vbscript'; - script.innerHTML = - "Function IEBinary_getByteAt(strBinary, iOffset)\r\n" - + " IEBinary_getByteAt = AscB(MidB(strBinary,iOffset+1,1))\r\n" - + "End Function\r\n" - + "Function IEBinary_getLength(strBinary)\r\n" - + " IEBinary_getLength = LenB(strBinary)\r\n" - + "End Function"; - document.head.appendChild(script); - - var EXIF = {}; - - (function() { - - var bDebug = false; - - EXIF.Tags = { - - // version tags - 0x9000: "ExifVersion", // EXIF version - 0xA000: "FlashpixVersion", // Flashpix format version - - // colorspace tags - 0xA001: "ColorSpace", // Color space information tag - - // image configuration - 0xA002: "PixelXDimension", // Valid width of meaningful image - 0xA003: "PixelYDimension", // Valid height of meaningful image - 0x9101: "ComponentsConfiguration", // Information about channels - 0x9102: "CompressedBitsPerPixel", // Compressed bits per pixel - - // user information - 0x927C: "MakerNote", // Any desired information written by the manufacturer - 0x9286: "UserComment", // Comments by user - - // related file - 0xA004: "RelatedSoundFile", // Name of related sound file - - // date and time - 0x9003: "DateTimeOriginal", // Date and time when the original image was generated - 0x9004: "DateTimeDigitized", // Date and time when the image was stored digitally - 0x9290: "SubsecTime", // Fractions of seconds for DateTime - 0x9291: "SubsecTimeOriginal", // Fractions of seconds for DateTimeOriginal - 0x9292: "SubsecTimeDigitized", // Fractions of seconds for DateTimeDigitized - - // picture-taking conditions - 0x829A: "ExposureTime", // Exposure time (in seconds) - 0x829D: "FNumber", // F number - 0x8822: "ExposureProgram", // Exposure program - 0x8824: "SpectralSensitivity", // Spectral sensitivity - 0x8827: "ISOSpeedRatings", // ISO speed rating - 0x8828: "OECF", // Optoelectric conversion factor - 0x9201: "ShutterSpeedValue", // Shutter speed - 0x9202: "ApertureValue", // Lens aperture - 0x9203: "BrightnessValue", // Value of brightness - 0x9204: "ExposureBias", // Exposure bias - 0x9205: "MaxApertureValue", // Smallest F number of lens - 0x9206: "SubjectDistance", // Distance to subject in meters - 0x9207: "MeteringMode", // Metering mode - 0x9208: "LightSource", // Kind of light source - 0x9209: "Flash", // Flash status - 0x9214: "SubjectArea", // Location and area of main subject - 0x920A: "FocalLength", // Focal length of the lens in mm - 0xA20B: "FlashEnergy", // Strobe energy in BCPS - 0xA20C: "SpatialFrequencyResponse", // - 0xA20E: "FocalPlaneXResolution", // Number of pixels in width direction per FocalPlaneResolutionUnit - 0xA20F: "FocalPlaneYResolution", // Number of pixels in height direction per FocalPlaneResolutionUnit - 0xA210: "FocalPlaneResolutionUnit", // Unit for measuring FocalPlaneXResolution and FocalPlaneYResolution - 0xA214: "SubjectLocation", // Location of subject in image - 0xA215: "ExposureIndex", // Exposure index selected on camera - 0xA217: "SensingMethod", // Image sensor type - 0xA300: "FileSource", // Image source (3 == DSC) - 0xA301: "SceneType", // Scene type (1 == directly photographed) - 0xA302: "CFAPattern", // Color filter array geometric pattern - 0xA401: "CustomRendered", // Special processing - 0xA402: "ExposureMode", // Exposure mode - 0xA403: "WhiteBalance", // 1 = auto white balance, 2 = manual - 0xA404: "DigitalZoomRation", // Digital zoom ratio - 0xA405: "FocalLengthIn35mmFilm", // Equivalent foacl length assuming 35mm film camera (in mm) - 0xA406: "SceneCaptureType", // Type of scene - 0xA407: "GainControl", // Degree of overall image gain adjustment - 0xA408: "Contrast", // Direction of contrast processing applied by camera - 0xA409: "Saturation", // Direction of saturation processing applied by camera - 0xA40A: "Sharpness", // Direction of sharpness processing applied by camera - 0xA40B: "DeviceSettingDescription", // - 0xA40C: "SubjectDistanceRange", // Distance to subject - - // other tags - 0xA005: "InteroperabilityIFDPointer", - 0xA420: "ImageUniqueID" // Identifier assigned uniquely to each image - }; - - EXIF.TiffTags = { - 0x0100: "ImageWidth", - 0x0101: "ImageHeight", - 0x8769: "ExifIFDPointer", - 0x8825: "GPSInfoIFDPointer", - 0xA005: "InteroperabilityIFDPointer", - 0x0102: "BitsPerSample", - 0x0103: "Compression", - 0x0106: "PhotometricInterpretation", - 0x0112: "Orientation", - 0x0115: "SamplesPerPixel", - 0x011C: "PlanarConfiguration", - 0x0212: "YCbCrSubSampling", - 0x0213: "YCbCrPositioning", - 0x011A: "XResolution", - 0x011B: "YResolution", - 0x0128: "ResolutionUnit", - 0x0111: "StripOffsets", - 0x0116: "RowsPerStrip", - 0x0117: "StripByteCounts", - 0x0201: "JPEGInterchangeFormat", - 0x0202: "JPEGInterchangeFormatLength", - 0x012D: "TransferFunction", - 0x013E: "WhitePoint", - 0x013F: "PrimaryChromaticities", - 0x0211: "YCbCrCoefficients", - 0x0214: "ReferenceBlackWhite", - 0x0132: "DateTime", - 0x010E: "ImageDescription", - 0x010F: "Make", - 0x0110: "Model", - 0x0131: "Software", - 0x013B: "Artist", - 0x8298: "Copyright" - } - - EXIF.GPSTags = { - 0x0000: "GPSVersionID", - 0x0001: "GPSLatitudeRef", - 0x0002: "GPSLatitude", - 0x0003: "GPSLongitudeRef", - 0x0004: "GPSLongitude", - 0x0005: "GPSAltitudeRef", - 0x0006: "GPSAltitude", - 0x0007: "GPSTimeStamp", - 0x0008: "GPSSatellites", - 0x0009: "GPSStatus", - 0x000A: "GPSMeasureMode", - 0x000B: "GPSDOP", - 0x000C: "GPSSpeedRef", - 0x000D: "GPSSpeed", - 0x000E: "GPSTrackRef", - 0x000F: "GPSTrack", - 0x0010: "GPSImgDirectionRef", - 0x0011: "GPSImgDirection", - 0x0012: "GPSMapDatum", - 0x0013: "GPSDestLatitudeRef", - 0x0014: "GPSDestLatitude", - 0x0015: "GPSDestLongitudeRef", - 0x0016: "GPSDestLongitude", - 0x0017: "GPSDestBearingRef", - 0x0018: "GPSDestBearing", - 0x0019: "GPSDestDistanceRef", - 0x001A: "GPSDestDistance", - 0x001B: "GPSProcessingMethod", - 0x001C: "GPSAreaInformation", - 0x001D: "GPSDateStamp", - 0x001E: "GPSDifferential" - } - - EXIF.StringValues = { - ExposureProgram: { - 0: "Not defined", - 1: "Manual", - 2: "Normal program", - 3: "Aperture priority", - 4: "Shutter priority", - 5: "Creative program", - 6: "Action program", - 7: "Portrait mode", - 8: "Landscape mode" - }, - MeteringMode: { - 0: "Unknown", - 1: "Average", - 2: "CenterWeightedAverage", - 3: "Spot", - 4: "MultiSpot", - 5: "Pattern", - 6: "Partial", - 255: "Other" - }, - LightSource: { - 0: "Unknown", - 1: "Daylight", - 2: "Fluorescent", - 3: "Tungsten (incandescent light)", - 4: "Flash", - 9: "Fine weather", - 10: "Cloudy weather", - 11: "Shade", - 12: "Daylight fluorescent (D 5700 - 7100K)", - 13: "Day white fluorescent (N 4600 - 5400K)", - 14: "Cool white fluorescent (W 3900 - 4500K)", - 15: "White fluorescent (WW 3200 - 3700K)", - 17: "Standard light A", - 18: "Standard light B", - 19: "Standard light C", - 20: "D55", - 21: "D65", - 22: "D75", - 23: "D50", - 24: "ISO studio tungsten", - 255: "Other" - }, - Flash: { - 0x0000: "Flash did not fire", - 0x0001: "Flash fired", - 0x0005: "Strobe return light not detected", - 0x0007: "Strobe return light detected", - 0x0009: "Flash fired, compulsory flash mode", - 0x000D: "Flash fired, compulsory flash mode, return light not detected", - 0x000F: "Flash fired, compulsory flash mode, return light detected", - 0x0010: "Flash did not fire, compulsory flash mode", - 0x0018: "Flash did not fire, auto mode", - 0x0019: "Flash fired, auto mode", - 0x001D: "Flash fired, auto mode, return light not detected", - 0x001F: "Flash fired, auto mode, return light detected", - 0x0020: "No flash function", - 0x0041: "Flash fired, red-eye reduction mode", - 0x0045: "Flash fired, red-eye reduction mode, return light not detected", - 0x0047: "Flash fired, red-eye reduction mode, return light detected", - 0x0049: "Flash fired, compulsory flash mode, red-eye reduction mode", - 0x004D: "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected", - 0x004F: "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected", - 0x0059: "Flash fired, auto mode, red-eye reduction mode", - 0x005D: "Flash fired, auto mode, return light not detected, red-eye reduction mode", - 0x005F: "Flash fired, auto mode, return light detected, red-eye reduction mode" - }, - SensingMethod: { - 1: "Not defined", - 2: "One-chip color area sensor", - 3: "Two-chip color area sensor", - 4: "Three-chip color area sensor", - 5: "Color sequential area sensor", - 7: "Trilinear sensor", - 8: "Color sequential linear sensor" - }, - SceneCaptureType: { - 0: "Standard", - 1: "Landscape", - 2: "Portrait", - 3: "Night scene" - }, - SceneType: { - 1: "Directly photographed" - }, - CustomRendered: { - 0: "Normal process", - 1: "Custom process" - }, - WhiteBalance: { - 0: "Auto white balance", - 1: "Manual white balance" - }, - GainControl: { - 0: "None", - 1: "Low gain up", - 2: "High gain up", - 3: "Low gain down", - 4: "High gain down" - }, - Contrast: { - 0: "Normal", - 1: "Soft", - 2: "Hard" - }, - Saturation: { - 0: "Normal", - 1: "Low saturation", - 2: "High saturation" - }, - Sharpness: { - 0: "Normal", - 1: "Soft", - 2: "Hard" - }, - SubjectDistanceRange: { - 0: "Unknown", - 1: "Macro", - 2: "Close view", - 3: "Distant view" - }, - FileSource: { - 3: "DSC" - }, - Components: { - 0: "", - 1: "Y", - 2: "Cb", - 3: "Cr", - 4: "R", - 5: "G", - 6: "B" - } - } - - function addEvent(oElement, strEvent, fncHandler) - { - if (oElement.addEventListener) { - oElement.addEventListener(strEvent, fncHandler, false); - } else if (oElement.attachEvent) { - oElement.attachEvent("on" + strEvent, fncHandler); - } - } - - - function imageHasData(oImg) - { - return !!(oImg.exifdata); - } - - function getImageData(oImg, fncCallback) - { - BinaryAjax( - oImg.src, - function(oHTTP) { - console.log('BINARY', oHTTP.binaryResponse); - var oEXIF = findEXIFinJPEG(oHTTP.binaryResponse); - oImg.exifdata = oEXIF || {}; - if (fncCallback) - fncCallback(); - } - ) - } - - function getImageDataFromDataURL(oImg, fncCallback) - { - var byteString = atob(oImg.src.split(',')[1]); - var f = new BinaryFile(byteString, 0, byteString.length) - var oEXIF = findEXIFinJPEG(f); - oImg.exifdata = oEXIF || {}; - if (fncCallback) - fncCallback(); - } - - function findEXIFinJPEG(oFile) { - var aMarkers = []; - - if (oFile.getByteAt(0) != 0xFF || oFile.getByteAt(1) != 0xD8) { - return false; // not a valid jpeg - } - - var iOffset = 2; - var iLength = oFile.getLength(); - while (iOffset < iLength) { - if (oFile.getByteAt(iOffset) != 0xFF) { - if (bDebug) - console.log("Not a valid marker at offset " + iOffset + ", found: " + oFile.getByteAt(iOffset)); - return false; // not a valid marker, something is wrong - } - - var iMarker = oFile.getByteAt(iOffset + 1); - - // we could implement handling for other markers here, - // but we're only looking for 0xFFE1 for EXIF data - - if (iMarker == 22400) { - if (bDebug) - console.log("Found 0xFFE1 marker"); - return readEXIFData(oFile, iOffset + 4, oFile.getShortAt(iOffset + 2, true) - 2); - iOffset += 2 + oFile.getShortAt(iOffset + 2, true); - - } else if (iMarker == 225) { - // 0xE1 = Application-specific 1 (for EXIF) - if (bDebug) - console.log("Found 0xFFE1 marker"); - return readEXIFData(oFile, iOffset + 4, oFile.getShortAt(iOffset + 2, true) - 2); - - } else { - iOffset += 2 + oFile.getShortAt(iOffset + 2, true); - } - - } - - } - - - function readTags(oFile, iTIFFStart, iDirStart, oStrings, bBigEnd) - { - var iEntries = oFile.getShortAt(iDirStart, bBigEnd); - var oTags = {}; - for (var i = 0; i < iEntries; i++) { - var iEntryOffset = iDirStart + i * 12 + 2; - var strTag = oStrings[oFile.getShortAt(iEntryOffset, bBigEnd)]; - if (!strTag && bDebug) - console.log("Unknown tag: " + oFile.getShortAt(iEntryOffset, bBigEnd)); - oTags[strTag] = readTagValue(oFile, iEntryOffset, iTIFFStart, iDirStart, bBigEnd); - } - return oTags; - } - - - function readTagValue(oFile, iEntryOffset, iTIFFStart, iDirStart, bBigEnd) - { - var iType = oFile.getShortAt(iEntryOffset + 2, bBigEnd); - var iNumValues = oFile.getLongAt(iEntryOffset + 4, bBigEnd); - var iValueOffset = oFile.getLongAt(iEntryOffset + 8, bBigEnd) + iTIFFStart; - - switch (iType) { - case 1: // byte, 8-bit unsigned int - case 7: // undefined, 8-bit byte, value depending on field - if (iNumValues == 1) { - return oFile.getByteAt(iEntryOffset + 8, bBigEnd); - } else { - var iValOffset = iNumValues > 4 ? iValueOffset : (iEntryOffset + 8); - var aVals = []; - for (var n = 0; n < iNumValues; n++) { - aVals[n] = oFile.getByteAt(iValOffset + n); - } - return aVals; - } - break; - - case 2: // ascii, 8-bit byte - var iStringOffset = iNumValues > 4 ? iValueOffset : (iEntryOffset + 8); - return oFile.getStringAt(iStringOffset, iNumValues - 1); - break; - - case 3: // short, 16 bit int - if (iNumValues == 1) { - return oFile.getShortAt(iEntryOffset + 8, bBigEnd); - } else { - var iValOffset = iNumValues > 2 ? iValueOffset : (iEntryOffset + 8); - var aVals = []; - for (var n = 0; n < iNumValues; n++) { - aVals[n] = oFile.getShortAt(iValOffset + 2 * n, bBigEnd); - } - return aVals; - } - break; - - case 4: // long, 32 bit int - if (iNumValues == 1) { - return oFile.getLongAt(iEntryOffset + 8, bBigEnd); - } else { - var aVals = []; - for (var n = 0; n < iNumValues; n++) { - aVals[n] = oFile.getLongAt(iValueOffset + 4 * n, bBigEnd); - } - return aVals; - } - break; - case 5: // rational = two long values, first is numerator, second is denominator - if (iNumValues == 1) { - return oFile.getLongAt(iValueOffset, bBigEnd) / oFile.getLongAt(iValueOffset + 4, bBigEnd); - } else { - var aVals = []; - for (var n = 0; n < iNumValues; n++) { - aVals[n] = oFile.getLongAt(iValueOffset + 8 * n, bBigEnd) / oFile.getLongAt(iValueOffset + 4 + 8 * n, bBigEnd); - } - return aVals; - } - break; - case 9: // slong, 32 bit signed int - if (iNumValues == 1) { - return oFile.getSLongAt(iEntryOffset + 8, bBigEnd); - } else { - var aVals = []; - for (var n = 0; n < iNumValues; n++) { - aVals[n] = oFile.getSLongAt(iValueOffset + 4 * n, bBigEnd); - } - return aVals; - } - break; - case 10: // signed rational, two slongs, first is numerator, second is denominator - if (iNumValues == 1) { - return oFile.getSLongAt(iValueOffset, bBigEnd) / oFile.getSLongAt(iValueOffset + 4, bBigEnd); - } else { - var aVals = []; - for (var n = 0; n < iNumValues; n++) { - aVals[n] = oFile.getSLongAt(iValueOffset + 8 * n, bBigEnd) / oFile.getSLongAt(iValueOffset + 4 + 8 * n, bBigEnd); - } - return aVals; - } - break; - } - } - - - function readEXIFData(oFile, iStart, iLength) - { - if (oFile.getStringAt(iStart, 4) != "Exif") { - if (bDebug) - console.log("Not valid EXIF data! " + oFile.getStringAt(iStart, 4)); - return false; - } - - var bBigEnd; - - var iTIFFOffset = iStart + 6; - - // test for TIFF validity and endianness - if (oFile.getShortAt(iTIFFOffset) == 0x4949) { - bBigEnd = false; - } else if (oFile.getShortAt(iTIFFOffset) == 0x4D4D) { - bBigEnd = true; - } else { - if (bDebug) - console.log("Not valid TIFF data! (no 0x4949 or 0x4D4D)"); - return false; - } - - if (oFile.getShortAt(iTIFFOffset + 2, bBigEnd) != 0x002A) { - if (bDebug) - console.log("Not valid TIFF data! (no 0x002A)"); - return false; - } - - if (oFile.getLongAt(iTIFFOffset + 4, bBigEnd) != 0x00000008) { - if (bDebug) - console.log("Not valid TIFF data! (First offset not 8)", oFile.getShortAt(iTIFFOffset + 4, bBigEnd)); - return false; - } - - var oTags = readTags(oFile, iTIFFOffset, iTIFFOffset + 8, EXIF.TiffTags, bBigEnd); - - if (oTags.ExifIFDPointer) { - var oEXIFTags = readTags(oFile, iTIFFOffset, iTIFFOffset + oTags.ExifIFDPointer, EXIF.Tags, bBigEnd); - for (var strTag in oEXIFTags) { - switch (strTag) { - case "LightSource" : - case "Flash" : - case "MeteringMode" : - case "ExposureProgram" : - case "SensingMethod" : - case "SceneCaptureType" : - case "SceneType" : - case "CustomRendered" : - case "WhiteBalance" : - case "GainControl" : - case "Contrast" : - case "Saturation" : - case "Sharpness" : - case "SubjectDistanceRange" : - case "FileSource" : - oEXIFTags[strTag] = EXIF.StringValues[strTag][oEXIFTags[strTag]]; - break; - - case "ExifVersion" : - case "FlashpixVersion" : - oEXIFTags[strTag] = String.fromCharCode(oEXIFTags[strTag][0], oEXIFTags[strTag][1], oEXIFTags[strTag][2], oEXIFTags[strTag][3]); - break; - - case "ComponentsConfiguration" : - oEXIFTags[strTag] = - EXIF.StringValues.Components[oEXIFTags[strTag][0]] - + EXIF.StringValues.Components[oEXIFTags[strTag][1]] - + EXIF.StringValues.Components[oEXIFTags[strTag][2]] - + EXIF.StringValues.Components[oEXIFTags[strTag][3]]; - break; - } - oTags[strTag] = oEXIFTags[strTag]; - } - } - - if (oTags.GPSInfoIFDPointer) { - var oGPSTags = readTags(oFile, iTIFFOffset, iTIFFOffset + oTags.GPSInfoIFDPointer, EXIF.GPSTags, bBigEnd); - for (var strTag in oGPSTags) { - switch (strTag) { - case "GPSVersionID" : - oGPSTags[strTag] = oGPSTags[strTag][0] - + "." + oGPSTags[strTag][1] - + "." + oGPSTags[strTag][2] - + "." + oGPSTags[strTag][3]; - break; - } - oTags[strTag] = oGPSTags[strTag]; - } - } - - return oTags; - } - - - EXIF.getData = function(oImg, fncCallback) - { - if (!oImg.complete) - return false; - if (!imageHasData(oImg)) { - getImageData(oImg, fncCallback); - } else { - if (fncCallback) - fncCallback(); - } - return true; - } - - EXIF.getDataFromDataURL = function(oImg, fncCallback) - { - if (!oImg.complete) - return false; - if (!imageHasData(oImg)) { - getImageDataFromDataURL(oImg, fncCallback); - } else { - if (fncCallback) - fncCallback(); - } - return true; - } - - EXIF.getTag = function(oImg, strTag) - { - if (!imageHasData(oImg)) - return; - return oImg.exifdata[strTag]; - } - - EXIF.getAllTags = function(oImg) - { - if (!imageHasData(oImg)) - return {}; - var oData = oImg.exifdata; - var oAllTags = {}; - for (var a in oData) { - if (oData.hasOwnProperty(a)) { - oAllTags[a] = oData[a]; - } - } - return oAllTags; - } - - EXIF.pretty = function(oImg) - { - if (!imageHasData(oImg)) - return ""; - var oData = oImg.exifdata; - var strPretty = ""; - for (var a in oData) { - if (oData.hasOwnProperty(a)) { - if (typeof oData[a] == "object") { - strPretty += a + " : [" + oData[a].length + " values]\r\n"; - } else { - strPretty += a + " : " + oData[a] + "\r\n"; - } - } - } - return strPretty; - } - - EXIF.readFromBinaryFile = function(oFile) { - return findEXIFinJPEG(oFile); - } - - function loadAllImages() - { - var aImages = document.getElementsByTagName("img"); - for (var i = 0; i < aImages.length; i++) { - if (aImages[i].getAttribute("exif") == "true") { - if (!aImages[i].complete) { - addEvent(aImages[i], "load", - function() { - EXIF.getData(this); - } - ); - } else { - EXIF.getData(aImages[i]); - } - } - } - } - - // automatically load exif data for all images with exif=true when doc is ready - jQuery(document).ready(loadAllImages); - - // load data for images manually - jQuery.fn.exifLoad = function(fncCallback) { - return this.each(function() { - EXIF.getData(this, fncCallback) - }); - } - - // load data for images manually - jQuery.fn.exifLoadFromDataURL = function(fncCallback) { - return this.each(function() { - EXIF.getDataFromDataURL(this, fncCallback) - return true; - }); - } - - jQuery.fn.exif = function(strTag) { - var aStrings = []; - this.each(function() { - aStrings.push(EXIF.getTag(this, strTag)); - }); - return aStrings; - } - - jQuery.fn.exifAll = function() { - var aStrings = []; - this.each(function() { - aStrings.push(EXIF.getAllTags(this)); - }); - return aStrings; - } - - jQuery.fn.exifPretty = function() { - var aStrings = []; - this.each(function() { - aStrings.push(EXIF.pretty(this)); - }); - return aStrings; - } - - - })(); - - -})();