chenbhao Claude Opus 4.6 commited on
Commit
6485104
·
1 Parent(s): 862182b

feat(LocalPicture): support CLI args for path/URL and golden ratio width

Browse files

Allow passing an image path or URL as a command-line argument. Default
falls back to the original wallpaper. Display width changed from 40% to
16.18% (golden ratio) for a more aesthetically balanced default.

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

src/ink-picture/__tests__/LocalPicture.test.tsx CHANGED
@@ -1,13 +1,13 @@
1
  #!/usr/bin/env bun
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
- * Press Ctrl+C to exit (image persists)
 
 
 
11
  */
12
 
13
  import { Jimp } from "jimp";
@@ -15,42 +15,57 @@ import React, { useEffect, useState } from "react";
15
  import { render, Box, Text, useApp } from "ink";
16
  import Image, { InkPictureProvider } from "../index.ts";
17
 
18
- const IMAGE_PATH = "/home/yuki/Pictures/Wallpapers/3god.jpg";
19
-
20
  // 终端字符尺寸(像素)
21
  const CELL_WIDTH = 8;
22
  const CELL_HEIGHT = 16;
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  function App() {
25
  const { exit } = useApp();
26
  const [dimensions, setDimensions] = useState<{
27
- width: number; // 字符列数
28
- height: number; // 字符行数
29
- pixelWidth: number; // 像素宽度
30
- pixelHeight: number; // 像素高度
31
  } | null>(null);
32
  const [err, setErr] = useState(false);
33
 
34
  useEffect(() => {
35
  (async () => {
36
  try {
37
- const image = await Jimp.read(IMAGE_PATH);
38
  const origW = image.bitmap.width;
39
  const origH = image.bitmap.height;
40
  const cols = process.stdout.columns ?? 80;
41
 
42
- // 1. 目标字符尺寸
43
- const targetW_chars = Math.floor(cols * 0.4);
44
-
45
- // 2. 转为像素尺寸(用于图片缩放)
46
  const targetW_pixels = targetW_chars * CELL_WIDTH;
47
  const targetH_pixels = Math.floor(targetW_pixels * (origH / origW));
48
-
49
- // 3. 确保最小高度(至少 3 行字符)
50
  const minH_pixels = 3 * CELL_HEIGHT;
51
  const finalH_pixels = Math.max(targetH_pixels, minH_pixels);
52
-
53
- // 4. 转回字符行数(用于 Ink 占位)
54
  const targetH_chars = Math.ceil(finalH_pixels / CELL_HEIGHT);
55
 
56
  setDimensions({
@@ -59,23 +74,21 @@ function App() {
59
  pixelWidth: targetW_pixels,
60
  pixelHeight: finalH_pixels,
61
  });
62
- } catch {
 
63
  setErr(true);
64
  }
65
  })();
66
  }, []);
67
 
68
- // Ctrl+C 直接退出,不清理图片
69
  useEffect(() => {
70
- const handleSigint = () => {
71
- exit();
72
- };
73
- process.on('SIGINT', handleSigint);
74
- return () => process.off('SIGINT', handleSigint);
75
  }, [exit]);
76
 
77
  if (err) {
78
- return <Text color="red">Failed to load image</Text>;
79
  }
80
 
81
  if (!dimensions) {
@@ -87,11 +100,11 @@ function App() {
87
  <InkPictureProvider>
88
  <Image
89
  src={IMAGE_PATH}
90
- width={dimensions.width} // 字符列数(Ink 占位)
91
- height={dimensions.height} // 字符行数(Ink 占位)
92
- pixelWidth={dimensions.pixelWidth} // 像素宽度(图片缩放)
93
- pixelHeight={dimensions.pixelHeight} // 像素高度(图片缩放)
94
- alt="3god"
95
  />
96
  </InkPictureProvider>
97
  </Box>
 
1
  #!/usr/bin/env bun
2
  /**
3
+ * Visual test: display a local image or URL using ink-picture + Ink.
 
 
 
4
  *
5
  * Usage:
6
+ * bun run src/ink-picture/__tests__/LocalPicture.test.tsx [path|url]
7
+ *
8
+ * Examples:
9
+ * bun run src/ink-picture/__tests__/LocalPicture.test.tsx ~/Pictures/IMAGE/image.png
10
+ * bun run src/ink-picture/__tests__/LocalPicture.test.tsx https://example.com/image.jpg
11
  */
12
 
13
  import { Jimp } from "jimp";
 
15
  import { render, Box, Text, useApp } from "ink";
16
  import Image, { InkPictureProvider } from "../index.ts";
17
 
 
 
18
  // 终端字符尺寸(像素)
19
  const CELL_WIDTH = 8;
20
  const CELL_HEIGHT = 16;
21
 
22
+ // 获取命令行参数
23
+ const args = process.argv.slice(2);
24
+ const IMAGE_PATH = args[0] || "/home/yuki/Pictures/Wallpapers/3god.jpg";
25
+
26
+ // 判断是 URL 还是本地路径
27
+ const isUrl = IMAGE_PATH.startsWith("http://") || IMAGE_PATH.startsWith("https://");
28
+
29
+ // 加载图片(支持本地和 URL)
30
+ async function loadImage(path: string) {
31
+ if (isUrl) {
32
+ // URL:先下载,再用 Jimp 读取
33
+ const response = await fetch(path);
34
+ if (!response.ok) {
35
+ throw new Error(`Failed to fetch: ${response.status}`);
36
+ }
37
+ const arrayBuffer = await response.arrayBuffer();
38
+ const buffer = Buffer.from(arrayBuffer);
39
+ return Jimp.fromBuffer(buffer);
40
+ } else {
41
+ // 本地路径:直接用 Jimp.read
42
+ return Jimp.read(path);
43
+ }
44
+ }
45
+
46
  function App() {
47
  const { exit } = useApp();
48
  const [dimensions, setDimensions] = useState<{
49
+ width: number;
50
+ height: number;
51
+ pixelWidth: number;
52
+ pixelHeight: number;
53
  } | null>(null);
54
  const [err, setErr] = useState(false);
55
 
56
  useEffect(() => {
57
  (async () => {
58
  try {
59
+ const image = await loadImage(IMAGE_PATH);
60
  const origW = image.bitmap.width;
61
  const origH = image.bitmap.height;
62
  const cols = process.stdout.columns ?? 80;
63
 
64
+ const targetW_chars = Math.floor(cols * 0.1618);
 
 
 
65
  const targetW_pixels = targetW_chars * CELL_WIDTH;
66
  const targetH_pixels = Math.floor(targetW_pixels * (origH / origW));
 
 
67
  const minH_pixels = 3 * CELL_HEIGHT;
68
  const finalH_pixels = Math.max(targetH_pixels, minH_pixels);
 
 
69
  const targetH_chars = Math.ceil(finalH_pixels / CELL_HEIGHT);
70
 
71
  setDimensions({
 
74
  pixelWidth: targetW_pixels,
75
  pixelHeight: finalH_pixels,
76
  });
77
+ } catch (e) {
78
+ console.error("Error loading image:", e);
79
  setErr(true);
80
  }
81
  })();
82
  }, []);
83
 
 
84
  useEffect(() => {
85
+ const handleSigint = () => exit();
86
+ process.on("SIGINT", handleSigint);
87
+ return () => process.off("SIGINT", handleSigint);
 
 
88
  }, [exit]);
89
 
90
  if (err) {
91
+ return <Text color="red">Failed to load image: {IMAGE_PATH}</Text>;
92
  }
93
 
94
  if (!dimensions) {
 
100
  <InkPictureProvider>
101
  <Image
102
  src={IMAGE_PATH}
103
+ width={dimensions.width}
104
+ height={dimensions.height}
105
+ pixelWidth={dimensions.pixelWidth}
106
+ pixelHeight={dimensions.pixelHeight}
107
+ alt={isUrl ? "url-image" : "local-image"}
108
  />
109
  </InkPictureProvider>
110
  </Box>