feat/image blob #8

Merged
CrispyBaguette merged 2 commits from feat/image-blob into master 2021-12-13 12:59:30 +00:00
5 changed files with 34 additions and 29 deletions

View File

@ -24,7 +24,7 @@
"web-vitals": "^1.1.2"
},
"scripts": {
"start": "react-scripts start",
"start": "BROWSER=none react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"

View File

@ -12,17 +12,18 @@ enum AppState {
}
function App() {
const [baseImage, setBaseImage] = React.useState<Uint8ClampedArray>();
const [ditheredImage, setDitheredImage] = React.useState<Uint8ClampedArray>();
const [baseImage, setBaseImage] = React.useState<Blob>();
const [ditheredImage, setDitheredImage] = React.useState<Blob>();
const [appState, setAppState] = React.useState<AppState>(AppState.NO_IMAGE);
const handleImageSubmit = async (data: Uint8ClampedArray) => {
const handleImageSubmit = async (data: Blob) => {
setBaseImage(data);
setAppState(AppState.IMAGE_LOADED);
try {
const ditheredImage = await new Ditherer().dither(data);
setDitheredImage(ditheredImage);
const imageArray = new Uint8ClampedArray(await data.arrayBuffer());
const ditheredImage = await new Ditherer().dither(imageArray);
setDitheredImage(new Blob([ditheredImage], { type: "image/png" }));
setAppState(AppState.IMAGE_PROCESSED);
} catch (e) {
console.error(e);
@ -50,11 +51,11 @@ function App() {
</p>
</article>
<ImageInput onImageSubmit={handleImageSubmit}></ImageInput>
{appState === AppState.IMAGE_LOADED && (
<ImagePreview imageData={baseImage as Uint8ClampedArray} />
{appState === AppState.IMAGE_LOADED && baseImage && (
<ImagePreview imageData={baseImage} />
)}
{appState === AppState.IMAGE_PROCESSED && (
<ImageOutput imageData={ditheredImage as Uint8ClampedArray} />
{appState === AppState.IMAGE_PROCESSED && ditheredImage && (
<ImageOutput imageData={ditheredImage} />
)}
</main>
</div>

View File

@ -1,11 +1,10 @@
import React, { FormEventHandler } from "react";
interface Props {
onImageSubmit: (image: Uint8ClampedArray) => void;
onImageSubmit: (image: Blob) => void;
}
function ImageInput({ onImageSubmit }: Props) {
let fileReader: FileReader;
const fileInputRef = React.useRef<HTMLInputElement>(null);
const handleSubmit: FormEventHandler = (e) => {
@ -18,16 +17,7 @@ function ImageInput({ onImageSubmit }: Props) {
return;
}
fileReader = new FileReader();
fileReader.onloadend = handleFileRead;
fileReader.readAsArrayBuffer(fileInputRef.current.files[0]);
};
const handleFileRead: EventListener = (e) => {
if (fileReader.result) {
const image = new Uint8ClampedArray(fileReader.result as ArrayBuffer);
onImageSubmit(image);
}
onImageSubmit(fileInputRef.current.files[0]);
};
return (

View File

@ -1,16 +1,23 @@
import FileSaver from "file-saver";
import { useEffect } from "react";
import "./ImageOutput.css";
interface OutputProps {
imageData: Uint8ClampedArray;
imageData: Blob;
}
function ImageOutput({ imageData }: OutputProps) {
const imageBlob = new Blob([imageData], { type: "image/png" });
const imageUrl = URL.createObjectURL(imageBlob);
const imageUrl = URL.createObjectURL(imageData);
useEffect(() => {
return () => {
URL.revokeObjectURL(imageUrl);
}
}, [imageUrl]);
const handleClick = () => {
FileSaver.saveAs(imageBlob, "image.png");
const extension = imageData.type.split("/")[1];
FileSaver.saveAs(imageData, `image.${extension}`);
};
return (

View File

@ -1,10 +1,17 @@
import { useEffect } from "react";
interface ImagePreviewProps {
imageData: Uint8ClampedArray;
imageData: Blob;
}
function ImagePreview({ imageData }: ImagePreviewProps) {
const imageBlob = new Blob([imageData], { type: "image/png" });
const imageUrl = URL.createObjectURL(imageBlob);
const imageUrl = URL.createObjectURL(imageData);
useEffect(() => {
return () => {
URL.revokeObjectURL(imageUrl);
}
}, [imageUrl]);
return (
<div className="blur-sm mx-auto">