import { Box, useIsScreenReaderEnabled, useStdout } from "src/ink"; import React, { useMemo } from "react"; import { useMeasuredSize } from "../../hooks/useMeasuredSize.js"; import usePosition from "../../hooks/usePosition.js"; import useProtocol from "../../hooks/useProtocol.js"; import type { GetVisibility, Visibility } from "../../hooks/useVisibility.js"; import { useVisibility } from "../../hooks/useVisibility.js"; import { useTerminalInfo } from "../../InkPictureProvider.js"; import AsciiImage from "./Ascii.js"; import BrailleImage from "./Braille.js"; import HalfBlockImage from "./HalfBlock.js"; import ITerm2Image from "./ITerm2.js"; import KittyImage from "./Kitty.js"; import type { ImageProps } from "./protocol.js"; import SixelImage from "./Sixel.js"; const imageProtocols = { ascii: AsciiImage, braille: BrailleImage, halfBlock: HalfBlockImage, iterm2: ITerm2Image, kitty: KittyImage, sixel: SixelImage, }; export type ImageProtocolName = keyof typeof imageProtocols; export type ImageProtocolHint = Partial>; const ImageRenderer = (props: ImageProps & { protocol: ImageProtocolName }) => { const ProtocolComponent = imageProtocols[props.protocol]; return ; }; type ImageComponentProps = Omit & { width?: number | string; height?: number | string; protocol?: ImageProtocolName | ImageProtocolHint; getVisibility?: GetVisibility; }; function Image({ protocol: specifiedProtocol, getVisibility, width = "100%", height = "100%", pixelWidth, pixelHeight, ...props }: ImageComponentProps) { const isScreenReaderEnabled = useIsScreenReaderEnabled(); const terminalInfo = useTerminalInfo(); const { stdout } = useStdout(); const protocol = useProtocol( typeof specifiedProtocol === "string" ? specifiedProtocol : undefined, ); const { containerRef, resolvedWidth, resolvedHeight } = useMeasuredSize( width, height, ); const position = usePosition(containerRef); const visibility = useVisibility( position, stdout.rows, stdout.columns, getVisibility, ); const effectiveProtocol = useMemo((): ImageProtocolName => { if (typeof specifiedProtocol === "string") return specifiedProtocol; const hints: ImageProtocolHint = specifiedProtocol ?? {}; const hint = hints[visibility]; if (hint) return hint; if (visibility === "full") return protocol; if ( protocol === "ascii" || protocol === "braille" || protocol === "halfBlock" ) return protocol; if (terminalInfo.supportsUnicode && terminalInfo.supportsColor) return "halfBlock"; if (terminalInfo.supportsUnicode) return "braille"; return "ascii"; }, [ visibility, protocol, specifiedProtocol, terminalInfo.supportsUnicode, terminalInfo.supportsColor, ]); if (isScreenReaderEnabled) { const { src, alt } = props; const label = `image: ${alt || (typeof src === "string" ? src : "binary image data")}`; return ( ); } return ( ); } export default Image;