mirror of
https://github.com/upscayl/upscayl.git
synced 2024-11-27 17:00:52 +01:00
Add custom width
This commit is contained in:
parent
f240cca433
commit
bece033f4d
@ -3,12 +3,14 @@ import { getMainWindow } from "../main-window";
|
||||
import {
|
||||
childProcesses,
|
||||
customModelsFolderPath,
|
||||
customWidth,
|
||||
noImageProcessing,
|
||||
saveOutputFolder,
|
||||
setCompression,
|
||||
setNoImageProcessing,
|
||||
setStopped,
|
||||
stopped,
|
||||
useCustomWidth,
|
||||
} from "../utils/config-variables";
|
||||
import logit from "../utils/logit";
|
||||
import { spawnUpscayl } from "../utils/spawn-upscayl";
|
||||
@ -47,11 +49,11 @@ const batchUpscayl = async (event, payload: BatchUpscaylPayload) => {
|
||||
|
||||
let initialScale = getModelScale(model);
|
||||
|
||||
const desiredScale = payload.scale as string;
|
||||
const desiredScale = useCustomWidth
|
||||
? customWidth || payload.scale
|
||||
: payload.scale;
|
||||
|
||||
const outputFolderName = `upscayl_${model}_x${
|
||||
noImageProcessing ? initialScale : desiredScale
|
||||
}`;
|
||||
const outputFolderName = `upscayl_${model}_${noImageProcessing ? initialScale : desiredScale}${useCustomWidth ? "px_" : "x_"}`;
|
||||
outputFolderPath += slash + outputFolderName;
|
||||
if (!fs.existsSync(outputFolderPath)) {
|
||||
fs.mkdirSync(outputFolderPath, { recursive: true });
|
||||
@ -78,9 +80,9 @@ const batchUpscayl = async (event, payload: BatchUpscaylPayload) => {
|
||||
model,
|
||||
gpuId,
|
||||
saveImageAs,
|
||||
initialScale
|
||||
initialScale,
|
||||
),
|
||||
logit
|
||||
logit,
|
||||
);
|
||||
|
||||
childProcesses.push(upscayl);
|
||||
@ -94,7 +96,7 @@ const batchUpscayl = async (event, payload: BatchUpscaylPayload) => {
|
||||
data = data.toString();
|
||||
mainWindow.webContents.send(
|
||||
COMMAND.FOLDER_UPSCAYL_PROGRESS,
|
||||
data.toString()
|
||||
data.toString(),
|
||||
);
|
||||
if (data.includes("invalid") || data.includes("failed")) {
|
||||
logit("❌ INVALID GPU OR INVALID FILES IN FOLDER - FAILED");
|
||||
@ -110,14 +112,14 @@ const batchUpscayl = async (event, payload: BatchUpscaylPayload) => {
|
||||
mainWindow.setProgressBar(-1);
|
||||
mainWindow.webContents.send(
|
||||
COMMAND.FOLDER_UPSCAYL_PROGRESS,
|
||||
data.toString()
|
||||
data.toString(),
|
||||
);
|
||||
failed = true;
|
||||
upscayl.kill();
|
||||
mainWindow &&
|
||||
mainWindow.webContents.send(
|
||||
COMMAND.UPSCAYL_ERROR,
|
||||
"Error upscaling image. Error: " + data
|
||||
"Error upscaling image. Error: " + data,
|
||||
);
|
||||
return;
|
||||
};
|
||||
@ -133,7 +135,7 @@ const batchUpscayl = async (event, payload: BatchUpscaylPayload) => {
|
||||
mainWindow.setProgressBar(-1);
|
||||
mainWindow.webContents.send(
|
||||
COMMAND.FOLDER_UPSCAYL_DONE,
|
||||
outputFolderPath
|
||||
outputFolderPath,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@ -148,19 +150,19 @@ const batchUpscayl = async (event, payload: BatchUpscaylPayload) => {
|
||||
isAlpha
|
||||
? `${outputFolderPath}${slash}${removeFileExtension(file)}.png`
|
||||
: `${outputFolderPath}${slash}${removeFileExtension(
|
||||
file
|
||||
file,
|
||||
)}.${saveImageAs}`,
|
||||
`${outputFolderPath}${slash}${removeFileExtension(
|
||||
file
|
||||
file,
|
||||
)}.${saveImageAs}`,
|
||||
desiredScale,
|
||||
saveImageAs,
|
||||
isAlpha
|
||||
isAlpha,
|
||||
);
|
||||
});
|
||||
mainWindow.webContents.send(
|
||||
COMMAND.FOLDER_UPSCAYL_DONE,
|
||||
outputFolderPath
|
||||
outputFolderPath,
|
||||
);
|
||||
showNotification("Upscayled", "Image upscayled successfully!");
|
||||
} catch (error) {
|
||||
@ -170,7 +172,7 @@ const batchUpscayl = async (event, payload: BatchUpscaylPayload) => {
|
||||
mainWindow.webContents.send(
|
||||
COMMAND.UPSCAYL_ERROR,
|
||||
"Error processing (scaling and converting) the image. Please report this error on Upscayl GitHub Issues page.\n" +
|
||||
error
|
||||
error,
|
||||
);
|
||||
showNotification("Upscayl Failure", "Failed to upscale image!");
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import { getMainWindow } from "../main-window";
|
||||
import {
|
||||
childProcesses,
|
||||
customModelsFolderPath,
|
||||
customWidth,
|
||||
noImageProcessing,
|
||||
outputFolderPath,
|
||||
saveOutputFolder,
|
||||
@ -10,6 +11,7 @@ import {
|
||||
setNoImageProcessing,
|
||||
setStopped,
|
||||
stopped,
|
||||
useCustomWidth,
|
||||
} from "../utils/config-variables";
|
||||
import slash from "../utils/slash";
|
||||
import { spawnUpscayl } from "../utils/spawn-upscayl";
|
||||
@ -55,7 +57,9 @@ const doubleUpscayl = async (event, payload: DoubleUpscaylPayload) => {
|
||||
|
||||
let initialScale = getModelScale(model);
|
||||
|
||||
const desiredScale = parseInt(payload.scale) * parseInt(payload.scale);
|
||||
const desiredScale = useCustomWidth
|
||||
? customWidth || parseInt(payload.scale) * parseInt(payload.scale)
|
||||
: parseInt(payload.scale) * parseInt(payload.scale);
|
||||
|
||||
const outFile =
|
||||
outputDir +
|
||||
@ -65,7 +69,7 @@ const doubleUpscayl = async (event, payload: DoubleUpscaylPayload) => {
|
||||
(noImageProcessing
|
||||
? parseInt(initialScale) * parseInt(initialScale)
|
||||
: desiredScale) +
|
||||
"x_" +
|
||||
(useCustomWidth ? "px_" : "x_") +
|
||||
model +
|
||||
"." +
|
||||
saveImageAs;
|
||||
@ -80,9 +84,9 @@ const doubleUpscayl = async (event, payload: DoubleUpscaylPayload) => {
|
||||
model,
|
||||
gpuId,
|
||||
saveImageAs,
|
||||
initialScale
|
||||
initialScale,
|
||||
),
|
||||
logit
|
||||
logit,
|
||||
);
|
||||
|
||||
childProcesses.push(upscayl);
|
||||
@ -119,7 +123,7 @@ const doubleUpscayl = async (event, payload: DoubleUpscaylPayload) => {
|
||||
mainWindow &&
|
||||
mainWindow.webContents.send(
|
||||
COMMAND.UPSCAYL_ERROR,
|
||||
"Error upscaling image. Error: " + data
|
||||
"Error upscaling image. Error: " + data,
|
||||
);
|
||||
showNotification("Upscayl Failure", "Failed to upscale image!");
|
||||
upscayl.kill();
|
||||
@ -140,12 +144,12 @@ const doubleUpscayl = async (event, payload: DoubleUpscaylPayload) => {
|
||||
isAlpha
|
||||
? (outFile + ".png").replace(
|
||||
/([^/\\]+)$/i,
|
||||
encodeURIComponent((outFile + ".png").match(/[^/\\]+$/i)![0])
|
||||
encodeURIComponent((outFile + ".png").match(/[^/\\]+$/i)![0]),
|
||||
)
|
||||
: outFile.replace(
|
||||
/([^/\\]+)$/i,
|
||||
encodeURIComponent(outFile.match(/[^/\\]+$/i)![0])
|
||||
)
|
||||
encodeURIComponent(outFile.match(/[^/\\]+$/i)![0]),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@ -157,15 +161,15 @@ const doubleUpscayl = async (event, payload: DoubleUpscaylPayload) => {
|
||||
outFile,
|
||||
desiredScale.toString(),
|
||||
saveImageAs,
|
||||
isAlpha
|
||||
isAlpha,
|
||||
);
|
||||
mainWindow.setProgressBar(-1);
|
||||
mainWindow.webContents.send(
|
||||
COMMAND.DOUBLE_UPSCAYL_DONE,
|
||||
outFile.replace(
|
||||
/([^/\\]+)$/i,
|
||||
encodeURIComponent(outFile.match(/[^/\\]+$/i)![0])
|
||||
)
|
||||
encodeURIComponent(outFile.match(/[^/\\]+$/i)![0]),
|
||||
),
|
||||
);
|
||||
if (isAlpha && saveImageAs === "jpg") {
|
||||
unlinkSync(outFile + ".png");
|
||||
@ -177,7 +181,7 @@ const doubleUpscayl = async (event, payload: DoubleUpscaylPayload) => {
|
||||
mainWindow.webContents.send(
|
||||
COMMAND.UPSCAYL_ERROR,
|
||||
"Error processing (scaling and converting) the image. Please report this error on Upscayl GitHub Issues page.\n" +
|
||||
error
|
||||
error,
|
||||
);
|
||||
showNotification("Upscayl Failure", "Failed to upscale image!");
|
||||
upscayl.kill();
|
||||
@ -199,9 +203,9 @@ const doubleUpscayl = async (event, payload: DoubleUpscaylPayload) => {
|
||||
model,
|
||||
gpuId,
|
||||
saveImageAs,
|
||||
initialScale
|
||||
initialScale,
|
||||
),
|
||||
logit
|
||||
logit,
|
||||
);
|
||||
|
||||
childProcesses.push(upscayl2);
|
||||
@ -228,7 +232,7 @@ const doubleUpscayl = async (event, payload: DoubleUpscaylPayload) => {
|
||||
mainWindow &&
|
||||
mainWindow.webContents.send(
|
||||
COMMAND.UPSCAYL_ERROR,
|
||||
"Error upscaling image. Error: " + data
|
||||
"Error upscaling image. Error: " + data,
|
||||
);
|
||||
showNotification("Upscayl Failure", "Failed to upscale image!");
|
||||
upscayl2.kill();
|
||||
|
@ -4,6 +4,7 @@ import COMMAND from "../../common/commands";
|
||||
import {
|
||||
compression,
|
||||
customModelsFolderPath,
|
||||
customWidth,
|
||||
folderPath,
|
||||
noImageProcessing,
|
||||
outputFolderPath,
|
||||
@ -13,6 +14,7 @@ import {
|
||||
setNoImageProcessing,
|
||||
setStopped,
|
||||
stopped,
|
||||
useCustomWidth,
|
||||
} from "../utils/config-variables";
|
||||
import convertAndScale from "../utils/convert-and-scale";
|
||||
import { getSingleImageArguments } from "../utils/get-arguments";
|
||||
@ -62,7 +64,9 @@ const imageUpscayl = async (event, payload: ImageUpscaylPayload) => {
|
||||
|
||||
let initialScale = getModelScale(model);
|
||||
|
||||
const desiredScale = payload.scale;
|
||||
const desiredScale = useCustomWidth
|
||||
? customWidth || payload.scale
|
||||
: payload.scale;
|
||||
|
||||
const outFile =
|
||||
outputDir +
|
||||
@ -70,7 +74,7 @@ const imageUpscayl = async (event, payload: ImageUpscaylPayload) => {
|
||||
fileName +
|
||||
"_upscayl_" +
|
||||
(noImageProcessing ? initialScale : desiredScale) +
|
||||
"x_" +
|
||||
(useCustomWidth ? "px_" : "x_") +
|
||||
model +
|
||||
"." +
|
||||
saveImageAs;
|
||||
@ -83,8 +87,8 @@ const imageUpscayl = async (event, payload: ImageUpscaylPayload) => {
|
||||
COMMAND.UPSCAYL_DONE,
|
||||
outFile.replace(
|
||||
/([^/\\]+)$/i,
|
||||
encodeURIComponent(outFile.match(/[^/\\]+$/i)![0])
|
||||
)
|
||||
encodeURIComponent(outFile.match(/[^/\\]+$/i)![0]),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
logit(
|
||||
@ -101,7 +105,7 @@ const imageUpscayl = async (event, payload: ImageUpscaylPayload) => {
|
||||
desiredScale,
|
||||
outFile,
|
||||
compression,
|
||||
})
|
||||
}),
|
||||
);
|
||||
const upscayl = spawnUpscayl(
|
||||
getSingleImageArguments(
|
||||
@ -112,9 +116,9 @@ const imageUpscayl = async (event, payload: ImageUpscaylPayload) => {
|
||||
model,
|
||||
initialScale,
|
||||
gpuId,
|
||||
saveImageAs
|
||||
saveImageAs,
|
||||
),
|
||||
logit
|
||||
logit,
|
||||
);
|
||||
|
||||
setChildProcesses(upscayl);
|
||||
@ -157,8 +161,8 @@ const imageUpscayl = async (event, payload: ImageUpscaylPayload) => {
|
||||
COMMAND.UPSCAYL_DONE,
|
||||
outFile.replace(
|
||||
/([^/\\]+)$/i,
|
||||
encodeURIComponent(outFile.match(/[^/\\]+$/i)![0])
|
||||
)
|
||||
encodeURIComponent(outFile.match(/[^/\\]+$/i)![0]),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@ -172,7 +176,7 @@ const imageUpscayl = async (event, payload: ImageUpscaylPayload) => {
|
||||
outFile,
|
||||
desiredScale,
|
||||
saveImageAs,
|
||||
isAlpha
|
||||
isAlpha,
|
||||
);
|
||||
// Remove the png file (default) if the saveImageAs is not png
|
||||
// fs.access(
|
||||
@ -190,20 +194,20 @@ const imageUpscayl = async (event, payload: ImageUpscaylPayload) => {
|
||||
COMMAND.UPSCAYL_DONE,
|
||||
outFile.replace(
|
||||
/([^/\\]+)$/i,
|
||||
encodeURIComponent(outFile.match(/[^/\\]+$/i)![0])
|
||||
)
|
||||
encodeURIComponent(outFile.match(/[^/\\]+$/i)![0]),
|
||||
),
|
||||
);
|
||||
showNotification("Upscayl", "Image upscayled successfully!");
|
||||
} catch (error) {
|
||||
logit(
|
||||
"❌ Error processing (scaling and converting) the image. Please report this error on GitHub.",
|
||||
error
|
||||
error,
|
||||
);
|
||||
upscayl.kill();
|
||||
mainWindow.webContents.send(
|
||||
COMMAND.UPSCAYL_ERROR,
|
||||
"Error processing (scaling and converting) the image. Please report this error on Upscayl GitHub Issues page.\n" +
|
||||
error
|
||||
error,
|
||||
);
|
||||
showNotification("Upscayl Failure", "Failed to upscale image!");
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ export let childProcesses: {
|
||||
}[] = [];
|
||||
export let noImageProcessing: boolean = false;
|
||||
export let turnOffNotifications: boolean = false;
|
||||
export let customWidth: string | null = null;
|
||||
export let useCustomWidth: boolean = false;
|
||||
|
||||
export function setImagePath(value: string | undefined): void {
|
||||
imagePath = value;
|
||||
@ -62,7 +64,7 @@ export function setChildProcesses(value: {
|
||||
JSON.stringify({
|
||||
binary: childProcesses[0].process.spawnfile,
|
||||
args: childProcesses[0].process.spawnargs,
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@ -76,6 +78,16 @@ export function setTurnOffNotifications(value: boolean): void {
|
||||
logit("🔕 Updating Turn Off Notifications: ", turnOffNotifications);
|
||||
}
|
||||
|
||||
export function setCustomWidth(value: string | null): void {
|
||||
customWidth = value;
|
||||
logit("📏 Updating Custom Width: ", customWidth);
|
||||
}
|
||||
|
||||
export function setUseCustomWidth(value: boolean): void {
|
||||
useCustomWidth = value;
|
||||
logit("📏 Updating Use Custom Width: ", useCustomWidth);
|
||||
}
|
||||
|
||||
// LOCAL STORAGE
|
||||
export function fetchLocalStorage(): void {
|
||||
const mainWindow = getMainWindow();
|
||||
@ -101,7 +113,7 @@ export function fetchLocalStorage(): void {
|
||||
mainWindow.webContents
|
||||
.executeJavaScript(
|
||||
'localStorage.getItem("lastCustomModelsFolderPath");',
|
||||
true
|
||||
true,
|
||||
)
|
||||
.then((lastCustomModelsFolderPath: string | null) => {
|
||||
if (lastCustomModelsFolderPath && lastCustomModelsFolderPath.length > 0) {
|
||||
@ -149,4 +161,22 @@ export function fetchLocalStorage(): void {
|
||||
setTurnOffNotifications(lastSaved === "true");
|
||||
}
|
||||
});
|
||||
|
||||
// GET CUSTOM WIDTH (STRING) FROM LOCAL STORAGE
|
||||
mainWindow.webContents
|
||||
.executeJavaScript('localStorage.getItem("customWidth");', true)
|
||||
.then((lastSaved: string | null) => {
|
||||
if (lastSaved !== null) {
|
||||
setCustomWidth(lastSaved);
|
||||
}
|
||||
});
|
||||
|
||||
// GET USE CUSTOM WIDTH (BOOLEAN) FROM LOCAL STORAGE
|
||||
mainWindow.webContents
|
||||
.executeJavaScript('localStorage.getItem("useCustomWidth");', true)
|
||||
.then((lastSaved: string | null) => {
|
||||
if (lastSaved !== null) {
|
||||
setUseCustomWidth(lastSaved === "true");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import fs from "fs";
|
||||
import sharp, { FormatEnum, Metadata } from "sharp";
|
||||
import logit from "./logit";
|
||||
import { compression } from "./config-variables";
|
||||
import { compression, customWidth } from "./config-variables";
|
||||
import { ImageFormat } from "./types";
|
||||
|
||||
const convertAndScale = async (
|
||||
@ -10,9 +10,9 @@ const convertAndScale = async (
|
||||
processedImagePath: string,
|
||||
scale: string,
|
||||
saveImageAs: ImageFormat,
|
||||
isAlpha: boolean
|
||||
isAlpha: boolean,
|
||||
) => {
|
||||
if (!isAlpha && scale === "4" && compression === 0) {
|
||||
if (!isAlpha && !customWidth && scale === "4" && compression === 0) {
|
||||
logit("Skipping compression for 4x scale and 0% compression");
|
||||
return;
|
||||
}
|
||||
@ -28,7 +28,7 @@ const convertAndScale = async (
|
||||
logit("🖼️ Checking if original image exists: ", originalImagePath);
|
||||
if (err) {
|
||||
throw new Error(
|
||||
"Could not grab the original image from the path provided! - " + err
|
||||
"Could not grab the original image from the path provided! - " + err,
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -38,23 +38,6 @@ const convertAndScale = async (
|
||||
}
|
||||
console.log("🚀 => originalImage:", originalImage);
|
||||
|
||||
// Resize the image to the scale
|
||||
const newImage = sharp(upscaledImagePath, {
|
||||
limitInputPixels: false,
|
||||
})
|
||||
.resize(
|
||||
originalImage.width && originalImage.width * parseInt(scale),
|
||||
originalImage.height && originalImage.height * parseInt(scale),
|
||||
{
|
||||
fit: "outside",
|
||||
}
|
||||
)
|
||||
.withMetadata({
|
||||
density: originalImage.density,
|
||||
orientation: originalImage.orientation,
|
||||
});
|
||||
|
||||
console.log("🚀 => newImage:", newImage);
|
||||
// Convert compression percentage (0-100) to compressionLevel (0-9)
|
||||
const compressionLevel = Math.round((compression / 100) * 9);
|
||||
|
||||
@ -63,13 +46,33 @@ const convertAndScale = async (
|
||||
JSON.stringify({
|
||||
originalWidth: originalImage.width,
|
||||
originalHeight: originalImage.height,
|
||||
customWidth,
|
||||
scale,
|
||||
saveImageAs,
|
||||
compressionPercentage: compression,
|
||||
compressionLevel,
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
// Resize the image to the scale
|
||||
const newImage = sharp(upscaledImagePath, {
|
||||
limitInputPixels: false,
|
||||
})
|
||||
.resize(
|
||||
customWidth
|
||||
? parseInt(customWidth)
|
||||
: originalImage.width && originalImage.width * parseInt(scale),
|
||||
customWidth
|
||||
? null
|
||||
: originalImage.height && originalImage.height * parseInt(scale),
|
||||
)
|
||||
.withMetadata({
|
||||
density: originalImage.density,
|
||||
orientation: originalImage.orientation,
|
||||
});
|
||||
|
||||
console.log("🚀 => newImage:", newImage);
|
||||
|
||||
const buffer = await newImage
|
||||
.withMetadata({
|
||||
density: originalImage.density,
|
||||
|
@ -3,7 +3,7 @@ import { atomWithStorage } from "jotai/utils";
|
||||
|
||||
export const customModelsPathAtom = atomWithStorage<string | null>(
|
||||
"customModelsPath",
|
||||
null
|
||||
null,
|
||||
);
|
||||
export const scaleAtom = atomWithStorage<"2" | "3" | "4">("scale", "4");
|
||||
export const batchModeAtom = atom<boolean>(false);
|
||||
@ -12,17 +12,17 @@ export const progressAtom = atom<string>("");
|
||||
|
||||
export const rememberOutputFolderAtom = atomWithStorage<boolean>(
|
||||
"rememberOutputFolder",
|
||||
false
|
||||
false,
|
||||
);
|
||||
|
||||
export const dontShowCloudModalAtom = atomWithStorage<boolean>(
|
||||
"dontShowCloudModal",
|
||||
false
|
||||
false,
|
||||
);
|
||||
|
||||
export const noImageProcessingAtom = atomWithStorage<boolean>(
|
||||
"noImageProcessing",
|
||||
false
|
||||
false,
|
||||
);
|
||||
|
||||
export const compressionAtom = atomWithStorage<number>("compression", 0);
|
||||
@ -31,12 +31,22 @@ export const overwriteAtom = atomWithStorage("overwrite", false);
|
||||
|
||||
export const turnOffNotificationsAtom = atomWithStorage(
|
||||
"turnOffNotifications",
|
||||
false
|
||||
false,
|
||||
);
|
||||
|
||||
export const viewTypeAtom = atomWithStorage<"slider" | "lens">(
|
||||
"viewType",
|
||||
"lens"
|
||||
"lens",
|
||||
);
|
||||
|
||||
export const lensSizeAtom = atomWithStorage<number>("lensSize", 100);
|
||||
|
||||
export const customWidthAtom = atomWithStorage<number | null>(
|
||||
"customWidth",
|
||||
null,
|
||||
);
|
||||
|
||||
export const useCustomWidthAtom = atomWithStorage<boolean>(
|
||||
"useCustomWidth",
|
||||
false,
|
||||
);
|
||||
|
51
renderer/components/settings-tab/CustomResolutionInput.tsx
Normal file
51
renderer/components/settings-tab/CustomResolutionInput.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import { customWidthAtom, useCustomWidthAtom } from "@/atoms/userSettingsAtom";
|
||||
import { useAtom } from "jotai";
|
||||
import React, { useState } from "react";
|
||||
|
||||
export function CustomResolutionInput() {
|
||||
const [useCustomWidth, setUseCustomWidth] = useAtom(useCustomWidthAtom);
|
||||
const [customWidth, setCustomWidth] = useAtom(customWidthAtom);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<p className="text-sm font-medium">CUSTOM OUTPUT WIDTH</p>
|
||||
<p className="text-xs text-base-content/80">
|
||||
<b>REQUIRES RESTART</b>
|
||||
<br />
|
||||
Use a custom width for the output images. The height will be adjusted
|
||||
automatically. Enabling this will override the scale setting.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="toggle"
|
||||
checked={useCustomWidth}
|
||||
onClick={(e) => {
|
||||
if (!e.currentTarget.checked) {
|
||||
localStorage.removeItem("customWidth");
|
||||
}
|
||||
setUseCustomWidth(!useCustomWidth);
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
type="number"
|
||||
value={customWidth}
|
||||
disabled={!useCustomWidth}
|
||||
onChange={(e) => {
|
||||
if (e.currentTarget.value === "") {
|
||||
setUseCustomWidth(false);
|
||||
setCustomWidth(null);
|
||||
localStorage.removeItem("customWidth");
|
||||
return;
|
||||
}
|
||||
setCustomWidth(parseInt(e.currentTarget.value));
|
||||
}}
|
||||
step="1"
|
||||
className="input input-primary mt-2 w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
import { useCustomWidthAtom } from "@/atoms/userSettingsAtom";
|
||||
import { useAtom } from "jotai";
|
||||
import React from "react";
|
||||
|
||||
type ImageScaleSelectProps = {
|
||||
@ -6,16 +8,21 @@ type ImageScaleSelectProps = {
|
||||
};
|
||||
|
||||
export function ImageScaleSelect({ scale, setScale }: ImageScaleSelectProps) {
|
||||
const [useCustomWidth, setUseCustomWidth] = useAtom(useCustomWidthAtom);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={`${useCustomWidth && "opacity-50"}`}>
|
||||
<div className="flex flex-row gap-1">
|
||||
<p className="text-sm font-medium">IMAGE SCALE</p>
|
||||
<p className="text-sm font-medium">
|
||||
IMAGE SCALE {useCustomWidth && "DISABLED"}
|
||||
</p>
|
||||
{/*
|
||||
<p className="badge-primary badge text-[10px] font-medium">
|
||||
EXPERIMENTAL
|
||||
</p> */}
|
||||
</div>
|
||||
<input
|
||||
disabled={useCustomWidth}
|
||||
type="range"
|
||||
min="1"
|
||||
max="4"
|
||||
|
@ -24,6 +24,7 @@ import { ResetSettings } from "./ResetSettings";
|
||||
import ProcessImageToggle from "./ProcessImageToggle";
|
||||
import { featureFlags } from "@common/feature-flags";
|
||||
import TurnOffNotificationsToggle from "./TurnOffNotificationsToggle";
|
||||
import { CustomResolutionInput } from "./CustomResolutionInput";
|
||||
|
||||
interface IProps {
|
||||
batchMode: boolean;
|
||||
@ -71,7 +72,7 @@ function SettingsTab({
|
||||
const modelOptions = useAtomValue(modelsListAtom);
|
||||
const [scale, setScale] = useAtom(scaleAtom);
|
||||
const [noImageProcessing, setNoImageProcessing] = useAtom(
|
||||
noImageProcessingAtom
|
||||
noImageProcessingAtom,
|
||||
);
|
||||
|
||||
const { logit } = useLog();
|
||||
@ -86,7 +87,7 @@ function SettingsTab({
|
||||
const currentlySavedImageFormat = localStorage.getItem("saveImageAs");
|
||||
logit(
|
||||
"⚙️ Getting saveImageAs from localStorage: ",
|
||||
currentlySavedImageFormat
|
||||
currentlySavedImageFormat,
|
||||
);
|
||||
setSaveImageAs(currentlySavedImageFormat);
|
||||
}
|
||||
@ -98,11 +99,11 @@ function SettingsTab({
|
||||
logit("🔀 Setting model to", modelOptions[0].value);
|
||||
} else {
|
||||
let currentlySavedModel = JSON.parse(
|
||||
localStorage.getItem("model")
|
||||
localStorage.getItem("model"),
|
||||
) as (typeof modelOptions)[0];
|
||||
if (
|
||||
modelOptions.find(
|
||||
(model) => model.value === currentlySavedModel.value
|
||||
(model) => model.value === currentlySavedModel.value,
|
||||
) === undefined
|
||||
) {
|
||||
localStorage.setItem("model", JSON.stringify(modelOptions[0]));
|
||||
@ -113,7 +114,7 @@ function SettingsTab({
|
||||
setModel(currentlySavedModel.value);
|
||||
logit(
|
||||
"⚙️ Getting model from localStorage: ",
|
||||
JSON.stringify(currentlySavedModel)
|
||||
JSON.stringify(currentlySavedModel),
|
||||
);
|
||||
}
|
||||
|
||||
@ -131,14 +132,14 @@ function SettingsTab({
|
||||
localStorage.setItem("rememberOutputFolder", "false");
|
||||
} else {
|
||||
const currentlySavedRememberOutputFolder = localStorage.getItem(
|
||||
"rememberOutputFolder"
|
||||
"rememberOutputFolder",
|
||||
);
|
||||
logit(
|
||||
"⚙️ Getting rememberOutputFolder from localStorage: ",
|
||||
currentlySavedRememberOutputFolder
|
||||
currentlySavedRememberOutputFolder,
|
||||
);
|
||||
setRememberOutputFolder(
|
||||
currentlySavedRememberOutputFolder === "true" ? true : false
|
||||
currentlySavedRememberOutputFolder === "true" ? true : false,
|
||||
);
|
||||
}
|
||||
}, []);
|
||||
@ -167,24 +168,26 @@ function SettingsTab({
|
||||
};
|
||||
|
||||
const upscaylVersion = navigator?.userAgent?.match(
|
||||
/Upscayl\/([\d\.]+\d+)/
|
||||
/Upscayl\/([\d\.]+\d+)/,
|
||||
)[1];
|
||||
|
||||
return (
|
||||
<div className="animate-step-in animate flex h-screen flex-col gap-7 overflow-y-auto p-5 overflow-x-hidden">
|
||||
<div className="animate-step-in animate flex h-screen flex-col gap-7 overflow-y-auto overflow-x-hidden p-5">
|
||||
<div className="flex flex-col gap-2 text-sm font-medium uppercase">
|
||||
<p>Having issues?</p>
|
||||
<a
|
||||
className="btn-primary btn"
|
||||
className="btn btn-primary"
|
||||
href="https://github.com/upscayl/upscayl/wiki/"
|
||||
target="_blank">
|
||||
target="_blank"
|
||||
>
|
||||
HELP ME!
|
||||
</a>
|
||||
{featureFlags.APP_STORE_BUILD && (
|
||||
<a
|
||||
className="btn-primary btn"
|
||||
className="btn btn-primary"
|
||||
href={`mailto:upscayl@gmail.com?subject=Upscayl%20Issue%3A%20%3CIssue%20name%20here%3E&body=Device%20Name%3A%20%3CYOUR%20DEVICE%20MODEL%3E%0AOperating%20System%3A%20%3CYOUR%20OPERATING%20SYSTEM%20VERSION%3E%0AUpscayl%20Version%3A%20${upscaylVersion}%0A%0AHi%2C%20I'm%20having%20an%20issue%20with%20Upscayl.%20%3CDESCRIBE%20ISSUE%20HERE%3E`}
|
||||
target="_blank">
|
||||
target="_blank"
|
||||
>
|
||||
EMAIL DEVELOPER
|
||||
</a>
|
||||
)}
|
||||
@ -217,6 +220,8 @@ function SettingsTab({
|
||||
{/* IMAGE SCALE */}
|
||||
<ImageScaleSelect scale={scale} setScale={setScale} />
|
||||
|
||||
<CustomResolutionInput />
|
||||
|
||||
<CompressionInput
|
||||
compression={compression}
|
||||
handleCompressionChange={handleCompressionChange}
|
||||
@ -247,10 +252,11 @@ function SettingsTab({
|
||||
{featureFlags.SHOW_UPSCAYL_CLOUD_INFO && (
|
||||
<>
|
||||
<button
|
||||
className="mb-5 rounded-btn p-1 mx-5 bg-success shadow-lg shadow-success/40 text-slate-50 animate-pulse text-sm"
|
||||
className="rounded-btn mx-5 mb-5 animate-pulse bg-success p-1 text-sm text-slate-50 shadow-lg shadow-success/40"
|
||||
onClick={() => {
|
||||
setShow(true);
|
||||
}}>
|
||||
}}
|
||||
>
|
||||
Introducing Upscayl Cloud
|
||||
</button>
|
||||
|
||||
|
@ -289,42 +289,14 @@ function LeftPaneImageSteps({
|
||||
<p className="step-heading">Step 4</p>
|
||||
{dimensions.width && dimensions.height && (
|
||||
<p className="mb-2 text-sm">
|
||||
Upscayl from <br />
|
||||
Upscayl from{" "}
|
||||
<span className="font-bold">
|
||||
{dimensions.width}x{dimensions.height}
|
||||
</span>{" "}
|
||||
to
|
||||
<div className="flex items-center gap-1">
|
||||
<input
|
||||
className="input input-primary h-8 w-16 px-2 py-0 text-sm font-bold"
|
||||
defaultValue={getUpscaleResolution().width}
|
||||
value={targetWidth}
|
||||
onChange={(e) => {
|
||||
if (parseInt(e.target.value) > 32768) {
|
||||
setTargetWidth(32768);
|
||||
} else if (e.target.value === "") {
|
||||
setTargetWidth(1);
|
||||
}
|
||||
setTargetWidth(parseInt(e.target.value));
|
||||
}}
|
||||
/>{" "}
|
||||
x{" "}
|
||||
<input
|
||||
className="input input-primary h-8 w-16 px-2 py-0 text-sm font-bold"
|
||||
defaultValue={getUpscaleResolution().width}
|
||||
value={targetHeight}
|
||||
onChange={(e) => {
|
||||
if (parseInt(e.target.value) > 32768) {
|
||||
setTargetHeight(32768);
|
||||
} else if (e.target.value === "") {
|
||||
setTargetHeight(1);
|
||||
} else setTargetHeight(parseInt(e.target.value));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/* <span className="font-bold">
|
||||
to{" "}
|
||||
<span className="font-bold">
|
||||
{getUpscaleResolution().width}x{getUpscaleResolution().height}
|
||||
</span> */}
|
||||
</span>
|
||||
</p>
|
||||
)}
|
||||
<button
|
||||
|
@ -138,7 +138,13 @@ const Home = () => {
|
||||
);
|
||||
// LOG
|
||||
window.electron.on(COMMAND.LOG, (_, data: string) => {
|
||||
logit(`🐞 BACKEND REPORTED: `, data);
|
||||
if (
|
||||
!data.includes("Updating") &&
|
||||
!data.includes("Custom Models Folder Path") &&
|
||||
!data.includes("Detected Custom Models")
|
||||
) {
|
||||
logit(`🐞 BACKEND REPORTED: `, data);
|
||||
}
|
||||
});
|
||||
// SCALING AND CONVERTING
|
||||
window.electron.on(COMMAND.SCALING_AND_CONVERTING, (_, data: string) => {
|
||||
|
Loading…
Reference in New Issue
Block a user