From 573e0575313c14558be08db72a02b1b29f3ad73d Mon Sep 17 00:00:00 2001 From: 3rd <3rd@users.noreply.github.com> Date: Tue, 4 Jul 2023 00:01:45 +0300 Subject: [PATCH] feat: extract cropping into renderer and handle with magick --- lua/image/backends/kitty/init.lua | 51 ++++----------------------- lua/image/backends/ueberzug.lua | 7 ++++ lua/image/renderer.lua | 57 ++++++++++++++++++++++++++++++- 3 files changed, 70 insertions(+), 45 deletions(-) diff --git a/lua/image/backends/kitty/init.lua b/lua/image/backends/kitty/init.lua index 377d2b5..e7f5a73 100644 --- a/lua/image/backends/kitty/init.lua +++ b/lua/image/backends/kitty/init.lua @@ -34,33 +34,11 @@ end -- extend from empty line strategy to use extmarks backend.render = function(image, x, y, width, height) - local term_size = utils.term.get_size() local with_virtual_placeholders = backend.state.options.kitty_method == "unicode-placeholders" -- save cursor helpers.move_cursor(x + 1, y + 1, true) - -- clear out of bounds images - if - y + height < image.bounds.top - or y > image.bounds.bottom - or x + width < image.bounds.left - or x > image.bounds.right - then - -- utils.debug( "deleting out of bounds image", { id = image.id, x = x, y = y, width = width, height = height, bounds = image.bounds }) - helpers.write_graphics({ - action = codes.control.action.delete, - display_delete = "i", - image_id = image.internal_id, - quiet = 2, - }) - image.is_rendered = false - backend.state.images[image.id] = image - helpers.restore_cursor() - return - end - -- utils.debug("kitty: rendering image" .. image.path, { id = image.id, x = x, y = y, width = width, height = height, bounds = image.bounds }) - -- transmit image helpers.write_graphics({ action = codes.control.action.transmit, @@ -93,33 +71,11 @@ backend.render = function(image, x, y, width, height) return end - -- default display - local pixel_width = width * term_size.cell_width - local pixel_height = height * term_size.cell_height - local pixel_top = 0 - - -- top crop - 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 - - -- bottom crop - if y + height > image.bounds.bottom then - -- - pixel_height = (image.bounds.bottom - y + 1) * term_size.cell_height - end - helpers.move_cursor(x + 1, y + 1, false, backend.state.options.kitty_tmux_write_delay) helpers.write_graphics({ action = codes.control.action.display, quiet = 2, image_id = image.internal_id, - display_width = pixel_width, - display_height = pixel_height, - display_y = pixel_top, display_zindex = -1, display_cursor_policy = codes.control.display_cursor_policy.do_not_move, placement_id = image.internal_id, @@ -130,6 +86,9 @@ backend.render = function(image, x, y, width, height) end backend.clear = function(image_id, shallow) + helpers.move_cursor(0, 0, true) + + -- one if image_id then local image = backend.state.images[image_id] if not image then return end @@ -141,8 +100,11 @@ backend.clear = function(image_id, shallow) }) image.is_rendered = false if not shallow then backend.state.images[image_id] = nil end + helpers.restore_cursor() return end + + --all helpers.write_graphics({ action = codes.control.action.delete, display_delete = "a", @@ -152,6 +114,7 @@ backend.clear = function(image_id, shallow) image.is_rendered = false if not shallow then backend.state.images[id] = nil end end + helpers.restore_cursor() end return backend diff --git a/lua/image/backends/ueberzug.lua b/lua/image/backends/ueberzug.lua index 467863c..ffc6729 100644 --- a/lua/image/backends/ueberzug.lua +++ b/lua/image/backends/ueberzug.lua @@ -59,10 +59,12 @@ local backend = { ---@diagnostic disable-next-line: assign-type-mismatch state = nil, } + backend.setup = function(state) backend.state = state if not child then spawn() end end + backend.render = function(image, x, y, width, height) if not child then return end child.write({ @@ -77,8 +79,11 @@ backend.render = function(image, x, y, width, height) image.is_rendered = true backend.state.images[image.id] = image end + backend.clear = function(image_id, shallow) if not child then return end + + -- one if image_id then local image = backend.state.images[image_id] if not image then return end @@ -90,6 +95,8 @@ backend.clear = function(image_id, shallow) if not shallow then backend.state.images[image_id] = nil end return end + + -- all for id, image in pairs(backend.state.images) do child.write({ action = "remove", diff --git a/lua/image/renderer.lua b/lua/image/renderer.lua index 870df4b..14e9be8 100644 --- a/lua/image/renderer.lua +++ b/lua/image/renderer.lua @@ -1,4 +1,5 @@ local utils = require("image/utils") +local magick = require("image.magick") ---@return { x: number, y: number } local get_global_offsets = function() @@ -222,6 +223,50 @@ local render = function(image, state) if prevent_rendering then absolute_y = -999999 end image.bounds = bounds + + -- clear out of bounds images + if + absolute_y + height < image.bounds.top + or absolute_y > image.bounds.bottom + or absolute_x + width < image.bounds.left + or absolute_x > image.bounds.right + then + if image.is_rendered then + -- utils.debug("deleting out of bounds image", { id = image.id, x = x, y = y, width = width, height = height, bounds = image.bounds }) + state.backend.clear(image.id, true) + else + state.images[image.id] = image + end + return true + 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 < image.bounds.top then + local visible_rows = height - (image.bounds.top - absolute_y) + pixel_height = visible_rows * term_size.cell_height + crop_offset_top = (image.bounds.top - absolute_y) * term_size.cell_height + absolute_y = image.bounds.top + needs_crop = true + end + + -- crop bottom + if absolute_y > image.bounds.bottom then + pixel_height = (image.bounds.bottom - absolute_y + 1) * term_size.cell_height + needs_crop = true + end + + -- crop right + if absolute_x + pixel_width > image.bounds.right then + pixel_width = (image.bounds.right - absolute_x) * term_size.cell_width + needs_crop = true + end + local rendered_geometry = { x = absolute_x, y = absolute_y, width = width, height = height } -- prevent useless rerendering @@ -235,8 +280,18 @@ local render = function(image, state) return true end - -- utils.debug(("(5) x: %d, y: %d, width: %d, height: %d y_offset: %d"):format(x, y, width, height, y_offset)) + -- perform crop + if needs_crop then + local cropped_image = magick.load_image(image.original_path) + cropped_image:set_format("png") + utils.debug(("cropping image: %d, %d, %d, %d"):format(pixel_width, pixel_height, 0, crop_offset_top)) + cropped_image:crop(pixel_width, pixel_height, 0, crop_offset_top) + local tmp_path = os.tmpname() .. ".png" + cropped_image:write(tmp_path) + image.path = tmp_path + end + -- utils.debug(("(5) x: %d, y: %d, width: %d, height: %d y_offset: %d"):format(x, y, width, height, y_offset)) state.backend.render(image, absolute_x, absolute_y, width, height) image.rendered_geometry = rendered_geometry