mirror of
https://github.com/kovidgoyal/kitty
synced 2026-06-08 14:18:26 +02:00
@@ -42,6 +42,15 @@ const (
|
||||
supported
|
||||
)
|
||||
|
||||
type fit_t int
|
||||
|
||||
const (
|
||||
fit_none fit_t = iota
|
||||
fit_width
|
||||
fit_height
|
||||
fit_both
|
||||
)
|
||||
|
||||
var transfer_by_file, transfer_by_memory transfer_mode
|
||||
|
||||
var files_channel chan input_arg
|
||||
@@ -49,6 +58,7 @@ var output_channel chan *image_data
|
||||
var num_of_items int
|
||||
var keep_going *atomic.Bool
|
||||
var screen_size *unix.Winsize
|
||||
var fit_mode fit_t
|
||||
|
||||
func send_output(imgd *image_data) {
|
||||
output_channel <- imgd
|
||||
@@ -87,6 +97,22 @@ func parse_z_index() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func parse_fit() (err error) {
|
||||
switch strings.ToLower(opts.Fit) {
|
||||
case "width":
|
||||
fit_mode = fit_width
|
||||
case "height":
|
||||
fit_mode = fit_height
|
||||
case "none", "neither":
|
||||
fit_mode = fit_none
|
||||
case "both":
|
||||
fit_mode = fit_both
|
||||
default:
|
||||
return fmt.Errorf("unknown fit specification: %#v", opts.Fit)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parse_place() (err error) {
|
||||
if opts.Place == "" {
|
||||
return nil
|
||||
@@ -130,8 +156,10 @@ func print_error(format string, args ...any) {
|
||||
|
||||
func main(cmd *cli.Command, o *Options, args []string) (rc int, err error) {
|
||||
opts = o
|
||||
err = parse_place()
|
||||
if err != nil {
|
||||
if err = parse_place(); err != nil {
|
||||
return 1, err
|
||||
}
|
||||
if err = parse_fit(); err != nil {
|
||||
return 1, err
|
||||
}
|
||||
err = parse_z_index()
|
||||
|
||||
@@ -22,9 +22,16 @@ be positioned at the top left corner of the image, instead of on the line after
|
||||
|
||||
--scale-up
|
||||
type=bool-set
|
||||
When used in combination with :option:`--place` it will cause images that are
|
||||
smaller than the specified area to be scaled up to use as much of the specified
|
||||
area as possible.
|
||||
Cause images that are smaller than the specified area to be scaled up to use as much
|
||||
of the specified area as possible. The specified area depends on either the :option:`--place`
|
||||
or the :option:`--fit` options.
|
||||
|
||||
|
||||
--fit
|
||||
choices=width,height,both,none
|
||||
default=width
|
||||
When not using :option:`--place`, control how the image is scaled relative to the screen.
|
||||
You can have it fit in the screen width or height or both or neither.
|
||||
|
||||
|
||||
--background
|
||||
|
||||
@@ -91,12 +91,37 @@ func add_frame(ctx *images.Context, imgd *image_data, img image.Image, left, top
|
||||
return &f
|
||||
}
|
||||
|
||||
func scale_up(width, height, maxWidth, maxHeight int) (newWidth, newHeight int) {
|
||||
if width == 0 || height == 0 {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
// Calculate the ratio to scale the width and the ratio to scale the height.
|
||||
// We use floating-point division for precision.
|
||||
widthRatio := float64(maxWidth) / float64(width)
|
||||
heightRatio := float64(maxHeight) / float64(height)
|
||||
|
||||
// To preserve the aspect ratio and fit within the limits, we must use the
|
||||
// smaller of the two scaling ratios.
|
||||
var ratio float64
|
||||
if widthRatio < heightRatio {
|
||||
ratio = widthRatio
|
||||
} else {
|
||||
ratio = heightRatio
|
||||
}
|
||||
|
||||
// Calculate the new dimensions and convert them back to uints.
|
||||
newWidth = int(float64(width) * ratio)
|
||||
newHeight = int(float64(height) * ratio)
|
||||
|
||||
return newWidth, newHeight
|
||||
}
|
||||
|
||||
func scale_image(imgd *image_data) bool {
|
||||
if imgd.needs_scaling {
|
||||
width, height := imgd.canvas_width, imgd.canvas_height
|
||||
if imgd.canvas_width < imgd.available_width && opts.ScaleUp && place != nil {
|
||||
r := float64(imgd.available_width) / float64(imgd.canvas_width)
|
||||
imgd.canvas_width, imgd.canvas_height = imgd.available_width, int(r*float64(imgd.canvas_height))
|
||||
if opts.ScaleUp && (imgd.canvas_width < imgd.available_width || imgd.canvas_height < imgd.available_height) && (imgd.available_height != inf || imgd.available_width != inf) {
|
||||
imgd.canvas_width, imgd.canvas_height = scale_up(imgd.canvas_width, imgd.canvas_height, imgd.available_width, imgd.available_height)
|
||||
}
|
||||
neww, newh := images.FitImage(imgd.canvas_width, imgd.canvas_height, imgd.available_width, imgd.available_height)
|
||||
imgd.needs_scaling = false
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"image"
|
||||
"io"
|
||||
"io/fs"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -196,15 +197,29 @@ type image_data struct {
|
||||
source_name string
|
||||
}
|
||||
|
||||
const inf = math.MaxInt
|
||||
|
||||
func set_basic_metadata(imgd *image_data) {
|
||||
if imgd.frames == nil {
|
||||
imgd.frames = make([]*image_frame, 0, 32)
|
||||
}
|
||||
imgd.available_width = int(screen_size.Xpixel)
|
||||
imgd.available_height = 10 * imgd.canvas_height
|
||||
if place != nil {
|
||||
imgd.available_width = place.width * int(screen_size.Xpixel) / int(screen_size.Col)
|
||||
imgd.available_height = place.height * int(screen_size.Ypixel) / int(screen_size.Row)
|
||||
} else {
|
||||
switch fit_mode {
|
||||
case fit_none:
|
||||
imgd.available_width, imgd.available_height = inf, inf
|
||||
case fit_both:
|
||||
imgd.available_width = int(screen_size.Xpixel)
|
||||
imgd.available_height = int(screen_size.Ypixel)
|
||||
case fit_width:
|
||||
imgd.available_width = int(screen_size.Xpixel)
|
||||
imgd.available_height = inf
|
||||
case fit_height:
|
||||
imgd.available_width = inf
|
||||
imgd.available_height = int(screen_size.Ypixel)
|
||||
}
|
||||
}
|
||||
imgd.needs_scaling = imgd.canvas_width > imgd.available_width || imgd.canvas_height > imgd.available_height || opts.ScaleUp
|
||||
imgd.needs_conversion = imgd.needs_scaling || remove_alpha != nil || flip || flop || imgd.format_uppercase != "PNG"
|
||||
|
||||
29
kittens/icat/scaling_test.go
Normal file
29
kittens/icat/scaling_test.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package icat
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var _ = fmt.Print
|
||||
|
||||
func TestScaling(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
w, h, pw, ph, ew, eh int
|
||||
}{
|
||||
{1000, 50, 800, 600, 800, 40},
|
||||
{1000, 50, 800000, 600, 12000, 600},
|
||||
{100, 50, 800, 600, 800, 400},
|
||||
{1920, 1080, 800, 600, 800, 450},
|
||||
{300, 900, 800, 600, 200, 600},
|
||||
{400, 300, 800, 600, 800, 600},
|
||||
} {
|
||||
aw, ah := scale_up(tc.w, tc.h, tc.pw, tc.ph)
|
||||
actual := image.Pt(aw, ah)
|
||||
expected := image.Pt(tc.ew, tc.eh)
|
||||
if actual != expected {
|
||||
t.Fatalf("want: %v got: %v", expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user