mirror of
https://github.com/upscayl/upscayl.git
synced 2025-02-23 22:03:42 +01:00
Update lens view
This commit is contained in:
parent
c5f4a7eedb
commit
7badfac026
@ -72,6 +72,8 @@ const ImageViewSettings = ({
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{viewType !== "lens" && (
|
||||
<>
|
||||
<div className="flex flex-col gap-2">
|
||||
<p className="text-sm font-medium">
|
||||
{t("APP.IMAGE_OPTIONS.ZOOM_AMOUNT_TITLE")} ({zoomAmount}%)
|
||||
@ -106,6 +108,8 @@ const ImageViewSettings = ({
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -332,8 +332,6 @@ const MainContent = ({
|
||||
|
||||
{!batchMode && viewType === "lens" && upscaledImagePath && imagePath && (
|
||||
<LensViewer
|
||||
zoomAmount={zoomAmount}
|
||||
lensSize={lensSize}
|
||||
sanitizedImagePath={sanitizedImagePath}
|
||||
sanitizedUpscaledImagePath={sanitizedUpscaledImagePath}
|
||||
/>
|
||||
|
@ -6,22 +6,21 @@ function InstructionsCard({ version, batchMode }) {
|
||||
const t = useAtomValue(translationAtom);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center rounded-btn bg-base-200 p-4">
|
||||
<p className="pb-1 text-lg font-semibold">
|
||||
<div className="flex flex-col items-center gap-4 rounded-btn bg-base-200 p-4">
|
||||
<p className="text-lg font-semibold">
|
||||
{batchMode
|
||||
? t("APP.RIGHT_PANE_INFO.SELECT_FOLDER")
|
||||
: t("APP.RIGHT_PANE_INFO.SELECT_IMAGE")}
|
||||
</p>
|
||||
{batchMode ? (
|
||||
<p className="w-full pb-5 text-center text-base-content/80 md:w-96">
|
||||
<p className="w-full text-center text-base-content/80 md:w-96">
|
||||
{t("APP.RIGHT_PANE_INFO.SELECT_FOLDER_DESCRIPTION")}
|
||||
</p>
|
||||
) : (
|
||||
<p className="w-full pb-5 text-center text-base-content/80 md:w-96">
|
||||
{t("APP.RIGHT_PANE_INFO.SELECT_IMAGES_DESCRIPTION")}
|
||||
<br />
|
||||
{t("APP.RIGHT_PANE_INFO.PASTE_IMAGE_DESCRIPTION")}
|
||||
</p>
|
||||
<div className="flex flex-col gap-1 text-center text-sm text-base-content/70">
|
||||
<p>{t("APP.RIGHT_PANE_INFO.SELECT_IMAGES_DESCRIPTION")}</p>
|
||||
<p>{t("APP.RIGHT_PANE_INFO.PASTE_IMAGE_DESCRIPTION")}</p>
|
||||
</div>
|
||||
)}
|
||||
<p className="badge badge-primary text-sm">Upscayl v{version}</p>
|
||||
</div>
|
||||
|
@ -1,48 +1,120 @@
|
||||
import React, { useRef, useState } from "react";
|
||||
import React, { useMemo, useRef, useState } from "react";
|
||||
|
||||
const LensViewer = ({
|
||||
zoomAmount,
|
||||
lensSize,
|
||||
sanitizedImagePath,
|
||||
sanitizedUpscaledImagePath,
|
||||
}: {
|
||||
zoomAmount: string;
|
||||
lensSize: number;
|
||||
sanitizedImagePath: string;
|
||||
sanitizedUpscaledImagePath: string;
|
||||
}) => {
|
||||
const [hoverPosition, setHoverPosition] = useState({ x: 0, y: 0 });
|
||||
const zoomLevel = 4; // Adjust zoom level as needed
|
||||
const originalImageContainerRef = useRef<HTMLDivElement>(null);
|
||||
const originalImageRef = useRef<HTMLImageElement>(null);
|
||||
|
||||
const [hoverPosition, setHoverPosition] = useState({
|
||||
x: 0,
|
||||
y: 0,
|
||||
pixelX: 0,
|
||||
pixelY: 0,
|
||||
bgPosX: 0,
|
||||
bgPosY: 0,
|
||||
});
|
||||
const zoomLevel = 4;
|
||||
|
||||
const handleMouseMove = (e: React.MouseEvent) => {
|
||||
const { left, top, width, height } =
|
||||
e.currentTarget.getBoundingClientRect();
|
||||
const x = ((e.clientX - left) / width) * 100;
|
||||
const y = ((e.clientY - top) / height) * 100;
|
||||
if (!originalImageRef.current || !originalImageContainerRef.current) return;
|
||||
|
||||
setHoverPosition({ x, y });
|
||||
const containerRect =
|
||||
originalImageContainerRef.current.getBoundingClientRect();
|
||||
|
||||
const imageAspectRatio =
|
||||
originalImageRef.current.naturalWidth /
|
||||
originalImageRef.current.naturalHeight;
|
||||
const containerAspectRatio = containerRect.width / containerRect.height;
|
||||
|
||||
let imageWidth = containerRect.width;
|
||||
let imageHeight = containerRect.height;
|
||||
let imageLeft = 0;
|
||||
let imageTop = 0;
|
||||
|
||||
if (containerAspectRatio > imageAspectRatio) {
|
||||
// Image is height-constrained
|
||||
imageWidth = imageHeight * imageAspectRatio;
|
||||
imageLeft = (containerRect.width - imageWidth) / 2;
|
||||
} else {
|
||||
// Image is width-constrained
|
||||
imageHeight = imageWidth / imageAspectRatio;
|
||||
imageTop = (containerRect.height - imageHeight) / 2;
|
||||
}
|
||||
|
||||
const offsetX = e.clientX - containerRect.left - imageLeft;
|
||||
const offsetY = e.clientY - containerRect.top - imageTop;
|
||||
|
||||
// Check if the mouse is within the actual image boundaries
|
||||
const isWithinImage =
|
||||
offsetX >= 0 &&
|
||||
offsetX <= imageWidth &&
|
||||
offsetY >= 0 &&
|
||||
offsetY <= imageHeight;
|
||||
|
||||
if (!isWithinImage) {
|
||||
setHoverPosition({
|
||||
x: -1000,
|
||||
y: -1000,
|
||||
pixelX: -1000,
|
||||
pixelY: -1000,
|
||||
bgPosX: -1000,
|
||||
bgPosY: -1000,
|
||||
}); // Move lens off-screen
|
||||
return;
|
||||
}
|
||||
|
||||
const x = (offsetX / imageWidth) * 100;
|
||||
const y = (offsetY / imageHeight) * 100;
|
||||
|
||||
// Calculate background position for zoom view
|
||||
const bgPosX =
|
||||
(offsetX / imageWidth) * originalImageRef.current.naturalWidth;
|
||||
const bgPosY =
|
||||
(offsetY / imageHeight) * originalImageRef.current.naturalHeight;
|
||||
|
||||
setHoverPosition({
|
||||
x,
|
||||
y,
|
||||
pixelX: e.clientX - containerRect.left,
|
||||
pixelY: e.clientY - containerRect.top,
|
||||
bgPosX,
|
||||
bgPosY,
|
||||
});
|
||||
};
|
||||
|
||||
const originalImage = "file:///" + sanitizedImagePath;
|
||||
const upscaledImage = "file:///" + sanitizedUpscaledImagePath;
|
||||
const originalImage = useMemo(
|
||||
() => "file:///" + sanitizedImagePath,
|
||||
[sanitizedImagePath],
|
||||
);
|
||||
const upscaledImage = useMemo(
|
||||
() => "file:///" + sanitizedUpscaledImagePath,
|
||||
[sanitizedUpscaledImagePath],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="group relative flex h-screen flex-col items-center">
|
||||
<div className="group relative flex h-full flex-col items-center">
|
||||
{/* Main image container */}
|
||||
<div
|
||||
className="relative h-full w-full cursor-crosshair bg-cover bg-no-repeat"
|
||||
onMouseMove={handleMouseMove}
|
||||
className="relative h-full w-full cursor-crosshair"
|
||||
ref={originalImageContainerRef}
|
||||
>
|
||||
<img
|
||||
src={originalImage}
|
||||
alt="Original"
|
||||
className="h-full w-full object-contain"
|
||||
onMouseMove={handleMouseMove}
|
||||
ref={originalImageRef}
|
||||
/>
|
||||
<div
|
||||
className="pointer-events-none absolute hidden h-12 w-12 border-2 border-white group-hover:block"
|
||||
className="pointer-events-none absolute hidden h-10 w-10 cursor-cell border border-primary bg-black/10 group-hover:block"
|
||||
style={{
|
||||
left: `${hoverPosition.x}%`,
|
||||
top: `${hoverPosition.y}%`,
|
||||
left: `${hoverPosition.pixelX}px`,
|
||||
top: `${hoverPosition.pixelY}px`,
|
||||
transform: "translate(-50%, -50%)",
|
||||
}}
|
||||
/>
|
||||
@ -50,10 +122,10 @@ const LensViewer = ({
|
||||
|
||||
{/* Enlarged views for original and upscaled images */}
|
||||
<div
|
||||
className="pointer-events-none absolute hidden gap-4 group-hover:flex "
|
||||
className="pointer-events-none absolute hidden group-hover:flex"
|
||||
style={{
|
||||
left: `${hoverPosition.x}%`,
|
||||
top: `${hoverPosition.y}%`, // Position below the cursor
|
||||
left: `${hoverPosition.pixelX}px`,
|
||||
top: `${hoverPosition.pixelY + 25}px`,
|
||||
transform: "translate(-50%, 0)",
|
||||
}}
|
||||
>
|
||||
@ -61,11 +133,11 @@ const LensViewer = ({
|
||||
className="relative h-48 w-48 border border-gray-300 bg-cover bg-no-repeat"
|
||||
style={{
|
||||
backgroundImage: `url(${originalImage})`,
|
||||
backgroundPosition: `${hoverPosition.x}% ${hoverPosition.y}%`,
|
||||
backgroundSize: `${100 * zoomLevel}%`, // Increase zoom level to match the white box
|
||||
backgroundPosition: `-${hoverPosition.bgPosX * zoomLevel - 96}px -${hoverPosition.bgPosY * zoomLevel - 96}px`,
|
||||
backgroundSize: `${originalImageRef.current?.naturalWidth * zoomLevel}px ${originalImageRef.current?.naturalHeight * zoomLevel}px`,
|
||||
}}
|
||||
>
|
||||
<span className="absolute bottom-1 left-1 rounded bg-black bg-opacity-60 px-2 py-1 text-sm text-white">
|
||||
<span className="absolute bottom-0 w-full bg-black bg-opacity-60 px-2 py-1 text-center text-xs text-white">
|
||||
Original
|
||||
</span>
|
||||
</div>
|
||||
@ -73,12 +145,12 @@ const LensViewer = ({
|
||||
className="relative h-48 w-48 border border-gray-300 bg-cover bg-no-repeat"
|
||||
style={{
|
||||
backgroundImage: `url(${upscaledImage})`,
|
||||
backgroundPosition: `${hoverPosition.x}% ${hoverPosition.y}%`,
|
||||
backgroundSize: `${100 * zoomLevel}%`, // Increase zoom level to match the white box
|
||||
backgroundPosition: `-${hoverPosition.bgPosX * zoomLevel - 96}px -${hoverPosition.bgPosY * zoomLevel - 96}px`,
|
||||
backgroundSize: `${originalImageRef.current?.naturalWidth * zoomLevel}px ${originalImageRef.current?.naturalHeight * zoomLevel}px`,
|
||||
}}
|
||||
>
|
||||
<span className="absolute bottom-1 left-1 rounded bg-black bg-opacity-60 px-2 py-1 text-sm text-white">
|
||||
AI Upscaled
|
||||
<span className="absolute bottom-0 w-full bg-black bg-opacity-60 px-2 py-1 text-center text-xs text-white">
|
||||
Upscayl AI
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -144,8 +144,8 @@
|
||||
},
|
||||
"RESET_BUTTON_TITLE": "Reset",
|
||||
"RIGHT_PANE_INFO": {
|
||||
"SELECT_FOLDER": "Select a Folder to Upscayl",
|
||||
"SELECT_IMAGE": "Select an Image to Upscayl",
|
||||
"SELECT_FOLDER": "Select a Folder",
|
||||
"SELECT_IMAGE": "Select an Image",
|
||||
"SELECT_FOLDER_DESCRIPTION": "Make sure that the folder doesn't contain anything except PNG, JPG, JPEG & WEBP images.",
|
||||
"SELECT_IMAGES_DESCRIPTION": "Select or drag and drop a PNG, JPG, JPEG or WEBP image.",
|
||||
"PASTE_IMAGE_DESCRIPTION": "Hit Ctrl + V or Cmd + V to Paste image from Clipboard"
|
||||
|
@ -144,8 +144,8 @@
|
||||
},
|
||||
"RESET_BUTTON_TITLE": "Restablecer",
|
||||
"RIGHT_PANE_INFO": {
|
||||
"SELECT_FOLDER": "Selecciona una carpeta para aumentar",
|
||||
"SELECT_IMAGE": "Selecciona una imagen para aumentar",
|
||||
"SELECT_FOLDER": "Selecciona una carpeta",
|
||||
"SELECT_IMAGE": "Selecciona una imagen",
|
||||
"SELECT_FOLDER_DESCRIPTION": "Asegúrate de que la carpeta no contenga nada excepto imágenes PNG, JPG, JPEG y WEBP.",
|
||||
"SELECT_IMAGES_DESCRIPTION": "Selecciona o arrastra y suelta una imagen PNG, JPG, JPEG o WEBP.",
|
||||
"PASTE_IMAGE_DESCRIPTION": "Presiona Ctrl + V o Cmd + V para pegar la imagen desde el portapapeles"
|
||||
|
Loading…
x
Reference in New Issue
Block a user