Home Reference Source

src/utils/scaleImg.js

import EXIF from 'exif-js';
import {decode} from 'base64-arraybuffer';
import {cropImage} from './cropImage';

const REGULAR_EXPRESSION_BASE64 = /^data:([A-Za-z-+/]+);base64,(.+)$/;

function isBase64(url) {
	return !!REGULAR_EXPRESSION_BASE64.test(url);
}

/**
 * Reset the orientation of an image and return the image in base64
 * Reference: https://stackoverflow.com/questions/20600800/js-client-side-exif-orientation-rotate-and-mirror-jpeg-images/31273162#31273162
 * @param {String} srcBase64 Base64 uri of an image
 * @param {Integer} srcOrientation Identify the orientation of an image
 * @return {String} Base64 uri of an transformed image
 */
function resetOrientation(srcBase64, srcOrientation) {
	let img = new Image();
	return new Promise((resolve) => {
		img.onload = function() {
			let canvas = document.createElement('canvas'),
				ctx = canvas.getContext('2d');

			// set proper canvas dimensions before transform & export
			if (srcOrientation > 4 && srcOrientation < 9) {
				canvas.width = this.height;
				canvas.height = this.width;
			} else {
				canvas.width = this.width;
				canvas.height = this.height;
			}

			// transform context before drawing image
			switch (srcOrientation) {
				case 2: ctx.transform(-1, 0, 0, 1, this.width, 0); break;
				case 3: ctx.transform(-1, 0, 0, -1, this.width, this.height); break;
				case 4: ctx.transform(1, 0, 0, -1, 0, this.height); break;
				case 5: ctx.transform(0, 1, 1, 0, 0, 0); break;
				case 6: ctx.transform(0, 1, -1, 0, this.height, 0); break;
				case 7: ctx.transform(0, -1, -1, 0, this.height, this.width); break;
				case 8: ctx.transform(0, -1, 1, 0, 0, this.width); break;
				default: break;
			}

			// draw image
			ctx.drawImage(img, 0, 0, this.width, this.height);
			let base64Url = ctx.canvas.toDataURL('image/png');
			img = null;
			canvas = null;
			resolve(base64Url);
		};
		img.src = srcBase64;
	});
}


/**
 * Scales an image to the size passed by parameters and returns a URI
 * with the new image encoded in base64
 * @param {string} url Base64 URI of an image
 * @param {number} width Desired width of the image
 * @param {number} height Desired height of the image
 * @return {Promise<string>} Base64 URI of a transformed image
 * @private
 */
export function scaleImg(url, width = 128, height = 128) {
	let type, data;
	if (!window) {
		return url;
	}
	return new Promise((resolve) => {
		if (!isBase64(url)) {
			return resolve();
		}
		[, type, data] = url.match(REGULAR_EXPRESSION_BASE64);
		let exifdata = EXIF.readFromBinaryFile(decode(data));
		if (exifdata) {
			return resolve(exifdata.Orientation);
		}
		return resolve();
	}).then((orientation) => {
		if (orientation) {
			return resetOrientation(url, orientation, type);
		}
		return url;
	}).then(imageUrl => cropImage(imageUrl, width, height));
}