feat: add option to disable image anti-aliasing (#14278)

## What this PR does

Closes #13869 
Adds a global setting to toggle image anti-aliasing in AFFiNE.

When disabled, images are rendered using nearest-neighbor scaling
(`image-rendering: pixelated`), preserving crisp pixels for pixel art,
sprites, icons, and low-resolution images.

## Why

Anti-aliasing causes small images to become blurry when scaled,
making it difficult to work with pixel art and technical assets.

## How to test

1. Open Settings → Appearance → Images
2. Toggle “Smooth image rendering”
3. Observe image scaling behavior:
   - ON: smooth / anti-aliased
   - OFF: pixelated / nearest-neighbor

## Notes

- Frontend-only change
- No backend required

# BEFORE
<img width="1911" height="909" alt="Screenshot 2026-01-18 202651"
src="https://github.com/user-attachments/assets/a40816c3-93fa-416d-90ec-38a919da182f"
/>

# AFTER
<img width="1919" height="910" alt="Screenshot 2026-01-18 202705"
src="https://github.com/user-attachments/assets/19fc348b-5f14-4e32-b6a8-a0905e569af5"
/>



<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added an Images section in Appearance with a toggle to switch image
antialiasing on/off (setting is persisted).

* **Style**
* When antialiasing is turned off, images render with pixelated scaling
for a crisp, non-smoothed look.

* **Localization**
* Added English labels and description for the new Images and
antialiasing options.

<sub>✏️ Tip: You can customize this high-level summary in your review
settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: DarkSky <25152247+darkskygit@users.noreply.github.com>
This commit is contained in:
Akshaj Rawat
2026-01-28 01:48:21 +05:30
committed by GitHub
parent 5041578768
commit 759aa1b684
9 changed files with 58 additions and 4 deletions

View File

@@ -32,6 +32,7 @@ export function App() {
BUILD_CONFIG.isElectron &&
environment.isMacOs &&
appSettings.enableBlurBackground;
return (
<FrameworkRoot framework={frameworkProvider}>
<ThemeProvider>

View File

@@ -322,3 +322,7 @@ math {
.ai-block-diff-deleted .affine-block-component {
margin: 0 !important;
}
html[data-image-antialiasing='off'] img {
image-rendering: pixelated;
}

View File

@@ -6,11 +6,14 @@ import { Provider } from 'jotai';
import type { PropsWithChildren } from 'react';
import { useMemo } from 'react';
import { useImageAntialiasing } from '../hooks/use-image-antialiasing';
export type AffineContextProps = PropsWithChildren<{
store?: ReturnType<typeof createStore>;
}>;
export function AffineContext(props: AffineContextProps) {
useImageAntialiasing();
return (
<ProviderComposer
contexts={useMemo(

View File

@@ -0,0 +1,12 @@
import { useEffect } from 'react';
import { useAppSettingHelper } from './affine/use-app-setting-helper';
export function useImageAntialiasing() {
const { appSettings } = useAppSettingHelper();
useEffect(() => {
document.documentElement.dataset.imageAntialiasing =
appSettings.disableImageAntialiasing ? 'off' : 'on';
}, [appSettings.disableImageAntialiasing]);
}

View File

@@ -197,6 +197,23 @@ export const AppearanceSettings = () => {
{enableThemeEditor ? <ThemeEditorSetting /> : null}
</SettingWrapper>
<SettingWrapper title={t['com.affine.appearanceSettings.images.title']()}>
<SettingRow
name={t['com.affine.appearanceSettings.images.antialiasing.title']()}
desc={t[
'com.affine.appearanceSettings.images.antialiasing.description'
]()}
data-testid="image-antialiasing-trigger"
>
<Switch
checked={!appSettings.disableImageAntialiasing}
onChange={checked =>
updateSettings('disableImageAntialiasing', !checked)
}
/>
</SettingRow>
</SettingWrapper>
{BUILD_CONFIG.isWeb && !environment.isMobile ? (
<SettingWrapper title={t['com.affine.setting.appearance.links']()}>
<SettingRow

View File

@@ -1,12 +1,12 @@
{
"ar": 98,
"ca": 100,
"ca": 99,
"da": 4,
"de": 99,
"el-GR": 98,
"en": 100,
"es-AR": 98,
"es-CL": 100,
"es-CL": 99,
"es": 98,
"fa": 98,
"fr": 100,
@@ -19,9 +19,9 @@
"pl": 100,
"pt-BR": 98,
"ru": 100,
"sv-SE": 99,
"sv-SE": 98,
"uk": 98,
"ur": 2,
"zh-Hans": 100,
"zh-Hant": 99
"zh-Hant": 98
}

View File

@@ -958,6 +958,18 @@ export function useAFFiNEI18N(): {
* `Customize Theme`
*/
["com.affine.appearanceSettings.customize-theme.title"](): string;
/**
* `Images`
*/
["com.affine.appearanceSettings.images.title"](): string;
/**
* `Smooth image rendering`
*/
["com.affine.appearanceSettings.images.antialiasing.title"](): string;
/**
* `When disabled, images are rendered using nearest-neighbor scaling for crisp pixels.`
*/
["com.affine.appearanceSettings.images.antialiasing.description"](): string;
/**
* `Reset all`
*/

View File

@@ -228,6 +228,9 @@
"com.affine.appearanceSettings.color.title": "Colour mode",
"com.affine.appearanceSettings.customize-theme.description": "Edit all AFFiNE theme variables here",
"com.affine.appearanceSettings.customize-theme.title": "Customize Theme",
"com.affine.appearanceSettings.images.title": "Images",
"com.affine.appearanceSettings.images.antialiasing.title": "Smooth image rendering",
"com.affine.appearanceSettings.images.antialiasing.description": "When disabled, images are rendered using nearest-neighbor scaling for crisp pixels.",
"com.affine.appearanceSettings.customize-theme.reset": "Reset all",
"com.affine.appearanceSettings.customize-theme.open": "Open Theme Editor",
"com.affine.appearanceSettings.font.description": "Choose your font style",