src/utils/scaleImg.js
import {decode} from 'base64-arraybuffer';
import EXIF from 'exif-js';
const REGULAR_EXPRESSION_BASE64 = /^data:([A-Za-z-+/]+);base64,(.+)$/;
function isBase64(url) {
return !!REGULAR_EXPRESSION_BASE64.test(url);
}
/**
* Crops an image to get a square picture
* @param {String} imageUrl Uri of an image
* @param {Integer} widthScalated Width of the image
* @param {Integer} heightScalated Height of the image
* @return {String} Base64 uri of a transformed image
* @private
*/
function cropImage(imageUrl, widthScalated, heightScalated) {
return new Promise((resolve) => {
if (!window) {
resolve(imageUrl);
}
let image = new Image();
image.onload = function() {
let canvas = document.createElement('canvas');
canvas.width = Math.min(this.width, widthScalated);
canvas.height = Math.min(this.height, heightScalated);
let sx = 0, sy = 0, dx = 0, dy = 0;
let sWidth = this.width;
let sHeight = this.width;
const dWidth = Math.min(this.width, widthScalated);
const dHeight = Math.min(this.height, heightScalated);
if (this.height > this.width) {
sy = (this.height - this.width) / 2;
} else if (this.height < this.width) {
sx = (this.width - this.height) / 2;
sWidth = sHeight = this.height;
}
canvas.getContext('2d').drawImage(this,
sx, sy,
sWidth,
sHeight,
dx, dy,
dWidth, dHeight);
const base64Url = canvas.toDataURL('image/png');
image = null;
canvas = null;
resolve(base64Url);
};
image.src = imageUrl;
});
}
/**
* 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);
const 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);
const 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));
}