mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
PDF free zoom mode revisit
this should implement feature request of zoom mode for multi-columns page in #501 This PR depends on koreader/koreader-base#435 How to use? 1. Tap the top left corner of a PDF/Djvu page to get into the flipping mode 2. Double-tap on text block will zoom in to that column 3. Double-tap on any area will zoom out to an overview of the page 4. repeat step 2 to focus to another page block How does it work? 1. We first find the mask of text blocks in the page. (Pic 1) 2. Then we intersect page boxes with user tap to form a page block. (Pic 2) 3. Finally we zoom the page to the page block and center current view to that block. (Pic 3)
This commit is contained in:
2
base
2
base
Submodule base updated: b1b0350697...6fa062f20c
@@ -136,9 +136,6 @@ DMINIBAR_HEIGHT = 7 -- Should be smaller than DMINIBAR_CONTAINER_HEI
|
||||
DMINIBAR_CONTAINER_HEIGHT = 14 -- Larger means more padding at the bottom, at the risk of eating into the last line
|
||||
DMINIBAR_FONT_SIZE = 14
|
||||
|
||||
-- gesture detector defaults
|
||||
DGESDETECT_DISABLE_DOUBLE_TAP = true
|
||||
|
||||
-- change this to any numerical value if you want to antomatically save settings when turning pages
|
||||
DAUTO_SAVE_PAGING_COUNT = nil
|
||||
|
||||
|
||||
@@ -267,30 +267,24 @@ function ReaderPaging:onToggleBookmarkFlipping()
|
||||
end
|
||||
|
||||
function ReaderPaging:enterFlippingMode()
|
||||
self.ui:handleEvent(Event:new("EnterFlippingMode"))
|
||||
self.orig_reflow_mode = self.view.document.configurable.text_wrap
|
||||
self.orig_scroll_mode = self.view.page_scroll
|
||||
self.orig_zoom_mode = self.view.zoom_mode
|
||||
DEBUG("store zoom mode", self.orig_zoom_mode)
|
||||
self.DGESDETECT_DISABLE_DOUBLE_TAP = DGESDETECT_DISABLE_DOUBLE_TAP
|
||||
|
||||
self.view.document.configurable.text_wrap = 0
|
||||
self.view.page_scroll = self.flipping_scroll_mode
|
||||
Input.disable_double_tap = false
|
||||
DGESDETECT_DISABLE_DOUBLE_TAP = false
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", self.flipping_zoom_mode))
|
||||
self.ui:handleEvent(Event:new("EnterFlippingMode", self.flipping_zoom_mode))
|
||||
end
|
||||
|
||||
function ReaderPaging:exitFlippingMode()
|
||||
self.ui:handleEvent(Event:new("ExitFlippingMode"))
|
||||
self.view.document.configurable.text_wrap = self.orig_reflow_mode
|
||||
self.view.page_scroll = self.orig_scroll_mode
|
||||
DGESDETECT_DISABLE_DOUBLE_TAP = self.DGESDETECT_DISABLE_DOUBLE_TAP
|
||||
Input.disable_double_tap = DGESDETECT_DISABLE_DOUBLE_TAP
|
||||
Input.disable_double_tap = true
|
||||
self.flipping_zoom_mode = self.view.zoom_mode
|
||||
self.flipping_scroll_mode = self.view.page_scroll
|
||||
DEBUG("restore zoom mode", self.orig_zoom_mode)
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", self.orig_zoom_mode))
|
||||
self.ui:handleEvent(Event:new("ExitFlippingMode", self.orig_zoom_mode))
|
||||
end
|
||||
|
||||
function ReaderPaging:updateOriginalPage(page)
|
||||
|
||||
@@ -113,7 +113,7 @@ function ReaderZooming:onReadSettings(config)
|
||||
end
|
||||
|
||||
function ReaderZooming:onSaveSettings()
|
||||
self.ui.doc_settings:saveSetting("zoom_mode", self.zoom_mode)
|
||||
self.ui.doc_settings:saveSetting("zoom_mode", self.orig_zoom_mode or self.zoom_mode)
|
||||
end
|
||||
|
||||
function ReaderZooming:onSpread(arg, ges)
|
||||
@@ -141,7 +141,6 @@ end
|
||||
function ReaderZooming:onToggleFreeZoom(arg, ges)
|
||||
if self.zoom_mode ~= "free" then
|
||||
self.orig_zoom = self.zoom
|
||||
self.orig_zoom_mode = self.zoom_mode
|
||||
local xpos, ypos
|
||||
self.zoom, xpos, ypos = self:getRegionalZoomCenter(self.current_page, ges.pos)
|
||||
DEBUG("zoom center", self.zoom, xpos, ypos)
|
||||
@@ -152,7 +151,7 @@ function ReaderZooming:onToggleFreeZoom(arg, ges)
|
||||
end
|
||||
self.view:SetZoomCenter(xpos, ypos)
|
||||
else
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", self.orig_zoom_mode or "page"))
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", "page"))
|
||||
end
|
||||
end
|
||||
|
||||
@@ -207,6 +206,20 @@ function ReaderZooming:onReZoom()
|
||||
return true
|
||||
end
|
||||
|
||||
function ReaderZooming:onEnterFlippingMode(zoom_mode)
|
||||
self.orig_zoom_mode = self.zoom_mode
|
||||
if zoom_mode == "free" then
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", "page"))
|
||||
else
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", zoom_mode))
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderZooming:onExitFlippingMode(zoom_mode)
|
||||
self.orig_zoom_mode = nil
|
||||
self.ui:handleEvent(Event:new("SetZoomMode", zoom_mode))
|
||||
end
|
||||
|
||||
function ReaderZooming:getZoom(pageno)
|
||||
-- check if we're in bbox mode and work on bbox if that's the case
|
||||
local zoom = nil
|
||||
@@ -254,22 +267,19 @@ end
|
||||
function ReaderZooming:getRegionalZoomCenter(pageno, pos)
|
||||
local p_pos = self.view:getSinglePagePosition(pos)
|
||||
local page_size = self.ui.document:getNativePageDimensions(pageno)
|
||||
local pos_x = p_pos.x / page_size.w / p_pos.zoom
|
||||
local pos_y = p_pos.y / page_size.h / p_pos.zoom
|
||||
local regions = self.ui.document:getPageRegions(pageno)
|
||||
DEBUG("get page regions", regions)
|
||||
local pos_x = p_pos.x / page_size.w
|
||||
local pos_y = p_pos.y / page_size.h
|
||||
local block = self.ui.document:getPageBlock(pageno, pos_x, pos_y)
|
||||
local margin = self.ui.document.configurable.page_margin * Screen:getDPI()
|
||||
for i = 1, #regions do
|
||||
if regions[i].x0 <= pos_x and pos_x <= regions[i].x1
|
||||
and regions[i].y0 <= pos_y and pos_y <= regions[i].y1 then
|
||||
local zoom = 1/(regions[i].x1 - regions[i].x0)
|
||||
zoom = zoom/(1 + 3*margin/zoom/page_size.w)
|
||||
local xpos = (regions[i].x0 + regions[i].x1)/2 * zoom * page_size.w
|
||||
local ypos = p_pos.y / p_pos.zoom * zoom
|
||||
return zoom, xpos, ypos
|
||||
end
|
||||
if block then
|
||||
local zoom = self.dimen.w / page_size.w / (block.x1 - block.x0)
|
||||
zoom = zoom/(1 + 3*margin/zoom/page_size.w)
|
||||
local xpos = (block.x0 + block.x1)/2 * zoom * page_size.w
|
||||
local ypos = p_pos.y / p_pos.zoom * zoom
|
||||
return zoom, xpos, ypos
|
||||
end
|
||||
return 2
|
||||
local zoom = 2*self.dimen.w / page_size.w
|
||||
return zoom/(1 + 3*margin/zoom/page_size.w)
|
||||
end
|
||||
|
||||
function ReaderZooming:setZoom()
|
||||
|
||||
@@ -88,7 +88,7 @@ local Input = {
|
||||
},
|
||||
|
||||
timer_callbacks = {},
|
||||
disable_double_tap = DGESDETECT_DISABLE_DOUBLE_TAP,
|
||||
disable_double_tap = true,
|
||||
|
||||
-- keyboard state:
|
||||
modifiers = {
|
||||
|
||||
@@ -69,8 +69,8 @@ function DjvuDocument:getOCRText(pageno, tboxes)
|
||||
return self.koptinterface:getOCRText(self, pageno, tboxes)
|
||||
end
|
||||
|
||||
function DjvuDocument:getPageRegions(pageno)
|
||||
return self.koptinterface:getPageRegions(self, pageno)
|
||||
function DjvuDocument:getPageBlock(pageno, x, y)
|
||||
return self.koptinterface:getPageBlock(self, pageno, x, y)
|
||||
end
|
||||
|
||||
function DjvuDocument:getUsedBBox(pageno)
|
||||
|
||||
@@ -540,10 +540,11 @@ end
|
||||
--[[
|
||||
get page regions in native page via optical method,
|
||||
--]]
|
||||
function KoptInterface:getPageRegions(doc, pageno)
|
||||
function KoptInterface:getPageBlock(doc, pageno, x, y)
|
||||
local kctx = nil
|
||||
local bbox = doc:getPageBBox(pageno)
|
||||
local context_hash = self:getContextHash(doc, pageno, bbox)
|
||||
local hash = "pageregions|"..context_hash
|
||||
local hash = "pageblocks|"..context_hash
|
||||
local cached = Cache:check(hash)
|
||||
if not cached then
|
||||
local page_size = Document.getNativePageDimensions(doc, pageno)
|
||||
@@ -553,17 +554,19 @@ function KoptInterface:getPageRegions(doc, pageno)
|
||||
y1 = page_size.h,
|
||||
}
|
||||
local kc = self:createContext(doc, pageno, bbox)
|
||||
kc:setZoom(1.0)
|
||||
local screen_size = Screen:getSize()
|
||||
-- leptonica needs a source image of at least 300dpi
|
||||
kc:setZoom(screen_size.w / page_size.w * 300 / self.screen_dpi)
|
||||
local page = doc._document:openPage(pageno)
|
||||
page:getPagePix(kc)
|
||||
local regions = kc:getPageRegions()
|
||||
Cache:insert(hash, CacheItem:new{ pageregions = regions })
|
||||
kc:findPageBlocks()
|
||||
Cache:insert(hash, CacheItem:new{ kctx = kc })
|
||||
page:close()
|
||||
kc:free()
|
||||
return regions
|
||||
kctx = kc
|
||||
else
|
||||
return cached.pageregions
|
||||
kctx = cached.kctx
|
||||
end
|
||||
return kctx:getPageBlock(x, y)
|
||||
end
|
||||
|
||||
--[[
|
||||
|
||||
@@ -77,8 +77,8 @@ function PdfDocument:getOCRText(pageno, tboxes)
|
||||
return self.koptinterface:getOCRText(self, pageno, tboxes)
|
||||
end
|
||||
|
||||
function PdfDocument:getPageRegions(pageno)
|
||||
return self.koptinterface:getPageRegions(self, pageno)
|
||||
function PdfDocument:getPageBlock(pageno, x, y)
|
||||
return self.koptinterface:getPageBlock(self, pageno, x, y)
|
||||
end
|
||||
|
||||
function PdfDocument:getUsedBBox(pageno)
|
||||
|
||||
@@ -181,8 +181,6 @@ function UIManager:close(widget, refreshtype, refreshregion)
|
||||
return
|
||||
end
|
||||
dbg("close widget", widget.id)
|
||||
-- TODO: Why do we the following?
|
||||
Input.disable_double_tap = DGESDETECT_DISABLE_DOUBLE_TAP
|
||||
local dirty = false
|
||||
for i = #self._window_stack, 1, -1 do
|
||||
if self._window_stack[i].widget == widget then
|
||||
|
||||
Reference in New Issue
Block a user