Notcurses-Native.git | examples/ | 06-imgview.raku


#!/usr/bin/env raku use lib 'lib'; use NativeCall; use Notcurses::Native; use Notcurses::Native::Types; use Notcurses::Native::Plane; use Notcurses::Native::Visual; use Notcurses::Native::Context; # Terminal image viewer — displays an image scaled to fit the terminal # Usage: raku examples/06-imgview.raku # raku examples/06-imgview.raku --pixel # q or Escape to quit sub MAIN(Str $path, Bool :$pixel = False) { die "File not found: $path" unless $path.IO.e; my $nc = notcurses_init(NotcursesOptions.new(:flags(NCOPTION_SUPPRESS_BANNERS)), Pointer) or die "Failed to initialize notcurses"; LEAVE { notcurses_stop($nc) if $nc.defined } my $std = notcurses_stdplane($nc); my uint32 ($rows, $cols); ncplane_dim_yx($std, $rows, $cols); # Load the image my $visual = ncvisual_from_file($path); unless $visual.defined { notcurses_stop($nc); die "Failed to load image: $path (is FFmpeg available?)"; } # Query native image size my $geom = Ncvgeom.new; my $probe = NcvisualOptions.new(:scaling(NCSCALE_NONE), :blitter(NCBLIT_1x1)); ncvisual_geom($nc, $visual, $probe, $geom); my $img-w = $geom.pixx; my $img-h = $geom.pixy; # Determine blitter: pixel if requested/supported, otherwise best available my $pixel-ok = notcurses_check_pixel_support($nc); my $blitter; my $blitter-name; if $pixel || $pixel-ok > 0 { $blitter = NCBLIT_PIXEL; $blitter-name = 'pixel'; } else { $blitter = ncvisual_media_defblitter($nc, NCSCALE_SCALE); $blitter-name = notcurses_str_blitter($blitter) // 'unknown'; } # Create a plane for the image (must be child of stdplane to composite) my $img-plane = ncplane_create($std, NcplaneOptions.new(:y(0), :x(0), :rows($rows - 1), :cols($cols))); # Blit onto our plane my $vopts = NcvisualOptions.new(:scaling(NCSCALE_SCALE), :blitter($blitter)); $vopts.set-plane($img-plane); my $result = ncvisual_blit($nc, $visual, $vopts); # Fall back through blitters if the chosen one fails if !$result.defined && $blitter == NCBLIT_PIXEL { $blitter = ncvisual_media_defblitter($nc, NCSCALE_SCALE); $blitter-name = notcurses_str_blitter($blitter) // 'fallback'; $vopts = NcvisualOptions.new(:scaling(NCSCALE_SCALE), :blitter($blitter)); $vopts.set-plane($img-plane); $result = ncvisual_blit($nc, $visual, $vopts); } if !$result.defined { $vopts = NcvisualOptions.new(:scaling(NCSCALE_SCALE), :blitter(NCBLIT_1x1)); $vopts.set-plane($img-plane); $result = ncvisual_blit($nc, $visual, $vopts); $blitter-name = '1x1'; } unless $result.defined { notcurses_stop($nc); die "Failed to render image"; } # Status bar ncplane_set_fg_rgb8($std, 180, 180, 180); ncplane_set_bg_rgb8($std, 30, 30, 30); my $status = " {$path.IO.basename} {$img-w}x{$img-h} [{$blitter-name}] q to quit "; ncplane_putstr_yx($std, $rows - 1, 0, $status ~ (' ' x max(0, $cols - $status.chars))); ncplane_set_bg_default($std); notcurses_render($nc); # Wait for q or Escape loop { my $ni = Ncinput.new; notcurses_get_blocking($nc, $ni); last if $ni.id == 'q'.ord || $ni.id == NCKEY_ESC; } ncplane_destroy($img-plane); ncvisual_destroy($visual); }