diff --git a/apps/readest-app/src/__tests__/components/ImageViewer.test.tsx b/apps/readest-app/src/__tests__/components/ImageViewer.test.tsx
new file mode 100644
index 00000000..93e44dd6
--- /dev/null
+++ b/apps/readest-app/src/__tests__/components/ImageViewer.test.tsx
@@ -0,0 +1,39 @@
+import { describe, it, expect, vi, afterEach } from 'vitest';
+import { render, cleanup } from '@testing-library/react';
+
+import ImageViewer from '@/app/reader/components/ImageViewer';
+
+vi.mock('@/hooks/useTranslation', () => ({
+ useTranslation: () => (s: string) => s,
+}));
+
+// useKeyDownActions pulls in EnvContext + device store; not under test here.
+vi.mock('@/hooks/useKeyDownActions', () => ({
+ useKeyDownActions: () => {},
+}));
+
+// ZoomControls reaches into the theme store and Tauri window APIs; stub it out.
+vi.mock('@/app/reader/components/ZoomControls', () => ({
+ __esModule: true,
+ default: () => null,
+}));
+
+afterEach(cleanup);
+
+const gridInsets = { top: 0, right: 0, bottom: 0, left: 0 };
+
+describe('ImageViewer', () => {
+ it('suppresses the native image callout on the zoomed image', () => {
+ // The WebView's native long-press image callout collides with the
+ // viewer's own pinch/pan handlers on Android and freezes the app. The
+ // zoomed
must live under a `.no-context-menu` ancestor so the
+ // global `.no-context-menu img { -webkit-touch-callout: none }` rule
+ // disables that callout. Mirrors the book-cover fix (PR #4345).
+ const { container } = render(
+ ,
+ );
+
+ const calloutSafeImage = container.querySelector('.no-context-menu img');
+ expect(calloutSafeImage).toBeTruthy();
+ });
+});
diff --git a/apps/readest-app/src/app/reader/components/ImageViewer.tsx b/apps/readest-app/src/app/reader/components/ImageViewer.tsx
index d8e6fa9a..4af6df17 100644
--- a/apps/readest-app/src/app/reader/components/ImageViewer.tsx
+++ b/apps/readest-app/src/app/reader/components/ImageViewer.tsx
@@ -367,12 +367,15 @@ const ImageViewer: React.FC = ({
if (!src) return null;
return (
+ // `no-context-menu` suppresses the WebView's native long-press image
+ // callout (via the `.no-context-menu img` rule). On Android it otherwise
+ // collides with the pinch/pan handlers below and freezes the app.