Image compression and upload

This commit is contained in:
2019-11-05 13:37:36 +05:30
parent 70fa6afda1
commit ec2f3401a8
4 changed files with 60 additions and 163 deletions

View File

@@ -1,16 +1,15 @@
import React from 'react';
import PropTypes from 'prop-types';
import {connect} from 'react-redux';
import {createPropsSelector} from 'reselect-immutable-helpers';
import {withStyles} from '@material-ui/core/styles';
import ImageService from './../../../../services/image.service.ts'
import {updateUploadModalState} from '../../../../pages/Home/actions';
import {getUploadModalState} from '../../../../pages/Home/selectors';
import { connect } from 'react-redux';
import { createPropsSelector } from 'reselect-immutable-helpers';
import { withStyles } from '@material-ui/core/styles';
import { updateUploadModalState } from '../../../../pages/Home/actions';
import { getUploadModalState } from '../../../../pages/Home/selectors';
import Dropzone from './../Dropzone'
import Progress from '../Progress';
import Modal from '@material-ui/core/Modal';
import Backdrop from '@material-ui/core/Backdrop';
import {Zoom, Paper, responsiveFontSizes} from '@material-ui/core';
import { Zoom, Paper } from '@material-ui/core';
const styles = theme => ({
modal: {
@@ -39,12 +38,12 @@ class Uploader extends React.Component {
successfullUploaded: false
};
this.onFilesAdded = this.onFilesAdded.bind(this);
this.uploadFile = this.uploadFile.bind(this);
this.upload = this.upload.bind(this);
this.sendRequest = this.sendRequest.bind(this);
this.renderActions = this.renderActions.bind(this);
this.renderProgress = this.renderProgress.bind(this);
this.compressAndUploadFiles = this.compressAndUploadFiles.bind(this);
this.compressFile = this.compressFile.bind(this);
this.compress = this.compress.bind(this);
}
onFilesAdded(files) {
@@ -76,7 +75,7 @@ class Uploader extends React.Component {
renderActions() {
if (this.state.successfullUploaded) {
return (
<button onClick={() => this.setState({files: [], successfullUploaded: false})}>
<button onClick={() => this.setState({ files: [], successfullUploaded: false })}>
Clear
</button>
);
@@ -92,58 +91,62 @@ class Uploader extends React.Component {
}
}
readURI(file){
return new Promise((resolve, reject) => {
let reader = new FileReader()
reader.onload = (ev) => {
resolve(ev.target.result)
}
reader.readAsDataURL(file)
})
}
handleChange(e){
this.readURI(e); // maybe call this with webworker or async library?
if (this.props.onChange !== undefined)
this.props.onChange(e); // propagate to parent component
}
compressAndUploadFiles(callback) {
const jic = new ImageService()
this.setState({ uploadProgress: {}, uploading: true });
const promises = [];
compressAndUploadFiles() {
this.state.files.forEach((file) => {
this.readURI(file).then((result) => {
file.image_source = result
this.compressFile(file, jic).then(async (result) => {
// callback(result)
promises.push(this.sendRequest(result));
try {
await Promise.all(promises);
this.setState({ successfullUploaded: true, uploading: false });
} catch (e) {
// Not Production ready! Do some error handling here instead...
this.setState({ successfullUploaded: true, uploading: false });
}
})
this.compress(file).then((result) => {
this.setState({ uploadProgress: {}, uploading: true });
// result.forEach((file) => {
this.upload(result)
// })
})
})
}
compressFile(file, jic) {
compress(file) {
return new Promise((resolve, reject) => {
resolve(jic.compress(file, 20))
});
const width = 500;
const height = 300;
const fileName = file.name;
const reader = new FileReader();
const fileVariants = []
reader.onload = event => {
const img = new Image();
img.src = event.target.result;
img.onload = () => {
const elem = document.createElement('canvas');
elem.width = width;
elem.height = height;
const ctx = elem.getContext('2d');
// img.width and img.height will contain the original dimensions
ctx.drawImage(img, 0, 0, width, height);
ctx.canvas.toBlob((blob1) => {
fileVariants.push(new File([blob1], `${fileName.split('.')[0]}_compressed_60.${fileName.split('.')[1]}`, {
type: 'image/jpeg',
lastModified: Date.now()
}))
ctx.canvas.toBlob((blob2) => {
fileVariants.push(new File([blob2], `${fileName.split('.')[0]}_compressed_20.${fileName.split('.')[1]}`, {
type: 'image/jpeg',
lastModified: Date.now()
}))
resolve(fileVariants)
}, 'image/jpeg', 0.2)
}, 'image/jpeg', 0.6)
}
}
reader.onerror = error => console.log(error);
reader.readAsDataURL(file);
})
}
async uploadFile(file) {
async upload(files) {
this.setState({ uploadProgress: {}, uploading: true });
const promises = [];
// this.state.files.forEach(file => {
promises.push(this.sendRequest(file));
promises.push(this.sendRequest(files));
// });
try {
await Promise.all(promises);
await Promise.all(promises).then(result => console.log('result === ' + result)).catch(err => console.log('error === ' + err));
this.setState({ successfullUploaded: true, uploading: false });
} catch (e) {
// Not Production ready! Do some error handling here instead...
@@ -151,20 +154,22 @@ class Uploader extends React.Component {
}
}
sendRequest(file) {
sendRequest(files) {
return new Promise((resolve, reject) => {
const req = new XMLHttpRequest();
const formData = new FormData();
formData.append("file", file, file.name);
files.forEach((file) => {
formData.append("file", file, file.name);
})
req.open("POST", "http://localhost:3001/upload");
req.send(formData);
});
}
render() {
const {classes, modalState, handleCloseDispatcher} = this.props
const { classes, modalState, handleCloseDispatcher } = this.props
return (
<div className="c-Uploader">
<Modal

View File

@@ -1,108 +0,0 @@
export default class ImageService {
constructor() { }
compress(source_img_file, quality, output_format) {
var img = document.createElement('img')
img.src = source_img_file.image_source;
var mime_type;
if (output_format === "png") {
mime_type = "image/png";
} else if (output_format === "webp") {
mime_type = "image/webp";
} else {
mime_type = "image/jpeg";
}
var cvs = document.createElement('canvas');
// cvs.width = img.naturalWidth;
// cvs.height = img.naturalHeight;
var ctx = cvs.getContext("2d").drawImage(img, 0, 0);
var newImageData = cvs.toDataURL(mime_type, quality / 100);
// var result_image_obj = new Image();
// result_image_obj.src = newImageData;
// return result_image_obj;
var byteString = atob(newImageData.split(',')[1]);
var mimeString = newImageData.split(',')[0].split(':')[1].split(';')[0];
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], {type: mimeString});
// return newImageData
}
upload(compressed_img_obj, upload_url, file_input_name, filename, successCallback, errorCallback, duringCallback, customHeaders) {
if (XMLHttpRequest.prototype.sendAsBinary === undefined) {
XMLHttpRequest.prototype.sendAsBinary = function (string) {
var bytes = Array.prototype.map.call(string, function (c) {
return c.charCodeAt(0) & 0xff;
});
this.send(new Uint8Array(bytes).buffer);
};
}
var type;
if (filename.substr(-4).toLowerCase() === ".png") {
type = "image/png";
} else if (filename.substr(-5).toLowerCase() === ".webp") {
type = "image/webp";
} else {
type = "image/jpeg";
}
var data = compressed_img_obj.src;
data = data.replace('data:' + type + ';base64,', '');
var xhr = new XMLHttpRequest();
xhr.open('POST', upload_url, true);
var boundary = 'someboundary';
xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
// Set custom request headers if customHeaders parameter is provided
if (customHeaders && typeof customHeaders === "object") {
for (var headerKey in customHeaders) {
xhr.setRequestHeader(headerKey, customHeaders[headerKey]);
}
}
// If a duringCallback function is set as a parameter, call that to notify about the upload progress
if (duringCallback && duringCallback instanceof Function) {
xhr.upload.onprogress = function (evt) {
if (evt.lengthComputable) {
duringCallback((evt.loaded / evt.total) * 100);
}
};
}
xhr.sendAsBinary(['--' + boundary, 'Content-Disposition: form-data; name="' + file_input_name + '"; filename="' + filename + '"', 'Content-Type: ' + type, '', atob(data), '--' + boundary + '--'].join('\r\n'));
xhr.onreadystatechange = function () {
if (this.readyState == 4) {
if (this.status == 200) {
successCallback(this.responseText);
} else if (this.status >= 400) {
if (errorCallback && errorCallback instanceof Function) {
errorCallback(this.responseText);
}
}
}
}
}
errorCallback() {
console.log('Error during image upload')
}
successCallback() {
console.log('Image Uploaded successfully!')
}
duringCallback() {
console.log('Image being uploaded now.')
}
}

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 MiB