mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 13:21:38 +03:00
imgcat: add resize and resample functionality
This is primarily to improve the chances of displaying an arbitrary image without resorting to additional external tools, that may be difficult or impossible to install. refs: #3716 refs: #3264
This commit is contained in:
parent
69e610041b
commit
e048410491
@ -1451,7 +1451,7 @@ _wezterm() {
|
||||
return 0
|
||||
;;
|
||||
wezterm__imgcat)
|
||||
opts="-h --width --height --no-preserve-aspect-ratio --position --no-move-cursor --hold --help [FILE_NAME]"
|
||||
opts="-h --width --height --no-preserve-aspect-ratio --position --no-move-cursor --hold --tmux-passthru --max-pixels --no-resample --resample-format --resample-filter --resize --show-resample-timing --help [FILE_NAME]"
|
||||
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||
return 0
|
||||
@ -1469,6 +1469,26 @@ _wezterm() {
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--tmux-passthru)
|
||||
COMPREPLY=($(compgen -W "disable enable detect" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--max-pixels)
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--resample-format)
|
||||
COMPREPLY=($(compgen -W "png jpeg input" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--resample-filter)
|
||||
COMPREPLY=($(compgen -W "nearest triangle catmull-rom gaussian lanczos3" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
--resize)
|
||||
COMPREPLY=($(compgen -f "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=()
|
||||
;;
|
||||
@ -1553,12 +1573,16 @@ _wezterm() {
|
||||
return 0
|
||||
;;
|
||||
wezterm__set__working__directory)
|
||||
opts="-h --help [CWD] [HOST]"
|
||||
opts="-h --tmux-passthru --help [CWD] [HOST]"
|
||||
if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
|
||||
return 0
|
||||
fi
|
||||
case "${prev}" in
|
||||
--tmux-passthru)
|
||||
COMPREPLY=($(compgen -W "disable enable detect" -- "${cur}"))
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
COMPREPLY=()
|
||||
;;
|
||||
|
@ -161,10 +161,18 @@ complete -c wezterm -n "__fish_seen_subcommand_from cli; and __fish_seen_subcomm
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l width -d 'Specify the display width; defaults to "auto" which automatically selects an appropriate size. You may also use an integer value `N` to specify the number of cells, or `Npx` to specify the number of pixels, or `N%` to size relative to the terminal width' -r
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l height -d 'Specify the display height; defaults to "auto" which automatically selects an appropriate size. You may also use an integer value `N` to specify the number of cells, or `Npx` to specify the number of pixels, or `N%` to size relative to the terminal height' -r
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l position -d 'Set the cursor position prior to displaying the image. The default is to use the current cursor position. Coordinates are expressed in cells with 0,0 being the top left cell position' -r
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l tmux-passthru -d 'How to manage passing the escape through to tmux' -r -f -a "{disable ,enable ,detect }"
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l max-pixels -d 'Set the maximum number of pixels per image frame. Images will be scaled down so that they do not exceed this size, unless `--no-resample` is also used. The default value matches the limit set by wezterm. Note that resampling the image here will reduce any animated images to a single frame' -r
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l resample-format -d 'Specify the image format to use to encode resampled/resized images. The default is to match the input format, but you can choose an alternative format' -r -f -a "{png ,jpeg ,input }"
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l resample-filter -d 'Specify the filtering technique used when resizing/resampling images. The default is a reasonable middle ground of speed and quality' -r -f -a "{nearest ,triangle ,catmull-rom ,gaussian ,lanczos3 }"
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l resize -d 'Pre-process the image to resize it to the specified dimensions, expressed as eg: 800x600 (width x height). The resize is independent of other parameters that control the image placement and dimensions in the terminal; this is provided as a convenience preprocessing step' -r
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l no-preserve-aspect-ratio -d 'Do not respect the aspect ratio. The default is to respect the aspect ratio'
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l no-move-cursor -d 'Do not move the cursor after displaying the image. Note that when used like this from the shell, there is a very high chance that shell prompt will overwrite the image; you may wish to also use `--hold` in that case'
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l hold -d 'Wait for enter to be pressed after displaying the image'
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -s h -l help -d 'Print help'
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l no-resample -d 'Do not resample images whose frames are larger than the max-pixels value. Note that this will typically result in the image refusing to display in wezterm'
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -l show-resample-timing -d 'When resampling or resizing, display some diagnostics around the timing/performance of that operation'
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from imgcat" -s h -l help -d 'Print help (see more with \'--help\')'
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from set-working-directory" -l tmux-passthru -d 'How to manage passing the escape through to tmux' -r -f -a "{disable ,enable ,detect }"
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from set-working-directory" -s h -l help -d 'Print help'
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from record" -s h -l help -d 'Print help'
|
||||
complete -c wezterm -n "__fish_seen_subcommand_from replay" -l explain -d 'Explain what is being sent/received'
|
||||
|
@ -382,16 +382,24 @@ _arguments "${_arguments_options[@]}" \
|
||||
'--width=[Specify the display width; defaults to "auto" which automatically selects an appropriate size. You may also use an integer value \`N\` to specify the number of cells, or \`Npx\` to specify the number of pixels, or \`N%\` to size relative to the terminal width]:WIDTH: ' \
|
||||
'--height=[Specify the display height; defaults to "auto" which automatically selects an appropriate size. You may also use an integer value \`N\` to specify the number of cells, or \`Npx\` to specify the number of pixels, or \`N%\` to size relative to the terminal height]:HEIGHT: ' \
|
||||
'--position=[Set the cursor position prior to displaying the image. The default is to use the current cursor position. Coordinates are expressed in cells with 0,0 being the top left cell position]:POSITION: ' \
|
||||
'--tmux-passthru=[How to manage passing the escape through to tmux]:TMUX_PASSTHRU:(disable enable detect)' \
|
||||
'--max-pixels=[Set the maximum number of pixels per image frame. Images will be scaled down so that they do not exceed this size, unless \`--no-resample\` is also used. The default value matches the limit set by wezterm. Note that resampling the image here will reduce any animated images to a single frame]:MAX_PIXELS: ' \
|
||||
'--resample-format=[Specify the image format to use to encode resampled/resized images. The default is to match the input format, but you can choose an alternative format]:RESAMPLE_FORMAT:(png jpeg input)' \
|
||||
'--resample-filter=[Specify the filtering technique used when resizing/resampling images. The default is a reasonable middle ground of speed and quality]:RESAMPLE_FILTER:(nearest triangle catmull-rom gaussian lanczos3)' \
|
||||
'--resize=[Pre-process the image to resize it to the specified dimensions, expressed as eg\: 800x600 (width x height). The resize is independent of other parameters that control the image placement and dimensions in the terminal; this is provided as a convenience preprocessing step]:WIDTHxHEIGHT: ' \
|
||||
'--no-preserve-aspect-ratio[Do not respect the aspect ratio. The default is to respect the aspect ratio]' \
|
||||
'--no-move-cursor[Do not move the cursor after displaying the image. Note that when used like this from the shell, there is a very high chance that shell prompt will overwrite the image; you may wish to also use \`--hold\` in that case]' \
|
||||
'--hold[Wait for enter to be pressed after displaying the image]' \
|
||||
'-h[Print help]' \
|
||||
'--help[Print help]' \
|
||||
'--no-resample[Do not resample images whose frames are larger than the max-pixels value. Note that this will typically result in the image refusing to display in wezterm]' \
|
||||
'--show-resample-timing[When resampling or resizing, display some diagnostics around the timing/performance of that operation]' \
|
||||
'-h[Print help (see more with '\''--help'\'')]' \
|
||||
'--help[Print help (see more with '\''--help'\'')]' \
|
||||
'::file_name -- The name of the image file to be displayed. If omitted, will attempt to read it from stdin:_files' \
|
||||
&& ret=0
|
||||
;;
|
||||
(set-working-directory)
|
||||
_arguments "${_arguments_options[@]}" \
|
||||
'--tmux-passthru=[How to manage passing the escape through to tmux]:TMUX_PASSTHRU:(disable enable detect)' \
|
||||
'-h[Print help]' \
|
||||
'--help[Print help]' \
|
||||
'::cwd -- The directory to specify. If omitted, will use the current directory of the process itself:_files -/' \
|
||||
|
@ -16,11 +16,20 @@ for mode in copy_mode search_mode ; do
|
||||
echo "\`\`\`" >> $fname
|
||||
done
|
||||
|
||||
cargo run --example narrow $PWD/target/debug/wezterm --help | ./target/debug/strip-ansi-escapes > docs/examples/cmd-synopsis-wezterm--help.txt
|
||||
# For whatever reason, running --help on macOS vs. Linux results in different
|
||||
# opinions on leading/trailing whitespace. In order to minimize diffs and
|
||||
# be more consistent, explicitly trim leading/trailing space from the
|
||||
# output stream.
|
||||
# <https://unix.stackexchange.com/a/552191/123914>
|
||||
trim_file() {
|
||||
perl -0777 -pe 's/^\n+|\n\K\n+$//g'
|
||||
}
|
||||
|
||||
cargo run --example narrow $PWD/target/debug/wezterm --help | ./target/debug/strip-ansi-escapes | trim_file > docs/examples/cmd-synopsis-wezterm--help.txt
|
||||
|
||||
for cmd in start ssh serial connect ls-fonts show-keys imgcat set-working-directory record replay ; do
|
||||
fname="docs/examples/cmd-synopsis-wezterm-${cmd}--help.txt"
|
||||
cargo run --example narrow $PWD/target/debug/wezterm $cmd --help | ./target/debug/strip-ansi-escapes > $fname
|
||||
cargo run --example narrow $PWD/target/debug/wezterm $cmd --help | ./target/debug/strip-ansi-escapes | trim_file > $fname
|
||||
done
|
||||
|
||||
for cmd in \
|
||||
@ -42,5 +51,5 @@ for cmd in \
|
||||
split-pane \
|
||||
; do
|
||||
fname="docs/examples/cmd-synopsis-wezterm-cli-${cmd}--help.txt"
|
||||
cargo run --example narrow $PWD/target/debug/wezterm cli $cmd --help | ./target/debug/strip-ansi-escapes > $fname
|
||||
cargo run --example narrow $PWD/target/debug/wezterm cli $cmd --help | ./target/debug/strip-ansi-escapes | trim_file > $fname
|
||||
done
|
||||
|
@ -41,6 +41,11 @@ As features stabilize some brief notes about them will accumulate here.
|
||||
in order to avoid the shell/prompt from mangling the image after it is printing.
|
||||
Support for this has limitations and will not take effect when the new
|
||||
`--position` argument is used. #3624
|
||||
* [wezterm imgcat](cli/imgcat.md) will now resample very large images in
|
||||
order to increase the chances of successfully displaying an arbitrary image.
|
||||
In addition, there are now a number of options for explicitly resizing
|
||||
as a preprocessing step, and controlling the filtering and format used
|
||||
by the resizing, along with showing diagnostics around the resize operation. #3264
|
||||
* Color schemes: [Ef-Cyprus](colorschemes/e/index.md#ef-cyprus),
|
||||
[Ef-Day](colorschemes/e/index.md#ef-day),
|
||||
[Ef-Deuteranopia-Dark](colorschemes/e/index.md#ef-deuteranopia-dark),
|
||||
|
@ -3,8 +3,9 @@ Output an image to the terminal
|
||||
Usage: wezterm imgcat [OPTIONS] [FILE_NAME]
|
||||
|
||||
Arguments:
|
||||
[FILE_NAME] The name of the image file to be displayed. If omitted, will
|
||||
attempt to read it from stdin
|
||||
[FILE_NAME]
|
||||
The name of the image file to be displayed. If omitted, will attempt
|
||||
to read it from stdin
|
||||
|
||||
Options:
|
||||
--width <WIDTH>
|
||||
@ -12,24 +13,84 @@ Options:
|
||||
selects an appropriate size. You may also use an integer value `N` to
|
||||
specify the number of cells, or `Npx` to specify the number of pixels,
|
||||
or `N%` to size relative to the terminal width
|
||||
|
||||
--height <HEIGHT>
|
||||
Specify the display height; defaults to "auto" which automatically
|
||||
selects an appropriate size. You may also use an integer value `N` to
|
||||
specify the number of cells, or `Npx` to specify the number of pixels,
|
||||
or `N%` to size relative to the terminal height
|
||||
|
||||
--no-preserve-aspect-ratio
|
||||
Do not respect the aspect ratio. The default is to respect the aspect
|
||||
ratio
|
||||
|
||||
--position <POSITION>
|
||||
Set the cursor position prior to displaying the image. The default is
|
||||
to use the current cursor position. Coordinates are expressed in cells
|
||||
with 0,0 being the top left cell position
|
||||
|
||||
--no-move-cursor
|
||||
Do not move the cursor after displaying the image. Note that when used
|
||||
like this from the shell, there is a very high chance that shell
|
||||
prompt will overwrite the image; you may wish to also use `--hold` in
|
||||
that case
|
||||
|
||||
--hold
|
||||
Wait for enter to be pressed after displaying the image
|
||||
|
||||
--tmux-passthru <TMUX_PASSTHRU>
|
||||
How to manage passing the escape through to tmux
|
||||
|
||||
[possible values: disable, enable, detect]
|
||||
|
||||
--max-pixels <MAX_PIXELS>
|
||||
Set the maximum number of pixels per image frame. Images will be
|
||||
scaled down so that they do not exceed this size, unless
|
||||
`--no-resample` is also used. The default value matches the limit set
|
||||
by wezterm. Note that resampling the image here will reduce any
|
||||
animated images to a single frame
|
||||
|
||||
[default: 25000000]
|
||||
|
||||
--no-resample
|
||||
Do not resample images whose frames are larger than the max-pixels
|
||||
value. Note that this will typically result in the image refusing to
|
||||
display in wezterm
|
||||
|
||||
--resample-format <RESAMPLE_FORMAT>
|
||||
Specify the image format to use to encode resampled/resized images.
|
||||
The default is to match the input format, but you can choose an
|
||||
alternative format
|
||||
|
||||
[default: input]
|
||||
[possible values: png, jpeg, input]
|
||||
|
||||
--resample-filter <RESAMPLE_FILTER>
|
||||
Specify the filtering technique used when resizing/resampling images.
|
||||
The default is a reasonable middle ground of speed and quality.
|
||||
|
||||
See
|
||||
<https://docs.rs/image/latest/image/imageops/enum.FilterType.html#examples>
|
||||
for examples of the different techniques and their tradeoffs.
|
||||
|
||||
[default: catmull-rom]
|
||||
[possible values: nearest, triangle, catmull-rom, gaussian, lanczos3]
|
||||
|
||||
--resize <WIDTHxHEIGHT>
|
||||
Pre-process the image to resize it to the specified dimensions,
|
||||
expressed as eg: 800x600 (width x height). The resize is independent
|
||||
of other parameters that control the image placement and dimensions in
|
||||
the terminal; this is provided as a convenience preprocessing step.
|
||||
|
||||
Resizing animated images will reduce the image to a single frame.
|
||||
|
||||
The `--resample-filter` and `--resample-format` options give some
|
||||
control over the quality of the resizing operation and the image
|
||||
format used.
|
||||
|
||||
--show-resample-timing
|
||||
When resampling or resizing, display some diagnostics around the
|
||||
timing/performance of that operation
|
||||
|
||||
-h, --help
|
||||
Print help
|
||||
Print help (see a summary with '-h')
|
||||
|
@ -1,7 +1,7 @@
|
||||
Advise the terminal of the current working directory by emitting an OSC 7 escape
|
||||
sequence
|
||||
|
||||
Usage: wezterm set-working-directory [CWD] [HOST]
|
||||
Usage: wezterm set-working-directory [OPTIONS] [CWD] [HOST]
|
||||
|
||||
Arguments:
|
||||
[CWD] The directory to specify. If omitted, will use the current directory
|
||||
@ -10,4 +10,8 @@ Arguments:
|
||||
system hostname will be used
|
||||
|
||||
Options:
|
||||
-h, --help Print help
|
||||
--tmux-passthru <TMUX_PASSTHRU>
|
||||
How to manage passing the escape through to tmux [possible values:
|
||||
disable, enable, detect]
|
||||
-h, --help
|
||||
Print help
|
||||
|
@ -183,6 +183,56 @@ struct ImgCatCommand {
|
||||
#[arg(long, value_parser)]
|
||||
tmux_passthru: Option<TmuxPassthru>,
|
||||
|
||||
/// Set the maximum number of pixels per image frame.
|
||||
/// Images will be scaled down so that they do not exceed this size,
|
||||
/// unless `--no-resample` is also used.
|
||||
/// The default value matches the limit set by wezterm.
|
||||
/// Note that resampling the image here will reduce any animated
|
||||
/// images to a single frame.
|
||||
#[arg(long, default_value = "25000000")]
|
||||
max_pixels: usize,
|
||||
|
||||
/// Do not resample images whose frames are larger than the
|
||||
/// max-pixels value.
|
||||
/// Note that this will typically result in the image refusing
|
||||
/// to display in wezterm.
|
||||
#[arg(long)]
|
||||
no_resample: bool,
|
||||
|
||||
/// Specify the image format to use to encode resampled/resized
|
||||
/// images. The default is to match the input format, but you
|
||||
/// can choose an alternative format.
|
||||
#[arg(long, default_value = "input")]
|
||||
resample_format: ResampleImageFormat,
|
||||
|
||||
/// Specify the filtering technique used when resizing/resampling
|
||||
/// images. The default is a reasonable middle ground of speed
|
||||
/// and quality.
|
||||
///
|
||||
/// See <https://docs.rs/image/latest/image/imageops/enum.FilterType.html#examples>
|
||||
/// for examples of the different techniques and their tradeoffs.
|
||||
#[arg(long, default_value = "catmull-rom")]
|
||||
resample_filter: ResampleFilter,
|
||||
|
||||
/// Pre-process the image to resize it to the specified dimensions,
|
||||
/// expressed as eg: 800x600 (width x height).
|
||||
/// The resize is independent of other parameters that control
|
||||
/// the image placement and dimensions in the terminal; this is provided
|
||||
/// as a convenience preprocessing step.
|
||||
///
|
||||
/// Resizing animated images will reduce the image to a single frame.
|
||||
///
|
||||
/// The `--resample-filter` and `--resample-format` options give
|
||||
/// some control over the quality of the resizing operation and
|
||||
/// the image format used.
|
||||
#[arg(long, name="WIDTHxHEIGHT", value_parser=ValueParser::new(width_x_height))]
|
||||
resize: Option<ImageDimension>,
|
||||
|
||||
/// When resampling or resizing, display some diagnostics
|
||||
/// around the timing/performance of that operation.
|
||||
#[arg(long)]
|
||||
show_resample_timing: bool,
|
||||
|
||||
/// The name of the image file to be displayed.
|
||||
/// If omitted, will attempt to read it from stdin.
|
||||
#[arg(value_parser, value_hint=ValueHint::FilePath)]
|
||||
@ -206,15 +256,54 @@ fn x_comma_y(arg: &str) -> Result<ImagePosition, String> {
|
||||
})?;
|
||||
Ok(ImagePosition { x, y })
|
||||
} else {
|
||||
Err(format!("Expected name=value, but got {}", arg))
|
||||
Err(format!("Expected x,y, but got {}", arg))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct ImageDimension {
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
fn width_x_height(arg: &str) -> Result<ImageDimension, String> {
|
||||
if let Some(eq) = arg.find('x') {
|
||||
let (left, right) = arg.split_at(eq);
|
||||
let width = left.parse().map_err(|err| {
|
||||
format!("Expected WxH to be integer values, got {arg}. '{left}': {err:#}")
|
||||
})?;
|
||||
let height = right[1..].parse().map_err(|err| {
|
||||
format!("Expected WxH to be integer values, got {arg}. '{right}': {err:#}")
|
||||
})?;
|
||||
Ok(ImageDimension { width, height })
|
||||
} else {
|
||||
Err(format!("Expected WxH, but got {}", arg))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, ValueEnum, Default)]
|
||||
enum ResampleFilter {
|
||||
Nearest,
|
||||
Triangle,
|
||||
#[default]
|
||||
CatmullRom,
|
||||
Gaussian,
|
||||
Lanczos3,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, ValueEnum, Default)]
|
||||
enum ResampleImageFormat {
|
||||
Png,
|
||||
Jpeg,
|
||||
#[default]
|
||||
Input,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) struct ImageInfo {
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub _format: image::ImageFormat,
|
||||
pub format: image::ImageFormat,
|
||||
}
|
||||
|
||||
impl ImgCatCommand {
|
||||
@ -292,16 +381,78 @@ impl ImgCatCommand {
|
||||
let reader = image::io::Reader::new(std::io::Cursor::new(data)).with_guessed_format()?;
|
||||
let format = reader
|
||||
.format()
|
||||
.ok_or_else(|| anyhow::anyhow!("unknown format!?"))?;
|
||||
.ok_or_else(|| anyhow::anyhow!("unknown image format!?"))?;
|
||||
let (width, height) = reader.into_dimensions()?;
|
||||
Ok(ImageInfo {
|
||||
width,
|
||||
height,
|
||||
_format: format,
|
||||
format,
|
||||
})
|
||||
}
|
||||
|
||||
fn run(&self) -> anyhow::Result<()> {
|
||||
fn resize_image(
|
||||
&self,
|
||||
data: &[u8],
|
||||
target_width: u32,
|
||||
target_height: u32,
|
||||
image_info: ImageInfo,
|
||||
) -> anyhow::Result<(Vec<u8>, ImageInfo)> {
|
||||
let start = std::time::Instant::now();
|
||||
let im = image::load_from_memory(data).with_context(|| match self.file_name.as_ref() {
|
||||
Some(file_name) => format!("loading image from file {file_name:?}"),
|
||||
None => format!("loading image from stdin"),
|
||||
})?;
|
||||
if self.show_resample_timing {
|
||||
eprintln!(
|
||||
"loading image took {:?} for {} stored bytes -> {image_info:?}",
|
||||
start.elapsed(),
|
||||
data.len()
|
||||
);
|
||||
}
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
use image::imageops::FilterType;
|
||||
let filter = match self.resample_filter {
|
||||
ResampleFilter::Nearest => FilterType::Nearest,
|
||||
ResampleFilter::Triangle => FilterType::Triangle,
|
||||
ResampleFilter::CatmullRom => FilterType::CatmullRom,
|
||||
ResampleFilter::Gaussian => FilterType::Gaussian,
|
||||
ResampleFilter::Lanczos3 => FilterType::Lanczos3,
|
||||
};
|
||||
let im = im.resize_to_fill(target_width, target_height, filter);
|
||||
if self.show_resample_timing {
|
||||
eprintln!("resizing took {:?}", start.elapsed());
|
||||
}
|
||||
|
||||
let mut data = vec![];
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
let output_format = match self.resample_format {
|
||||
ResampleImageFormat::Png => image::ImageFormat::Png,
|
||||
ResampleImageFormat::Jpeg => image::ImageFormat::Jpeg,
|
||||
ResampleImageFormat::Input => image_info.format,
|
||||
};
|
||||
im.write_to(&mut std::io::Cursor::new(&mut data), output_format)
|
||||
.with_context(|| format!("encoding resampled image as {output_format:?}"))?;
|
||||
|
||||
let new_info = ImageInfo {
|
||||
width: target_width,
|
||||
height: target_height,
|
||||
format: output_format,
|
||||
};
|
||||
|
||||
if self.show_resample_timing {
|
||||
eprintln!(
|
||||
"encoding took {:?} to produce {} stored bytes -> {new_info:?}",
|
||||
start.elapsed(),
|
||||
data.len()
|
||||
);
|
||||
}
|
||||
|
||||
Ok((data, new_info))
|
||||
}
|
||||
|
||||
fn get_image_data(&self) -> anyhow::Result<(Vec<u8>, ImageInfo)> {
|
||||
let mut data = Vec::new();
|
||||
if let Some(file_name) = self.file_name.as_ref() {
|
||||
let mut f = std::fs::File::open(file_name)
|
||||
@ -312,6 +463,34 @@ impl ImgCatCommand {
|
||||
stdin.read_to_end(&mut data)?;
|
||||
}
|
||||
|
||||
let image_info = Self::image_dimensions(&data)?;
|
||||
|
||||
let (data, image_info) = if let Some(dimension) = self.resize {
|
||||
self.resize_image(&data, dimension.width, dimension.height, image_info)?
|
||||
} else {
|
||||
(data, image_info)
|
||||
};
|
||||
|
||||
let total_pixels = image_info.width.saturating_mul(image_info.height) as usize;
|
||||
|
||||
if !self.no_resample && total_pixels > self.max_pixels {
|
||||
let max_area = self.max_pixels as f32;
|
||||
let area = total_pixels as f32;
|
||||
|
||||
let scale = area / max_area;
|
||||
|
||||
let target_width = (image_info.width as f32 / scale).floor() as u32;
|
||||
let target_height = (image_info.height as f32 / scale).floor() as u32;
|
||||
|
||||
self.resize_image(&data, target_width, target_height, image_info)
|
||||
} else {
|
||||
Ok((data, image_info))
|
||||
}
|
||||
}
|
||||
|
||||
fn run(&self) -> anyhow::Result<()> {
|
||||
let (data, image_info) = self.get_image_data()?;
|
||||
|
||||
let caps = Capabilities::new_from_env()?;
|
||||
let mut term = termwiz::terminal::new_terminal(caps)?;
|
||||
term.set_raw_mode()?;
|
||||
@ -357,13 +536,12 @@ impl ImgCatCommand {
|
||||
|
||||
let (begin, end) = self.tmux_passthru.unwrap_or_default().get();
|
||||
|
||||
let image_dims = Self::image_dimensions(&data)
|
||||
.map(|info| self.compute_image_cell_dimensions(info, term_size));
|
||||
let image_dims = self.compute_image_cell_dimensions(image_info, term_size);
|
||||
|
||||
if let (Ok((_cursor_x, cursor_y)), true) = (&image_dims, needs_force_cursor_move) {
|
||||
if let ((_cursor_x, cursor_y), true) = (image_dims, needs_force_cursor_move) {
|
||||
// Before we emit the image, we need to emit some new lines so that
|
||||
// if the image would scroll the display, things end up in the right place
|
||||
let new_lines = "\n".repeat(*cursor_y);
|
||||
let new_lines = "\n".repeat(cursor_y);
|
||||
print!("{new_lines}");
|
||||
|
||||
// and move back up again.
|
||||
@ -371,7 +549,7 @@ impl ImgCatCommand {
|
||||
// column as a result of doing this.
|
||||
term.render(&[Change::CursorPosition {
|
||||
x: Position::Absolute(0),
|
||||
y: Position::Relative(-1 * (*cursor_y as isize)),
|
||||
y: Position::Relative(-1 * (cursor_y as isize)),
|
||||
}])?;
|
||||
}
|
||||
|
||||
@ -389,12 +567,12 @@ impl ImgCatCommand {
|
||||
)));
|
||||
println!("{begin}{osc}{end}");
|
||||
|
||||
if let (Ok((_cursor_x, cursor_y)), true) = (&image_dims, needs_force_cursor_move) {
|
||||
if let ((_cursor_x, cursor_y), true) = (image_dims, needs_force_cursor_move) {
|
||||
// tell the terminal that doesn't fully understand the image sequence
|
||||
// to move the cursor to where it should end up
|
||||
term.render(&[Change::CursorPosition {
|
||||
x: Position::Absolute(0),
|
||||
y: Position::Relative(*cursor_y as isize),
|
||||
y: Position::Relative(cursor_y as isize),
|
||||
}])?;
|
||||
} else if self.position.is_some() {
|
||||
print!("{restore_cursor}");
|
||||
|
Loading…
Reference in New Issue
Block a user