[CoverImage] Add rotate image option (#13604)
Some checks failed
macos / macOS 13 x86-64 🔨15.2 🎯10.15 (push) Has been cancelled
macos / macOS 14 ARM64 🔨15.4 🎯11.0 (push) Has been cancelled

New option to disable image rotation in cover image plugin.

Fix #12308
This commit is contained in:
apgrc
2025-04-21 13:12:48 -06:00
committed by GitHub
parent 79f326b5d0
commit c3024387ec

View File

@@ -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()