1
0
mirror of https://github.com/upscayl/upscayl.git synced 2024-09-24 03:18:28 +02:00

Added video preview and scaling

This commit is contained in:
Feenix 2022-11-25 13:00:03 +05:30
parent 8593e3812b
commit a579f52eab
6 changed files with 319 additions and 81 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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>