Skip to content

Commit

Permalink
Optimize Images for Upload using Canvas
Browse files Browse the repository at this point in the history
  • Loading branch information
KhaledEmaraDev committed Jan 16, 2021
1 parent 64a822d commit ca6ae7c
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 134 deletions.
44 changes: 16 additions & 28 deletions frontend/src/components/GroupHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import { gql, useMutation } from "@apollo/client";
import { connect } from "react-redux";
import { setDialog, showSnackbar, fillForm } from "../state/actions";

import optimizeImage from "../utils/image";

const DELETE_GROUP = gql`
mutation DeleteGroup($group_id: ID!) {
deleteGroup(groupId: $group_id)
Expand Down Expand Up @@ -222,45 +224,31 @@ function GroupHeader(props) {
};
}, []);

const handleCoverChange = (event) => {
const handleCoverChange = async (event) => {
const files = event.target.files;
if (files.length > 0) {
setCover(URL.createObjectURL(files[0]));

const reader = new FileReader();
reader.readAsDataURL(files[0]);
reader.onloadend = () => {
changeCover({
variables: {
group_id: id,
image: reader.result,
},
});
};
reader.onerror = () => {
showSnackbar("Something went wrong!");
};
const optimizedImage = await optimizeImage(files[0]);
changeCover({
variables: {
image: optimizedImage,
},
});
}
};

const handlePhotoChange = (event) => {
const handlePhotoChange = async (event) => {
const files = event.target.files;
if (files.length > 0) {
setPhoto(URL.createObjectURL(files[0]));

const reader = new FileReader();
reader.readAsDataURL(files[0]);
reader.onloadend = () => {
changeImage({
variables: {
group_id: id,
image: reader.result,
},
});
};
reader.onerror = () => {
showSnackbar("Something went wrong!");
};
const optimizedImage = await optimizeImage(files[0]);
changeImage({
variables: {
image: optimizedImage,
},
});
}
};

Expand Down
44 changes: 16 additions & 28 deletions frontend/src/components/PageHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import { gql, useMutation } from "@apollo/client";
import { connect } from "react-redux";
import { setDialog, showSnackbar, fillForm } from "../state/actions";

import optimizeImage from "../utils/image";

const DELETE_PAGE = gql`
mutation DeletePage($page_id: ID!) {
deletePage(pageId: $page_id)
Expand Down Expand Up @@ -216,45 +218,31 @@ function PageHeader(props) {
};
}, []);

const handleCoverChange = (event) => {
const handleCoverChange = async (event) => {
const files = event.target.files;
if (files.length > 0) {
setCover(URL.createObjectURL(files[0]));

const reader = new FileReader();
reader.readAsDataURL(files[0]);
reader.onloadend = () => {
changeCover({
variables: {
page_id: id,
image: reader.result,
},
});
};
reader.onerror = () => {
showSnackbar("Something went wrong!");
};
const optimizedImage = await optimizeImage(files[0]);
changeCover({
variables: {
image: optimizedImage,
},
});
}
};

const handlePhotoChange = (event) => {
const handlePhotoChange = async (event) => {
const files = event.target.files;
if (files.length > 0) {
setPhoto(URL.createObjectURL(files[0]));

const reader = new FileReader();
reader.readAsDataURL(files[0]);
reader.onloadend = () => {
changeImage({
variables: {
page_id: id,
image: reader.result,
},
});
};
reader.onerror = () => {
showSnackbar("Something went wrong!");
};
const optimizedImage = await optimizeImage(files[0]);
changeImage({
variables: {
image: optimizedImage,
},
});
}
};

Expand Down
42 changes: 16 additions & 26 deletions frontend/src/components/ProfileHeader.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import { gql, useMutation } from "@apollo/client";
import { connect } from "react-redux";
import { setDialog, showSnackbar, fillForm } from "../state/actions";

import optimizeImage from "../utils/image";

const FOLLOW_USER = gql`
mutation FollowUser($user_id: ID!) {
follow(id: $user_id) {
Expand Down Expand Up @@ -235,43 +237,31 @@ function ProfileHeader(props) {
};
}, []);

const handleCoverChange = (event) => {
const handleCoverChange = async (event) => {
const files = event.target.files;
if (files.length > 0) {
setCover(URL.createObjectURL(files[0]));

const reader = new FileReader();
reader.readAsDataURL(files[0]);
reader.onloadend = () => {
changeCover({
variables: {
image: reader.result,
},
});
};
reader.onerror = () => {
showSnackbar("Something went wrong!");
};
const optimizedImage = await optimizeImage(files[0]);
changeCover({
variables: {
image: optimizedImage,
},
});
}
};

const handlePhotoChange = (event) => {
const handlePhotoChange = async (event) => {
const files = event.target.files;
if (files.length > 0) {
setPhoto(URL.createObjectURL(files[0]));

const reader = new FileReader();
reader.readAsDataURL(files[0]);
reader.onloadend = () => {
changeImage({
variables: {
image: reader.result,
},
});
};
reader.onerror = () => {
showSnackbar("Something went wrong!");
};
const optimizedImage = await optimizeImage(files[0]);
changeImage({
variables: {
image: optimizedImage,
},
});
}
};

Expand Down
26 changes: 11 additions & 15 deletions frontend/src/dialogs/CreateGroupDialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { gql, useMutation } from "@apollo/client";
import { connect } from "react-redux";
import { setDialog, showSnackbar } from "../state/actions";

import optimizeImage from "../utils/image";

const CREATE_GROUP = gql`
mutation CreateGroup(
$title: String!
Expand Down Expand Up @@ -109,22 +111,16 @@ function CreatePostDialog(props) {
setCardContentHeight(cardContent.current.offsetHeight);
});

const handleCreate = () => {
const handleCreate = async () => {
if (cover) {
const reader = new FileReader();
reader.readAsDataURL(cover);
reader.onloadend = () => {
createGroup({
variables: {
title,
current_user_id: user.id,
cover_image: reader.result,
},
});
};
reader.onerror = () => {
showSnackbar("Something went wrong!");
};
const optimizedImage = await optimizeImage(cover);
createGroup({
variables: {
title,
current_user_id: user.id,
cover_image: optimizedImage,
},
});
} else {
createGroup({
variables: {
Expand Down
24 changes: 10 additions & 14 deletions frontend/src/dialogs/CreatePageDialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { gql, useMutation } from "@apollo/client";
import { connect } from "react-redux";
import { setDialog, showSnackbar } from "../state/actions";

import optimizeImage from "../utils/image";

const CREATE_PAGE = gql`
mutation CreatePage(
$title: String!
Expand Down Expand Up @@ -107,21 +109,15 @@ function CreatePostDialog(props) {
setCardContentHeight(cardContent.current.offsetHeight);
});

const handleCreate = () => {
const handleCreate = async () => {
if (cover) {
const reader = new FileReader();
reader.readAsDataURL(cover);
reader.onloadend = () => {
createPage({
variables: {
title,
cover_image: reader.result,
},
});
};
reader.onerror = () => {
showSnackbar("Something went wrong!");
};
const optimizedImage = await optimizeImage(cover);
createPage({
variables: {
title,
cover_image: optimizedImage,
},
});
} else {
createPage({
variables: {
Expand Down
42 changes: 19 additions & 23 deletions frontend/src/dialogs/CreatePostDialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { gql, useMutation } from "@apollo/client";
import { connect } from "react-redux";
import { setDialog, showSnackbar } from "../state/actions";

import optimizeImage from "../utils/image";

const ADD_PROFILE_POST = gql`
mutation AddProfilePost($text: String!, $image: String) {
createPost(body: $text, imageSrc: $image) {
Expand Down Expand Up @@ -134,30 +136,24 @@ function CreatePostDialog(props) {
setCardContentHeight(cardContent.current.offsetHeight);
});

const handlePost = () => {
const handlePost = async () => {
if (media) {
const reader = new FileReader();
reader.readAsDataURL(media);
reader.onloadend = () => {
switch (postForm.type) {
case "profile":
addProfilePost({ variables: { text, image: reader.result } });
break;
case "group":
addGroupPost({
variables: { group_id: postForm.id, text, image: reader.result },
});
break;
case "page":
addPagePost({
variables: { page_id: postForm.id, text, image: reader.result },
});
break;
}
};
reader.onerror = () => {
showSnackbar("Something went wrong!");
};
const optimizedImage = await optimizeImage(media);
switch (postForm.type) {
case "profile":
addProfilePost({ variables: { text, image: optimizedImage } });
break;
case "group":
addGroupPost({
variables: { group_id: postForm.id, text, image: optimizedImage },
});
break;
case "page":
addPagePost({
variables: { page_id: postForm.id, text, image: optimizedImage },
});
break;
}
} else {
switch (postForm.type) {
case "profile":
Expand Down
49 changes: 49 additions & 0 deletions frontend/src/utils/image.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const MAX_WIDTH = 1280;
const QUALITY = 0.92;

const readPhoto = async (photo) => {
const canvas = document.createElement("canvas");
const img = document.createElement("img");

img.src = await new Promise((resolve) => {
const reader = new FileReader();
reader.onload = (e) => resolve(e.target.result);
reader.readAsDataURL(photo);
});
await new Promise((resolve) => {
img.onload = resolve;
});

// draw image in canvas element
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext("2d").drawImage(img, 0, 0, canvas.width, canvas.height);

return canvas;
};

const scaleCanvas = (canvas, scale) => {
const scaledCanvas = document.createElement("canvas");
scaledCanvas.width = canvas.width * scale;
scaledCanvas.height = canvas.height * scale;

scaledCanvas
.getContext("2d")
.drawImage(canvas, 0, 0, scaledCanvas.width, scaledCanvas.height);

return scaledCanvas;
};

export default async (photo) => {
let canvas = await readPhoto(photo);

while (canvas.width >= 2 * MAX_WIDTH) {
canvas = scaleCanvas(canvas, 0.5);
}

if (canvas.width > MAX_WIDTH) {
canvas = scaleCanvas(canvas, MAX_WIDTH / canvas.width);
}

return canvas.toDataURL("image/jpeg", QUALITY);
};

0 comments on commit ca6ae7c

Please sign in to comment.