Correct rotate of image using EXIF (#7422)

master
Yamagishi Kazutoshi 7 years ago committed by Eugen Rochko
parent d2ee48977c
commit 6832110af4
  1. 87
      app/javascript/mastodon/utils/resize_image.js
  2. 1
      package.json
  3. 4
      yarn.lock

@ -1,3 +1,5 @@
import EXIF from 'exif-js';
const MAX_IMAGE_DIMENSION = 1280;
const getImageUrl = inputFile => new Promise((resolve, reject) => {
@ -28,23 +30,62 @@ const loadImage = inputFile => new Promise((resolve, reject) => {
}).catch(reject);
});
export default inputFile => new Promise((resolve, reject) => {
if (!inputFile.type.match(/image.*/) || inputFile.type === 'image/gif') {
resolve(inputFile);
const getOrientation = (img, type = 'image/png') => new Promise(resolve => {
if (type !== 'image/jpeg') {
resolve(1);
return;
}
loadImage(inputFile).then(img => {
EXIF.getData(img, () => {
const orientation = EXIF.getTag(img, 'Orientation');
resolve(orientation);
});
});
const processImage = (img, { width, height, orientation, type = 'image/png' }) => new Promise(resolve => {
const canvas = document.createElement('canvas');
const { width, height } = img;
[canvas.width, canvas.height] = orientation < 5 ? [width, height] : [height, width];
let newWidth, newHeight;
const context = canvas.getContext('2d');
if (width < MAX_IMAGE_DIMENSION && height < MAX_IMAGE_DIMENSION) {
resolve(inputFile);
return;
switch (orientation) {
case 2:
context.translate(width, 0);
break;
case 3:
context.translate(width, height);
break;
case 4:
context.translate(0, height);
break;
case 5:
context.rotate(0.5 * Math.PI);
context.translate(1, -1);
break;
case 6:
context.rotate(0.5 * Math.PI);
context.translate(0, -height);
break;
case 7:
context.rotate(0.5, Math.PI);
context.translate(width, -height);
break;
case 8:
context.rotate(-0.5, Math.PI);
context.translate(-width, 0);
break;
}
context.drawImage(img, 0, 0, width, height);
canvas.toBlob(resolve, type);
});
const resizeImage = (img, type = 'image/png') => new Promise((resolve, reject) => {
const { width, height } = img;
let newWidth, newHeight;
if (width > height) {
newHeight = height * MAX_IMAGE_DIMENSION / width;
newWidth = MAX_IMAGE_DIMENSION;
@ -56,11 +97,31 @@ export default inputFile => new Promise((resolve, reject) => {
newHeight = MAX_IMAGE_DIMENSION;
}
canvas.width = newWidth;
canvas.height = newHeight;
getOrientation(img, type)
.then(orientation => processImage(img, {
width: newWidth,
height: newHeight,
orientation,
type,
}))
.then(resolve)
.catch(reject);
});
canvas.getContext('2d').drawImage(img, 0, 0, newWidth, newHeight);
export default inputFile => new Promise((resolve, reject) => {
if (!inputFile.type.match(/image.*/) || inputFile.type === 'image/gif') {
resolve(inputFile);
return;
}
loadImage(inputFile).then(img => {
if (img.width < MAX_IMAGE_DIMENSION && img.height < MAX_IMAGE_DIMENSION) {
resolve(inputFile);
return;
}
canvas.toBlob(resolve, inputFile.type);
resizeImage(img, inputFile.type)
.then(resolve)
.catch(() => resolve(inputFile));
}).catch(reject);
});

@ -49,6 +49,7 @@
"emoji-mart": "Gargron/emoji-mart#build",
"es6-symbol": "^3.1.1",
"escape-html": "^1.0.3",
"exif-js": "^2.3.0",
"express": "^4.16.2",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "^0.11.2",

@ -2601,6 +2601,10 @@ execa@^0.7.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
exif-js@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/exif-js/-/exif-js-2.3.0.tgz#9d10819bf571f873813e7640241255ab9ce1a814"
expand-brackets@^0.1.4:
version "0.1.5"
resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b"

Loading…
Cancel
Save