@ -46,8 +46,17 @@ function ImageCacheItem:onFree()
end
local ImageWidget = Widget : new {
-- Can be provided with a path to a file
file = nil ,
-- or an already made BlitBuffer (ie: made by Mupdf.renderImage())
image = nil ,
-- Whether BlitBuffer rendered from file should be cached
file_do_cache = true ,
-- Whether provided BlitBuffer can be modified by us and SHOULD be free() by us,
-- normally true unless our caller wants to reuse it's provided image
image_disposable = true ,
invert = nil ,
dim = nil ,
hide = nil ,
@ -62,15 +71,19 @@ local ImageWidget = Widget:new{
-- widget size. i.e. either fit the width or fit the height according to the
-- original image size.
autostretch = false ,
-- when overflow is set to true, image will be stretched to fit the widget
-- size vertically and horizontally, without impact original aspect ratio.
-- But overflow part will be ignored.
overflow = false ,
_bb = nil
-- when pre_rotate is not 0, native image is rotated by this angle
-- before applying the other autostretch/autoscale settings
pre_rotate = 0 ,
-- former 'overflow' setting removed, as logic was wrong
_bb = nil ,
_bb_disposable = true -- whether we should free() our _bb
}
function ImageWidget : _loadimage ( )
self._bb = self.image
-- don't touch or free if caller doesn't want that
self._bb_disposable = self.image_disposable
end
function ImageWidget : _loadfile ( )
@ -82,9 +95,11 @@ function ImageWidget:_loadfile()
if cache then
-- hit cache
self._bb = cache.bb
self._bb_disposable = false -- don't touch or free a cached _bb
else
if self.height and self.height > 200 then -- don't cache big images
if not self.file_do_cache then
self._bb = Mupdf.renderImageFile ( self.file , self.width , self.height )
self._bb_disposable = true -- we made it, we can modify and free it
else
-- cache this image
logger.dbg ( " cache " , hash )
@ -94,6 +109,7 @@ function ImageWidget:_loadfile()
cache.size = cache.bb . pitch * cache.bb . h * cache.bb : getBpp ( ) / 8
ImageCache : insert ( hash , cache )
self._bb = cache.bb
self._bb_disposable = false -- don't touch or free a cached _bb
end
end
else
@ -112,6 +128,14 @@ function ImageWidget:_render()
else
error ( " cannot render image " )
end
if self.pre_rotate ~= 0 then
if not self._bb_disposable then
-- we can't modify _bb, make a copy
self._bb = self._bb : copy ( )
self._bb_disposable = true -- new object will have to be freed
end
self._bb : rotate ( self.pre_rotate ) -- rotate in-place
end
local native_w , native_h = self._bb : getWidth ( ) , self._bb : getHeight ( )
local w , h = self.width , self.height
if self.autoscale then
@ -126,22 +150,20 @@ function ImageWidget:_render()
h = self.height
w = self.width * ratio
else
h = self.height * ratio
w = self.width
end
elseif self.overflow then
local ratio = native_w / self.width / native_h * self.height
if ratio < 1 then
h = self.height / ratio
w = self.width
else
h = self.height
w = self.width / ratio
end
end
end
if ( w and w ~= native_w ) or ( h and h ~= native_h ) then
self._bb = self._bb : scale ( w or native_w , h or native_h )
-- We're making a new blitbuffer, we need to explicitely free
-- the old one to not leak memory
local new_bb = self._bb : scale ( w or native_w , h or native_h )
if self._bb_disposable then
self._bb : free ( )
end
self._bb = new_bb
self._bb_disposable = true -- new object will have to be freed
end
end
@ -177,11 +199,20 @@ function ImageWidget:paintTo(bb, x, y)
end
end
-- This will normally be called by our WidgetContainer:free()
-- But it SHOULD explicitely be called if we are getting replaced
-- (ie: in some other widget's update()), to not leak memory with
-- BlitBuffer zombies
function ImageWidget : free ( )
if self.image then
self.image : free ( )
self.image = nil
if self. _bb and self._bb_disposable and self._bb . fre e then
self. _bb : free ( )
self. _bb = nil
end
end
function ImageWidget : onCloseWidget ( )
-- free when UIManager:close() was called
self : free ( )
end
return ImageWidget