CRE/ImageViewer: get scaled blitbuffer when long-press on SVG

Get a Lua userdata wrapping a crengine LVSvgImageSource object
when long-press on a SVG image, and have crengine/LunaSVG render
it smoothly scaled to the requested size by ImageViewer.
pull/9516/head
poire-z 2 years ago
parent 1c44c4c584
commit 76a7d83079

@ -1008,7 +1008,9 @@ function ReaderHighlight:onHold(arg, ges)
-- check if we were holding on an image
-- we provide want_frames=true, so we get a list of images for
-- animated GIFs (supported by ImageViewer)
local image = self.ui.document:getImageFromPosition(self.hold_pos, true)
-- We provide accept_cre_scalable_image=true to get, if the image is a SVG image,
-- a function that ImageViewer can use to get a perfect bb at any scale factor.
local image = self.ui.document:getImageFromPosition(self.hold_pos, true, true)
if image then
logger.dbg("hold on image")
local ImageViewer = require("ui/widget/imageviewer")

@ -539,14 +539,40 @@ function CreDocument:getCoverPageImage()
end
end
function CreDocument:getImageFromPosition(pos, want_frames)
local data, size = self._document:getImageDataFromPosition(pos.x, pos.y)
function CreDocument:getImageFromPosition(pos, want_frames, accept_cre_scalable_image)
local data, size, cre_img = self._document:getImageDataFromPosition(pos.x, pos.y, accept_cre_scalable_image)
if data and size then
logger.dbg("CreDocument: got image data from position", data, size)
local image = RenderImage:renderImageData(data, size, want_frames)
C.free(data) -- free the userdata we got from crengine
return image
end
if cre_img then
-- The image is a scalable image (SVG), and we got an image object from crengine, that
-- can draw itself at any requested scale factor: returns a function, that will be used
-- by ImageViewer to get the perfect bb.
return function(scale, w, h)
logger.dbg("CreImage: scaling for", scale, w, h)
if not cre_img then
return
end
if scale == false then -- used to signal we are done with the object
cre_img:free()
cre_img = false
return
end
-- scale will be used if non-0, otherwise the bb will be made to fit in w/h,
-- keeping the original aspect ratio
local image_data, image_w, image_h, image_scale = cre_img:renderScaled(scale, w, h)
if image_data then
-- This data is held in the cre_img object, so this bb is only
-- valid as long as this object is alive, and until the next
-- call to this function that will replace this data.
local bb = Blitbuffer.new(image_w, image_h, Blitbuffer.TYPE_BBRGB32, image_data)
return bb, image_scale
end
end
end
end
function CreDocument:getWordFromPosition(pos)

@ -75,6 +75,7 @@ local ImageViewer = InputContainer:new{
_image_wg = nil,
_images_list = nil,
_images_list_disposable = nil,
_scaled_image_func = nil,
}
@ -147,6 +148,12 @@ function ImageViewer:init()
self._images_list_disposable = self.image_disposable
self.image_disposable = self._images_list.image_disposable
end
-- If self.image is a function (scalable SVG image object provided by crengine),
-- it can be used to get the perfect bb for any scale_factor
if type(self.image) == "function" then
self._scaled_image_func = self.image
self.image = self._scaled_image_func(1) -- native image size, that we need to know
end
-- Widget layout
if self._scale_to_fit == nil then -- initialize our toggle
@ -410,6 +417,16 @@ function ImageViewer:_new_image_wg()
rotation_angle = rotate_clockwise and 90 or 270
end
if self._scaled_image_func then
local scale_factor_used
self.image, scale_factor_used = self._scaled_image_func(self.scale_factor, max_image_w, max_image_h)
if self.scale_factor == 0 then
-- onZoomIn/Out need to know the current scale factor, that they won't be
-- able to fetch from _image_wg as we force it to be 1. So, remember it.
self._scale_factor_0 = scale_factor_used
end
end
self._image_wg = ImageWidget:new{
file = self.file,
image = self.image,
@ -418,7 +435,7 @@ function ImageViewer:_new_image_wg()
width = max_image_w,
height = max_image_h,
rotation_angle = rotation_angle,
scale_factor = self.scale_factor,
scale_factor = self._scaled_image_func and 1 or self.scale_factor,
center_x_ratio = self._center_x_ratio,
center_y_ratio = self._center_y_ratio,
}
@ -621,7 +638,7 @@ end
function ImageViewer:onZoomIn(inc)
if self.scale_factor == 0 then
-- Get the scale_factor made out for best fit
self.scale_factor = self._image_wg:getScaleFactor()
self.scale_factor = self._scale_factor_0 or self._image_wg:getScaleFactor()
end
if not inc then inc = 0.2 end -- default for key zoom event
self.scale_factor = self.scale_factor + inc
@ -636,7 +653,7 @@ end
function ImageViewer:onZoomOut(dec)
if self.scale_factor == 0 then
-- Get the scale_factor made out for best fit
self.scale_factor = self._image_wg:getScaleFactor()
self.scale_factor = self._scale_factor_0 or self._image_wg:getScaleFactor()
end
if not dec then dec = 0.2 end -- default for key zoom event
self.scale_factor = self.scale_factor - dec
@ -725,6 +742,10 @@ function ImageViewer:onCloseWidget()
logger.dbg("ImageViewer:onCloseWidget: free self._images_list", self._images_list)
self._images_list:free()
end
if self._scaled_image_func then
self._scaled_image_func(false) -- invoke :free() on the creimage object
self._scaled_image_func = nil
end
-- Those, on the other hand, are always initialized, but may not actually be in our widget tree right now,
-- depending on what we needed to show, so they might not get sent a CloseWidget event.

Loading…
Cancel
Save