mirror of
https://github.com/upscayl/upscayl.git
synced 2026-04-25 03:00:05 -04:00
Added video pane
This commit is contained in:
20
renderer/components/ImageOptions.tsx
Normal file
20
renderer/components/ImageOptions.tsx
Normal file
@@ -0,0 +1,20 @@
|
||||
import React from "react";
|
||||
|
||||
const ImageOptions = () => {
|
||||
return (
|
||||
<div className="animate rounded-btn collapse absolute top-0 z-50 m-2 w-96 opacity-25 hover:opacity-100">
|
||||
<input type="checkbox" className="peer" />
|
||||
<div className="collapse-title bg-base-100 text-center text-sm font-semibold uppercase text-primary-content peer-checked:bg-base-300 peer-checked:text-base-content">
|
||||
Show/Hide Image Settings
|
||||
</div>
|
||||
|
||||
<div className="collapse-content bg-base-100 text-base-content">
|
||||
<div className="p-5">
|
||||
<button className="btn-primary btn">Start Again</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ImageOptions;
|
||||
@@ -21,7 +21,7 @@ interface IProps {
|
||||
setIsVideo: (arg: boolean) => void;
|
||||
}
|
||||
|
||||
function LeftPaneSteps({
|
||||
function LeftPaneImageSteps({
|
||||
progress,
|
||||
selectImageHandler,
|
||||
selectFolderHandler,
|
||||
@@ -70,38 +70,17 @@ function LeftPaneSteps({
|
||||
|
||||
return (
|
||||
<div className="animate-step-in animate flex h-screen flex-col gap-7 overflow-y-auto p-5 overflow-x-hidden">
|
||||
<div className="flex items-center justify-center gap-2 font-medium">
|
||||
<p>Image</p>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio-1"
|
||||
className="radio"
|
||||
checked={!isVideo}
|
||||
onClick={() => setIsVideo(false)}
|
||||
/>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio-1"
|
||||
className="radio"
|
||||
checked={isVideo}
|
||||
onClick={() => setIsVideo(true)}
|
||||
/>
|
||||
<p>Video</p>
|
||||
</div>
|
||||
|
||||
{/* BATCH OPTION */}
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="toggle"
|
||||
onClick={handleBatchMode}
|
||||
></input>
|
||||
<div
|
||||
className="tooltip tooltip-right relative z-50"
|
||||
data-tip="This will let you upscale all files in a folder at once"
|
||||
>
|
||||
<p className="mr-1 inline-block cursor-help text-sm">Batch Upscale</p>
|
||||
</div>
|
||||
onClick={handleBatchMode}></input>
|
||||
<p
|
||||
className="mr-1 inline-block cursor-help text-sm"
|
||||
data-tip="This will let you upscale all files in a folder at once">
|
||||
Batch Upscale
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* STEP 1 */}
|
||||
@@ -109,8 +88,7 @@ function LeftPaneSteps({
|
||||
<p className="step-heading">Step 1</p>
|
||||
<button
|
||||
className="btn-primary btn"
|
||||
onClick={!batchMode ? selectImageHandler : selectFolderHandler}
|
||||
>
|
||||
onClick={!batchMode ? selectImageHandler : selectFolderHandler}>
|
||||
Select {batchMode ? "Folder" : "Image"}
|
||||
</button>
|
||||
</div>
|
||||
@@ -133,7 +111,7 @@ function LeftPaneSteps({
|
||||
/>
|
||||
|
||||
{model !== "models-DF2K" && !batchMode && (
|
||||
<div className="mt-2 flex items-center gap-1">
|
||||
<div className="mt-4 flex items-center gap-1">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="checkbox"
|
||||
@@ -150,16 +128,14 @@ function LeftPaneSteps({
|
||||
className="cursor-pointer text-sm"
|
||||
onClick={(e) => {
|
||||
setDoubleUpscayl(!doubleUpscayl);
|
||||
}}
|
||||
>
|
||||
}}>
|
||||
Double Upscayl
|
||||
</p>
|
||||
<div
|
||||
className="tooltip"
|
||||
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."
|
||||
>
|
||||
<span className="badge-info badge cursor-help">i</span>
|
||||
</div>
|
||||
<button
|
||||
className="badge-info badge cursor-help"
|
||||
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
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -173,30 +149,20 @@ function LeftPaneSteps({
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* ADVANCED OPTION */}
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<input type="checkbox" className="checkbox" onClick={handleBatchMode} />
|
||||
<p
|
||||
className="mr-1 inline-block cursor-help text-sm"
|
||||
data-tip="This will let you upscale all files in a folder at once"
|
||||
>
|
||||
Advanced Options
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* STEP 4 */}
|
||||
<div className="animate-step-in">
|
||||
<p className="step-heading">Step 4</p>
|
||||
<button
|
||||
className="btn-accent btn"
|
||||
onClick={upscaylHandler}
|
||||
disabled={progress.length > 0}
|
||||
>
|
||||
disabled={progress.length > 0}>
|
||||
{progress.length > 0 ? "Upscayling⏳" : "Upscayl"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ReactTooltip class="max-w-sm" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default LeftPaneSteps;
|
||||
export default LeftPaneImageSteps;
|
||||
108
renderer/components/LeftPaneVideoSteps.tsx
Normal file
108
renderer/components/LeftPaneVideoSteps.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
import React from "react";
|
||||
import Select from "react-select";
|
||||
import ReactTooltip from "react-tooltip";
|
||||
|
||||
interface IProps {
|
||||
progress: string;
|
||||
selectImageHandler: () => Promise<void>;
|
||||
selectFolderHandler: () => Promise<void>;
|
||||
handleModelChange: (e: any) => void;
|
||||
handleDrop: (e: any) => void;
|
||||
outputHandler: () => Promise<void>;
|
||||
upscaylHandler: () => Promise<void>;
|
||||
batchMode: boolean;
|
||||
setBatchMode: (arg: any) => void;
|
||||
imagePath: string;
|
||||
outputPath: string;
|
||||
doubleUpscayl: boolean;
|
||||
setDoubleUpscayl: (arg: boolean) => void;
|
||||
model: string;
|
||||
isVideo: boolean;
|
||||
setIsVideo: (arg: boolean) => void;
|
||||
}
|
||||
|
||||
function LeftPaneVideoSteps({
|
||||
progress,
|
||||
selectImageHandler,
|
||||
selectFolderHandler,
|
||||
handleModelChange,
|
||||
handleDrop,
|
||||
outputHandler,
|
||||
upscaylHandler,
|
||||
batchMode,
|
||||
setBatchMode,
|
||||
imagePath,
|
||||
outputPath,
|
||||
doubleUpscayl,
|
||||
setDoubleUpscayl,
|
||||
model,
|
||||
isVideo,
|
||||
setIsVideo,
|
||||
}: IProps) {
|
||||
const handleBatchMode = () => {
|
||||
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-y-auto p-5 overflow-x-hidden">
|
||||
{/* STEP 1 */}
|
||||
<div data-tip={imagePath}>
|
||||
<p className="step-heading">Step 1</p>
|
||||
<button
|
||||
className="btn-primary btn"
|
||||
onClick={!batchMode ? selectImageHandler : selectFolderHandler}>
|
||||
Select Video
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* STEP 2 */}
|
||||
<div className="animate-step-in" data-tip={outputPath}>
|
||||
<p className="step-heading">Step 2</p>
|
||||
<p className="mb-2 text-sm">Defaults to Video's path</p>
|
||||
<button className="btn-primary btn" onClick={outputHandler}>
|
||||
Set Output Folder
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* STEP 4 */}
|
||||
<div className="animate-step-in">
|
||||
<p className="step-heading">Step 4</p>
|
||||
<button
|
||||
className="btn-accent btn"
|
||||
onClick={upscaylHandler}
|
||||
disabled={progress.length > 0}>
|
||||
{progress.length > 0 ? "Upscayling⏳" : "Upscayl"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<ReactTooltip class="max-w-sm" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default LeftPaneVideoSteps;
|
||||
@@ -8,13 +8,16 @@ 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 LeftPaneSteps from "../components/LeftPaneImageSteps";
|
||||
import RightPaneInfo from "../components/RightPaneInfo";
|
||||
import ImageOptions from "../components/ImageOptions";
|
||||
import LeftPaneVideoSteps from "../components/LeftPaneVideoSteps";
|
||||
import LeftPaneImageSteps from "../components/LeftPaneImageSteps";
|
||||
|
||||
const Home = () => {
|
||||
const [imagePath, SetImagePath] = useState("");
|
||||
const [upscaledImagePath, setUpscaledImagePath] = useState("");
|
||||
const [outputPath, SetOutputPath] = useState("");
|
||||
const [outputPath, setOutputPath] = useState("");
|
||||
const [scaleFactor, setScaleFactor] = useState(4);
|
||||
const [progress, setProgress] = useState("");
|
||||
const [model, setModel] = useState("realesrgan-x4plus");
|
||||
@@ -25,6 +28,8 @@ const Home = () => {
|
||||
const [upscaledBatchFolderPath, setUpscaledBatchFolderPath] = useState("");
|
||||
const [doubleUpscayl, setDoubleUpscayl] = useState(false);
|
||||
const [isVideo, setIsVideo] = useState(false);
|
||||
const [videoPath, setVideoPath] = useState("");
|
||||
const [upscaledVideoPath, setUpscaledVideoPath] = useState("");
|
||||
|
||||
const resetImagePaths = () => {
|
||||
setProgress("");
|
||||
@@ -38,7 +43,6 @@ const Home = () => {
|
||||
|
||||
useEffect(() => {
|
||||
setLoaded(true);
|
||||
const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)");
|
||||
|
||||
setVersion(navigator?.userAgent?.match(/Upscayl\/([\d\.]+\d+)/)[1]);
|
||||
|
||||
@@ -127,6 +131,18 @@ const Home = () => {
|
||||
}
|
||||
}, [imagePath]);
|
||||
|
||||
const selectVideoHandler = async () => {
|
||||
resetImagePaths();
|
||||
|
||||
var path = await window.electron.invoke(commands.SELECT_VIDEO);
|
||||
|
||||
if (path !== "cancelled") {
|
||||
setVideoPath(path);
|
||||
var dirname = path.match(/(.*)[\/\\]/)[1] || "";
|
||||
setOutputPath(dirname);
|
||||
}
|
||||
};
|
||||
|
||||
const selectImageHandler = async () => {
|
||||
resetImagePaths();
|
||||
|
||||
@@ -135,7 +151,7 @@ const Home = () => {
|
||||
if (path !== "cancelled") {
|
||||
SetImagePath(path);
|
||||
var dirname = path.match(/(.*)[\/\\]/)[1] || "";
|
||||
SetOutputPath(dirname);
|
||||
setOutputPath(dirname);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -146,7 +162,7 @@ const Home = () => {
|
||||
|
||||
if (path !== "cancelled") {
|
||||
setBatchFolderPath(path);
|
||||
SetOutputPath(path + "_upscayled");
|
||||
setOutputPath(path + "_upscayled");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -195,7 +211,7 @@ const Home = () => {
|
||||
SetImagePath(filePath);
|
||||
var dirname = filePath.match(/(.*)[\/\\]/)[1] || "";
|
||||
console.log("🚀 => handleDrop => dirname", dirname);
|
||||
SetOutputPath(dirname);
|
||||
setOutputPath(dirname);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -215,14 +231,14 @@ const Home = () => {
|
||||
} else {
|
||||
SetImagePath(filePath);
|
||||
var dirname = filePath.match(/(.*)[\/\\]/)[1] || "";
|
||||
SetOutputPath(dirname);
|
||||
setOutputPath(dirname);
|
||||
}
|
||||
};
|
||||
|
||||
const outputHandler = async () => {
|
||||
var path = await window.electron.invoke(commands.SELECT_FOLDER);
|
||||
if (path !== "cancelled") {
|
||||
SetOutputPath(path);
|
||||
setOutputPath(path);
|
||||
} else {
|
||||
console.log("Getting output path from input file");
|
||||
}
|
||||
@@ -272,27 +288,64 @@ const Home = () => {
|
||||
)}
|
||||
{/* HEADER */}
|
||||
<Header />
|
||||
|
||||
<div className="flex items-center justify-center gap-2 pb-4 font-medium">
|
||||
<p>Image</p>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio-1"
|
||||
className="radio"
|
||||
checked={!isVideo}
|
||||
onChange={() => setIsVideo(false)}
|
||||
/>
|
||||
<input
|
||||
type="radio"
|
||||
name="radio-1"
|
||||
className="radio"
|
||||
checked={isVideo}
|
||||
onChange={() => setIsVideo(true)}
|
||||
/>
|
||||
<p>Video</p>
|
||||
</div>
|
||||
{/* 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}
|
||||
isVideo={isVideo}
|
||||
setIsVideo={setIsVideo}
|
||||
/>
|
||||
|
||||
{isVideo ? (
|
||||
<LeftPaneVideoSteps
|
||||
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}
|
||||
isVideo={isVideo}
|
||||
setIsVideo={setIsVideo}
|
||||
/>
|
||||
) : (
|
||||
<LeftPaneImageSteps
|
||||
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}
|
||||
isVideo={isVideo}
|
||||
setIsVideo={setIsVideo}
|
||||
/>
|
||||
)}
|
||||
<Footer />
|
||||
</div>
|
||||
|
||||
@@ -303,8 +356,7 @@ const Home = () => {
|
||||
onDragOver={(e) => handleDragOver(e)}
|
||||
onDragEnter={(e) => handleDragEnter(e)}
|
||||
onDragLeave={(e) => handleDragLeave(e)}
|
||||
onPaste={(e) => handlePaste(e)}
|
||||
>
|
||||
onPaste={(e) => handlePaste(e)}>
|
||||
{progress.length > 0 &&
|
||||
upscaledImagePath.length === 0 &&
|
||||
upscaledBatchFolderPath.length === 0 ? (
|
||||
@@ -349,47 +401,49 @@ const Home = () => {
|
||||
</p>
|
||||
<button
|
||||
className="bg-gradient-blue rounded-lg p-3 font-medium text-white/90 transition-colors"
|
||||
onClick={openFolderHandler}
|
||||
>
|
||||
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="origin-bottom scale-[200%] bg-[#1d1c23]"
|
||||
/>
|
||||
</>
|
||||
}
|
||||
className="h-screen"
|
||||
/>
|
||||
<>
|
||||
<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"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
38
renderer/public/down-arrow.svg
Normal file
38
renderer/public/down-arrow.svg
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" fill="#fff"
|
||||
viewBox="0 0 330 330" xml:space="preserve">
|
||||
<path id="XMLID_225_" d="M325.607,79.393c-5.857-5.857-15.355-5.858-21.213,0.001l-139.39,139.393L25.607,79.393
|
||||
c-5.857-5.857-15.355-5.858-21.213,0.001c-5.858,5.858-5.858,15.355,0,21.213l150.004,150c2.813,2.813,6.628,4.393,10.606,4.393
|
||||
s7.794-1.581,10.606-4.394l149.996-150C331.465,94.749,331.465,85.251,325.607,79.393z"/>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 826 B |
Reference in New Issue
Block a user