File size: 2,996 Bytes
f73174f
 
6485104
412f992
f73174f
6485104
 
 
 
 
f73174f
 
412f992
6d1207a
412f992
 
3e3eb0a
f73174f
ab32188
 
 
 
6485104
 
 
 
 
 
 
 
 
 
3e3eb0a
6485104
 
 
 
 
f73174f
412f992
 
6485104
 
 
 
412f992
 
 
 
 
 
6485104
412f992
 
 
ab32188
6485104
ab32188
 
 
 
 
 
 
 
 
 
 
 
6485104
9ec41c1
412f992
9ec41c1
412f992
 
 
f73174f
 
6485104
 
412f992
 
 
9ec41c1
412f992
 
 
 
 
f73174f
 
 
 
412f992
 
6485104
 
 
 
 
412f992
f73174f
 
412f992
f73174f
 
412f992
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#!/usr/bin/env bun
/**
 * Visual test: display a local image or URL using ink-picture + Ink.
 *
 * Usage:
 *   bun run src/ink-picture/__tests__/LocalPicture.test.tsx [path|url]
 *
 * Examples:
 *   bun run src/ink-picture/__tests__/LocalPicture.test.tsx ~/Pictures/IMAGE/image.png
 *   bun run src/ink-picture/__tests__/LocalPicture.test.tsx https://example.com/image.jpg
 */

import { Jimp } from "jimp";
import { useEffect, useState } from "react";
import { render, Box, Text, useApp } from "ink";
import Image, { InkPictureProvider } from "../index.ts";
import { loadImageFromUrl } from "../utils/jimpURL.ts";

// 终端字符尺寸(像素)
const CELL_WIDTH = 8;
const CELL_HEIGHT = 16;

// 获取命令行参数
const args = process.argv.slice(2);
const IMAGE_PATH = args[0] || "/home/yuki/Pictures/Wallpapers/3god.jpg";

// 判断是 URL 还是本地路径
const isUrl = IMAGE_PATH.startsWith("http://") || IMAGE_PATH.startsWith("https://");

// 加载图片(支持本地和 URL)
async function loadImage(path: string) {
  if (isUrl) {
    return loadImageFromUrl(path);
  } else {
    return Jimp.read(path);
  }
}

function App() {
  const { exit } = useApp();
  const [dimensions, setDimensions] = useState<{
    width: number;
    height: number;
    pixelWidth: number;
    pixelHeight: number;
  } | null>(null);
  const [err, setErr] = useState(false);

  useEffect(() => {
    (async () => {
      try {
        const image = await loadImage(IMAGE_PATH);
        const origW = image.bitmap.width;
        const origH = image.bitmap.height;
        const cols = process.stdout.columns ?? 80;

        const targetW_chars = Math.floor(cols * 0.1618);
        const targetW_pixels = targetW_chars * CELL_WIDTH;
        const targetH_pixels = Math.floor(targetW_pixels * (origH / origW));
        const minH_pixels = 3 * CELL_HEIGHT;
        const finalH_pixels = Math.max(targetH_pixels, minH_pixels);
        const targetH_chars = Math.ceil(finalH_pixels / CELL_HEIGHT);

        setDimensions({
          width: targetW_chars,
          height: targetH_chars,
          pixelWidth: targetW_pixels,
          pixelHeight: finalH_pixels,
        });
      } catch (e) {
        console.error(e);
        setErr(true);
        exit();
      }
    })();
  }, []);

  useEffect(() => {
    const handleSigint = () => exit();
    process.on("SIGINT", handleSigint);
  }, [exit]);

  if (err) {
    return <Text color="red">Failed to fetch: {IMAGE_PATH}</Text>;
  }

  if (!dimensions) {
    return <Text>Loading...</Text>;
  }

  return (
    <Box flexDirection="column">
      <InkPictureProvider>
        <Image
          src={IMAGE_PATH}
          width={dimensions.width}
          height={dimensions.height}
          pixelWidth={dimensions.pixelWidth}
          pixelHeight={dimensions.pixelHeight}
          alt={isUrl ? "url-image" : "local-image"}
        />
      </InkPictureProvider>
    </Box>
  );
}

const { waitUntilExit } = render(<App />);
await waitUntilExit();