feat/image blob #8
@ -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>
|
||||
|
@ -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 (
|
||||
|
@ -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 (
|
||||
|
@ -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">
|
||||
|
Loading…
Reference in New Issue
Block a user