summaryrefslogtreecommitdiffstats
path: root/webapp/components/setting_picture.jsx
diff options
context:
space:
mode:
authorRich Barton <emptyarray@users.noreply.github.com>2017-07-10 06:51:07 -0700
committerChristopher Speller <crspeller@gmail.com>2017-07-10 06:51:07 -0700
commit998b8f70c2d88151b080657dea1ce0b9aca36d58 (patch)
treea9c74e7745005bcd588797b36e9b076c82cd7253 /webapp/components/setting_picture.jsx
parentb03b9d736297a536bb1385c80f76f55473c9f637 (diff)
downloadchat-998b8f70c2d88151b080657dea1ce0b9aca36d58.tar.gz
chat-998b8f70c2d88151b080657dea1ce0b9aca36d58.tar.bz2
chat-998b8f70c2d88151b080657dea1ce0b9aca36d58.zip
PLT-6659 Fixed upload thumbnails that weren't properly rotated (#6816)
- Used client-side EXIF data to rotate profile picture thumbnails - Added a small package for correctly translating EXIF orientation into CSS transforms - Instead of displaying the image using FileReader, used URL.createObjectURL because it is faster - For upload thumbnails, the original behavior was scaling the entire original image, without accounting for EXIF rotate. I changed this to use the thumbnail image, which does respect rotation. - The preview image was not available when the upload request returned, because handling the preview image creation was in a goroutine. I used sync.WaitGroup to block until the preview image creation is done.
Diffstat (limited to 'webapp/components/setting_picture.jsx')
-rw-r--r--webapp/components/setting_picture.jsx72
1 files changed, 68 insertions, 4 deletions
diff --git a/webapp/components/setting_picture.jsx b/webapp/components/setting_picture.jsx
index faa463cc7..ec6dfbd20 100644
--- a/webapp/components/setting_picture.jsx
+++ b/webapp/components/setting_picture.jsx
@@ -5,6 +5,7 @@ import PropTypes from 'prop-types';
import React, {Component} from 'react';
import {FormattedMessage} from 'react-intl';
+import exif2css from 'exif2css';
import FormError from 'components/form_error.jsx';
import loadingGif from 'images/load.gif';
@@ -41,26 +42,89 @@ export default class SettingPicture extends Component {
}
}
+ componentWillUnmount() {
+ if (this.previewBlob) {
+ URL.revokeObjectURL(this.previewBlob);
+ }
+ }
+
setPicture = (file) => {
if (file) {
- var reader = new FileReader();
+ this.previewBlob = URL.createObjectURL(file);
+ var reader = new FileReader();
reader.onload = (e) => {
+ const orientation = this.getExifOrientation(e.target.result);
+ const orientationStyles = this.getOrientationStyles(orientation);
+
this.setState({
- image: e.target.result
+ image: this.previewBlob,
+ orientationStyles
});
};
- reader.readAsDataURL(file);
+ reader.readAsArrayBuffer(file);
+ }
+ }
+
+ // based on https://stackoverflow.com/questions/7584794/accessing-jpeg-exif-rotation-data-in-javascript-on-the-client-side/32490603#32490603
+ getExifOrientation(data) {
+ var view = new DataView(data);
+
+ if (view.getUint16(0, false) !== 0xFFD8) {
+ return -2;
+ }
+
+ var length = view.byteLength;
+ var offset = 2;
+
+ while (offset < length) {
+ var marker = view.getUint16(offset, false);
+ offset += 2;
+
+ if (marker === 0xFFE1) {
+ if (view.getUint32(offset += 2, false) !== 0x45786966) {
+ return -1;
+ }
+
+ var little = view.getUint16(offset += 6, false) === 0x4949;
+ offset += view.getUint32(offset + 4, little);
+ var tags = view.getUint16(offset, little);
+ offset += 2;
+
+ for (var i = 0; i < tags; i++) {
+ if (view.getUint16(offset + (i * 12), little) === 0x0112) {
+ return view.getUint16(offset + (i * 12) + 8, little);
+ }
+ }
+ } else if ((marker & 0xFF00) === 0xFF00) {
+ offset += view.getUint16(offset, false);
+ } else {
+ break;
+ }
}
+ return -1;
+ }
+
+ getOrientationStyles(orientation) {
+ const {
+ transform,
+ 'transform-origin': transformOrigin
+ } = exif2css(orientation);
+ return {transform, transformOrigin};
}
render() {
let img;
if (this.props.file) {
+ const imageStyles = {
+ backgroundImage: 'url(' + this.state.image + ')',
+ ...this.state.orientationStyles
+ };
+
img = (
<div
className='profile-img-preview'
- style={{backgroundImage: 'url(' + this.state.image + ')'}}
+ style={imageStyles}
/>
);
} else {