chenbhao Claude Opus 4.6 commited on
Commit
412f992
·
1 Parent(s): 00d812d

fix: preserve image aspect ratio with cover() and dynamic height calculation

Browse files

Replace non-proportional resize() with cover() in useImage hook, and
compute target height from original aspect ratio in LocalPicture test
instead of hardcoding a terminal-rows-based ratio.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

src/ink-picture/__tests__/LocalPicture.test.tsx CHANGED
@@ -2,37 +2,70 @@
2
  /**
3
  * Visual test: display a local image using ink-picture + Ink.
4
  *
 
 
 
5
  * Usage:
6
  * bun run src/ink-picture/__tests__/LocalPicture.test.tsx
7
  */
8
 
9
- import React, { useEffect } from 'react'
10
- import { render, Box, useApp } from 'ink'
11
- import Image, { InkPictureProvider } from '../index.ts'
12
-
13
- const IMAGE_PATH = '/home/yuki/Pictures/Wallpapers/3god.jpg'
14
 
15
- const cols = process.stdout.columns ?? 80
16
- const rows = process.stdout.rows ?? 40
17
- const imgWidth = Math.floor(cols * 0.6)
18
- const imgHeight = Math.floor(rows * 0.4)
19
 
20
  function App() {
21
- const { exit } = useApp()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
  useEffect(() => {
24
- const timer = setTimeout(() => exit(), 3000)
25
- return () => clearTimeout(timer)
26
- }, [exit])
 
 
 
 
 
 
 
 
27
 
28
  return (
29
  <Box flexDirection="column">
30
  <InkPictureProvider>
31
- <Image src={IMAGE_PATH} width={imgWidth} height={imgHeight} alt="3god" />
 
 
 
 
 
32
  </InkPictureProvider>
33
  </Box>
34
- )
35
  }
36
 
37
- const { waitUntilExit } = render(<App />)
38
- await waitUntilExit()
 
2
  /**
3
  * Visual test: display a local image using ink-picture + Ink.
4
  *
5
+ * Height is auto-calculated from the original aspect ratio:
6
+ * only width is fixed (60% of terminal columns).
7
+ *
8
  * Usage:
9
  * bun run src/ink-picture/__tests__/LocalPicture.test.tsx
10
  */
11
 
12
+ import { Jimp } from "jimp";
13
+ import React, { useEffect, useState } from "react";
14
+ import { render, Box, Text, useApp } from "ink";
15
+ import Image, { InkPictureProvider } from "../index.ts";
 
16
 
17
+ const IMAGE_PATH = "/home/yuki/Pictures/Wallpapers/3god.jpg";
 
 
 
18
 
19
  function App() {
20
+ const { exit } = useApp();
21
+ const [dimensions, setDimensions] = useState<{
22
+ width: number;
23
+ height: number;
24
+ } | null>(null);
25
+ const [err, setErr] = useState(false);
26
+
27
+ useEffect(() => {
28
+ (async () => {
29
+ try {
30
+ const image = await Jimp.read(IMAGE_PATH);
31
+ const origW = image.bitmap.width;
32
+ const origH = image.bitmap.height;
33
+ const cols = process.stdout.columns ?? 80;
34
+ const targetW = Math.floor(cols * 0.6);
35
+ const targetH = Math.floor(targetW * (origH / origW) / 2);
36
+ setDimensions({ width: targetW, height: targetH });
37
+ } catch {
38
+ setErr(true);
39
+ }
40
+ })();
41
+ }, []);
42
 
43
  useEffect(() => {
44
+ const timer = setTimeout(() => exit(), 3000);
45
+ return () => clearTimeout(timer);
46
+ }, [exit]);
47
+
48
+ if (err) {
49
+ return <Text color="red">Failed to load image</Text>;
50
+ }
51
+
52
+ if (!dimensions) {
53
+ return <Text>Loading...</Text>;
54
+ }
55
 
56
  return (
57
  <Box flexDirection="column">
58
  <InkPictureProvider>
59
+ <Image
60
+ src={IMAGE_PATH}
61
+ width={dimensions.width}
62
+ height={dimensions.height}
63
+ alt="3god"
64
+ />
65
  </InkPictureProvider>
66
  </Box>
67
+ );
68
  }
69
 
70
+ const { waitUntilExit } = render(<App />);
71
+ await waitUntilExit();
src/ink-picture/hooks/useImage.ts CHANGED
@@ -43,7 +43,7 @@ export function useImage<T extends "pixels" | "png" = "pixels">(options: {
43
  }
44
 
45
  setError(false);
46
- image.resize({ w: pixelWidth, h: pixelHeight });
47
 
48
  if (mode === "png") {
49
  const result = await getPngBuffer(image);
 
43
  }
44
 
45
  setError(false);
46
+ image.cover({ w: pixelWidth, h: pixelHeight });
47
 
48
  if (mode === "png") {
49
  const result = await getPngBuffer(image);