mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
[CoverImage] Add rotate image option (#13604)
New option to disable image rotation in cover image plugin. Fix #12308
This commit is contained in:
@@ -60,7 +60,7 @@ local function isFileOk(filename)
|
||||
end
|
||||
|
||||
local function getExtension(filename)
|
||||
local _, name = util.splitFilePathName(filename)
|
||||
local dummy, name = util.splitFilePathName(filename)
|
||||
return util.getFileNameSuffix(name):lower()
|
||||
end
|
||||
|
||||
@@ -79,6 +79,7 @@ function CoverImage:init()
|
||||
self.cover_image_grayscale = G_reader_settings:isTrue("cover_image_grayscale")
|
||||
self.cover_image_stretch_limit = G_reader_settings:readSetting("cover_image_stretch_limit", 8)
|
||||
self.cover_image_background = G_reader_settings:readSetting("cover_image_background", "black")
|
||||
self.cover_image_rotate = G_reader_settings:readSetting("cover_image_rotate", true)
|
||||
self.cover_image_fallback_path = G_reader_settings:readSetting("cover_image_fallback_path",
|
||||
default_fallback_path)
|
||||
self.cover_image_cache_path = G_reader_settings:readSetting("cover_image_cache_path",
|
||||
@@ -110,90 +111,95 @@ function CoverImage:cleanUpImage()
|
||||
end
|
||||
|
||||
function CoverImage:createCoverImage(doc_settings)
|
||||
if self:coverEnabled() and doc_settings:nilOrFalse("exclude_cover_image") then
|
||||
local cover_image, custom_cover = FileManagerBookInfo:getCoverImage(self.ui.document)
|
||||
if cover_image then
|
||||
local cache_file = self:getCacheFile(custom_cover)
|
||||
if lfs.attributes(cache_file, "mode") == "file" then
|
||||
logger.dbg("CoverImage: cache file already exists")
|
||||
ffiutil.copyFile(cache_file, self.cover_image_path)
|
||||
lfs.touch(cache_file) -- update date
|
||||
return
|
||||
end
|
||||
if not (self:coverEnabled() and doc_settings:nilOrFalse("exclude_cover_image")) then
|
||||
return
|
||||
end
|
||||
|
||||
local s_w, s_h = Screen:getWidth(), Screen:getHeight()
|
||||
local i_w, i_h = cover_image:getWidth(), cover_image:getHeight()
|
||||
local scale_factor = math.min(s_w / i_w, s_h / i_h)
|
||||
local cover_image, custom_cover = FileManagerBookInfo:getCoverImage(self.ui.document)
|
||||
if not cover_image then
|
||||
return
|
||||
end
|
||||
|
||||
if Screen:getRotationMode() == Screen.DEVICE_ROTATED_UPSIDE_DOWN
|
||||
or Screen:getRotationMode() == Screen.DEVICE_ROTATED_CLOCKWISE then
|
||||
local cache_file = self:getCacheFile(custom_cover)
|
||||
if lfs.attributes(cache_file, "mode") == "file" then
|
||||
logger.dbg("CoverImage: cache file already exists")
|
||||
ffiutil.copyFile(cache_file, self.cover_image_path)
|
||||
lfs.touch(cache_file) -- update date
|
||||
return
|
||||
end
|
||||
|
||||
local flipped_cover = cover_image:rotatedCopy(180)
|
||||
cover_image:free()
|
||||
cover_image = flipped_cover
|
||||
end
|
||||
local s_w, s_h = Screen:getWidth(), Screen:getHeight()
|
||||
local i_w, i_h = cover_image:getWidth(), cover_image:getHeight()
|
||||
local scale_factor = math.min(s_w / i_w, s_h / i_h)
|
||||
|
||||
if self.cover_image_background == "none" or scale_factor == 1 then
|
||||
local act_format = self.cover_image_format == "auto" and getExtension(self.cover_image_path) or self.cover_image_format
|
||||
if not cover_image:writeToFile(self.cover_image_path, act_format, self.cover_image_quality, self.cover_image_grayscale) then
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Error writing file") .. "\n" .. self.cover_image_path,
|
||||
show_icon = true,
|
||||
})
|
||||
end
|
||||
cover_image:free()
|
||||
ffiutil.copyFile(self.cover_image_path, cache_file)
|
||||
self:cleanCache()
|
||||
return
|
||||
end
|
||||
if self.cover_image_rotate and (
|
||||
Screen:getRotationMode() == Screen.DEVICE_ROTATED_UPSIDE_DOWN or
|
||||
Screen:getRotationMode() == Screen.DEVICE_ROTATED_CLOCKWISE
|
||||
) then
|
||||
local rotated_cover = cover_image:rotatedCopy(180)
|
||||
cover_image:free()
|
||||
cover_image = rotated_cover
|
||||
end
|
||||
|
||||
local screen_ratio = s_w / s_h
|
||||
local image_ratio = i_w / i_h
|
||||
local ratio_divergence_percent = math.abs(100 - image_ratio / screen_ratio * 100)
|
||||
if self.cover_image_background == "none" or scale_factor == 1 then
|
||||
local act_format = self.cover_image_format == "auto" and getExtension(self.cover_image_path) or self.cover_image_format
|
||||
if not cover_image:writeToFile(self.cover_image_path, act_format, self.cover_image_quality, self.cover_image_grayscale) then
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Error writing file") .. "\n" .. self.cover_image_path,
|
||||
show_icon = true,
|
||||
})
|
||||
end
|
||||
cover_image:free()
|
||||
ffiutil.copyFile(self.cover_image_path, cache_file)
|
||||
self:cleanCache()
|
||||
return
|
||||
end
|
||||
|
||||
logger.dbg("CoverImage: geometries screen=" .. screen_ratio .. ", image=" .. image_ratio .. "; ratio=" .. ratio_divergence_percent)
|
||||
local screen_ratio = s_w / s_h
|
||||
local image_ratio = i_w / i_h
|
||||
local ratio_divergence_percent = math.abs(100 - image_ratio / screen_ratio * 100)
|
||||
|
||||
local image
|
||||
if ratio_divergence_percent < self.cover_image_stretch_limit then -- stretch
|
||||
logger.dbg("CoverImage: stretch to fullscreen")
|
||||
image = RenderImage:scaleBlitBuffer(cover_image, s_w, s_h)
|
||||
else -- scale
|
||||
local scaled_w, scaled_h = math.floor(i_w * scale_factor), math.floor(i_h * scale_factor)
|
||||
logger.dbg("CoverImage: scale to fullscreen, fill background")
|
||||
logger.dbg("CoverImage: geometries screen=" .. screen_ratio .. ", image=" .. image_ratio .. "; ratio=" .. ratio_divergence_percent)
|
||||
|
||||
cover_image = RenderImage:scaleBlitBuffer(cover_image, scaled_w, scaled_h)
|
||||
-- new buffer with screen dimensions,
|
||||
image = Blitbuffer.new(s_w, s_h, cover_image:getType()) -- new buffer, filled with black
|
||||
if self.cover_image_background == "white" then
|
||||
image:fill(Blitbuffer.COLOR_WHITE)
|
||||
elseif self.cover_image_background == "gray" then
|
||||
image:fill(Blitbuffer.COLOR_GRAY)
|
||||
end
|
||||
-- copy scaled image to buffer
|
||||
if s_w > scaled_w then -- move right
|
||||
image:blitFrom(cover_image, math.floor((s_w - scaled_w) / 2), 0, 0, 0, scaled_w, scaled_h)
|
||||
else -- move down
|
||||
image:blitFrom(cover_image, 0, math.floor((s_h - scaled_h) / 2), 0, 0, scaled_w, scaled_h)
|
||||
end
|
||||
end
|
||||
local image
|
||||
if ratio_divergence_percent < self.cover_image_stretch_limit then -- stretch
|
||||
logger.dbg("CoverImage: stretch to fullscreen")
|
||||
image = RenderImage:scaleBlitBuffer(cover_image, s_w, s_h)
|
||||
else -- scale
|
||||
local scaled_w, scaled_h = math.floor(i_w * scale_factor), math.floor(i_h * scale_factor)
|
||||
logger.dbg("CoverImage: scale to fullscreen, fill background")
|
||||
|
||||
cover_image:free()
|
||||
|
||||
local act_format = self.cover_image_format == "auto" and getExtension(self.cover_image_path) or self.cover_image_format
|
||||
if not image:writeToFile(self.cover_image_path, act_format, self.cover_image_quality, self.cover_image_grayscale) then
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Error writing file") .. "\n" .. self.cover_image_path,
|
||||
show_icon = true,
|
||||
})
|
||||
end
|
||||
|
||||
image:free()
|
||||
logger.dbg("CoverImage: image written to " .. self.cover_image_path)
|
||||
|
||||
ffiutil.copyFile(self.cover_image_path, cache_file)
|
||||
self:cleanCache()
|
||||
cover_image = RenderImage:scaleBlitBuffer(cover_image, scaled_w, scaled_h)
|
||||
-- new buffer with screen dimensions,
|
||||
image = Blitbuffer.new(s_w, s_h, cover_image:getType()) -- new buffer, filled with black
|
||||
if self.cover_image_background == "white" then
|
||||
image:fill(Blitbuffer.COLOR_WHITE)
|
||||
elseif self.cover_image_background == "gray" then
|
||||
image:fill(Blitbuffer.COLOR_GRAY)
|
||||
end
|
||||
-- copy scaled image to buffer
|
||||
if s_w > scaled_w then -- move right
|
||||
image:blitFrom(cover_image, math.floor((s_w - scaled_w) / 2), 0, 0, 0, scaled_w, scaled_h)
|
||||
else -- move down
|
||||
image:blitFrom(cover_image, 0, math.floor((s_h - scaled_h) / 2), 0, 0, scaled_w, scaled_h)
|
||||
end
|
||||
end
|
||||
|
||||
cover_image:free()
|
||||
|
||||
local act_format = self.cover_image_format == "auto" and getExtension(self.cover_image_path) or self.cover_image_format
|
||||
if not image:writeToFile(self.cover_image_path, act_format, self.cover_image_quality, self.cover_image_grayscale) then
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Error writing file") .. "\n" .. self.cover_image_path,
|
||||
show_icon = true,
|
||||
})
|
||||
end
|
||||
|
||||
image:free()
|
||||
logger.dbg("CoverImage: image written to " .. self.cover_image_path)
|
||||
|
||||
ffiutil.copyFile(self.cover_image_path, cache_file)
|
||||
self:cleanCache()
|
||||
end
|
||||
|
||||
function CoverImage:onCloseDocument()
|
||||
@@ -228,10 +234,15 @@ end
|
||||
function CoverImage:getCacheFile(custom_cover)
|
||||
local custom_cover_mtime = custom_cover and lfs.attributes(custom_cover, "modification") or ""
|
||||
local dummy, document_name = util.splitFilePathName(self.ui.document.file)
|
||||
local rotated = ""
|
||||
if self.cover_image_rotate then
|
||||
rotated = "_rotated_"
|
||||
end
|
||||
|
||||
-- use document_name here. Title may contain characters not allowed on every filesystem (esp. vfat on /sdcard)
|
||||
local key = document_name .. custom_cover_mtime .. self.cover_image_quality .. self.cover_image_stretch_limit
|
||||
.. self.cover_image_background .. self.cover_image_format .. tostring(self.cover_image_grayscale)
|
||||
.. Screen:getRotationMode()
|
||||
.. Screen:getRotationMode() .. rotated
|
||||
|
||||
return self.cover_image_cache_path .. self.cover_image_cache_prefix .. md5(key) .. "." .. getExtension(self.cover_image_path)
|
||||
end
|
||||
@@ -654,6 +665,23 @@ function CoverImage:menuEntrySBF()
|
||||
self:menuEntryBackground("black", _("black")),
|
||||
self:menuEntryBackground("white", _("white")),
|
||||
self:menuEntryBackground("gray", _("gray")),
|
||||
{
|
||||
text = _("Rotate image"),
|
||||
keep_menu_open = true,
|
||||
help_text_func = function()
|
||||
return T(_("Rotate the generated image to follow the device orientation. Enable this when the native system does not rotate the background image to follow system orientation. Disable this if your device correctly handles screen saver rotation."), self.cover_image_stretch_limit)
|
||||
end,
|
||||
checked_func = function()
|
||||
return self.cover_image_rotate
|
||||
end,
|
||||
callback = function()
|
||||
self.cover_image_rotate = not self.cover_image_rotate
|
||||
G_reader_settings:saveSetting("cover_image_rotate", self.cover_image_rotate)
|
||||
if self:coverEnabled() then
|
||||
self:createCoverImage(self.ui.doc_settings)
|
||||
end
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Original image"),
|
||||
checked_func = function()
|
||||
|
||||
Reference in New Issue
Block a user