diff --git a/zubhub_frontend/zubhub/package-lock.json b/zubhub_frontend/zubhub/package-lock.json index e45e64352..45cbb65a3 100644 --- a/zubhub_frontend/zubhub/package-lock.json +++ b/zubhub_frontend/zubhub/package-lock.json @@ -3424,6 +3424,11 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, + "blueimp-canvas-to-blob": { + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/blueimp-canvas-to-blob/-/blueimp-canvas-to-blob-3.28.0.tgz", + "integrity": "sha512-5q+YHzgGsuHQ01iouGgJaPJXod2AzTxJXmVv90PpGrRxU7G7IqgPqWXz+PBmt3520jKKi6irWbNV87DicEa7wg==" + }, "bn.js": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz", @@ -4175,6 +4180,15 @@ } } }, + "compressorjs": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/compressorjs/-/compressorjs-1.0.7.tgz", + "integrity": "sha512-ca+H8CGrn0LG103//VQmXBbNdvzvHiW26LGdWncp4RmLNbNQjaaFWIUxMN9++hbhGobLtofkHoxzzXGisNyD3w==", + "requires": { + "blueimp-canvas-to-blob": "^3.28.0", + "is-blob": "^2.1.0" + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -7709,6 +7723,11 @@ "binary-extensions": "^2.0.0" } }, + "is-blob": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-blob/-/is-blob-2.1.0.tgz", + "integrity": "sha512-SZ/fTft5eUhQM6oF/ZaASFDEdbFVe89Imltn9uZr03wdKMcWNVYSMjQPFtg05QuNkt5l5c135ElvXEQG0rk4tw==" + }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -16422,6 +16441,14 @@ "microevent.ts": "~0.1.1" } }, + "workerize-loader": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/workerize-loader/-/workerize-loader-1.3.0.tgz", + "integrity": "sha512-utWDc8K6embcICmRBUUkzanPgKBb8yM1OHfh6siZfiMsswE8wLCa9CWS+L7AARz0+Th4KH4ZySrqer/OJ9WuWw==", + "requires": { + "loader-utils": "^2.0.0" + } + }, "wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", diff --git a/zubhub_frontend/zubhub/package.json b/zubhub_frontend/zubhub/package.json index ff3bb616c..eef40fcfc 100644 --- a/zubhub_frontend/zubhub/package.json +++ b/zubhub_frontend/zubhub/package.json @@ -11,6 +11,7 @@ "@testing-library/react": "^11.1.2", "@testing-library/user-event": "^12.2.2", "aws-sdk": "^2.813.0", + "compressorjs": "^1.0.7", "date-fns": "^2.16.1", "formik": "^2.2.5", "nanoid": "^3.1.20", @@ -26,6 +27,7 @@ "redux-thunk": "^2.3.0", "slick-carousel": "^1.8.1", "web-vitals": "^0.2.4", + "workerize-loader": "^1.3.0", "yup": "^0.29.3" }, "scripts": { diff --git a/zubhub_frontend/zubhub/src/assets/js/Compressor.js b/zubhub_frontend/zubhub/src/assets/js/Compressor.js new file mode 100644 index 000000000..5132545cb --- /dev/null +++ b/zubhub_frontend/zubhub/src/assets/js/Compressor.js @@ -0,0 +1,35 @@ +import Compressor from "compressorjs"; + + + +const Compress = (images,setImages) => { + let compressed = []; + + for (let index = 0; index < images.length; index += 1) { + let image = images[index]; + + if (image) { + new Compressor(image, { + quality: 0.6, + convertSize: 100000, + success: (result) => { + compressed.push(result); + shouldSetImages(compressed, images, setImages); + }, + error: (error) => { + console.warn(error.message); + compressed.push(image); + shouldSetImages(compressed, images, setImages); + }, + }) + } + } + }; + + const shouldSetImages = (compressed, images, setImages) =>{ + if(compressed.length === images.length){ + setImages(compressed); + } + } + +export default Compress \ No newline at end of file diff --git a/zubhub_frontend/zubhub/src/assets/js/removeMetaDataWorker.js b/zubhub_frontend/zubhub/src/assets/js/removeMetaDataWorker.js new file mode 100644 index 000000000..40f864d6c --- /dev/null +++ b/zubhub_frontend/zubhub/src/assets/js/removeMetaDataWorker.js @@ -0,0 +1,69 @@ +export const removeMetaData =(imageArr)=>{ +let newImageArr = []; + + for(let index=0; index < imageArr.length; index++){ + let fr = new FileReader(); + fr.onload = process; + fr.mainFile = imageArr[index]; + fr.readAsArrayBuffer(imageArr[index]); + } + + function process(){ + let dv = new DataView(this.result); + let offset = 0, recess = 0; + let pieces = []; + let i = 0; + if (dv.getUint16(offset) === 0xffd8){ + offset += 2; + let app1 = dv.getUint16(offset); + offset += 2; + while (offset < dv.byteLength){ + if (app1 === 0xffe1){ + + pieces[i] = {recess:recess,offset:offset-2}; + recess = offset + dv.getUint16(offset); + i++; + } + else if (app1 === 0xffda){ + break; + } + offset += dv.getUint16(offset); + app1 = dv.getUint16(offset); + offset += 2; + } + + if (pieces.length > 0){ + let newPieces = []; + pieces.forEach(function(v){ + newPieces.push(this.result.slice(v.recess, v.offset)); + }, this); + newPieces.push(this.result.slice(recess)); + newImageArr.push(new Blob(newPieces, {type: imageArr[newImageArr.length].type})); + + if(newImageArr.length === imageArr.length){ + postMessage(newImageArr); + } + + } + else { + newImageArr.push(this.mainFile); + + if(newImageArr.length === imageArr.length){ + postMessage(newImageArr); + } + } + } + else { + newImageArr.push(this.mainFile); + + if(newImageArr.length === imageArr.length){ + postMessage(newImageArr); + } + } + + + } + +} + + diff --git a/zubhub_frontend/zubhub/src/components/pages/projects/projects_components/CreateProject.jsx b/zubhub_frontend/zubhub/src/components/pages/projects/projects_components/CreateProject.jsx index 6ae455f18..13263745a 100644 --- a/zubhub_frontend/zubhub/src/components/pages/projects/projects_components/CreateProject.jsx +++ b/zubhub_frontend/zubhub/src/components/pages/projects/projects_components/CreateProject.jsx @@ -9,6 +9,8 @@ import ErrorPage from "../../infos/ErrorPage"; import clsx from "clsx"; import PropTypes from "prop-types"; import DO, { doConfig } from "../../../../assets/js/DO"; +import worker from "workerize-loader!../../../../assets/js/removeMetaDataWorker"; // eslint-disable-line import/no-webpack-loader-syntax +import Compressor from "../../../../assets/js/Compressor"; import { nanoid } from "nanoid"; import { withStyles, fade } from "@material-ui/core/styles"; import Grid from "@material-ui/core/Grid"; @@ -164,7 +166,7 @@ class CreateProject extends Component { materials_used: [], image_upload: { upload_dialog: false, - images_to_upload: 0, + images_to_upload: [], successful_uploads: 0, upload_info: {}, upload_percent: 0, @@ -225,7 +227,7 @@ class CreateProject extends Component { this.setState({ image_upload }, () => { if ( - this.state.image_upload.images_to_upload === + this.state.image_upload.images_to_upload.length === this.state.image_upload.successful_uploads ) { this.upload_project(); @@ -272,50 +274,41 @@ class CreateProject extends Component { if (!this.props.auth.token) { this.props.history.push("/login"); } else { - let media_fields = this.mediaFieldsValidation(); + let { image_upload } = this.state; + let media_fields = this.mediaFieldsValidation( + image_upload.images_to_upload + ); - if (media_fields.image_is_empty && media_fields.video_is_empty) { - this.props.setErrors({ - project_images: "you must provide either image(s) or video url", - }); - this.props.setErrors({ - video: "you must provide either image(s) or video url", - }); - } else if (media_fields.too_many_images === true) { - this.props.setErrors({ project_images: "too many images uploaded" }); - } else if (media_fields.image_size_too_large === true) { - this.props.setErrors({ - project_images: "one or more of your image is greater than 3mb", - }); + if (media_fields.image_is_empty && Object.keys(media_fields).length > 1) { + return; } else if (media_fields.image_is_empty) { this.upload_project(); } else { - let project_images = document.querySelector("#project_images").files; - - let { image_upload } = this.state; - image_upload.images_to_upload = project_images.length; image_upload.upload_dialog = true; image_upload.upload_percent = 0; this.setState({ image_upload }); - for (let index = 0; index < project_images.length; index++) { - this.upload(project_images[index]); + for ( + let index = 0; + index < image_upload.images_to_upload.length; + index++ + ) { + this.upload(image_upload.images_to_upload[index]); } } } }; - mediaFieldsValidation = () => { + mediaFieldsValidation = (images) => { let image_upload_button = document.querySelector("#image_upload_button"); - let media_fields = document.querySelector("#project_images"); let video = document.querySelector("#video"); let imageCount = document.querySelector(".imageCountStyle"); - imageCount.innerText = media_fields.files.length; + imageCount.innerText = images.length; imageCount.style.fontSize = "0.8rem"; let result = {}; - if (media_fields.files.length < 1) { + if (images.length < 1) { result["image_is_empty"] = true; if (video.value === "") { image_upload_button.setAttribute( @@ -330,7 +323,7 @@ class CreateProject extends Component { }); result["video_is_empty"] = true; } - } else if (media_fields.files.length > 10) { + } else if (images.length > 10) { image_upload_button.setAttribute( "style", "border-color:#F54336; color:#F54336" @@ -340,8 +333,8 @@ class CreateProject extends Component { } else { let image_size_too_large = false; - for (let index = 0; index < media_fields.files.length; index++) { - if (media_fields.files[index].size / 1000 > 3072) { + for (let index = 0; index < images.length; index++) { + if (images[index].size / 1000 > 10240) { image_size_too_large = true; } } @@ -351,7 +344,7 @@ class CreateProject extends Component { "border-color:#F54336; color:#F54336" ); this.props.setErrors({ - project_images: "one or more of your image is greater than 3mb", + project_images: "one or more of your image is greater than 10mb", }); result["image_size_too_large"] = image_size_too_large; } @@ -366,6 +359,36 @@ class CreateProject extends Component { return result; }; + handleImageFieldChange = (e) => { + e.preventDefault(); + let images = document.querySelector("#project_images"); + let media_fields = this.mediaFieldsValidation(images.files); + + if ( + Object.keys(media_fields).length === 0 || + (!(Object.keys(media_fields).length === 1) && media_fields.video_is_empty) + ) { + console.log(images.files); + + this.removeMetaData(images.files); + } + }; + + removeMetaData = (images) => { + const newWorker = worker(); + newWorker.removeMetaData(images); + newWorker.addEventListener("message", (e) => { + Compressor(e.data, this.setImages); + }); + }; + + setImages = (compressed) => { + let { image_upload } = this.state; + image_upload.images_to_upload = compressed; + + this.setState({ image_upload }); + }; + handleImageButtonClick = () => { document.querySelector("#project_images").click(); this.props.setFieldTouched("project_images"); @@ -574,7 +597,7 @@ class CreateProject extends Component { id="project_images" name="project_images" multiple - onChange={this.mediaFieldsValidation} + onChange={this.handleImageFieldChange} onBlur={this.props.handleBlur} />