1
0
mirror of https://github.com/upscayl/upscayl.git synced 2024-11-23 23:21:05 +01:00

Removed jsx

This commit is contained in:
Feenix 2022-11-12 02:11:28 +05:30
parent a2e7cc16a7
commit 973525bac9
16 changed files with 484 additions and 890 deletions

25
main/binaries.js Normal file
View File

@ -0,0 +1,25 @@
"use strict";
/*
appRootDir is the resources directory inside the unpacked electron app temp directory.
resources contains app.asar file, that contains the main and renderer files.
We're putting resources/{os}/bin from project inside resources/bin of electron. Same for the models directory as well.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.modelsPath = exports.execPath = void 0;
const path_1 = require("path");
const getPlatform_1 = require("./getPlatform");
const electron_is_dev_1 = __importDefault(require("electron-is-dev"));
const electron_1 = require("electron");
const appRootDir = electron_1.app.getAppPath();
const binariesPath = electron_is_dev_1.default
? (0, path_1.join)(appRootDir, "resources", (0, getPlatform_1.getPlatform)(), "bin")
: (0, path_1.join)((0, path_1.dirname)(appRootDir), "bin");
const execPath = (execName) => (0, path_1.resolve)((0, path_1.join)(binariesPath, `./upscayl-${execName}`));
exports.execPath = execPath;
const modelsPath = electron_is_dev_1.default
? (0, path_1.resolve)((0, path_1.join)(appRootDir, "resources", "models"))
: (0, path_1.resolve)((0, path_1.join)((0, path_1.dirname)(appRootDir), "models"));
exports.modelsPath = modelsPath;

BIN
main/build/icon.icns Normal file

Binary file not shown.

BIN
main/build/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

17
main/commands.js Normal file
View File

@ -0,0 +1,17 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
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",
DOUBLE_UPSCAYL: "Double Upscale the Image",
DOUBLE_UPSCAYL_DONE: "Double Upscaling Done",
DOUBLE_UPSCAYL_PROGRESS: "Send Double Upscayl Progress from Main to Renderer",
FOLDER_UPSCAYL: "Upscale a Folder",
FOLDER_UPSCAYL_DONE: "Folder upscaling successful",
FOLDER_UPSCAYL_PROGRESS: "Send Folder Upscaling Progress from Main to Renderer",
OPEN_FOLDER: "Open Folder",
};
exports.default = commands;

20
main/getPlatform.js Normal file
View File

@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getPlatform = void 0;
const os_1 = require("os");
const getPlatform = () => {
switch ((0, os_1.platform)()) {
case "aix":
case "freebsd":
case "linux":
case "openbsd":
case "android":
return "linux";
case "darwin":
case "sunos":
return "mac";
case "win32":
return "win";
}
};
exports.getPlatform = getPlatform;

390
main/index.js Normal file
View File

@ -0,0 +1,390 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
// Native
const path_1 = require("path");
const url_1 = require("url");
const child_process_1 = require("child_process");
const fs_1 = __importDefault(require("fs"));
const electron_updater_1 = require("electron-updater");
const getPlatform_1 = require("./getPlatform");
const binaries_1 = require("./binaries");
// Packages
const electron_1 = require("electron");
const electron_is_dev_1 = __importDefault(require("electron-is-dev"));
const electron_next_1 = __importDefault(require("electron-next"));
const commands_1 = __importDefault(require("./commands"));
// Prepare the renderer once the app is ready
let mainWindow;
electron_1.app.on("ready", () => __awaiter(void 0, void 0, void 0, function* () {
yield (0, electron_next_1.default)("./renderer");
console.log("🚀 Icon Path: ", (0, path_1.join)(__dirname, "build", "icon.png"));
console.log("🚀 Development Mode? :", electron_is_dev_1.default);
console.log("🚀 RS Executable Path: ", (0, binaries_1.execPath)(""));
console.log("🚀 Models: ", binaries_1.modelsPath);
mainWindow = new electron_1.BrowserWindow({
icon: (0, path_1.join)(__dirname, "build", "icon.png"),
width: 1100,
height: 740,
minHeight: 500,
minWidth: 500,
show: false,
backgroundColor: "#171717",
webPreferences: {
nodeIntegration: true,
webSecurity: false,
preload: (0, path_1.join)(__dirname, "preload.js"),
},
});
const url = electron_is_dev_1.default
? "http://localhost:8000"
: (0, url_1.format)({
pathname: (0, path_1.join)(__dirname, "../renderer/out/index.html"),
protocol: "file:",
slashes: true,
});
mainWindow.setMenuBarVisibility(false);
mainWindow.loadURL(url);
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
electron_1.shell.openExternal(url);
return { action: "deny" };
});
mainWindow.once("ready-to-show", () => {
mainWindow.show();
mainWindow.webContents.setZoomFactor(1);
});
if (!electron_is_dev_1.default) {
electron_updater_1.autoUpdater.checkForUpdates();
}
}));
// Quit the app once all windows are closed
electron_1.app.on("window-all-closed", electron_1.app.quit);
console.log(electron_1.app.getAppPath());
//------------------------Select File-----------------------------//
// ! DONT FORGET TO RESTART THE APP WHEN YOU CHANGE CODE HERE
electron_1.ipcMain.handle(commands_1.default.SELECT_FILE, () => __awaiter(void 0, void 0, void 0, function* () {
const { canceled, filePaths } = yield electron_1.dialog.showOpenDialog({
properties: ["openFile", "multiSelections"],
});
if (canceled) {
console.log("operation cancelled");
return "cancelled";
}
else {
console.log(filePaths[0]);
// CREATE input AND upscaled FOLDER
return filePaths[0];
}
}));
//------------------------Select Folder-----------------------------//
electron_1.ipcMain.handle(commands_1.default.SELECT_FOLDER, (event, message) => __awaiter(void 0, void 0, void 0, function* () {
const { canceled, filePaths } = yield electron_1.dialog.showOpenDialog({
properties: ["openDirectory"],
});
if (canceled) {
console.log("operation cancelled");
return "cancelled";
}
else {
console.log(filePaths[0]);
return filePaths[0];
}
}));
//------------------------Double Upscayl-----------------------------//
electron_1.ipcMain.on(commands_1.default.DOUBLE_UPSCAYL, (event, payload) => __awaiter(void 0, void 0, void 0, function* () {
const model = payload.model;
let inputDir = payload.imagePath.match(/(.*)[\/\\]/)[1] || "";
let outputDir = payload.outputPath;
// COPY IMAGE TO TMP FOLDER
const platform = (0, getPlatform_1.getPlatform)();
const fullfileName = platform === "win"
? payload.imagePath.split("\\").slice(-1)[0]
: payload.imagePath.split("/").slice(-1)[0];
const fileName = (0, path_1.parse)(fullfileName).name;
const fileExt = (0, path_1.parse)(fullfileName).ext;
const outFile = outputDir + "/" + fileName + "_upscayl_8x_" + model + fileExt;
// UPSCALE
let upscayl = (0, child_process_1.spawn)((0, binaries_1.execPath)("realesrgan"), [
"-i",
inputDir + "/" + fullfileName,
"-o",
outFile,
"-s",
4,
"-m",
binaries_1.modelsPath,
"-n",
model,
], {
cwd: undefined,
detached: false,
});
let failed = false;
// TAKE UPSCAYL OUTPUT
upscayl.stderr.on("data", (data) => {
// CONVERT DATA TO STRING
data = data.toString();
// PRINT TO CONSOLE
console.log(data);
// SEND UPSCAYL PROGRESS TO RENDERER
mainWindow.webContents.send(commands_1.default.DOUBLE_UPSCAYL_PROGRESS, data);
// IF PROGRESS HAS ERROR, UPSCAYL FAILED
if (data.includes("invalid gpu") || data.includes("failed")) {
failed = true;
}
});
// IF ERROR
upscayl.on("error", (data) => {
data.toString();
// SEND UPSCAYL PROGRESS TO RENDERER
mainWindow.webContents.send(commands_1.default.DOUBLE_UPSCAYL_PROGRESS, data);
// SET FAILED TO TRUE
failed = true;
return;
});
// ON UPSCAYL DONE
upscayl.on("close", (code) => {
// IF NOT FAILED
if (!failed) {
// UPSCALE
let upscayl2 = (0, child_process_1.spawn)((0, binaries_1.execPath)("realesrgan"), ["-i", outFile, "-o", outFile, "-s", 4, "-m", binaries_1.modelsPath, "-n", model], {
cwd: undefined,
detached: false,
});
let failed2 = false;
// TAKE UPSCAYL OUTPUT
upscayl2.stderr.on("data", (data) => {
// CONVERT DATA TO STRING
data = data.toString();
// PRINT TO CONSOLE
console.log(data);
// SEND UPSCAYL PROGRESS TO RENDERER
mainWindow.webContents.send(commands_1.default.DOUBLE_UPSCAYL_PROGRESS, data);
// IF PROGRESS HAS ERROR, UPSCAYL FAILED
if (data.includes("invalid gpu") || data.includes("failed")) {
failed2 = true;
}
});
// IF ERROR
upscayl2.on("error", (data) => {
data.toString();
// SEND UPSCAYL PROGRESS TO RENDERER
mainWindow.webContents.send(commands_1.default.DOUBLE_UPSCAYL_PROGRESS, data);
// SET FAILED TO TRUE
failed2 = true;
return;
});
upscayl2.on("close", (code) => {
if (!failed2) {
console.log("Done upscaling");
mainWindow.webContents.send(commands_1.default.DOUBLE_UPSCAYL_DONE, outFile);
}
});
}
});
}));
//------------------------Image Upscayl-----------------------------//
electron_1.ipcMain.on(commands_1.default.UPSCAYL, (event, payload) => __awaiter(void 0, void 0, void 0, function* () {
const model = payload.model;
const scale = payload.scaleFactor;
let inputDir = payload.imagePath.match(/(.*)[\/\\]/)[1] || "";
let outputDir = payload.outputPath;
// COPY IMAGE TO TMP FOLDER
const platform = (0, getPlatform_1.getPlatform)();
const fullfileName = platform === "win"
? payload.imagePath.split("\\").slice(-1)[0]
: payload.imagePath.split("/").slice(-1)[0];
console.log(fullfileName);
const fileName = (0, path_1.parse)(fullfileName).name;
const fileExt = (0, path_1.parse)(fullfileName).ext;
const outFile = model.includes("realesrgan")
? outputDir + "/" + fileName + "_upscayl_" + scale + "x_" + model + fileExt
: outputDir +
"/" +
fileName +
"_upscayl_sharpened_" +
scale +
"x_" +
model +
fileExt;
// UPSCALE
if (fs_1.default.existsSync(outFile)) {
// If already upscayled, just output that file
mainWindow.webContents.send(commands_1.default.UPSCAYL_DONE, outFile);
}
else {
let upscayl = null;
switch (model) {
case "realesrgan-x4plus":
case "realesrgan-x4plus-anime":
upscayl = (0, child_process_1.spawn)((0, binaries_1.execPath)("realesrgan"), [
"-i",
inputDir + "/" + fullfileName,
"-o",
outFile,
"-s",
scale === 2 ? 4 : scale,
"-m",
binaries_1.modelsPath,
"-n",
model,
], {
cwd: undefined,
detached: false,
});
break;
case "models-DF2K":
upscayl = (0, child_process_1.spawn)((0, binaries_1.execPath)("realsr"), [
"-i",
inputDir + "/" + fullfileName,
"-o",
outFile,
"-s",
scale,
"-x",
"-m",
binaries_1.modelsPath + "/" + model,
], {
cwd: undefined,
detached: false,
});
break;
}
let failed = false;
upscayl === null || upscayl === void 0 ? void 0 : upscayl.stderr.on("data", (data) => {
console.log("🚀 => upscayl.stderr.on => stderr.toString()", data.toString());
data = data.toString();
mainWindow.webContents.send(commands_1.default.UPSCAYL_PROGRESS, data.toString());
if (data.includes("invalid gpu") || data.includes("failed")) {
failed = true;
}
});
upscayl === null || upscayl === void 0 ? void 0 : upscayl.on("error", (data) => {
mainWindow.webContents.send(commands_1.default.UPSCAYL_PROGRESS, data.toString());
failed = true;
return;
});
// Send done comamnd when
upscayl === null || upscayl === void 0 ? void 0 : upscayl.on("close", (code) => {
if (failed !== true) {
console.log("Done upscaling");
mainWindow.webContents.send(commands_1.default.UPSCAYL_DONE, outFile);
}
});
}
}));
//------------------------Upscayl Folder-----------------------------//
electron_1.ipcMain.on(commands_1.default.FOLDER_UPSCAYL, (event, payload) => __awaiter(void 0, void 0, void 0, function* () {
const model = payload.model;
let inputDir = payload.batchFolderPath;
let outputDir = model.includes("realesrgan")
? payload.outputPath
: payload.outputPath + "_sharpened";
console.log(outputDir);
if (!fs_1.default.existsSync(outputDir)) {
fs_1.default.mkdirSync(outputDir, { recursive: true });
}
// UPSCALE
let upscayl = null;
switch (model) {
case "realesrgan-x4plus":
case "realesrgan-x4plus-anime":
upscayl = (0, child_process_1.spawn)((0, binaries_1.execPath)("realesrgan"), [
"-i",
inputDir,
"-o",
outputDir,
"-s",
4,
"-m",
binaries_1.modelsPath,
"-n",
model,
], {
cwd: undefined,
detached: false,
});
break;
case "models-DF2K":
upscayl = (0, child_process_1.spawn)((0, binaries_1.execPath)("realsr"), [
"-i",
inputDir,
"-o",
outputDir,
"-s",
4,
"-x",
"-m",
binaries_1.modelsPath + "/" + model,
], {
cwd: undefined,
detached: false,
});
break;
}
let failed = false;
upscayl === null || upscayl === void 0 ? void 0 : upscayl.stderr.on("data", (data) => {
console.log("🚀 => upscayl.stderr.on => stderr.toString()", data.toString());
data = data.toString();
mainWindow.webContents.send(commands_1.default.FOLDER_UPSCAYL_PROGRESS, data.toString());
if (data.includes("invalid gpu") || data.includes("failed")) {
failed = true;
}
});
upscayl === null || upscayl === void 0 ? void 0 : upscayl.on("error", (data) => {
mainWindow.webContents.send(commands_1.default.FOLDER_UPSCAYL_PROGRESS, data.toString());
failed = true;
return;
});
// Send done comamnd when
upscayl === null || upscayl === void 0 ? void 0 : upscayl.on("close", (code) => {
if (failed !== true) {
console.log("Done upscaling");
mainWindow.webContents.send(commands_1.default.FOLDER_UPSCAYL_DONE, outputDir);
}
});
}));
electron_1.ipcMain.on(commands_1.default.OPEN_FOLDER, (event, payload) => __awaiter(void 0, void 0, void 0, function* () {
console.log(payload);
electron_1.shell.openPath(payload);
}));
//------------------------Auto-Update Code-----------------------------//
// ! AUTO UPDATE STUFF
electron_updater_1.autoUpdater.on("update-available", ({ releaseNotes, releaseName }) => {
const dialogOpts = {
type: "info",
buttons: ["Ok"],
title: "Application Update",
message: process.platform === "win32"
? releaseNotes
: releaseName,
detail: "A new version is being downloaded.",
};
electron_1.dialog.showMessageBox(dialogOpts).then((returnValue) => { });
});
electron_updater_1.autoUpdater.on("update-downloaded", (event) => {
const dialogOpts = {
type: "info",
buttons: ["Restart", "Later"],
title: "Application Update",
message: process.platform === "win32"
? event.releaseNotes
: event.releaseName,
detail: "A new version has been downloaded. Restart the application to apply the updates.",
};
electron_1.dialog.showMessageBox(dialogOpts).then((returnValue) => {
if (returnValue.response === 0)
electron_updater_1.autoUpdater.quitAndInstall();
});
});

11
main/preload.js Normal file
View File

@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const electron_1 = require("electron");
// 'ipcRenderer' will be available in index.js with the method 'window.electron'
electron_1.contextBridge.exposeInMainWorld("electron", {
send: (command, payload) => electron_1.ipcRenderer.send(command, payload),
on: (command, func) => electron_1.ipcRenderer.on(command, (event, args) => {
func(event, args);
}),
invoke: (command, payload) => electron_1.ipcRenderer.invoke(command, payload),
});

21
main/utils.js Normal file
View File

@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const child_process_1 = require("child_process");
const binaries_1 = require("./binaries");
/**
*
* @param {*} inputFile
* @param {*} outFile
* @param {*} modelsPath
* @param {*} model
* @returns
*/
function upscaylImage(inputFile, outFile, modelsPath, model) {
// UPSCALE
let upscayl = (0, child_process_1.spawn)((0, binaries_1.execPath)("realesrgan"), ["-i", inputFile, "-o", outFile, "-s", "4", "-m", modelsPath, "-n", model], {
cwd: undefined,
detached: false,
});
return upscayl;
}
module.exports = { upscaylImage };

View File

@ -1,162 +0,0 @@
{
"name": "upscayl",
"private": true,
"version": "1.5.5",
"productName": "Upscayl",
"homepage": "https://github.com/TGS963/upscayl",
"contributors": [
{
"name": "Nayam Amarshe",
"email": "nayam@amars.he",
"url": "https://github.com/NayamAmarshe"
},
{
"name": "TGS963",
"email": "tgs@963.com",
"url": "https://github.com/TGS963"
}
],
"email": "simplelogin-newsletter.j1zez@aleeas.com",
"license": "AGPL-3.0",
"description": "Upscayl - Free and Open Source AI Image Upscaler",
"keywords": [
"AI",
"Upscaler",
"Image Upscale",
"Linux image upscale",
"Topaz Gigapixel",
"Linux",
"KDE",
"Gnome"
],
"main": "main/index.js",
"scripts": {
"clean": "rimraf dist renderer/.next renderer/out",
"start": "electron .",
"build": "next build renderer && next export renderer",
"tsc": "tsc",
"pack-app": "npm run build && electron-builder --dir",
"dist": "npm run build && DEBUG=* electron-builder",
"dist:appimage": "npm run build && DEBUG=* electron-builder build -l AppImage",
"dist:flatpak": "npm run build && DEBUG=* electron-builder build -l flatpak",
"dist:zip": "npm run build && DEBUG=* electron-builder build -l zip",
"dist:dmg": "npm run build && DEBUG=* electron-builder build -m dmg",
"dist:msi": "npm run build && DEBUG=* electron-builder build -w nsis",
"dist:pkg": "npm run build && DEBUG=* electron-builder build -m pkg",
"publish-app": "npm run build && electron-builder -wl --publish always",
"publish-linux-app": "npm run build && electron-builder -l --publish always",
"publish-win-app": "npm run build && electron-builder -w --publish always",
"publish-mac-app": "npm run build && electron-builder -m --publish always"
},
"build": {
"productName": "Upscayl",
"appId": "org.upscayl.app",
"artifactName": "${name}-${version}-${os}.${ext}",
"asar": true,
"extraFiles": [
{
"from": "resources/${os}/bin",
"to": "resources/bin",
"filter": [
"**/*"
]
},
{
"from": "resources/models",
"to": "resources/models",
"filter": [
"**/*"
]
}
],
"mac": {
"type": "distribution",
"hardenedRuntime": true,
"entitlements": "main/resources/entitlements.mac.plist",
"entitlementsInherit": "main/resources/entitlements.mac.plist",
"gatekeeperAssess": false,
"target": [
{
"target": "dmg",
"arch": [
"x64"
]
}
]
},
"dmg": {
"contents": [
{
"x": 130,
"y": 220
},
{
"x": 410,
"y": 220,
"type": "link",
"path": "/Applications"
}
]
},
"linux": {
"publish": [
"github"
],
"target": [
"AppImage",
"flatpak",
"zip"
],
"category": "Graphics;2DGraphics;RasterGraphics;ImageProcessing;"
},
"win": {
"publish": [
"github"
],
"target": [
"nsis"
],
"icon": "main/build/icon.png"
},
"files": [
"main",
"renderer/out"
]
},
"devDependencies": {
"@types/electron": "^1.6.10",
"@types/node": "^18.11.9",
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.8",
"autoprefixer": "^10.4.13",
"electron": "^21.2.2",
"electron-builder": "^23.6.0",
"next": "^13.0.2",
"postcss": "^8.4.18",
"prettier": "^2.7.1",
"prettier-plugin-tailwindcss": "^0.1.13",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"tailwindcss": "^3.2.2",
"typescript": "^4.8.4"
},
"dependencies": {
"app-root-dir": "^1.0.2",
"electron-is-dev": "^2.0.0",
"electron-is-packaged": "^1.0.2",
"electron-next": "^3.1.5",
"electron-root-path": "^1.1.0",
"electron-updater": "^5.3.0",
"image-size": "^1.0.2",
"react-compare-slider": "^2.2.0",
"react-dropzone": "^14.2.3",
"react-image-zoom": "^1.3.1",
"react-magnifier": "^3.0.4",
"react-select": "^5.6.0",
"react-tooltip": "^4.4.3",
"tailwind-scrollbar": "^2.0.1"
},
"volta": {
"node": "16.17.0"
}
}

View File

@ -1,38 +0,0 @@
import React from "react";
function Footer() {
return (
<div className="p-2 text-center text-sm text-neutral-500">
<p>
Copyright © 2022 -{" "}
<a
className="font-bold"
href="https://github.com/upscayl/upscayl"
target="_blank"
>
Upscayl
</a>
</p>
<p>
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>
);
}
export default Footer;

View File

@ -1,24 +0,0 @@
import React from "react";
export default function Header() {
return (
<a
href="https://github.com/upscayl/upscayl"
target="_blank"
className="outline-none focus-visible:ring-2"
>
<div className="flex items-center gap-3 px-5 py-5">
<img
src="icon.png"
className="inline-block w-14"
alt="Upscayl Logo"
data-tip="Star us on GitHub 😁"
/>
<div className="flex flex-col justify-center">
<h1 className="text-3xl font-bold text-neutral-50">Upscayl</h1>
<p className="text-neutral-400">AI Image Upscaler</p>
</div>
</div>
</a>
);
}

View File

@ -1,203 +0,0 @@
import React from "react";
import Select from "react-select";
import ReactTooltip from "react-tooltip";
function LeftPaneSteps(props) {
const handleBatchMode = () => {
props.setBatchMode((oldValue) => !oldValue);
};
const customStyles = {
option: (provided, state) => ({
...provided,
borderBottom: "1px dotted pink",
color: state.isSelected ? "red" : "blue",
padding: 20,
}),
control: () => ({
// none of react-select's styles are passed to <Control />
width: 200,
}),
singleValue: (provided, state) => {
const opacity = state.isDisabled ? 0.5 : 1;
const transition = "opacity 300ms";
return { ...provided, opacity, transition };
},
};
const modelOptions = [
{ label: "General Photo", value: "realesrgan-x4plus" },
{ label: "Digital Art", value: "realesrgan-x4plus-anime" },
{ label: "Sharpen Image", value: "models-DF2K" },
];
return (
<div className="animate-step-in animate flex h-screen flex-col gap-7 overflow-auto p-5">
{/* BATCH OPTION */}
<div className="flex flex-row items-end">
<p
className="mr-1 inline-block cursor-help text-sm text-white/70"
data-tip="This will let you upscale all files in a folder at once"
>
Batch Upscale:
</p>
<button
className={`animate relative inline-block h-5 w-8 cursor-pointer rounded-full outline-none focus-visible:shadow-lg focus-visible:shadow-purple-500 ${
props.batchMode ? "bg-gradient-purple" : "bg-neutral-500"
}`}
onClick={handleBatchMode}
>
<div
className={`${
props.batchMode ? "translate-x-4" : "translate-x-1"
} animate absolute top-1/2 h-3 w-3 -translate-y-1/2 rounded-full bg-neutral-100`}
></div>
</button>
</div>
{/* STEP 1 */}
<div data-tip={props.imagePath}>
<p className="step-heading">Step 1</p>
<button
className="animate bg-gradient-red rounded-lg p-3 font-medium text-white/90 outline-none transition-colors focus-visible:shadow-lg focus-visible:shadow-red-500"
onClick={
!props.batchMode
? props.selectImageHandler
: props.selectFolderHandler
}
>
Select {props.batchMode ? "Folder" : "Image"}
</button>
</div>
{/* STEP 2 */}
<div className="animate-step-in">
<p className="step-heading">Step 2</p>
<p className="mb-2 text-sm text-white/60">Select Upscaling Type</p>
<Select
options={modelOptions}
components={{
IndicatorSeparator: () => null,
DropdownIndicator: () => null,
}}
onChange={props.handleModelChange}
className="react-select-container"
classNamePrefix="react-select"
defaultValue={modelOptions[0]}
theme={(theme) => ({
...theme,
colors: {
...theme.colors,
primary: "rgb(71 85 105)",
primary25: "#f5f5f5",
primary50: "#f5f5f5",
},
})}
styles={{
input: (provided, state) => ({
...provided,
color: "rgb(100 100 100)",
}),
dropdownIndicator: (provided, state) => ({
...provided,
color: "rgb(15 15 15)",
}),
placeholder: (provided, state) => ({
...provided,
color: "rgb(15 15 15)",
fontWeight: "500",
}),
singleValue: (provided, state) => ({
...provided,
color: "rgb(15 15 15)",
fontWeight: "500",
}),
menu: (provided, state) => ({
...provided,
background: "#f5f5f5",
}),
}}
/>
{/* <select
name="select-model"
onDrop={(e) => props.handleDrop(e)}
className="animate bg-gradient-white block cursor-pointer rounded-lg p-3 font-medium text-black/90 outline-none hover:bg-slate-200 focus-visible:ring-2 focus-visible:ring-slate-400"
onChange={props.handleModelChange}
>
<option value="realesrgan-x4plus">General Photo</option>
<option value="realesrgan-x4plus-anime">Digital Art</option>
<option value="models-DF2K">Sharpen Image</option>
</select> */}
{props.model !== "models-DF2K" && !props.batchMode && (
<div className="mt-2 flex items-center gap-1">
<input
type="checkbox"
className="checked:bg-gradient-white h-4 w-4 cursor-pointer appearance-none rounded-full bg-white/30 transition duration-200 focus:outline-none focus-visible:border focus-visible:shadow-lg focus-visible:shadow-white/40"
checked={props.doubleUpscayl}
onChange={(e) => {
if (e.target.checked) {
props.setDoubleUpscayl(true);
} else {
props.setDoubleUpscayl(false);
}
}}
/>
<p
className={`inline-block cursor-pointer select-none rounded-full text-sm font-medium ${
props.doubleUpscayl
? "bg-gradient-white px-2 text-black/90"
: "text-white/50"
}`}
onClick={(e) => {
props.setDoubleUpscayl(!props.doubleUpscayl);
}}
>
Double Upscayl
</p>
<span
className="cursor-help rounded-full bg-white/20 px-3 text-center font-bold text-white/40"
data-tip="Enable this option to get an 8x upscayl. Note that this may not always work properly with all images, for example, images with really large resolutions."
>
i
</span>
</div>
)}
</div>
{/* STEP 3 */}
<div className="animate-step-in" data-tip={props.outputPath}>
<p className="step-heading">Step 3</p>
<p className="mb-2 text-sm text-white/60">Defaults to Image's path</p>
<button
className="animate bg-gradient mt-1 rounded-lg p-3 font-medium text-black/90 outline-none transition-colors focus-visible:shadow-lg focus-visible:shadow-green-500"
onClick={props.outputHandler}
>
Set Output Folder
</button>
</div>
{/* STEP 4 */}
<div className="animate-step-in">
<p className="step-heading">Step 4</p>
<button
className="animate bg-gradient-upscayl rounded-lg p-3 font-medium text-white/90 outline-none transition-colors focus-visible:shadow-lg focus-visible:shadow-violet-500"
onClick={props.upscaylHandler}
disabled={props.progress.length > 0}
>
{props.progress.length > 0 ? "Upscayling⏳" : "Upscayl"}
</button>
</div>
<ReactTooltip
className="max-w-md break-words bg-neutral-900 text-neutral-50"
place="top"
/>
</div>
);
}
export default LeftPaneSteps;

View File

@ -1,20 +0,0 @@
import React from "react";
import Animated from "../public/loading.svg";
import Image from "next/image";
function ProgressBar(props) {
console.log(props.sharpening);
return (
<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">
<Image src={Animated} />
<p className="font-bold text-neutral-50">{props.progress}</p>
<p className="text-sm font-medium text-neutral-200">
Doing the Upscayl magic...
</p>
</div>
</div>
);
}
export default ProgressBar;

View File

@ -1,14 +0,0 @@
import React from "react";
function ResetButton(props) {
return (
<button
className="animate bg-gradient-blue absolute top-1 right-1 z-10 rounded-full py-2 px-4 text-white opacity-30 hover:opacity-100"
onClick={props.resetImagePaths}
>
Reset
</button>
);
}
export default ResetButton;

View File

@ -1,20 +0,0 @@
import React from "react";
function RightPaneInfo({ version, batchMode }) {
return (
<>
<p className="p-5 pb-0 text-lg font-medium text-neutral-400">
Select {batchMode ? "a Folder" : "an Image"} to Upscale
</p>
{batchMode && (
<p className="w-full py-5 text-center text-neutral-500 md:w-96">
Make sure that the folder doesn't contain anything except PNG, JPG,
JPEG & WEBP images.
</p>
)}
<p className="text-neutral-600">Upscayl v{version}</p>
</>
);
}
export default RightPaneInfo;

View File

@ -1,409 +0,0 @@
import { useState, useEffect, useRef, useCallback } from "react";
import commands from "../../main/commands";
import {
ReactCompareSlider,
ReactCompareSliderImage,
} from "react-compare-slider";
import Header from "../components/Header";
import Footer from "../components/Footer";
import ProgressBar from "../components/ProgressBar";
import ResetButton from "../components/ResetButton";
import LeftPaneSteps from "../components/LeftPaneSteps";
import RightPaneInfo from "../components/RightPaneInfo";
const Home = () => {
const [imagePath, SetImagePath] = 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 [version, setVersion] = useState("");
const [batchMode, setBatchMode] = useState(false);
const [batchFolderPath, setBatchFolderPath] = useState("");
const [upscaledBatchFolderPath, setUpscaledBatchFolderPath] = useState("");
const [doubleUpscayl, setDoubleUpscayl] = useState(false);
const resetImagePaths = () => {
setProgress("");
SetImagePath("");
setUpscaledImagePath("");
setBatchFolderPath("");
setUpscaledBatchFolderPath("");
};
useEffect(() => {
setLoaded(true);
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
setVersion(navigator.userAgent.match(/Upscayl\/([\d\.]+\d+)/)[1]);
const handleErrors = (data) => {
if (data.includes("invalid gpu")) {
alert(
"Error. Please make sure you have a Vulkan compatible GPU (Most modern GPUs support Vulkan). Upscayl does not work with CPU or iGPU sadly."
);
resetImagePaths();
} else if (data.includes("failed")) {
if (batchMode) return;
alert(
data.includes("encode") ? "ENCODING ERROR => " : "DECODING ERROR => ",
"This image is possibly corrupt or not supported by Upscayl. You could try converting the image into another format and upscaling again. Otherwise, make sure that the output path is correct and you have the proper write permissions for the directory. If not, then unfortuantely this image is not supported by Upscayl, sorry."
);
resetImagePaths();
} else if (data.includes("uncaughtException")) {
alert(
"Upscayl encountered an error. Possibly, the upscayl binary failed to execute the commands properly. Try launching Upscayl using commandline through Terminal and see if you get any information. You can post an issue on Upscayl's GitHub repository for more help."
);
resetImagePaths();
}
};
window.electron.on(commands.UPSCAYL_PROGRESS, (_, data) => {
console.log(
"🚀 => file: index.jsx => line 61 => window.electron.on => data",
data
);
if (data.length > 0 && data.length < 10) {
setProgress(data);
}
handleErrors(data);
});
window.electron.on(commands.FOLDER_UPSCAYL_PROGRESS, (_, data) => {
if (data.length > 0 && data.length < 10) {
setProgress(data);
}
handleErrors(data);
});
window.electron.on(commands.DOUBLE_UPSCAYL_PROGRESS, (_, data) => {
if (data.length > 0 && data.length < 10) {
setProgress(data);
}
handleErrors(data);
});
window.electron.on(commands.UPSCAYL_DONE, (_, data) => {
setProgress("");
setUpscaledImagePath(data);
});
window.electron.on(commands.FOLDER_UPSCAYL_DONE, (_, data) => {
setProgress("");
setUpscaledBatchFolderPath(data);
});
window.electron.on(commands.DOUBLE_UPSCAYL_DONE, (_, data) => {
setUpscaledImagePath(data);
});
}, []);
useEffect(() => {
setProgress("");
}, [batchMode]);
useEffect(() => {
if (imagePath.length > 0) {
const filePath = imagePath;
console.log(
"🚀 => file: index.jsx => line 109 => useEffect => filePath",
filePath
);
const extension = imagePath.toLocaleLowerCase().split(".").pop();
console.log(
"🚀 => file: index.jsx => line 111 => useEffect => extension",
extension
);
if (!allowedFileTypes.includes(extension.toLowerCase())) {
alert("Please select an image");
resetImagePaths();
}
}
}, [imagePath]);
const selectImageHandler = async () => {
resetImagePaths();
var path = await window.electron.invoke(commands.SELECT_FILE);
if (path !== "cancelled") {
SetImagePath(path);
var dirname = path.match(/(.*)[\/\\]/)[1] || "";
SetOutputPath(dirname);
}
};
const selectFolderHandler = async () => {
resetImagePaths();
var path = await window.electron.invoke(commands.SELECT_FOLDER);
if (path !== "cancelled") {
setBatchFolderPath(path);
SetOutputPath(path + "_upscayled");
}
};
const handleModelChange = (e) => {
setModel(e.value);
if (e.value === "models-DF2K") {
setDoubleUpscayl(false);
}
};
const handleDragEnter = (e) => {
e.preventDefault();
console.log("drag enter");
};
const handleDragLeave = (e) => {
e.preventDefault();
console.log("drag leave");
};
const handleDragOver = (e) => {
e.preventDefault();
console.log("drag over");
};
const openFolderHandler = (e) => {
window.electron.send(commands.OPEN_FOLDER, upscaledBatchFolderPath);
};
const allowedFileTypes = ["png", "jpg", "jpeg", "webp"];
const handleDrop = (e) => {
e.preventDefault();
resetImagePaths();
const type = e.dataTransfer.items[0].type;
console.log("🚀 => handleDrop => type", type);
const filePath = e.dataTransfer.files[0].path;
console.log("🚀 => handleDrop => filePath", filePath);
const extension = e.dataTransfer.files[0].name.split(".").at(-1);
console.log("🚀 => handleDrop => extension", extension);
if (
!type.includes("image") ||
!allowedFileTypes.includes(extension.toLowerCase())
) {
alert("Please drag and drop an image");
} else {
SetImagePath(filePath);
var dirname = filePath.match(/(.*)[\/\\]/)[1] || "";
console.log("🚀 => handleDrop => dirname", dirname);
SetOutputPath(dirname);
}
};
const handlePaste = (e) => {
console.log(e);
resetImagePaths();
e.preventDefault();
const type = e.clipboardData.items[0].type;
const filePath = e.clipboardData.files[0].path;
const extension = e.clipboardData.files[0].name.split(".").at(-1);
if (
!type.includes("image") &&
!allowedFileTypes.includes(extension.toLowerCase())
) {
alert("Please drag and drop an image");
} else {
SetImagePath(filePath);
var dirname = filePath.match(/(.*)[\/\\]/)[1] || "";
SetOutputPath(dirname);
}
};
const outputHandler = async () => {
var path = await window.electron.invoke(commands.SELECT_FOLDER);
if (path !== "cancelled") {
SetOutputPath(path);
} else {
console.log("Getting output path from input file");
}
};
const upscaylHandler = async () => {
setUpscaledImagePath("");
if (imagePath !== "" || batchFolderPath !== "") {
setProgress("Hold on...");
if (model === "models-DF2K") {
setDoubleUpscayl(false);
}
if (doubleUpscayl) {
await window.electron.send(commands.DOUBLE_UPSCAYL, {
imagePath,
outputPath,
model,
});
} else if (batchMode) {
setDoubleUpscayl(false);
await window.electron.send(commands.FOLDER_UPSCAYL, {
scaleFactor,
batchFolderPath,
outputPath,
model,
});
} else {
await window.electron.send(commands.UPSCAYL, {
scaleFactor,
imagePath,
outputPath,
model,
});
}
} else {
alert("Please select an image to upscale");
}
};
return (
<div className="flex h-screen w-screen flex-row overflow-hidden bg-[#1d1c23]">
<div className="flex h-screen w-96 flex-col bg-[#26222c]">
{((!batchMode && imagePath.length > 0) ||
(batchMode && batchFolderPath.length > 0)) && (
<ResetButton resetImagePaths={resetImagePaths} />
)}
{/* HEADER */}
<Header />
{/* LEFT PANE */}
<LeftPaneSteps
progress={progress}
selectImageHandler={selectImageHandler}
selectFolderHandler={selectFolderHandler}
handleModelChange={handleModelChange}
handleDrop={handleDrop}
outputHandler={outputHandler}
upscaylHandler={upscaylHandler}
batchMode={batchMode}
setBatchMode={setBatchMode}
imagePath={imagePath}
outputPath={outputPath}
doubleUpscayl={doubleUpscayl}
setDoubleUpscayl={setDoubleUpscayl}
model={model}
/>
<Footer />
</div>
{/* RIGHT PANE */}
<div
className="relative flex h-screen w-full flex-col items-center justify-center"
onDrop={(e) => handleDrop(e)}
onDragOver={(e) => handleDragOver(e)}
onDragEnter={(e) => handleDragEnter(e)}
onDragLeave={(e) => handleDragLeave(e)}
onPaste={(e) => handlePaste(e)}
>
{progress.length > 0 &&
upscaledImagePath.length === 0 &&
upscaledBatchFolderPath.length === 0 ? (
<ProgressBar progress={progress} />
) : null}
{((!batchMode &&
imagePath.length === 0 &&
upscaledImagePath.length === 0) ||
(batchMode &&
batchFolderPath.length === 0 &&
upscaledBatchFolderPath.length === 0)) && (
<RightPaneInfo version={version} batchMode={batchMode} />
)}
{!batchMode &&
upscaledImagePath.length === 0 &&
imagePath.length > 0 && (
<img
className="h-full w-full object-contain"
src={
"file://" +
`${upscaledImagePath ? upscaledImagePath : imagePath}`
}
draggable="false"
alt=""
/>
)}
{batchMode &&
upscaledBatchFolderPath.length === 0 &&
batchFolderPath.length > 0 && (
<p className="select-none font-bold text-neutral-50">
Selected folder: {batchFolderPath}
</p>
)}
{batchMode && upscaledBatchFolderPath.length > 0 && (
<>
<p className="select-none py-4 font-bold text-neutral-50">
All done!
</p>
<button
className="bg-gradient-blue rounded-lg p-3 font-medium text-white/90 transition-colors"
onClick={openFolderHandler}
>
Open Upscayled Folder
</button>
</>
)}
{!batchMode && imagePath.length > 0 && upscaledImagePath.length > 0 && (
<ReactCompareSlider
itemOne={
<>
<p className="absolute bottom-1 left-1 rounded-md bg-black p-1 text-sm font-medium text-white opacity-30">
Original
</p>
<ReactCompareSliderImage
src={"file://" + imagePath}
alt="Original"
style={{
objectFit: "contain",
}}
className="bg-[#1d1c23]"
/>
</>
}
itemTwo={
<>
<p className="absolute bottom-1 right-1 rounded-md bg-black p-1 text-sm font-medium text-white opacity-30">
Upscayled
</p>
<ReactCompareSliderImage
src={"file://" + upscaledImagePath}
alt="Upscayl"
style={{
objectFit: "contain",
}}
className="bg-[#1d1c23]"
/>
</>
}
className="h-screen"
/>
)}
{/* {imagePath.length === 0 && batchFolderPath.length === 0 ? (
<RightPaneInfo version={version} />
) : upscaledImagePath.length === 0 &&
upscaledBatchFolderPath.length === 0 ? (
!batchMode ? (
) : (
)
) : !batchMode ? (
) : (
)} */}
</div>
</div>
);
};
export default Home;