Skip to content

Commit

Permalink
Merge pull request #531 from AlanDrake/upscale-pixelated
Browse files Browse the repository at this point in the history
Add upscale smooth/pixelated option
  • Loading branch information
RvanderLaan authored Feb 4, 2023
2 parents 2335a2d + 24445be commit 813384a
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 5 deletions.
4 changes: 4 additions & 0 deletions src/frontend/containers/ContentView/GalleryItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,16 @@ export const Thumbnail = observer(({ file, mounted, forceNoThumbnail }: ItemProp
return <span className="image-loading" />;
} else if (imageSource.tag === 'ready') {
if ('ok' in imageSource.value) {
const is_lowres = file.width < 320 || file.height < 320;
return (
<img
src={encodeFilePath(imageSource.value.ok)}
alt=""
data-file-id={file.id}
onError={handleImageError}
style={
is_lowres && uiStore.upscaleMode == 'pixelated' ? { imageRendering: 'pixelated' } : {}
}
/>
);
} else {
Expand Down
7 changes: 5 additions & 2 deletions src/frontend/containers/ContentView/SlideMode/ZoomPan.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
tryPreventDefault,
Vec2,
} from './utils';
import { UpscaleMode } from '../../../stores/UiStore';

const OVERZOOM_TOLERANCE = 0.05;
const DOUBLE_TAP_THRESHOLD = 250;
Expand All @@ -41,6 +42,7 @@ export interface ZoomPanProps {
imageDimension: Dimension;
containerDimension: Dimension;
onClose?: () => void;
upscaleMode: UpscaleMode;

transitionStart?: Transform;
transitionEnd?: Transform;
Expand Down Expand Up @@ -296,7 +298,7 @@ export default class ZoomPan extends React.Component<ZoomPanProps, ZoomPanState>
onWheel: this.handleMouseWheel,
onDragStart: tryPreventDefault,
onContextMenu: tryPreventDefault,
style: imageStyle(this.state),
style: imageStyle(this.state, this.props.upscaleMode),
})}
</div>
);
Expand Down Expand Up @@ -485,9 +487,10 @@ export const CONTAINER_DEFAULT_STYLE = {
margin: 'auto',
};

function imageStyle({ top, left, scale }: ZoomPanState): CSSProperties {
function imageStyle({ top, left, scale }: ZoomPanState, upscaleMode: UpscaleMode): CSSProperties {
return {
transform: `translate3d(${Math.trunc(left)}px, ${Math.trunc(top)}px, 0) scale(${scale})`,
imageRendering: scale >= 2 && upscaleMode === 'pixelated' ? 'pixelated' : undefined,
};
}

Expand Down
5 changes: 5 additions & 0 deletions src/frontend/containers/ContentView/SlideMode/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { CommandDispatcher } from '../Commands';
import { ContentRect } from '../utils';
import ZoomPan, { CONTAINER_DEFAULT_STYLE, SlideTransform } from '../SlideMode/ZoomPan';
import { createDimension, createTransform, Vec2 } from './utils';
import { UpscaleMode } from 'src/frontend/stores/UiStore';

const SlideMode = observer(({ contentRect }: { contentRect: ContentRect }) => {
const { uiStore } = useStore();
Expand Down Expand Up @@ -177,6 +178,7 @@ const SlideView = observer(({ width, height }: SlideViewProps) => {
transitionStart={transitionStart}
transitionEnd={uiStore.isSlideMode ? undefined : transitionStart}
onClose={uiStore.disableSlideMode}
upscaleMode={uiStore.upscaleMode}
/>
)}
<NavigationButtons
Expand All @@ -197,6 +199,7 @@ interface ZoomableImageProps {
transitionStart?: SlideTransform;
transitionEnd?: SlideTransform;
onClose: () => void;
upscaleMode: UpscaleMode;
}

const ZoomableImage: React.FC<ZoomableImageProps> = ({
Expand All @@ -207,6 +210,7 @@ const ZoomableImage: React.FC<ZoomableImageProps> = ({
transitionStart,
transitionEnd,
onClose,
upscaleMode,
}: ZoomableImageProps) => {
const { imageLoader } = useStore();
const { absolutePath, width: imgWidth, height: imgHeight } = file;
Expand Down Expand Up @@ -277,6 +281,7 @@ const ZoomableImage: React.FC<ZoomableImageProps> = ({
transitionStart={transitionStart}
transitionEnd={transitionEnd}
onClose={onClose}
upscaleMode={upscaleMode}
>
{(props) => (
<img
Expand Down
19 changes: 16 additions & 3 deletions src/frontend/containers/ContentView/menu-items.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
import { ClientTag } from 'src/entities/Tag';
import { useStore } from 'src/frontend/contexts/StoreContext';
import { IconSet } from 'widgets';
import { MenuItem, MenuSubItem } from 'widgets/menus';
import { MenuItem, MenuRadioItem, MenuSubItem } from 'widgets/menus';
import { LocationTreeItemRevealer } from '../Outliner/LocationsPanel';
import { TagsTreeItemRevealer } from '../Outliner/TagsPanel/TagsTree';
import SysPath from 'path';
Expand Down Expand Up @@ -160,7 +160,7 @@ export const FileViewerMenuItems = ({ file }: { file: ClientFile }) => {
);
};

export const SlideFileViewerMenuItems = ({ file }: { file: ClientFile }) => {
export const SlideFileViewerMenuItems = observer(({ file }: { file: ClientFile }) => {
const { uiStore } = useStore();

const handlePreviewWindow = () => {
Expand All @@ -175,9 +175,22 @@ export const SlideFileViewerMenuItems = ({ file }: { file: ClientFile }) => {
text="Open In Preview Window"
icon={IconSet.PREVIEW}
/>

<MenuSubItem text="Upscale filtering..." icon={IconSet.VIEW_GRID}>
<MenuRadioItem
onClick={uiStore.setUpscaleModeSmooth}
checked={uiStore.upscaleMode === 'smooth'}
text="Smooth"
/>
<MenuRadioItem
onClick={uiStore.setUpscaleModePixelated}
checked={uiStore.upscaleMode === 'pixelated'}
text="Pixelated"
/>
</MenuSubItem>
</>
);
};
});

export const ExternalAppMenuItems = observer(({ file }: { file: ClientFile }) => {
const { uiStore } = useStore();
Expand Down
17 changes: 17 additions & 0 deletions src/frontend/containers/Settings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,23 @@ const Appearance = observer(() => {
</fieldset>
</div>

<div className="input-group">
<RadioGroup name="Picture upscaling">
<Radio
label="Smooth"
checked={uiStore.upscaleMode === 'smooth'}
value="smooth"
onChange={uiStore.setUpscaleModeSmooth}
/>
<Radio
label="Pixelated"
checked={uiStore.upscaleMode === 'pixelated'}
value="pixelated"
onChange={uiStore.setUpscaleModePixelated}
/>
</RadioGroup>
</div>

<h3>Thumbnail</h3>

<div className="input-group">
Expand Down
19 changes: 19 additions & 0 deletions src/frontend/stores/UiStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const enum ViewMethod {
}
export type ThumbnailSize = 'small' | 'medium' | 'large' | number;
type ThumbnailShape = 'square' | 'letterbox';
export type UpscaleMode = 'smooth' | 'pixelated';
export const PREFERENCES_STORAGE_KEY = 'preferences';

export interface IHotkeyMap {
Expand Down Expand Up @@ -100,6 +101,7 @@ type PersistentPreferenceFields =
| 'method'
| 'thumbnailSize'
| 'thumbnailShape'
| 'upscaleMode'
| 'hotkeyMap'
| 'isThumbnailTagOverlayEnabled'
| 'isThumbnailFilenameOverlayEnabled'
Expand Down Expand Up @@ -148,6 +150,7 @@ class UiStore {
@observable firstItem: number = 0;
@observable thumbnailSize: ThumbnailSize | number = 'medium';
@observable thumbnailShape: ThumbnailShape = 'square';
@observable upscaleMode: UpscaleMode = 'smooth';

@observable isToolbarTagPopoverOpen: boolean = false;
/** Dialog for removing unlinked files from Allusion's database */
Expand Down Expand Up @@ -216,6 +219,14 @@ class UiStore {
this.setThumbnailShape('letterbox');
}

@action.bound setUpscaleModeSmooth() {
this.setUpscaleMode('smooth');
}

@action.bound setUpscaleModePixelated() {
this.setUpscaleMode('pixelated');
}

@action.bound setFirstItem(index: number = 0) {
if (isFinite(index) && index < this.rootStore.fileStore.fileList.length) {
this.firstItem = index;
Expand Down Expand Up @@ -812,6 +823,9 @@ class UiStore {
if (prefs.thumbnailShape) {
this.setThumbnailShape(prefs.thumbnailShape);
}
if (prefs.upscaleMode) {
this.setUpscaleMode(prefs.upscaleMode);
}
this.isThumbnailTagOverlayEnabled = Boolean(prefs.isThumbnailTagOverlayEnabled ?? true);
this.isThumbnailFilenameOverlayEnabled = Boolean(prefs.isThumbnailFilenameOverlayEnabled ?? false); // eslint-disable-line prettier/prettier
this.isThumbnailResolutionOverlayEnabled = Boolean(prefs.isThumbnailResolutionOverlayEnabled ?? false); // eslint-disable-line prettier/prettier
Expand Down Expand Up @@ -866,6 +880,7 @@ class UiStore {
method: this.method,
thumbnailSize: this.thumbnailSize,
thumbnailShape: this.thumbnailShape,
upscaleMode: this.upscaleMode,
hotkeyMap: { ...this.hotkeyMap },
isThumbnailFilenameOverlayEnabled: this.isThumbnailFilenameOverlayEnabled,
isThumbnailTagOverlayEnabled: this.isThumbnailTagOverlayEnabled,
Expand Down Expand Up @@ -928,6 +943,10 @@ class UiStore {
@action private setThumbnailShape(shape: ThumbnailShape) {
this.thumbnailShape = shape;
}

@action private setUpscaleMode(mode: UpscaleMode) {
this.upscaleMode = mode;
}
}

export default UiStore;

0 comments on commit 813384a

Please sign in to comment.