1
0
mirror of https://github.com/upscayl/upscayl.git synced 2024-09-24 03:18:28 +02:00
This commit is contained in:
Nayam Amarshe 2024-01-23 14:14:32 +05:30
parent 602cb72fdb
commit fad4560c12
6 changed files with 1531 additions and 7206 deletions

8439
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -210,9 +210,9 @@
"@types/react-dom": "^18.0.11", "@types/react-dom": "^18.0.11",
"autoprefixer": "^10.4.16", "autoprefixer": "^10.4.16",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"daisyui": "^3.9.3", "daisyui": "^3.9.4",
"electron": "^27.0.2", "electron": "^27.2.4",
"electron-builder": "^24.6.4", "electron-builder": "^24.9.1",
"next": "^13.5.6", "next": "^13.5.6",
"postcss": "^8.4.31", "postcss": "^8.4.31",
"prettier": "^3.0.0", "prettier": "^3.0.0",

View File

@ -33,3 +33,10 @@ export const turnOffNotificationsAtom = atomWithStorage(
"turnOffNotifications", "turnOffNotifications",
false false
); );
export const viewTypeAtom = atomWithStorage<"slider" | "lens">(
"viewType",
"lens"
);
export const lensSizeAtom = atomWithStorage<number>("lensSize", 100);

View File

@ -1,5 +1,7 @@
import { lensSizeAtom, viewTypeAtom } from "@/atoms/userSettingsAtom";
import SidebarClosed from "@/components/icons/SidebarClosed"; import SidebarClosed from "@/components/icons/SidebarClosed";
import SidebarOpened from "@/components/icons/SidebarOpened"; import SidebarOpened from "@/components/icons/SidebarOpened";
import { useAtom } from "jotai";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
const ImageOptions = ({ const ImageOptions = ({
@ -14,6 +16,8 @@ const ImageOptions = ({
hideZoomOptions?: boolean; hideZoomOptions?: boolean;
}) => { }) => {
const [openSidebar, setOpenSidebar] = useState(false); const [openSidebar, setOpenSidebar] = useState(false);
const [viewType, setViewType] = useAtom(viewTypeAtom);
const [lensSize, setLensSize] = useAtom(lensSizeAtom);
useEffect(() => { useEffect(() => {
if (!localStorage.getItem("zoomAmount")) { if (!localStorage.getItem("zoomAmount")) {
@ -24,13 +28,11 @@ const ImageOptions = ({
}, []); }, []);
return ( return (
<div className=""> <div
{/* <div onDoubleClick={(e) => {
className={`bg-base-100 p-4 rounded-btn rounded-r-none fixed top-1/2 right-0 z-50 shadow-xl shadow-black group flex items-center gap-2`} e.stopPropagation();
onClick={() => setOpenSidebar(!openSidebar)}> }}
<Sidebar className="text-white text-xl" /> className="w-full h-full absolute">
</div> */}
<div <div
className={`transition-all duration-500 bg-base-100 text-base-content h-screen w-[28rem] fixed right-0 top-0 z-50 shadow-xl shadow-black ${ className={`transition-all duration-500 bg-base-100 text-base-content h-screen w-[28rem] fixed right-0 top-0 z-50 shadow-xl shadow-black ${
openSidebar ? "right-0" : "-right-full translate-x-full" openSidebar ? "right-0" : "-right-full translate-x-full"
@ -46,65 +48,43 @@ const ImageOptions = ({
<SidebarClosed className="text-white text-xl" /> <SidebarClosed className="text-white text-xl" />
)} )}
</div> </div>
<div className="flex flex-col justify-center gap-5 overflow-auto p-5"> <div className="flex flex-col justify-center gap-5 overflow-auto p-5">
<button className="btn-primary btn" onClick={resetImagePaths}> <button className="btn-primary btn" onClick={resetImagePaths}>
Reset Image Reset Image
</button> </button>
{!hideZoomOptions && ( {!hideZoomOptions && (
<div className="flex flex-row items-center gap-2"> <div className="flex flex-col gap-2">
<p className="w-20">Zoom:</p> <p className="font-medium text-sm">Zoom Amount ({zoomAmount}%)</p>
<button <input
className={`btn-primary btn ${ type="range"
zoomAmount === "100%" ? "btn-secondary" : "btn-primary" min="100"
}`} max="990"
onClick={() => { step={10}
setZoomAmount("100%"); className="range range-md"
localStorage.setItem("zoomAmount", "100%"); value={parseInt(zoomAmount)}
}}> onChange={(e) => {
100% setZoomAmount(e.target.value);
</button> localStorage.setItem("zoomAmount", e.target.value);
<button }}
className={`btn-primary btn ${ />
zoomAmount === "125%" ? "btn-secondary" : "btn-primary"
}`}
onClick={() => {
setZoomAmount("125%");
localStorage.setItem("zoomAmount", "125%");
}}>
125%
</button>
<button
className={`btn-primary btn ${
zoomAmount === "150%" ? "btn-secondary" : "btn-primary"
}`}
onClick={() => {
setZoomAmount("150%");
localStorage.setItem("zoomAmount", "150%");
}}>
150%
</button>
<button
className={`btn-primary btn ${
zoomAmount === "175%" ? "btn-secondary" : "btn-primary"
}`}
onClick={() => {
setZoomAmount("175%");
localStorage.setItem("zoomAmount", "175%");
}}>
175%
</button>
<button
className={`btn-primary btn ${
zoomAmount === "200%" ? "btn-secondary" : "btn-primary"
}`}
onClick={() => {
setZoomAmount("200%");
localStorage.setItem("zoomAmount", "200%");
}}>
200%
</button>
</div> </div>
)} )}
<div className="flex flex-col gap-2">
<p className="font-medium text-sm">Lens Size ({lensSize / 10})</p>
<input
type="range"
min="20"
max="400"
step={10}
className="range range-md"
value={lensSize}
onChange={(e) => {
setLensSize(parseInt(e.target.value));
}}
/>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
"use client"; "use client";
import { useState, useEffect, useCallback } from "react"; import { useState, useEffect, useCallback, useRef } from "react";
import COMMAND from "../../common/commands"; import COMMAND from "../../common/commands";
import { ReactCompareSlider } from "react-compare-slider"; import { ReactCompareSlider } from "react-compare-slider";
import Header from "../components/Header"; import Header from "../components/Header";
@ -15,6 +15,7 @@ import { logAtom } from "../atoms/logAtom";
import { modelsListAtom } from "../atoms/modelsListAtom"; import { modelsListAtom } from "../atoms/modelsListAtom";
import { import {
batchModeAtom, batchModeAtom,
lensSizeAtom,
compressionAtom, compressionAtom,
dontShowCloudModalAtom, dontShowCloudModalAtom,
noImageProcessingAtom, noImageProcessingAtom,
@ -22,6 +23,7 @@ import {
overwriteAtom, overwriteAtom,
progressAtom, progressAtom,
scaleAtom, scaleAtom,
viewTypeAtom,
} from "../atoms/userSettingsAtom"; } from "../atoms/userSettingsAtom";
import useLog from "../components/hooks/useLog"; import useLog from "../components/hooks/useLog";
import { UpscaylCloudModal } from "../components/UpscaylCloudModal"; import { UpscaylCloudModal } from "../components/UpscaylCloudModal";
@ -51,7 +53,7 @@ const Home = () => {
const [doubleUpscaylCounter, setDoubleUpscaylCounter] = useState(0); const [doubleUpscaylCounter, setDoubleUpscaylCounter] = useState(0);
const [gpuId, setGpuId] = useState(""); const [gpuId, setGpuId] = useState("");
const [saveImageAs, setSaveImageAs] = useState("png"); const [saveImageAs, setSaveImageAs] = useState("png");
const [zoomAmount, setZoomAmount] = useState("100%"); const [zoomAmount, setZoomAmount] = useState("100");
const [backgroundPosition, setBackgroundPosition] = useState("0% 0%"); const [backgroundPosition, setBackgroundPosition] = useState("0% 0%");
const [dimensions, setDimensions] = useState({ const [dimensions, setDimensions] = useState({
width: null, width: null,
@ -61,6 +63,8 @@ const Home = () => {
const [isLoading, setIsLoading] = useState(true); const [isLoading, setIsLoading] = useState(true);
const [showCloudModal, setShowCloudModal] = useState(false); const [showCloudModal, setShowCloudModal] = useState(false);
const [cursorPosition, setCursorPosition] = useState({ x: 0, y: 0 });
// ATOMIC STATES // ATOMIC STATES
const [outputPath, setOutputPath] = useAtom(outputPathAtom); const [outputPath, setOutputPath] = useAtom(outputPathAtom);
const [compression, setCompression] = useAtom(compressionAtom); const [compression, setCompression] = useAtom(compressionAtom);
@ -75,10 +79,22 @@ const Home = () => {
const noImageProcessing = useAtomValue(noImageProcessingAtom); const noImageProcessing = useAtomValue(noImageProcessingAtom);
const [news, setNews] = useAtom(newsAtom); const [news, setNews] = useAtom(newsAtom);
const [showNewsModal, setShowNewsModal] = useAtom(showNewsModalAtom); const [showNewsModal, setShowNewsModal] = useAtom(showNewsModalAtom);
const viewType = useAtomValue(viewTypeAtom);
const lensSize = useAtomValue(lensSizeAtom);
const { logit } = useLog(); const { logit } = useLog();
// * EFFECTS const handleMouseMoveCompare = (e: React.MouseEvent) => {
const { left, top, height, width } =
e.currentTarget.getBoundingClientRect();
const x = e.clientX - left;
const y = e.clientY - top;
setCursorPosition({ x, y });
const xZoom = ((e.pageX - left) / width) * 100;
const yZoom = ((e.pageY - top) / height) * 100;
setBackgroundPosition(`${xZoom}% ${yZoom}%`);
};
// SET CONFIG VARIABLES ON FIRST RUN // SET CONFIG VARIABLES ON FIRST RUN
useEffect(() => { useEffect(() => {
// UPSCAYL VERSION // UPSCAYL VERSION
@ -611,7 +627,6 @@ const Home = () => {
stopHandler={stopHandler} stopHandler={stopHandler}
/> />
) : null} ) : null}
{/* DEFAULT PANE INFO */} {/* DEFAULT PANE INFO */}
{((!batchMode && {((!batchMode &&
imagePath.length === 0 && imagePath.length === 0 &&
@ -621,7 +636,6 @@ const Home = () => {
upscaledBatchFolderPath.length === 0)) && ( upscaledBatchFolderPath.length === 0)) && (
<RightPaneInfo version={version} batchMode={batchMode} /> <RightPaneInfo version={version} batchMode={batchMode} />
)} )}
{/* SHOW SELECTED IMAGE */} {/* SHOW SELECTED IMAGE */}
{!batchMode && {!batchMode &&
upscaledImagePath.length === 0 && upscaledImagePath.length === 0 &&
@ -647,7 +661,6 @@ const Home = () => {
/> />
</> </>
)} )}
{/* BATCH UPSCALE SHOW SELECTED FOLDER */} {/* BATCH UPSCALE SHOW SELECTED FOLDER */}
{batchMode && {batchMode &&
upscaledBatchFolderPath.length === 0 && upscaledBatchFolderPath.length === 0 &&
@ -657,7 +670,6 @@ const Home = () => {
{batchFolderPath} {batchFolderPath}
</p> </p>
)} )}
{/* BATCH UPSCALE DONE INFO */} {/* BATCH UPSCALE DONE INFO */}
{batchMode && upscaledBatchFolderPath.length > 0 && ( {batchMode && upscaledBatchFolderPath.length > 0 && (
<> <>
@ -671,59 +683,109 @@ const Home = () => {
</button> </button>
</> </>
)} )}
<ImageOptions
zoomAmount={zoomAmount}
setZoomAmount={setZoomAmount}
resetImagePaths={resetImagePaths}
/>
{!batchMode &&
viewType === "lens" &&
upscaledImagePath &&
imagePath && (
<div
className="relative group overflow-hidden h-full w-full"
onMouseMove={handleMouseMoveCompare}>
<img
className={`absolute left-0 top-0 object-contain w-full h-full group-hover:scale-[${
zoomAmount + "%"
}]`}
src={"file:///" + imagePath}
style={{
backgroundPosition: "0% 0%",
transformOrigin: backgroundPosition,
}}
/>
<div
className={`absolute left-0 top-0 bg-white mix-blend-difference w-full h-full group-hover:visible invisible group-hover:scale-[${
zoomAmount + "%"
}]`}
style={{
clipPath: `circle(${
(lensSize + 2) / (parseInt(zoomAmount) / 100)
}px at ${cursorPosition.x}px ${cursorPosition.y}px)`,
backgroundPosition: "0% 0%",
transformOrigin: backgroundPosition,
}}
/>
<img
className={`absolute top-0 object-contain left-0 w-full h-full group-hover:scale-[${
zoomAmount + "%"
}]`}
src={"file:///" + upscaledImagePath}
style={{
clipPath: `circle(${
lensSize / (parseInt(zoomAmount) / 100)
}px at ${cursorPosition.x}px ${cursorPosition.y}px)`,
backgroundPosition: "0% 0%",
transformOrigin: backgroundPosition,
}}
/>
</div>
)}
{/* COMPARISON SLIDER */} {/* COMPARISON SLIDER */}
{!batchMode && imagePath.length > 0 && upscaledImagePath.length > 0 && ( {!batchMode &&
<> viewType === "slider" &&
<ImageOptions imagePath.length > 0 &&
zoomAmount={zoomAmount} upscaledImagePath.length > 0 && (
setZoomAmount={setZoomAmount} <>
resetImagePaths={resetImagePaths} <ReactCompareSlider
/> itemOne={
<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 className="absolute bottom-1 left-1 rounded-md bg-black p-1 text-sm font-medium text-white opacity-30"> </p>
Original
</p>
<img <img
/* USE REGEX TO GET THE FILENAME AND ENCODE IT INTO PROPER FORM IN ORDER TO AVOID ERRORS DUE TO SPECIAL CHARACTERS */ /* USE REGEX TO GET THE FILENAME AND ENCODE IT INTO PROPER FORM IN ORDER TO AVOID ERRORS DUE TO SPECIAL CHARACTERS */
src={"file:///" + imagePath} src={"file:///" + imagePath}
alt="Original" alt="Original"
onMouseMove={handleMouseMove} onMouseMove={handleMouseMove}
style={{ style={{
objectFit: "contain", objectFit: "contain",
backgroundPosition: "0% 0%", backgroundPosition: "0% 0%",
transformOrigin: backgroundPosition, transformOrigin: backgroundPosition,
}} }}
className={`h-full w-full bg-gradient-to-br from-base-300 to-base-100 transition-transform group-hover:scale-[${zoomAmount}]`} className={`h-full w-full bg-gradient-to-br from-base-300 to-base-100 transition-transform group-hover:scale-[${
/> parseInt(zoomAmount.slice(0, -1)) / 100
</> }]`}
} />
itemTwo={ </>
<> }
<p className="absolute bottom-1 right-1 rounded-md bg-black p-1 text-sm font-medium text-white opacity-30"> itemTwo={
Upscayled <>
</p> <p className="absolute bottom-1 right-1 rounded-md bg-black p-1 text-sm font-medium text-white opacity-30">
<img Upscayled
/* USE REGEX TO GET THE FILENAME AND ENCODE IT INTO PROPER FORM IN ORDER TO AVOID ERRORS DUE TO SPECIAL CHARACTERS */ </p>
src={"file:///" + upscaledImagePath} <img
alt="Upscayl" /* USE REGEX TO GET THE FILENAME AND ENCODE IT INTO PROPER FORM IN ORDER TO AVOID ERRORS DUE TO SPECIAL CHARACTERS */
style={{ src={"file:///" + upscaledImagePath}
objectFit: "contain", alt="Upscayl"
backgroundPosition: "0% 0%", style={{
transformOrigin: backgroundPosition, objectFit: "contain",
}} backgroundPosition: "0% 0%",
onMouseMove={handleMouseMove} transformOrigin: backgroundPosition,
className={`h-full w-full bg-gradient-to-br from-base-300 to-base-100 transition-transform group-hover:scale-[${zoomAmount}]`} }}
/> onMouseMove={handleMouseMove}
</> className={`h-full w-full bg-gradient-to-br from-base-300 to-base-100 transition-transform group-hover:scale-[${
} zoomAmount || "100%"
className="group h-screen" }%]`}
/> />
</> </>
)} }
className="group h-screen"
/>
</>
)}
</div> </div>
</div> </div>
); );

View File

@ -4,11 +4,10 @@ module.exports = {
"./renderer/components/**/*.{js,ts,jsx,tsx}", "./renderer/components/**/*.{js,ts,jsx,tsx}",
], ],
safelist: [ safelist: [
"group-hover:scale-[100%]", ...[...Array(99).keys()].flatMap((index) => [
"group-hover:scale-[125%]", `group-hover:scale-[${index * 10}%]`,
"group-hover:scale-[150%]", `group-hover:scale-[${index * 10}%]`,
"group-hover:scale-[175%]", ]),
"group-hover:scale-[200%]",
], ],
theme: { theme: {
extend: { extend: {