aboutsummaryrefslogtreecommitdiffstats
path: root/library/cropperjs/src/js/utilities.js
diff options
context:
space:
mode:
authorzotlabs <mike@macgirvin.com>2020-01-14 13:34:56 -0800
committerzotlabs <mike@macgirvin.com>2020-01-14 13:34:56 -0800
commit293d411efb28b8f20a0208e3c52883e9fbb8cea7 (patch)
treea8b0af66015815d56342daf8301ab5ae095eda0a /library/cropperjs/src/js/utilities.js
parent2a287e6def5ab54037222c963ab0875faf62fc1a (diff)
parentd96f4340e80207a29a5c1c49cae8c25e3934d5ae (diff)
downloadvolse-hubzilla-293d411efb28b8f20a0208e3c52883e9fbb8cea7.tar.gz
volse-hubzilla-293d411efb28b8f20a0208e3c52883e9fbb8cea7.tar.bz2
volse-hubzilla-293d411efb28b8f20a0208e3c52883e9fbb8cea7.zip
Merge branch 'dev' of https://framagit.org/hubzilla/core into dev
Diffstat (limited to 'library/cropperjs/src/js/utilities.js')
-rw-r--r--library/cropperjs/src/js/utilities.js524
1 files changed, 251 insertions, 273 deletions
diff --git a/library/cropperjs/src/js/utilities.js b/library/cropperjs/src/js/utilities.js
index 50b586a76..bb5c7c24c 100644
--- a/library/cropperjs/src/js/utilities.js
+++ b/library/cropperjs/src/js/utilities.js
@@ -1,6 +1,4 @@
-import {
- WINDOW,
-} from './constants';
+import { IS_BROWSER, WINDOW } from './constants';
/**
* Check if the given value is not a number.
@@ -17,6 +15,13 @@ export function isNumber(value) {
}
/**
+ * Check if the given value is a positive number.
+ * @param {*} value - The value to check.
+ * @returns {boolean} Returns `true` if the given value is a positive number, else `false`.
+ */
+export const isPositiveNumber = (value) => value > 0 && value < Infinity;
+
+/**
* Check if the given value is undefined.
* @param {*} value - The value to check.
* @returns {boolean} Returns `true` if the given value is undefined, else `false`.
@@ -51,7 +56,7 @@ export function isPlainObject(value) {
const { prototype } = constructor;
return constructor && prototype && hasOwnProperty.call(prototype, 'isPrototypeOf');
- } catch (e) {
+ } catch (error) {
return false;
}
}
@@ -65,23 +70,29 @@ export function isFunction(value) {
return typeof value === 'function';
}
+const { slice } = Array.prototype;
+
+/**
+ * Convert array-like or iterable object to an array.
+ * @param {*} value - The value to convert.
+ * @returns {Array} Returns a new array.
+ */
+export function toArray(value) {
+ return Array.from ? Array.from(value) : slice.call(value);
+}
+
/**
* Iterate the given data.
* @param {*} data - The data to iterate.
* @param {Function} callback - The process function for each element.
* @returns {*} The original data.
*/
-export function each(data, callback) {
+export function forEach(data, callback) {
if (data && isFunction(callback)) {
if (Array.isArray(data) || isNumber(data.length)/* array-like */) {
- const { length } = data;
- let i;
-
- for (i = 0; i < length; i += 1) {
- if (callback.call(data, data[i], i, data) === false) {
- break;
- }
- }
+ toArray(data).forEach((value, key) => {
+ callback.call(data, value, key, data);
+ });
} else if (isObject(data)) {
Object.keys(data).forEach((key) => {
callback.call(data, data[key], key, data);
@@ -94,43 +105,29 @@ export function each(data, callback) {
/**
* Extend the given object.
- * @param {*} obj - The object to be extended.
- * @param {*} args - The rest objects which will be merged to the first object.
+ * @param {*} target - The target object to extend.
+ * @param {*} args - The rest objects for merging to the target object.
* @returns {Object} The extended object.
*/
-export function extend(obj, ...args) {
- if (isObject(obj) && args.length > 0) {
- if (Object.assign) {
- return Object.assign(obj, ...args);
- }
-
+export const assign = Object.assign || function assign(target, ...args) {
+ if (isObject(target) && args.length > 0) {
args.forEach((arg) => {
if (isObject(arg)) {
Object.keys(arg).forEach((key) => {
- obj[key] = arg[key];
+ target[key] = arg[key];
});
}
});
}
- return obj;
-}
-
-/**
- * Takes a function and returns a new one that will always have a particular context.
- * @param {Function} fn - The target function.
- * @param {Object} context - The new context for the function.
- * @returns {boolean} The new function.
- */
-export function proxy(fn, context, ...args) {
- return (...args2) => fn.apply(context, args.concat(args2));
-}
+ return target;
+};
-const REGEXP_DECIMALS = /\.\d*(?:0|9){12}\d*$/i;
+const REGEXP_DECIMALS = /\.\d*(?:0|9){12}\d*$/;
/**
* Normalize decimal number.
- * Check out {@link http://0.30000000000000004.com/ }
+ * Check out {@link http://0.30000000000000004.com/}
* @param {number} value - The value to normalize.
* @param {number} [times=100000000000] - The times for normalizing.
* @returns {number} Returns the normalized number.
@@ -139,7 +136,7 @@ export function normalizeDecimalNumber(value, times = 100000000000) {
return REGEXP_DECIMALS.test(value) ? (Math.round(value * times) / times) : value;
}
-const REGEXP_SUFFIX = /^(?:width|height|left|top|marginLeft|marginTop)$/;
+const REGEXP_SUFFIX = /^width|height|left|top|marginLeft|marginTop$/;
/**
* Apply styles to the given element.
@@ -149,9 +146,9 @@ const REGEXP_SUFFIX = /^(?:width|height|left|top|marginLeft|marginTop)$/;
export function setStyle(element, styles) {
const { style } = element;
- each(styles, (value, property) => {
+ forEach(styles, (value, property) => {
if (REGEXP_SUFFIX.test(property) && isNumber(value)) {
- value += 'px';
+ value = `${value}px`;
}
style[property] = value;
@@ -165,9 +162,9 @@ export function setStyle(element, styles) {
* @returns {boolean} Returns `true` if the special class was found.
*/
export function hasClass(element, value) {
- return element.classList ?
- element.classList.contains(value) :
- element.className.indexOf(value) > -1;
+ return element.classList
+ ? element.classList.contains(value)
+ : element.className.indexOf(value) > -1;
}
/**
@@ -181,7 +178,7 @@ export function addClass(element, value) {
}
if (isNumber(element.length)) {
- each(element, (elem) => {
+ forEach(element, (elem) => {
addClass(elem, value);
});
return;
@@ -212,7 +209,7 @@ export function removeClass(element, value) {
}
if (isNumber(element.length)) {
- each(element, (elem) => {
+ forEach(element, (elem) => {
removeClass(elem, value);
});
return;
@@ -240,7 +237,7 @@ export function toggleClass(element, value, added) {
}
if (isNumber(element.length)) {
- each(element, (elem) => {
+ forEach(element, (elem) => {
toggleClass(elem, value, added);
});
return;
@@ -254,15 +251,15 @@ export function toggleClass(element, value, added) {
}
}
-const REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g;
+const REGEXP_CAMEL_CASE = /([a-z\d])([A-Z])/g;
/**
- * Hyphenate the given value.
- * @param {string} value - The value to hyphenate.
- * @returns {string} The hyphenated value.
+ * Transform the given string from camelCase to kebab-case
+ * @param {string} value - The value to transform.
+ * @returns {string} The transformed value.
*/
-export function hyphenate(value) {
- return value.replace(REGEXP_HYPHENATE, '$1-$2').toLowerCase();
+export function toParamCase(value) {
+ return value.replace(REGEXP_CAMEL_CASE, '$1-$2').toLowerCase();
}
/**
@@ -274,11 +271,13 @@ export function hyphenate(value) {
export function getData(element, name) {
if (isObject(element[name])) {
return element[name];
- } else if (element.dataset) {
+ }
+
+ if (element.dataset) {
return element.dataset[name];
}
- return element.getAttribute(`data-${hyphenate(name)}`);
+ return element.getAttribute(`data-${toParamCase(name)}`);
}
/**
@@ -293,7 +292,7 @@ export function setData(element, name, data) {
} else if (element.dataset) {
element.dataset[name] = data;
} else {
- element.setAttribute(`data-${hyphenate(name)}`, data);
+ element.setAttribute(`data-${toParamCase(name)}`, data);
}
}
@@ -306,22 +305,50 @@ export function removeData(element, name) {
if (isObject(element[name])) {
try {
delete element[name];
- } catch (e) {
- element[name] = null;
+ } catch (error) {
+ element[name] = undefined;
}
} else if (element.dataset) {
// #128 Safari not allows to delete dataset property
try {
delete element.dataset[name];
- } catch (e) {
- element.dataset[name] = null;
+ } catch (error) {
+ element.dataset[name] = undefined;
}
} else {
- element.removeAttribute(`data-${hyphenate(name)}`);
+ element.removeAttribute(`data-${toParamCase(name)}`);
}
}
const REGEXP_SPACES = /\s\s*/;
+const onceSupported = (() => {
+ let supported = false;
+
+ if (IS_BROWSER) {
+ let once = false;
+ const listener = () => {};
+ const options = Object.defineProperty({}, 'once', {
+ get() {
+ supported = true;
+ return once;
+ },
+
+ /**
+ * This setter can fix a `TypeError` in strict mode
+ * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only}
+ * @param {boolean} value - The value to set
+ */
+ set(value) {
+ once = value;
+ },
+ });
+
+ WINDOW.addEventListener('test', listener, options);
+ WINDOW.removeEventListener('test', listener, options);
+ }
+
+ return supported;
+})();
/**
* Remove event listener from the target element.
@@ -331,24 +358,28 @@ const REGEXP_SPACES = /\s\s*/;
* @param {Object} options - The event options.
*/
export function removeListener(element, type, listener, options = {}) {
- if (!isFunction(listener)) {
- return;
- }
+ let handler = listener;
- const types = type.trim().split(REGEXP_SPACES);
+ type.trim().split(REGEXP_SPACES).forEach((event) => {
+ if (!onceSupported) {
+ const { listeners } = element;
- if (types.length > 1) {
- each(types, (t) => {
- removeListener(element, t, listener, options);
- });
- return;
- }
+ if (listeners && listeners[event] && listeners[event][listener]) {
+ handler = listeners[event][listener];
+ delete listeners[event][listener];
- if (element.removeEventListener) {
- element.removeEventListener(type, listener, options);
- } else if (element.detachEvent) {
- element.detachEvent(`on${type}`, listener);
- }
+ if (Object.keys(listeners[event]).length === 0) {
+ delete listeners[event];
+ }
+
+ if (Object.keys(listeners).length === 0) {
+ delete element.listeners;
+ }
+ }
+ }
+
+ element.removeEventListener(event, handler, options);
+ });
}
/**
@@ -359,33 +390,32 @@ export function removeListener(element, type, listener, options = {}) {
* @param {Object} options - The event options.
*/
export function addListener(element, type, listener, options = {}) {
- if (!isFunction(listener)) {
- return;
- }
+ let handler = listener;
- const types = type.trim().split(REGEXP_SPACES);
+ type.trim().split(REGEXP_SPACES).forEach((event) => {
+ if (options.once && !onceSupported) {
+ const { listeners = {} } = element;
- if (types.length > 1) {
- each(types, (t) => {
- addListener(element, t, listener, options);
- });
- return;
- }
+ handler = (...args) => {
+ delete listeners[event][listener];
+ element.removeEventListener(event, handler, options);
+ listener.apply(element, args);
+ };
- if (options.once) {
- const originalListener = listener;
+ if (!listeners[event]) {
+ listeners[event] = {};
+ }
- listener = (...args) => {
- removeListener(element, type, listener, options);
- return originalListener.apply(element, args);
- };
- }
+ if (listeners[event][listener]) {
+ element.removeEventListener(event, listeners[event][listener], options);
+ }
- if (element.addEventListener) {
- element.addEventListener(type, listener, options);
- } else if (element.attachEvent) {
- element.attachEvent(`on${type}`, listener);
- }
+ listeners[event][listener] = handler;
+ element.listeners = listeners;
+ }
+
+ element.addEventListener(event, handler, options);
+ });
}
/**
@@ -396,39 +426,21 @@ export function addListener(element, type, listener, options = {}) {
* @returns {boolean} Indicate if the event is default prevented or not.
*/
export function dispatchEvent(element, type, data) {
- if (element.dispatchEvent) {
- let event;
-
- // Event and CustomEvent on IE9-11 are global objects, not constructors
- if (isFunction(Event) && isFunction(CustomEvent)) {
- if (isUndefined(data)) {
- event = new Event(type, {
- bubbles: true,
- cancelable: true,
- });
- } else {
- event = new CustomEvent(type, {
- detail: data,
- bubbles: true,
- cancelable: true,
- });
- }
- } else if (isUndefined(data)) {
- event = document.createEvent('Event');
- event.initEvent(type, true, true);
- } else {
- event = document.createEvent('CustomEvent');
- event.initCustomEvent(type, true, true, data);
- }
-
- // IE9+
- return element.dispatchEvent(event);
- } else if (element.fireEvent) {
- // IE6-10 (native events only)
- return element.fireEvent(`on${type}`);
+ let event;
+
+ // Event and CustomEvent on IE9-11 are global objects, not constructors
+ if (isFunction(Event) && isFunction(CustomEvent)) {
+ event = new CustomEvent(type, {
+ detail: data,
+ bubbles: true,
+ cancelable: true,
+ });
+ } else {
+ event = document.createEvent('CustomEvent');
+ event.initCustomEvent(type, true, true, data);
}
- return true;
+ return element.dispatchEvent(event);
}
/**
@@ -437,31 +449,16 @@ export function dispatchEvent(element, type, data) {
* @returns {Object} The offset data.
*/
export function getOffset(element) {
- const doc = document.documentElement;
const box = element.getBoundingClientRect();
return {
- left: box.left + (
- (window.scrollX || (doc && doc.scrollLeft) || 0) - ((doc && doc.clientLeft) || 0)
- ),
- top: box.top + (
- (window.scrollY || (doc && doc.scrollTop) || 0) - ((doc && doc.clientTop) || 0)
- ),
+ left: box.left + (window.pageXOffset - document.documentElement.clientLeft),
+ top: box.top + (window.pageYOffset - document.documentElement.clientTop),
};
}
-/**
- * Empty an element.
- * @param {Element} element - The element to empty.
- */
-export function empty(element) {
- while (element.firstChild) {
- element.removeChild(element.firstChild);
- }
-}
-
const { location } = WINDOW;
-const REGEXP_ORIGINS = /^(https?:)\/\/([^:/?#]+):?(\d*)/i;
+const REGEXP_ORIGINS = /^(\w+:)\/\/([^:/?#]*):?(\d*)/i;
/**
* Check if the given URL is a cross origin URL.
@@ -471,10 +468,10 @@ const REGEXP_ORIGINS = /^(https?:)\/\/([^:/?#]+):?(\d*)/i;
export function isCrossOriginURL(url) {
const parts = url.match(REGEXP_ORIGINS);
- return parts && (
- parts[1] !== location.protocol ||
- parts[2] !== location.hostname ||
- parts[3] !== location.port
+ return parts !== null && (
+ parts[1] !== location.protocol
+ || parts[2] !== location.hostname
+ || parts[3] !== location.port
);
}
@@ -486,7 +483,7 @@ export function isCrossOriginURL(url) {
export function addTimestamp(url) {
const timestamp = `timestamp=${(new Date()).getTime()}`;
- return (url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp);
+ return url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp;
}
/**
@@ -533,65 +530,19 @@ export function getTransforms({
};
}
-const { navigator } = WINDOW;
-const IS_SAFARI_OR_UIWEBVIEW = navigator && /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(navigator.userAgent);
-
-/**
- * Get an image's natural sizes.
- * @param {string} image - The target image.
- * @param {Function} callback - The callback function.
- */
-export function getImageNaturalSizes(image, callback) {
- // Modern browsers (except Safari)
- if (image.naturalWidth && !IS_SAFARI_OR_UIWEBVIEW) {
- callback(image.naturalWidth, image.naturalHeight);
- return;
- }
-
- const newImage = document.createElement('img');
- const body = document.body || document.documentElement;
-
- newImage.onload = () => {
- callback(newImage.width, newImage.height);
-
- if (!IS_SAFARI_OR_UIWEBVIEW) {
- body.removeChild(newImage);
- }
- };
-
- newImage.src = image.src;
-
- // iOS Safari will convert the image automatically
- // with its orientation once append it into DOM (#279)
- if (!IS_SAFARI_OR_UIWEBVIEW) {
- newImage.style.cssText = (
- 'left:0;' +
- 'max-height:none!important;' +
- 'max-width:none!important;' +
- 'min-height:0!important;' +
- 'min-width:0!important;' +
- 'opacity:0;' +
- 'position:absolute;' +
- 'top:0;' +
- 'z-index:-1;'
- );
- body.appendChild(newImage);
- }
-}
-
/**
* Get the max ratio of a group of pointers.
* @param {string} pointers - The target pointers.
* @returns {number} The result ratio.
*/
export function getMaxZoomRatio(pointers) {
- const pointers2 = extend({}, pointers);
+ const pointers2 = { ...pointers };
const ratios = [];
- each(pointers, (pointer, pointerId) => {
+ forEach(pointers, (pointer, pointerId) => {
delete pointers2[pointerId];
- each(pointers2, (pointer2) => {
+ forEach(pointers2, (pointer2) => {
const x1 = Math.abs(pointer.startX - pointer2.startX);
const y1 = Math.abs(pointer.startY - pointer2.startY);
const x2 = Math.abs(pointer.endX - pointer2.endX);
@@ -621,14 +572,11 @@ export function getPointer({ pageX, pageY }, endOnly) {
endY: pageY,
};
- if (endOnly) {
- return end;
- }
-
- return extend({
+ return endOnly ? end : ({
startX: pageX,
startY: pageY,
- }, end);
+ ...end,
+ });
}
/**
@@ -641,7 +589,7 @@ export function getPointersCenter(pointers) {
let pageY = 0;
let count = 0;
- each(pointers, ({ startX, startY }) => {
+ forEach(pointers, ({ startX, startY }) => {
pageX += startX;
pageY += startY;
count += 1;
@@ -657,11 +605,6 @@ export function getPointersCenter(pointers) {
}
/**
- * Check if the given value is a finite number.
- */
-export const isFinite = Number.isFinite || WINDOW.isFinite;
-
-/**
* Get the max sizes in a rectangle under the given aspect ratio.
* @param {Object} data - The original sizes.
* @param {string} [type='contain'] - The adjust type.
@@ -675,9 +618,10 @@ export function getAdjustedSizes(
},
type = 'contain', // or 'cover'
) {
- const isValidNumber = value => isFinite(value) && value > 0;
+ const isValidWidth = isPositiveNumber(width);
+ const isValidHeight = isPositiveNumber(height);
- if (isValidNumber(width) && isValidNumber(height)) {
+ if (isValidWidth && isValidHeight) {
const adjustedWidth = height * aspectRatio;
if ((type === 'contain' && adjustedWidth > width) || (type === 'cover' && adjustedWidth < width)) {
@@ -685,9 +629,9 @@ export function getAdjustedSizes(
} else {
width = height * aspectRatio;
}
- } else if (isValidNumber(width)) {
+ } else if (isValidWidth) {
height = width / aspectRatio;
- } else if (isValidNumber(height)) {
+ } else if (isValidHeight) {
width = height * aspectRatio;
}
@@ -738,6 +682,9 @@ export function getRotatedSizes({ width, height, degree }) {
export function getSourceCanvas(
image,
{
+ aspectRatio: imageAspectRatio,
+ naturalWidth: imageNaturalWidth,
+ naturalHeight: imageNaturalHeight,
rotate = 0,
scaleX = 1,
scaleY = 1,
@@ -771,11 +718,32 @@ export function getSourceCanvas(
}, 'cover');
const width = Math.min(maxSizes.width, Math.max(minSizes.width, naturalWidth));
const height = Math.min(maxSizes.height, Math.max(minSizes.height, naturalHeight));
+
+ // Note: should always use image's natural sizes for drawing as
+ // imageData.naturalWidth === canvasData.naturalHeight when rotate % 180 === 90
+ const destMaxSizes = getAdjustedSizes({
+ aspectRatio: imageAspectRatio,
+ width: maxWidth,
+ height: maxHeight,
+ });
+ const destMinSizes = getAdjustedSizes({
+ aspectRatio: imageAspectRatio,
+ width: minWidth,
+ height: minHeight,
+ }, 'cover');
+ const destWidth = Math.min(
+ destMaxSizes.width,
+ Math.max(destMinSizes.width, imageNaturalWidth),
+ );
+ const destHeight = Math.min(
+ destMaxSizes.height,
+ Math.max(destMinSizes.height, imageNaturalHeight),
+ );
const params = [
- -width / 2,
- -height / 2,
- width,
- height,
+ -destWidth / 2,
+ -destHeight / 2,
+ destWidth,
+ destHeight,
];
canvas.width = normalizeDecimalNumber(width);
@@ -788,7 +756,7 @@ export function getSourceCanvas(
context.scale(scaleX, scaleY);
context.imageSmoothingEnabled = imageSmoothingEnabled;
context.imageSmoothingQuality = imageSmoothingQuality;
- context.drawImage(image, ...params.map(param => Math.floor(normalizeDecimalNumber(param))));
+ context.drawImage(image, ...params.map((param) => Math.floor(normalizeDecimalNumber(param))));
context.restore();
return canvas;
}
@@ -804,11 +772,10 @@ const { fromCharCode } = String;
*/
export function getStringFromCharCode(dataView, start, length) {
let str = '';
- let i;
length += start;
- for (i = start; i < length; i += 1) {
+ for (let i = start; i < length; i += 1) {
str += fromCharCode(dataView.getUint8(i));
}
@@ -828,7 +795,7 @@ export function dataURLToArrayBuffer(dataURL) {
const arrayBuffer = new ArrayBuffer(binary.length);
const uint8 = new Uint8Array(arrayBuffer);
- each(uint8, (value, i) => {
+ forEach(uint8, (value, i) => {
uint8[i] = binary.charCodeAt(i);
});
@@ -842,15 +809,20 @@ export function dataURLToArrayBuffer(dataURL) {
* @returns {string} The result Data URL.
*/
export function arrayBufferToDataURL(arrayBuffer, mimeType) {
- const uint8 = new Uint8Array(arrayBuffer);
- let data = '';
+ const chunks = [];
- // TypedArray.prototype.forEach is not supported in some browsers.
- each(uint8, (value) => {
- data += fromCharCode(value);
- });
+ // Chunk Typed Array for better performance (#435)
+ const chunkSize = 8192;
+ let uint8 = new Uint8Array(arrayBuffer);
- return `data:${mimeType};base64,${btoa(data)}`;
+ while (uint8.length > 0) {
+ // XXX: Babel's `toConsumableArray` helper will throw error in IE or Safari 9
+ // eslint-disable-next-line prefer-spread
+ chunks.push(fromCharCode.apply(null, toArray(uint8.subarray(0, chunkSize))));
+ uint8 = uint8.subarray(chunkSize);
+ }
+
+ return `data:${mimeType};base64,${btoa(chunks.join(''))}`;
}
/**
@@ -858,69 +830,75 @@ export function arrayBufferToDataURL(arrayBuffer, mimeType) {
* @param {ArrayBuffer} arrayBuffer - The array buffer to read.
* @returns {number} The read orientation value.
*/
-export function getOrientation(arrayBuffer) {
+export function resetAndGetOrientation(arrayBuffer) {
const dataView = new DataView(arrayBuffer);
let orientation;
- let littleEndian;
- let app1Start;
- let ifdStart;
-
- // Only handle JPEG image (start by 0xFFD8)
- if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) {
- const length = dataView.byteLength;
- let offset = 2;
-
- while (offset < length) {
- if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) {
- app1Start = offset;
- break;
- }
- offset += 1;
+ // Ignores range error when the image does not have correct Exif information
+ try {
+ let littleEndian;
+ let app1Start;
+ let ifdStart;
+
+ // Only handle JPEG image (start by 0xFFD8)
+ if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) {
+ const length = dataView.byteLength;
+ let offset = 2;
+
+ while (offset + 1 < length) {
+ if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) {
+ app1Start = offset;
+ break;
+ }
+
+ offset += 1;
+ }
}
- }
- if (app1Start) {
- const exifIDCode = app1Start + 4;
- const tiffOffset = app1Start + 10;
+ if (app1Start) {
+ const exifIDCode = app1Start + 4;
+ const tiffOffset = app1Start + 10;
- if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') {
- const endianness = dataView.getUint16(tiffOffset);
+ if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') {
+ const endianness = dataView.getUint16(tiffOffset);
- littleEndian = endianness === 0x4949;
+ littleEndian = endianness === 0x4949;
- if (littleEndian || endianness === 0x4D4D /* bigEndian */) {
- if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) {
- const firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
+ if (littleEndian || endianness === 0x4D4D /* bigEndian */) {
+ if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) {
+ const firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
- if (firstIFDOffset >= 0x00000008) {
- ifdStart = tiffOffset + firstIFDOffset;
+ if (firstIFDOffset >= 0x00000008) {
+ ifdStart = tiffOffset + firstIFDOffset;
+ }
}
}
}
}
- }
- if (ifdStart) {
- const length = dataView.getUint16(ifdStart, littleEndian);
- let offset;
- let i;
+ if (ifdStart) {
+ const length = dataView.getUint16(ifdStart, littleEndian);
+ let offset;
+ let i;
- for (i = 0; i < length; i += 1) {
- offset = ifdStart + (i * 12) + 2;
+ for (i = 0; i < length; i += 1) {
+ offset = ifdStart + (i * 12) + 2;
- if (dataView.getUint16(offset, littleEndian) === 0x0112 /* Orientation */) {
- // 8 is the offset of the current tag's value
- offset += 8;
+ if (dataView.getUint16(offset, littleEndian) === 0x0112 /* Orientation */) {
+ // 8 is the offset of the current tag's value
+ offset += 8;
- // Get the original orientation value
- orientation = dataView.getUint16(offset, littleEndian);
+ // Get the original orientation value
+ orientation = dataView.getUint16(offset, littleEndian);
- // Override the orientation with its default value
- dataView.setUint16(offset, 1, littleEndian);
- break;
+ // Override the orientation with its default value
+ dataView.setUint16(offset, 1, littleEndian);
+ break;
+ }
}
}
+ } catch (error) {
+ orientation = 1;
}
return orientation;