diff options
author | Yamagishi Kazutoshi <ykzts@desire.sh> | 2018-05-09 15:41:07 +0900 |
---|---|---|
committer | Eugen Rochko <eugen@zeonfederated.com> | 2018-05-09 08:41:07 +0200 |
commit | 6832110af46e31831788c599b70ac047c7512e16 (patch) | |
tree | 5562c2d9080174f7a7dddc13f39498ed2d7587b2 /app/javascript | |
parent | d2ee48977c8b663465504b44ae3d648cadd29aab (diff) |
Correct rotate of image using EXIF (#7422)
Diffstat (limited to 'app/javascript')
-rw-r--r-- | app/javascript/mastodon/utils/resize_image.js | 107 |
1 files changed, 84 insertions, 23 deletions
diff --git a/app/javascript/mastodon/utils/resize_image.js b/app/javascript/mastodon/utils/resize_image.js index 6442eda38..54459de3e 100644 --- a/app/javascript/mastodon/utils/resize_image.js +++ b/app/javascript/mastodon/utils/resize_image.js @@ -1,3 +1,5 @@ +import EXIF from 'exif-js'; + const MAX_IMAGE_DIMENSION = 1280; const getImageUrl = inputFile => new Promise((resolve, reject) => { @@ -28,6 +30,84 @@ const loadImage = inputFile => new Promise((resolve, reject) => { }).catch(reject); }); +const getOrientation = (img, type = 'image/png') => new Promise(resolve => { + if (type !== 'image/jpeg') { + resolve(1); + return; + } + + 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'); + [canvas.width, canvas.height] = orientation < 5 ? [width, height] : [height, width]; + + const context = canvas.getContext('2d'); + + 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; + } else if (height > width) { + newWidth = width * MAX_IMAGE_DIMENSION / height; + newHeight = MAX_IMAGE_DIMENSION; + } else { + newWidth = MAX_IMAGE_DIMENSION; + newHeight = MAX_IMAGE_DIMENSION; + } + + getOrientation(img, type) + .then(orientation => processImage(img, { + width: newWidth, + height: newHeight, + orientation, + type, + })) + .then(resolve) + .catch(reject); +}); + export default inputFile => new Promise((resolve, reject) => { if (!inputFile.type.match(/image.*/) || inputFile.type === 'image/gif') { resolve(inputFile); @@ -35,32 +115,13 @@ export default inputFile => new Promise((resolve, reject) => { } loadImage(inputFile).then(img => { - const canvas = document.createElement('canvas'); - const { width, height } = img; - - let newWidth, newHeight; - - if (width < MAX_IMAGE_DIMENSION && height < MAX_IMAGE_DIMENSION) { + if (img.width < MAX_IMAGE_DIMENSION && img.height < MAX_IMAGE_DIMENSION) { resolve(inputFile); return; } - if (width > height) { - newHeight = height * MAX_IMAGE_DIMENSION / width; - newWidth = MAX_IMAGE_DIMENSION; - } else if (height > width) { - newWidth = width * MAX_IMAGE_DIMENSION / height; - newHeight = MAX_IMAGE_DIMENSION; - } else { - newWidth = MAX_IMAGE_DIMENSION; - newHeight = MAX_IMAGE_DIMENSION; - } - - canvas.width = newWidth; - canvas.height = newHeight; - - canvas.getContext('2d').drawImage(img, 0, 0, newWidth, newHeight); - - canvas.toBlob(resolve, inputFile.type); + resizeImage(img, inputFile.type) + .then(resolve) + .catch(() => resolve(inputFile)); }).catch(reject); }); |