Skip to content

Commit

Permalink
feat: allow kitty to handle cropping in default mode for better perf
Browse files Browse the repository at this point in the history
  • Loading branch information
3rd committed Jul 3, 2023
1 parent 11a5452 commit 814af48
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 42 deletions.
63 changes: 56 additions & 7 deletions lua/image/backends/kitty/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ end
local backend = {
---@diagnostic disable-next-line: assign-type-mismatch
state = nil,
features = {
crop = true,
},
}

-- TODO: check for kitty
Expand All @@ -24,6 +27,8 @@ backend.setup = function(state)
return
end

if state.options.kitty_method == "unicode-placeholders" then backend.features.crop = false end

vim.api.nvim_create_autocmd("VimLeavePre", {
pattern = "*",
callback = function()
Expand All @@ -37,7 +42,7 @@ backend.render = function(image, x, y, width, height)
local with_virtual_placeholders = backend.state.options.kitty_method == "unicode-placeholders"

-- transmit image
if transmitted_images[image.id] ~= image.crop_hash then
local transmit = function()
helpers.write_graphics({
action = codes.control.action.transmit,
image_id = image.internal_id,
Expand All @@ -47,7 +52,17 @@ backend.render = function(image, x, y, width, height)
display_virtual_placeholder = with_virtual_placeholders and 1 or 0,
quiet = 2,
}, image.path)
transmitted_images[image.id] = true
end
if backend.features.crop then
if not transmitted_images[image.id] then
transmit()
transmitted_images[image.id] = true
end
else
if transmitted_images[image.id] ~= image.crop_hash then
transmit()
transmitted_images[image.id] = image.crop_hash
end
end

-- unicode placeholders
Expand All @@ -70,15 +85,43 @@ backend.render = function(image, x, y, width, height)
return
end

helpers.move_cursor(x + 1, y + 1, true, backend.state.options.kitty_tmux_write_delay)
helpers.write_graphics({
local display_payload = {
action = codes.control.action.display,
quiet = 2,
image_id = image.internal_id,
display_zindex = -1,
display_cursor_policy = codes.control.display_cursor_policy.do_not_move,
placement_id = image.internal_id,
})
}

-- crop
if backend.features.crop then
local term_size = utils.term.get_size()
local pixel_width = width * term_size.cell_width
local pixel_height = height * term_size.cell_height
local pixel_top = 0

-- crop top
if y < image.bounds.top then
local visible_rows = height - (image.bounds.top - y)
pixel_height = visible_rows * term_size.cell_height
pixel_top = (image.bounds.top - y) * term_size.cell_height
y = image.bounds.top
end

-- crop bottom
if y + height > image.bounds.bottom then pixel_height = (image.bounds.bottom - y + 1) * term_size.cell_height end

-- crop right
if x + width > image.bounds.right then pixel_width = (image.bounds.right - x) * term_size.cell_width end

display_payload.display_width = pixel_width
display_payload.display_height = pixel_height
display_payload.display_y = pixel_top
end

helpers.move_cursor(x + 1, y + 1, true, backend.state.options.kitty_tmux_write_delay)
helpers.write_graphics(display_payload)
image.is_rendered = true
backend.state.images[image.id] = image
helpers.restore_cursor()
Expand All @@ -96,7 +139,10 @@ backend.clear = function(image_id, shallow)
quiet = 2,
})
image.is_rendered = false
if not shallow then backend.state.images[image_id] = nil end
if not shallow then
backend.state.images[image_id] = nil
transmitted_images[image.id] = nil
end
return
end

Expand All @@ -108,7 +154,10 @@ backend.clear = function(image_id, shallow)
})
for id, image in pairs(backend.state.images) do
image.is_rendered = false
if not shallow then backend.state.images[id] = nil end
if not shallow then
backend.state.images[id] = nil
transmitted_images[image.id] = nil
end
end
end

Expand Down
3 changes: 3 additions & 0 deletions lua/image/backends/ueberzug.lua
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ end
local backend = {
---@diagnostic disable-next-line: assign-type-mismatch
state = nil,
features = {
crop = false,
},
}

backend.setup = function(state)
Expand Down
72 changes: 37 additions & 35 deletions lua/image/renderer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -252,49 +252,51 @@ local render = function(image, state)
end

-- crop
local pixel_width = width * term_size.cell_width
local pixel_height = height * term_size.cell_height
local crop_offset_top = 0
local needs_crop = false

-- crop top
if absolute_y < bounds.top then
local visible_rows = height - (bounds.top - absolute_y)
pixel_height = visible_rows * term_size.cell_height
crop_offset_top = (bounds.top - absolute_y) * term_size.cell_height
absolute_y = bounds.top
needs_crop = true
end
if not state.backend.features.crop then
local pixel_width = width * term_size.cell_width
local pixel_height = height * term_size.cell_height
local crop_offset_top = 0
local needs_crop = false

-- crop top
if absolute_y < bounds.top then
local visible_rows = height - (bounds.top - absolute_y)
pixel_height = visible_rows * term_size.cell_height
crop_offset_top = (bounds.top - absolute_y) * term_size.cell_height
absolute_y = bounds.top
needs_crop = true
end

-- crop bottom
if absolute_y + height > bounds.bottom then
pixel_height = (bounds.bottom - absolute_y + 1) * term_size.cell_height
needs_crop = true
end
-- crop bottom
if absolute_y + height > bounds.bottom then
pixel_height = (bounds.bottom - absolute_y + 1) * term_size.cell_height
needs_crop = true
end

-- crop right
if absolute_x + width > bounds.right then
pixel_width = (bounds.right - absolute_x) * term_size.cell_width
needs_crop = true
end
-- crop right
if absolute_x + width > bounds.right then
pixel_width = (bounds.right - absolute_x) * term_size.cell_width
needs_crop = true
end

-- perform crop
local crop_hash = needs_crop and ("%d-%d-%d-%d"):format(pixel_width, pixel_height, 0, crop_offset_top) or nil
if crop_hash or (image.crop_hash ~= crop_hash) then
local cropped_image = magick.load_image(image.original_path)
cropped_image:set_format("png")
cropped_image:crop(pixel_width, pixel_height, 0, crop_offset_top)
local tmp_path = state.tmp_dir .. "/" .. utils.random.id() .. ".png"
cropped_image:write(tmp_path)
cropped_image:destroy()
image.path = tmp_path
image.crop_hash = crop_hash
-- perform crop
local crop_hash = needs_crop and ("%d-%d-%d-%d"):format(pixel_width, pixel_height, 0, crop_offset_top) or nil
if crop_hash or (image.crop_hash ~= crop_hash) then
local cropped_image = magick.load_image(image.original_path)
cropped_image:set_format("png")
cropped_image:crop(pixel_width, pixel_height, 0, crop_offset_top)
local tmp_path = state.tmp_dir .. "/" .. utils.random.id() .. ".png"
cropped_image:write(tmp_path)
cropped_image:destroy()
image.path = tmp_path
image.crop_hash = crop_hash
end
end

-- utils.debug(("(5) x: %d, y: %d, width: %d, height: %d y_offset: %d"):format(x, y, width, height, y_offset))
image.bounds = bounds
state.backend.render(image, absolute_x, absolute_y, width, height)
image.rendered_geometry = rendered_geometry
image.bounds = bounds

return true
end
Expand Down
4 changes: 4 additions & 0 deletions lua/types.lua
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,12 @@
---@field kitty_method "normal"|"unicode-placeholders"
---@field kitty_tmux_write_delay? number

---@class BackendFeatures
---@field crop boolean

---@class Backend
---@field state State
---@field features BackendFeatures
---@field setup fun(state: State)
---@field render fun(image: Image, x: number, y: number, width?: number, height?: number)
---@field clear fun(id?: string, shallow?: boolean)
Expand Down

0 comments on commit 814af48

Please sign in to comment.