1
0
mirror of https://github.com/upscayl/upscayl.git synced 2024-11-24 07:30:19 +01:00

Added sharp

This commit is contained in:
Feenix 2022-08-18 15:23:23 +05:30
parent 3f9e7b1be7
commit 3e9f790347
15 changed files with 9128 additions and 446 deletions

9
constants/commands.js Normal file
View File

@ -0,0 +1,9 @@
const commands = {
SELECT_FILE: "Select a File",
SELECT_FOLDER: "Select a Folder",
UPSCAYL: "Upscale the Image",
UPSCAYL_DONE: "Upscaling Done",
UPSCAYL_PROGRESS: "Send Progress from Main to Renderer",
};
module.exports = commands;

0
constants/models.js Normal file
View File

View File

@ -3,6 +3,7 @@ const { join, parse } = require("path");
const { format } = require("url"); const { format } = require("url");
const { spawn } = require("child_process"); const { spawn } = require("child_process");
const fs = require("fs"); const fs = require("fs");
const sizeOf = require("image-size");
const { execPath, modelsPath } = require("./binaries"); const { execPath, modelsPath } = require("./binaries");
@ -13,9 +14,12 @@ const {
ipcMain, ipcMain,
dialog, dialog,
ipcRenderer, ipcRenderer,
shell,
} = require("electron"); } = require("electron");
const isDev = require("electron-is-dev"); const isDev = require("electron-is-dev");
const prepareNext = require("electron-next"); const prepareNext = require("electron-next");
const commands = require("../constants/commands");
const sharp = require("sharp");
// Prepare the renderer once the app is ready // Prepare the renderer once the app is ready
let mainWindow; let mainWindow;
@ -25,9 +29,12 @@ app.on("ready", async () => {
mainWindow = new BrowserWindow({ mainWindow = new BrowserWindow({
width: 1100, width: 1100,
height: 700, height: 700,
minHeight: 500,
minWidth: 500,
webPreferences: { webPreferences: {
autoHideMenuBar: true, autoHideMenuBar: true,
nodeIntegration: true, nodeIntegration: true,
webSecurity: false,
preload: join(__dirname, "preload.js"), preload: join(__dirname, "preload.js"),
}, },
}); });
@ -42,17 +49,19 @@ app.on("ready", async () => {
mainWindow.setMenuBarVisibility(false); mainWindow.setMenuBarVisibility(false);
// mainWindow.maximize(); // mainWindow.maximize();
mainWindow.loadURL(url); mainWindow.loadURL(url);
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
shell.openExternal(url);
return { action: "deny" };
});
}); });
// Quit the app once all windows are closed // Quit the app once all windows are closed
app.on("window-all-closed", app.quit); app.on("window-all-closed", app.quit);
// ! DONT FORGET TO RESTART THE APP WHEN YOU CHANGE CODE HERE // ! DONT FORGET TO RESTART THE APP WHEN YOU CHANGE CODE HERE
ipcMain.on("sendMessage", (_, message) => {
console.log(message);
});
ipcMain.handle("open", async () => { ipcMain.handle(commands.SELECT_FILE, async () => {
const { canceled, filePaths } = await dialog.showOpenDialog({ const { canceled, filePaths } = await dialog.showOpenDialog({
properties: ["openFile", "multiSelections"], properties: ["openFile", "multiSelections"],
}); });
@ -65,34 +74,37 @@ ipcMain.handle("open", async () => {
// CREATE input AND upscaled FOLDER // CREATE input AND upscaled FOLDER
return filePaths[0]; return filePaths[0];
} }
}) });
ipcMain.handle("output", async (event, message) => {
ipcMain.handle(commands.SELECT_FOLDER, async (event, message) => {
const { canceled, filePaths } = await dialog.showOpenDialog({ const { canceled, filePaths } = await dialog.showOpenDialog({
properties: ["openDirectory"], properties: ["openDirectory"],
}); });
if (canceled) { if (canceled) {
console.log("operation cancelled"); console.log("operation cancelled");
return "cancelled"; return "cancelled";
} } else {
else { console.log(filePaths[0]);
console.log(filePaths[0])
return filePaths[0]; return filePaths[0];
} }
}) });
ipcMain.on("upscayl", async (event, paths) => { ipcMain.on(commands.UPSCAYL, async (event, payload) => {
const scale = "4"; console.log(payload);
let inputDir = paths[0].match(/(.*)[\/\\]/)[1]||''; const model = payload.model;
const scale = payload.scaleFactor;
let inputDir = payload.imagePath.match(/(.*)[\/\\]/)[1] || "";
/*if (!fs.existsSync(inputDir)) { /*if (!fs.existsSync(inputDir)) {
fs.mkdirSync(inputDir); fs.mkdirSync(inputDir);
}*/ }*/
let outputDir = paths[1]; let outputDir = payload.outputPath;
/*if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir); // if (!fs.existsSync(outputDir)) {
}*/ // fs.mkdirSync(outputDir);
// }
// COPY IMAGE TO upscaled FOLDER // COPY IMAGE TO upscaled FOLDER
const fullfileName = paths[0].split("/").slice(-1)[0]; const fullfileName = payload.imagePath.split("/").slice(-1)[0];
const fileName = parse(fullfileName).name; const fileName = parse(fullfileName).name;
const fileExt = parse(fullfileName).ext; const fileExt = parse(fullfileName).ext;
@ -101,15 +113,17 @@ ipcMain.on("upscayl", async (event, paths) => {
execPath, execPath,
[ [
"-i", "-i",
inputDir+'/'+fullfileName, inputDir + "/" + fullfileName,
"-o", "-o",
outputDir+'/'+fileName+"_upscaled_"+scale+'x'+fileExt, outputDir + "/" + fileName + "_upscayled_" + scale + "x" + fileExt,
"-s", "-s",
scale, scale === 2 ? 4 : scale,
"-m", "-m",
modelsPath, modelsPath, // if (!fs.existsSync(outputDir)) {
// fs.mkdirSync(outputDir);
// }
"-n", "-n",
"realesrgan-x4plus", model,
], ],
{ {
cwd: null, cwd: null,
@ -120,11 +134,14 @@ ipcMain.on("upscayl", async (event, paths) => {
upscayl.stderr.on("data", (stderr) => { upscayl.stderr.on("data", (stderr) => {
console.log(stderr.toString()); console.log(stderr.toString());
stderr = stderr.toString(); stderr = stderr.toString();
mainWindow.webContents.send("output", stderr.toString()); mainWindow.webContents.send(commands.UPSCAYL_PROGRESS, stderr.toString());
}); });
upscayl.on("close", (code) => { upscayl.on("close", (code) => {
console.log("Done upscaling"); console.log("Done upscaling");
mainWindow.webContents.send("done"); mainWindow.webContents.send(
commands.UPSCAYL_DONE,
outputDir + "/" + fileName + "_upscayled_" + scale + "x" + fileExt
);
}); });
}) });

View File

@ -8,10 +8,4 @@ contextBridge.exposeInMainWorld("electron", {
func(event, args); func(event, args);
}), }),
invoke: (command, payload) => ipcRenderer.invoke(command, payload), invoke: (command, payload) => ipcRenderer.invoke(command, payload),
startListen: (func) => {
ipcRenderer.addListener("stdout",func)
},
stopListen: (func) => {
ipcRenderer.removeListener("stdout",func)
},
}); });

7236
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -67,6 +67,10 @@
"electron-is-dev": "^2.0.0", "electron-is-dev": "^2.0.0",
"electron-is-packaged": "^1.0.2", "electron-is-packaged": "^1.0.2",
"electron-next": "^3.1.5", "electron-next": "^3.1.5",
"electron-root-path": "^1.0.16" "electron-root-path": "^1.0.16",
"image-size": "^1.0.2",
"react-compare-slider": "^2.2.0",
"sharp": "^0.30.7",
"tailwind-scrollbar": "^1.3.1"
} }
} }

View File

@ -1,84 +1,219 @@
import { useState, useEffect, useRef } from "react"; import { useState, useEffect, useRef } from "react";
import commands from "../../constants/commands";
import {
ReactCompareSlider,
ReactCompareSliderImage,
} from "react-compare-slider";
const Home = () => { const Home = () => {
const [imagePath, SetImagePath] = useState(); const [imagePath, SetImagePath] = useState("");
const [outputPath, SetOutputPath] = useState(); const [upscaledImagePath, setUpscaledImagePath] = useState("");
const [outputPath, SetOutputPath] = useState("");
const [scaleFactor, setScaleFactor] = useState(4);
const [progress, setProgress] = useState("");
const [model, setModel] = useState("realesrgan-x4plus");
const [loaded, setLoaded] = useState(false); const [loaded, setLoaded] = useState(false);
useEffect(() => { useEffect(() => {
const handleMessage = (_event, args) => console.log(args)
window.electron.startListen(handleMessage)
// send(command, payload)
window.electron.send("sendMessage", { message: "Hello!" });
setLoaded(true); setLoaded(true);
window.electron.on("output", (_, data) => { window.electron.on(commands.UPSCAYL_PROGRESS, (_, data) => {
if (data.length > 0 && data.length < 10) console.log(data); if (data.length > 0 && data.length < 10) setProgress(data);
}); });
window.electron.on("done", (_, data) => { window.electron.on(commands.UPSCAYL_DONE, (_, data) => {
console.log("DONE!"); setUpscaledImagePath(data);
}); });
return () => {
window.electron.stopListen(handleMessage)
}
}, []); }, []);
const imageHandler = async () => { const selectImageHandler = async () => {
var path = await window.electron.invoke("open"); SetImagePath("");
if (path != "cancelled") { setUpscaledImagePath("");
setProgress("");
var path = await window.electron.invoke(commands.SELECT_FILE);
if (path !== "cancelled") {
SetImagePath(path); SetImagePath(path);
var dirname = path.match(/(.*)[\/\\]/)[1]||'' var dirname = path.match(/(.*)[\/\\]/)[1] || "";
SetOutputPath(dirname) SetOutputPath(dirname);
} }
}; };
const outputHandler = async () => {
var path = await window.electron.invoke("output"); const outputHandler = async () => {
if (path != "cancelled") { var path = await window.electron.invoke(commands.SELECT_FOLDER);
SetOutputPath(path) if (path !== "cancelled") {
} SetOutputPath(path);
else{ } else {
console.log("Getting output path from input file") console.log("Getting output path from input file");
} }
}; };
const upscaylHandler = async () => {
window.electron.send("upscayl", [imagePath, outputPath]); const upscaylHandler = async () => {
}; setProgress("0.00%");
await window.electron.send(commands.UPSCAYL, {
scaleFactor,
imagePath,
outputPath,
model,
});
};
useEffect(() => {
console.log(progress);
}, [progress]);
return ( return (
<div className="flex h-screen w-screen flex-row bg-neutral-900"> <div className="flex h-screen w-screen flex-row overflow-hidden bg-neutral-900">
<div className="flex h-screen w-96 flex-col bg-neutral-800 p-5"> <div className="flex h-screen w-96 flex-col bg-neutral-800">
<h1 className="text-3xl font-bold text-neutral-50">Upscayl</h1> {/* HEADER */}
<div className="mt-10"> <h1 className="pl-5 pt-5 text-3xl font-bold text-neutral-50">
Upscayl
</h1>
<p className="mb-2 pl-5 text-neutral-400">AI Image Upscaler</p>
{/* LEFT PANE */}
<div className="h-screen overflow-auto p-5">
{/* STEP 1 */}
<div className="mt-5">
<p className="mb-2 font-medium text-neutral-100">Step 1</p> <p className="mb-2 font-medium text-neutral-100">Step 1</p>
<button className="rounded-lg bg-sky-400 p-3" onClick={imageHandler}> <button
className="rounded-lg bg-rose-400 p-3"
onClick={selectImageHandler}
>
Select Image Select Image
</button> </button>
</div> </div>
{/* STEP 2 */}
<div className="mt-10"> <div className="mt-10">
<p className="mb-2 font-medium text-neutral-100">Step 2</p> <p className="font-medium text-neutral-100">Step 2</p>
<p className="mb-1 text-neutral-300">Select Scale Factor:</p> <p className="mb-2 text-sm text-neutral-400">Select Scale Factor</p>
<div className="flex flex-row gap-2"> <div className="animate flex flex-row gap-2">
<button className="rounded-lg bg-red-400 p-3">2x</button> <button
<button className="rounded-lg bg-red-400 p-3">4x</button> className={`h-12 w-12 rounded-lg ${
<button className="rounded-lg bg-red-400 p-3">6x</button> scaleFactor === 2 ? "bg-yellow-400" : "bg-neutral-400"
}`}
onClick={() => setScaleFactor(2)}
>
2x
</button>
<button
className={`h-12 w-12 rounded-lg ${
scaleFactor === 3 ? "bg-yellow-400" : "bg-neutral-400"
}`}
onClick={() => setScaleFactor(3)}
>
3x
</button>
<button
className={`h-12 w-12 rounded-lg ${
scaleFactor === 4 ? "bg-yellow-400" : "bg-neutral-400"
}`}
onClick={() => setScaleFactor(6)}
>
4x
</button>
</div> </div>
</div> </div>
{/* STEP 3 */}
<div className="mt-10"> <div className="mt-10">
<p className="mb-2 font-medium text-neutral-100">Step 3</p> <p className="font-medium text-neutral-100">Step 3</p>
<button className="rounded-lg bg-violet-400 p-3" onClick={outputHandler}> <p className="mb-2 text-sm text-neutral-400">
Defaults to Image's path
</p>
<button
className="rounded-lg bg-teal-400 p-3"
onClick={outputHandler}
>
Set Output Folder Set Output Folder
</button> </button>
</div> </div>
{/* STEP 4 */}
<div className="mt-10"> <div className="mt-10">
<p className="mb-2 font-medium text-neutral-100">Step 4</p> <p className="mb-2 font-medium text-neutral-100">Step 4</p>
<button className="rounded-lg bg-green-400 p-3" onClick={upscaylHandler}>Upscayl</button> <button
className="rounded-lg bg-sky-400 p-3"
onClick={upscaylHandler}
>
Upscayl
</button>
</div> </div>
</div> </div>
<div className="flex h-screen w-full flex-col items-center justify-center p-5">
<p className="text-lg font-medium text-neutral-400"> <div className="p-2 text-center text-sm text-neutral-500">
<p>
Copyright © 2022 -{" "}
<a
className="font-bold"
href="https://github.com/TGS963/upscayl"
target="_blank"
>
Upscayl
</a>
</p>
<p>
Made by{" "}
<a
href="https://github.com/TGS963"
className="font-bold"
target="_blank"
>
TGS963
</a>{" "}
and{" "}
<a
href="https://github.com/NayamAmarshe"
className="font-bold"
target="_blank"
>
Nayam Amarshe
</a>
</p>
</div>
</div>
{/* RIGHT PANE */}
<div className="relative flex h-screen w-full flex-col items-center justify-center">
{progress.length > 0 && (
<div className="absolute flex h-full w-full flex-col items-center justify-center bg-black/50 backdrop-blur-lg">
<div className="flex flex-col items-center gap-2">
<img src="/loading.svg" className="w-10" alt="Loading" />
<p className="font-bold text-neutral-50">{progress}</p>
</div>
</div>
)}
{imagePath.length === 0 ? (
<p className="p-5 text-lg font-medium text-neutral-400">
Select an Image to Upscale Select an Image to Upscale
</p> </p>
) : upscaledImagePath.length === 0 ? (
<img
className="h-full w-full object-contain"
src={
"file://" + `${upscaledImagePath ? upscaledImagePath : imagePath}`
}
alt=""
/>
) : (
<ReactCompareSlider
itemOne={
<ReactCompareSliderImage
src={"file://" + imagePath}
alt="Original"
/>
}
itemTwo={
<ReactCompareSliderImage
src={"file://" + upscaledImagePath}
alt="Upscayl"
/>
}
className="h-full"
/>
)}
</div> </div>
</div> </div>
); );

View File

@ -0,0 +1,55 @@
<!-- By Sam Herbert (@sherb), for everyone. More @ http://goo.gl/7AJzbL -->
<svg width="58" height="58" viewBox="0 0 58 58" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<g transform="translate(2 1)" stroke="#FFF" stroke-width="1.5">
<circle cx="42.601" cy="11.462" r="5" fill-opacity="1" fill="#fff">
<animate attributeName="fill-opacity"
begin="0s" dur="1.3s"
values="1;0;0;0;0;0;0;0" calcMode="linear"
repeatCount="indefinite" />
</circle>
<circle cx="49.063" cy="27.063" r="5" fill-opacity="0" fill="#fff">
<animate attributeName="fill-opacity"
begin="0s" dur="1.3s"
values="0;1;0;0;0;0;0;0" calcMode="linear"
repeatCount="indefinite" />
</circle>
<circle cx="42.601" cy="42.663" r="5" fill-opacity="0" fill="#fff">
<animate attributeName="fill-opacity"
begin="0s" dur="1.3s"
values="0;0;1;0;0;0;0;0" calcMode="linear"
repeatCount="indefinite" />
</circle>
<circle cx="27" cy="49.125" r="5" fill-opacity="0" fill="#fff">
<animate attributeName="fill-opacity"
begin="0s" dur="1.3s"
values="0;0;0;1;0;0;0;0" calcMode="linear"
repeatCount="indefinite" />
</circle>
<circle cx="11.399" cy="42.663" r="5" fill-opacity="0" fill="#fff">
<animate attributeName="fill-opacity"
begin="0s" dur="1.3s"
values="0;0;0;0;1;0;0;0" calcMode="linear"
repeatCount="indefinite" />
</circle>
<circle cx="4.938" cy="27.063" r="5" fill-opacity="0" fill="#fff">
<animate attributeName="fill-opacity"
begin="0s" dur="1.3s"
values="0;0;0;0;0;1;0;0" calcMode="linear"
repeatCount="indefinite" />
</circle>
<circle cx="11.399" cy="11.462" r="5" fill-opacity="0" fill="#fff">
<animate attributeName="fill-opacity"
begin="0s" dur="1.3s"
values="0;0;0;0;0;0;1;0" calcMode="linear"
repeatCount="indefinite" />
</circle>
<circle cx="27" cy="5" r="5" fill-opacity="0" fill="#fff">
<animate attributeName="fill-opacity"
begin="0s" dur="1.3s"
values="0;0;0;0;0;0;0;1" calcMode="linear"
repeatCount="indefinite" />
</circle>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -3,6 +3,21 @@
@tailwind utilities; @tailwind utilities;
@layer base { @layer base {
::-webkit-scrollbar {
@apply w-3;
}
::-webkit-scrollbar-track {
@apply rounded-full bg-neutral-700;
}
::-webkit-scrollbar-thumb {
@apply rounded-full bg-neutral-500;
}
::-webkit-scrollbar-thumb:hover {
@apply rounded-full bg-neutral-400;
}
} }
@ -10,5 +25,4 @@
.animate { .animate {
@apply transition-all duration-300 ease-in-out; @apply transition-all duration-300 ease-in-out;
} }
} }

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -7,5 +7,5 @@ module.exports = {
extend: {}, extend: {},
}, },
darkMode: "class", darkMode: "class",
plugins: [], plugins: [require("tailwind-scrollbar")],
}; };

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 934 KiB

919
yarn.lock

File diff suppressed because it is too large Load Diff