feat: add image upscaling option and allow force stretching beyond native resolution

main
I Luk Kim 3 weeks ago
parent 0774c130de
commit e4269041ee

@ -537,21 +537,39 @@ kbd {
} }
.manga-page img { .manga-page img {
max-width: 100%;
max-height: 100%;
object-fit: contain; object-fit: contain;
display: block; display: block;
pointer-events: none; pointer-events: none;
} }
.fit-width .manga-page img { /* Allow Upscale Mode (Default: stretch to fill container) */
.manga-page.allow-upscale.fit-width img {
width: 100%; width: 100%;
height: auto; height: auto;
max-width: none;
max-height: none;
} }
.fit-height .manga-page img { .manga-page.allow-upscale.fit-height img {
height: 100%; height: 100%;
width: auto; width: auto;
max-width: none;
max-height: none;
}
/* No Upscale Mode (Limit max dimensions to native image size) */
.manga-page.no-upscale.fit-width img {
width: auto;
max-width: 100%;
height: auto;
max-height: 100%;
}
.manga-page.no-upscale.fit-height img {
height: auto;
max-height: 100%;
width: auto;
max-width: 100%;
} }
/* Page loading / error states */ /* Page loading / error states */

@ -5,10 +5,11 @@ interface MangaPageProps {
imageUrl: string; imageUrl: string;
referer: string; referer: string;
fitMode: FitMode; fitMode: FitMode;
allowUpscale?: boolean;
fetchImage: (url: string, referer: string) => Promise<string>; fetchImage: (url: string, referer: string) => Promise<string>;
} }
export function MangaPage({ imageUrl, referer, fitMode, fetchImage }: MangaPageProps) { export function MangaPage({ imageUrl, referer, fitMode, allowUpscale = true, fetchImage }: MangaPageProps) {
const [src, setSrc] = useState<string>(''); const [src, setSrc] = useState<string>('');
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [error, setError] = useState(false); const [error, setError] = useState(false);
@ -44,6 +45,8 @@ export function MangaPage({ imageUrl, referer, fitMode, fetchImage }: MangaPageP
original: 'fit-original', original: 'fit-original',
}[fitMode]; }[fitMode];
const upscaleClass = allowUpscale ? 'allow-upscale' : 'no-upscale';
if (loading) { if (loading) {
return ( return (
<div className="page-placeholder"> <div className="page-placeholder">
@ -70,7 +73,7 @@ export function MangaPage({ imageUrl, referer, fitMode, fetchImage }: MangaPageP
} }
return ( return (
<div className={`manga-page ${fitClass}`}> <div className={`manga-page ${fitClass} ${upscaleClass}`}>
<img <img
src={src} src={src}
alt="" alt=""

@ -309,6 +309,7 @@ export function MangaViewer({
imageUrl={imgUrl} imageUrl={imgUrl}
referer={referer} referer={referer}
fitMode={settings.fitMode} fitMode={settings.fitMode}
allowUpscale={settings.allowUpscale}
fetchImage={fetchImage} fetchImage={fetchImage}
/> />
))} ))}

@ -138,6 +138,30 @@ export function SettingsPanel({ settings, totalImages, onChange, onClose }: Sett
</div> </div>
</div> </div>
{/* Upscale Mode */}
<div className="settings-group">
<label className="settings-label">
<span className="settings-hint"> </span>
</label>
<div className="option-grid cols-2">
<button
className={`option-card compact ${settings.allowUpscale ? 'selected' : ''}`}
onClick={() => onChange({ allowUpscale: true })}
>
<span> ( )</span>
<small> </small>
</button>
<button
className={`option-card compact ${!settings.allowUpscale ? 'selected' : ''}`}
onClick={() => onChange({ allowUpscale: false })}
>
<span> ( )</span>
<small> </small>
</button>
</div>
</div>
{/* Background Color */} {/* Background Color */}
<div className="settings-group"> <div className="settings-group">
<label className="settings-label"></label> <label className="settings-label"></label>

@ -7,6 +7,7 @@ const defaultSettings: ViewerSettings = {
mode: 'spread', mode: 'spread',
direction: 'ltr', direction: 'ltr',
fitMode: 'width', fitMode: 'width',
allowUpscale: true,
backgroundColor: 'black', backgroundColor: 'black',
spreadStartOffset: 0, spreadStartOffset: 0,
}; };

@ -15,6 +15,7 @@ export interface ViewerSettings {
mode: ViewerMode; mode: ViewerMode;
direction: ReadingDirection; direction: ReadingDirection;
fitMode: FitMode; fitMode: FitMode;
allowUpscale: boolean;
backgroundColor: BackgroundColor; backgroundColor: BackgroundColor;
/** 0-indexed page that starts the first "paired" spread. Pages before this are shown solo. */ /** 0-indexed page that starts the first "paired" spread. Pages before this are shown solo. */
spreadStartOffset: number; spreadStartOffset: number;

Loading…
Cancel
Save