PaletteSwitcher/client/src/App.tsx

117 lines
3.3 KiB
TypeScript
Raw Normal View History

2021-12-11 15:51:45 +00:00
import React from "react";
2021-12-11 15:19:48 +00:00
import "./App.css";
function App() {
2021-12-11 15:19:48 +00:00
const [imageSrc, setImageSrc] = React.useState("");
const fileInput = React.useRef<HTMLInputElement>(null);
const handleClick = async () => {
if (!fileInput.current) {
return;
}
const workerProxy: any = await wasmWorker("main.wasm");
setImageSrc("");
// Check if a file was selected
if (fileInput.current.files!.length === 0) {
alert("No file selected");
return;
}
const reader = new FileReader();
reader.readAsArrayBuffer(fileInput.current.files![0]);
reader.onloadend = async (evt) => {
if (evt.target!.readyState === FileReader.DONE) {
const imageData = new Uint8Array(evt.target!.result as ArrayBuffer);
2021-12-11 16:54:15 +00:00
const ditheredImageArray = await workerProxy.DitherNord(imageData);
const imageBlob = new Blob([ditheredImageArray.buffer], {
type: "image/png",
});
const url = URL.createObjectURL(imageBlob);
setImageSrc(url);
2021-12-11 15:19:48 +00:00
}
};
};
return (
2021-12-11 15:19:48 +00:00
<div className="App">
<input
type="file"
id="source-image"
ref={fileInput}
accept="image/png, image/jpeg"
/>
<button id="go-btn" type="button" onClick={handleClick}>
Go
</button>
<a id="output-wrapper" download="output.png" href={imageSrc}>
<div className="container">
<img
id="output"
alt="dithering output"
src={imageSrc}
2021-12-11 15:51:45 +00:00
style={{ display: imageSrc !== "" ? "block" : "none" }}
2021-12-11 15:19:48 +00:00
/>
</div>
</a>
</div>
);
}
2021-12-11 15:19:48 +00:00
function wasmWorker(modulePath: string) {
// Create an object to later interact with
const proxy: any = {};
// Keep track of the messages being sent
// so we can resolve them correctly
let id = 0;
let idPromises: any = {};
return new Promise((resolve, reject) => {
const worker = new Worker("./worker.js");
worker.postMessage({ eventType: "INITIALISE", eventData: modulePath });
worker.addEventListener("message", function (event: any) {
const { eventType, eventData, eventId } = event.data;
if (eventType === "INITIALISED") {
const methods = event.data.eventData;
methods.forEach((method: any) => {
proxy[method] = (...args: any[]) => {
return new Promise((resolve, reject) => {
worker.postMessage({
eventType: "CALL",
eventData: {
method: method,
arguments: Array.from(args),
},
eventId: id,
});
idPromises[id] = { resolve, reject };
id++;
});
};
});
resolve(proxy);
return;
} else if (eventType === "RESULT") {
if (eventId !== undefined && idPromises[eventId]) {
idPromises[eventId].resolve(eventData);
delete idPromises[eventId];
}
} else if (eventType === "ERROR") {
if (eventId !== undefined && idPromises[eventId]) {
idPromises[eventId].reject(event.data.eventData);
delete idPromises[eventId];
}
}
});
worker.addEventListener("error", function (error: any) {
reject(error);
});
});
}
export default App;