mirror of
https://github.com/upscayl/upscayl.git
synced 2025-01-31 04:03:51 +01:00
Added video preview and scaling
This commit is contained in:
parent
8593e3812b
commit
a579f52eab
@ -327,6 +327,112 @@ ipcMain.on(commands.UPSCAYL, async (event, payload) => {
|
||||
}
|
||||
});
|
||||
|
||||
//------------------------Video Upscayl-----------------------------//
|
||||
ipcMain.on(commands.UPSCAYL_VIDEO, async (event, payload) => {
|
||||
const model = payload.model;
|
||||
const scale = payload.scaleFactor;
|
||||
let inputDir = payload.videoPath.match(/(.*)[\/\\]/)[1] || "";
|
||||
let outputDir = payload.outputPath;
|
||||
|
||||
// COPY IMAGE TO TMP FOLDER
|
||||
const platform = getPlatform();
|
||||
const fullfileName =
|
||||
platform === "win"
|
||||
? payload.videoPath.split("\\").slice(-1)[0]
|
||||
: payload.videoPath.split("/").slice(-1)[0];
|
||||
console.log(fullfileName);
|
||||
const fileName = parse(fullfileName).name;
|
||||
const fileExt = 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.existsSync(outFile)) {
|
||||
// If already upscayled, just output that file
|
||||
mainWindow.webContents.send(commands.UPSCAYL_DONE, outFile);
|
||||
} else {
|
||||
let upscayl: ChildProcessWithoutNullStreams | null = null;
|
||||
switch (model) {
|
||||
case "realesrgan-x4plus":
|
||||
case "realesrgan-x4plus-anime":
|
||||
upscayl = spawn(
|
||||
execPath("realesrgan"),
|
||||
[
|
||||
"-i",
|
||||
inputDir + "/" + fullfileName,
|
||||
"-o",
|
||||
outFile,
|
||||
"-s",
|
||||
scale === 2 ? 4 : scale,
|
||||
"-m",
|
||||
modelsPath,
|
||||
"-n",
|
||||
model,
|
||||
],
|
||||
{
|
||||
cwd: undefined,
|
||||
detached: false,
|
||||
}
|
||||
);
|
||||
break;
|
||||
case "models-DF2K":
|
||||
upscayl = spawn(
|
||||
execPath("realsr"),
|
||||
[
|
||||
"-i",
|
||||
inputDir + "/" + fullfileName,
|
||||
"-o",
|
||||
outFile,
|
||||
"-s",
|
||||
scale,
|
||||
"-x",
|
||||
"-m",
|
||||
modelsPath + "/" + model,
|
||||
],
|
||||
{
|
||||
cwd: undefined,
|
||||
detached: false,
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
let failed = false;
|
||||
upscayl?.stderr.on("data", (data) => {
|
||||
console.log(
|
||||
"🚀 => upscayl.stderr.on => stderr.toString()",
|
||||
data.toString()
|
||||
);
|
||||
data = data.toString();
|
||||
mainWindow.webContents.send(commands.UPSCAYL_PROGRESS, data.toString());
|
||||
if (data.includes("invalid gpu") || data.includes("failed")) {
|
||||
failed = true;
|
||||
}
|
||||
});
|
||||
|
||||
upscayl?.on("error", (data) => {
|
||||
mainWindow.webContents.send(commands.UPSCAYL_PROGRESS, data.toString());
|
||||
failed = true;
|
||||
return;
|
||||
});
|
||||
|
||||
// Send done comamnd when
|
||||
upscayl?.on("close", (code) => {
|
||||
if (failed !== true) {
|
||||
console.log("Done upscaling");
|
||||
mainWindow.webContents.send(commands.UPSCAYL_DONE, outFile);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//------------------------Upscayl Folder-----------------------------//
|
||||
ipcMain.on(commands.FOLDER_UPSCAYL, async (event, payload) => {
|
||||
const model = payload.model;
|
||||
|
@ -13,5 +13,8 @@ const commands = {
|
||||
FOLDER_UPSCAYL_DONE: "Folder upscaling successful",
|
||||
FOLDER_UPSCAYL_PROGRESS: "Send Folder Upscaling Progress from Main to Renderer",
|
||||
OPEN_FOLDER: "Open Folder",
|
||||
UPSCAYL_VIDEO: "Upscale the Video",
|
||||
UPSCAYL_VIDEO_DONE: "Video Upscaling Done",
|
||||
UPSCAYL_VIDEO_PROGRESS: "Send Video Upscale Progress from Main to Renderer",
|
||||
};
|
||||
exports.default = commands;
|
||||
|
@ -285,6 +285,96 @@ electron_1.ipcMain.on(commands_1.default.UPSCAYL, (event, payload) => __awaiter(
|
||||
});
|
||||
}
|
||||
}));
|
||||
//------------------------Video Upscayl-----------------------------//
|
||||
electron_1.ipcMain.on(commands_1.default.UPSCAYL_VIDEO, (event, payload) => __awaiter(void 0, void 0, void 0, function* () {
|
||||
const model = payload.model;
|
||||
const scale = payload.scaleFactor;
|
||||
let inputDir = payload.videoPath.match(/(.*)[\/\\]/)[1] || "";
|
||||
let outputDir = payload.outputPath;
|
||||
// COPY IMAGE TO TMP FOLDER
|
||||
const platform = (0, getPlatform_1.default)();
|
||||
const fullfileName = platform === "win"
|
||||
? payload.videoPath.split("\\").slice(-1)[0]
|
||||
: payload.videoPath.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;
|
||||
|
@ -4,18 +4,13 @@ import ReactTooltip from "react-tooltip";
|
||||
|
||||
interface IProps {
|
||||
progress: string;
|
||||
selectImageHandler: () => Promise<void>;
|
||||
selectFolderHandler: () => Promise<void>;
|
||||
selectVideoHandler: () => Promise<void>;
|
||||
handleModelChange: (e: any) => void;
|
||||
handleDrop: (e: any) => void;
|
||||
outputHandler: () => Promise<void>;
|
||||
upscaylHandler: () => Promise<void>;
|
||||
batchMode: boolean;
|
||||
setBatchMode: (arg: any) => void;
|
||||
imagePath: string;
|
||||
videoPath: string;
|
||||
outputPath: string;
|
||||
doubleUpscayl: boolean;
|
||||
setDoubleUpscayl: (arg: boolean) => void;
|
||||
model: string;
|
||||
isVideo: boolean;
|
||||
setIsVideo: (arg: boolean) => void;
|
||||
@ -23,26 +18,17 @@ interface IProps {
|
||||
|
||||
function LeftPaneVideoSteps({
|
||||
progress,
|
||||
selectImageHandler,
|
||||
selectFolderHandler,
|
||||
selectVideoHandler,
|
||||
handleModelChange,
|
||||
handleDrop,
|
||||
outputHandler,
|
||||
upscaylHandler,
|
||||
batchMode,
|
||||
setBatchMode,
|
||||
imagePath,
|
||||
videoPath,
|
||||
outputPath,
|
||||
doubleUpscayl,
|
||||
setDoubleUpscayl,
|
||||
model,
|
||||
isVideo,
|
||||
setIsVideo,
|
||||
}: IProps) {
|
||||
const handleBatchMode = () => {
|
||||
setBatchMode((oldValue) => !oldValue);
|
||||
};
|
||||
|
||||
const customStyles = {
|
||||
option: (provided, state) => ({
|
||||
...provided,
|
||||
@ -63,26 +49,42 @@ function LeftPaneVideoSteps({
|
||||
};
|
||||
|
||||
const modelOptions = [
|
||||
{ label: "General Photo", value: "realesrgan-x4plus" },
|
||||
{ label: "Digital Art", value: "realesrgan-x4plus-anime" },
|
||||
{ label: "Sharpen Image", value: "models-DF2K" },
|
||||
{ label: "2x Digital Art", value: "realesr-animevideov3-x2" },
|
||||
{ label: "3x Digital Art", value: "realesr-animevideov3-x3" },
|
||||
{ label: "4x Digital Art", value: "realesr-animevideov3-x4" },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="animate-step-in animate flex h-screen flex-col gap-7 overflow-y-auto p-5 overflow-x-hidden">
|
||||
{/* STEP 1 */}
|
||||
<div data-tip={imagePath}>
|
||||
<div data-tip={videoPath}>
|
||||
<p className="step-heading">Step 1</p>
|
||||
<button
|
||||
className="btn-primary btn"
|
||||
onClick={!batchMode ? selectImageHandler : selectFolderHandler}>
|
||||
<button className="btn-primary btn" onClick={selectVideoHandler}>
|
||||
Select Video
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* STEP 2 */}
|
||||
<div className="animate-step-in" data-tip={outputPath}>
|
||||
<div className="animate-step-in">
|
||||
<p className="step-heading">Step 2</p>
|
||||
<p className="mb-2 text-sm">Select Scaling</p>
|
||||
|
||||
<Select
|
||||
options={modelOptions}
|
||||
components={{
|
||||
IndicatorSeparator: () => null,
|
||||
DropdownIndicator: () => null,
|
||||
}}
|
||||
onChange={handleModelChange}
|
||||
className="react-select-container"
|
||||
classNamePrefix="react-select"
|
||||
defaultValue={modelOptions[0]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* STEP 3 */}
|
||||
<div className="animate-step-in" data-tip={outputPath}>
|
||||
<p className="step-heading">Step 3</p>
|
||||
<p className="mb-2 text-sm">Defaults to Video's path</p>
|
||||
<button className="btn-primary btn" onClick={outputHandler}>
|
||||
Set Output Folder
|
||||
|
@ -1,7 +1,12 @@
|
||||
import React from "react";
|
||||
|
||||
function RightPaneInfo({ version, batchMode }) {
|
||||
return (
|
||||
function RightPaneInfo({ version, batchMode, isVideo }) {
|
||||
return isVideo ? (
|
||||
<>
|
||||
<p className="p-5 pb-1 text-lg font-semibold">Select Video to Upscale</p>
|
||||
<p className="text-sm">Upscayl v{version}</p>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p className="p-5 pb-1 text-lg font-semibold">
|
||||
Select {batchMode ? "a Folder" : "an Image"} to Upscale
|
||||
|
@ -123,7 +123,7 @@ const Home = () => {
|
||||
}, [batchMode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (imagePath.length > 0) {
|
||||
if (imagePath.length > 0 && !isVideo) {
|
||||
const filePath = imagePath;
|
||||
console.log(
|
||||
"🚀 => file: index.jsx => line 109 => useEffect => filePath",
|
||||
@ -140,15 +140,21 @@ const Home = () => {
|
||||
alert("Please select an image");
|
||||
resetImagePaths();
|
||||
}
|
||||
} else if (videoPath.length > 0) {
|
||||
} else if (videoPath.length > 0 && isVideo) {
|
||||
const filePath = videoPath;
|
||||
|
||||
console.log("🚀 => file: index.tsx => line 146 => filePath", filePath);
|
||||
|
||||
const extension = videoPath.toLocaleLowerCase().split(".").pop();
|
||||
|
||||
console.log("🚀 => file: index.tsx => line 150 => extension", extension);
|
||||
|
||||
if (!allowedVideoFileTypes.includes(extension.toLowerCase())) {
|
||||
alert("Please select an MP4, WebM or MKV video");
|
||||
resetImagePaths();
|
||||
}
|
||||
} else {
|
||||
resetImagePaths();
|
||||
}
|
||||
}, [imagePath, videoPath]);
|
||||
|
||||
@ -334,14 +340,20 @@ const Home = () => {
|
||||
name="radio-1"
|
||||
className="radio"
|
||||
checked={!isVideo}
|
||||
onChange={() => setIsVideo(false)}
|
||||
onChange={() => {
|
||||
setIsVideo(false);
|
||||
console.log("isImage");
|
||||
}}
|
||||
/>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio-1"
|
||||
className="radio"
|
||||
checked={isVideo}
|
||||
onChange={() => setIsVideo(true)}
|
||||
onChange={() => {
|
||||
setIsVideo(true);
|
||||
console.log("isVideo");
|
||||
}}
|
||||
/>
|
||||
<p>Video</p>
|
||||
</div>
|
||||
@ -349,18 +361,13 @@ const Home = () => {
|
||||
{isVideo ? (
|
||||
<LeftPaneVideoSteps
|
||||
progress={progress}
|
||||
selectImageHandler={selectImageHandler}
|
||||
selectFolderHandler={selectFolderHandler}
|
||||
selectVideoHandler={selectVideoHandler}
|
||||
handleModelChange={handleModelChange}
|
||||
handleDrop={handleDrop}
|
||||
outputHandler={outputHandler}
|
||||
upscaylHandler={upscaylHandler}
|
||||
batchMode={batchMode}
|
||||
setBatchMode={setBatchMode}
|
||||
imagePath={imagePath}
|
||||
outputPath={outputPath}
|
||||
doubleUpscayl={doubleUpscayl}
|
||||
setDoubleUpscayl={setDoubleUpscayl}
|
||||
videoPath={videoPath}
|
||||
model={model}
|
||||
isVideo={isVideo}
|
||||
setIsVideo={setIsVideo}
|
||||
@ -398,20 +405,33 @@ const Home = () => {
|
||||
onPaste={(e) => handlePaste(e)}>
|
||||
{progress.length > 0 &&
|
||||
upscaledImagePath.length === 0 &&
|
||||
upscaledBatchFolderPath.length === 0 ? (
|
||||
upscaledBatchFolderPath.length === 0 &&
|
||||
upscaledVideoPath.length === 0 ? (
|
||||
<ProgressBar progress={progress} />
|
||||
) : null}
|
||||
|
||||
{((!batchMode &&
|
||||
{/* DEFAULT PANE INFO */}
|
||||
{((!isVideo &&
|
||||
!batchMode &&
|
||||
imagePath.length === 0 &&
|
||||
upscaledImagePath.length === 0) ||
|
||||
(batchMode &&
|
||||
(!isVideo &&
|
||||
batchMode &&
|
||||
batchFolderPath.length === 0 &&
|
||||
upscaledBatchFolderPath.length === 0)) && (
|
||||
<RightPaneInfo version={version} batchMode={batchMode} />
|
||||
upscaledBatchFolderPath.length === 0) ||
|
||||
(isVideo &&
|
||||
videoPath.length === 0 &&
|
||||
upscaledVideoPath.length === 0)) && (
|
||||
<RightPaneInfo
|
||||
version={version}
|
||||
batchMode={batchMode}
|
||||
isVideo={isVideo}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* SHOW SELECTED IMAGE */}
|
||||
{!batchMode &&
|
||||
!isVideo &&
|
||||
upscaledImagePath.length === 0 &&
|
||||
imagePath.length > 0 && (
|
||||
<img
|
||||
@ -425,6 +445,7 @@ const Home = () => {
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* BATCH UPSCALE SHOW SELECTED FOLDER */}
|
||||
{batchMode &&
|
||||
upscaledBatchFolderPath.length === 0 &&
|
||||
batchFolderPath.length > 0 && (
|
||||
@ -433,6 +454,7 @@ const Home = () => {
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* BATCH UPSCALE DONE INFO */}
|
||||
{batchMode && upscaledBatchFolderPath.length > 0 && (
|
||||
<>
|
||||
<p className="text-neutral-50 select-none py-4 font-bold">
|
||||
@ -446,43 +468,53 @@ const Home = () => {
|
||||
</>
|
||||
)}
|
||||
|
||||
{!batchMode && imagePath.length > 0 && upscaledImagePath.length > 0 && (
|
||||
<>
|
||||
<ImageOptions />
|
||||
<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="origin-bottom scale-[200%] bg-[#1d1c23]"
|
||||
/>
|
||||
</>
|
||||
}
|
||||
className="h-screen"
|
||||
/>
|
||||
</>
|
||||
{/* COMPARISON SLIDER */}
|
||||
{!batchMode &&
|
||||
!isVideo &&
|
||||
imagePath.length > 0 &&
|
||||
upscaledImagePath.length > 0 && (
|
||||
<>
|
||||
<ImageOptions />
|
||||
<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="origin-bottom scale-[200%] bg-[#1d1c23]"
|
||||
/>
|
||||
</>
|
||||
}
|
||||
className="h-screen"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
{isVideo && videoPath.length > 0 && upscaledVideoPath.length === 0 && (
|
||||
<video autoPlay controls className="m-10 w-11/12 rounded-2xl">
|
||||
<source src={"file://" + videoPath} type="video/mp4" />
|
||||
</video>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user