feat: pass pixelWidth/pixelHeight from Image props to Kitty renderer
Browse filesPreviously the test computed accurate pixel dimensions from the original
image's aspect ratio, but the prop chain never forwarded them through
ImageComponentProps -> ImageRenderer -> KittyImage -> useImage, so
KittyImage always computed pixels from resolved chars × cell size (losing
aspect ratio information). Now the full chain forwards pixelWidth/
pixelHeight as overrides, letting the test control exact pixel scaling
while width/height still drive Ink layout and Kitty placement bounds.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
src/ink-picture/__tests__/LocalPicture.test.tsx
CHANGED
|
@@ -40,7 +40,7 @@ function App() {
|
|
| 40 |
const cols = process.stdout.columns ?? 80;
|
| 41 |
|
| 42 |
// 1. 目标字符尺寸
|
| 43 |
-
const targetW_chars = Math.floor(cols * 0.
|
| 44 |
|
| 45 |
// 2. 转为像素尺寸(用于图片缩放)
|
| 46 |
const targetW_pixels = targetW_chars * CELL_WIDTH;
|
|
|
|
| 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;
|
src/ink-picture/components/image/Kitty.tsx
CHANGED
|
@@ -18,7 +18,7 @@ import type { ImageProps } from "./protocol.js";
|
|
| 18 |
function KittyImage(props: ImageProps) {
|
| 19 |
const terminalInfo = useTerminalInfo();
|
| 20 |
const { stdout } = useStdout();
|
| 21 |
-
const { src, width, height, alt } = props;
|
| 22 |
|
| 23 |
const { containerRef, resolvedWidth, resolvedHeight } = useMeasuredSize(
|
| 24 |
width,
|
|
@@ -27,13 +27,14 @@ function KittyImage(props: ImageProps) {
|
|
| 27 |
|
| 28 |
const componentPosition = usePosition(containerRef);
|
| 29 |
|
| 30 |
-
|
| 31 |
-
const
|
|
|
|
| 32 |
|
| 33 |
const { imageData, error } = useImage({
|
| 34 |
src,
|
| 35 |
-
pixelWidth,
|
| 36 |
-
pixelHeight,
|
| 37 |
mode: "png",
|
| 38 |
});
|
| 39 |
|
|
@@ -118,6 +119,7 @@ function KittyImage(props: ImageProps) {
|
|
| 118 |
ref={containerRef}
|
| 119 |
width={width}
|
| 120 |
height={height}
|
|
|
|
| 121 |
alt={alt}
|
| 122 |
error={error}
|
| 123 |
loaded={!!imageId}
|
|
|
|
| 18 |
function KittyImage(props: ImageProps) {
|
| 19 |
const terminalInfo = useTerminalInfo();
|
| 20 |
const { stdout } = useStdout();
|
| 21 |
+
const { src, width, height, pixelWidth, pixelHeight, alt } = props;
|
| 22 |
|
| 23 |
const { containerRef, resolvedWidth, resolvedHeight } = useMeasuredSize(
|
| 24 |
width,
|
|
|
|
| 27 |
|
| 28 |
const componentPosition = usePosition(containerRef);
|
| 29 |
|
| 30 |
+
// Use external pixel dimensions if provided, otherwise compute from chars
|
| 31 |
+
const actualPixelWidth = pixelWidth ?? resolvedWidth * (terminalInfo?.cellWidth ?? 0);
|
| 32 |
+
const actualPixelHeight = pixelHeight ?? resolvedHeight * (terminalInfo?.cellHeight ?? 0);
|
| 33 |
|
| 34 |
const { imageData, error } = useImage({
|
| 35 |
src,
|
| 36 |
+
pixelWidth: actualPixelWidth,
|
| 37 |
+
pixelHeight: actualPixelHeight,
|
| 38 |
mode: "png",
|
| 39 |
});
|
| 40 |
|
|
|
|
| 119 |
ref={containerRef}
|
| 120 |
width={width}
|
| 121 |
height={height}
|
| 122 |
+
imageHeight={actualPixelHeight}
|
| 123 |
alt={alt}
|
| 124 |
error={error}
|
| 125 |
loaded={!!imageId}
|
src/ink-picture/components/image/index.tsx
CHANGED
|
@@ -44,6 +44,8 @@ function Image({
|
|
| 44 |
getVisibility,
|
| 45 |
width = "100%",
|
| 46 |
height = "100%",
|
|
|
|
|
|
|
| 47 |
...props
|
| 48 |
}: ImageComponentProps) {
|
| 49 |
const isScreenReaderEnabled = useIsScreenReaderEnabled();
|
|
@@ -121,6 +123,8 @@ function Image({
|
|
| 121 |
key={effectiveProtocol}
|
| 122 |
width={resolvedWidth}
|
| 123 |
height={resolvedHeight}
|
|
|
|
|
|
|
| 124 |
{...props}
|
| 125 |
/>
|
| 126 |
</Box>
|
|
|
|
| 44 |
getVisibility,
|
| 45 |
width = "100%",
|
| 46 |
height = "100%",
|
| 47 |
+
pixelWidth,
|
| 48 |
+
pixelHeight,
|
| 49 |
...props
|
| 50 |
}: ImageComponentProps) {
|
| 51 |
const isScreenReaderEnabled = useIsScreenReaderEnabled();
|
|
|
|
| 123 |
key={effectiveProtocol}
|
| 124 |
width={resolvedWidth}
|
| 125 |
height={resolvedHeight}
|
| 126 |
+
pixelWidth={pixelWidth}
|
| 127 |
+
pixelHeight={pixelHeight}
|
| 128 |
{...props}
|
| 129 |
/>
|
| 130 |
</Box>
|
src/ink-picture/components/image/protocol.ts
CHANGED
|
@@ -13,6 +13,10 @@ export interface ImageProps {
|
|
| 13 |
height: number | string;
|
| 14 |
/** Alternative text displayed while loading or on error */
|
| 15 |
alt?: string;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
}
|
| 17 |
|
| 18 |
/**
|
|
|
|
| 13 |
height: number | string;
|
| 14 |
/** Alternative text displayed while loading or on error */
|
| 15 |
alt?: string;
|
| 16 |
+
/** Override pixel width for image scaling (default: resolved from width) */
|
| 17 |
+
pixelWidth?: number;
|
| 18 |
+
/** Override pixel height for image scaling (default: resolved from height) */
|
| 19 |
+
pixelHeight?: number;
|
| 20 |
}
|
| 21 |
|
| 22 |
/**
|