From 5983050d797bd2c08b9afc365e7c4e6a770498b6 Mon Sep 17 00:00:00 2001 From: chrox Date: Wed, 15 Jun 2016 01:50:59 +0800 Subject: [PATCH] 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) --- base | 2 +- defaults.lua | 3 -- frontend/apps/reader/modules/readerpaging.lua | 12 ++--- .../apps/reader/modules/readerzooming.lua | 44 ++++++++++++------- frontend/device/input.lua | 2 +- frontend/document/djvudocument.lua | 4 +- frontend/document/koptinterface.lua | 19 ++++---- frontend/document/pdfdocument.lua | 4 +- frontend/ui/uimanager.lua | 2 - 9 files changed, 47 insertions(+), 45 deletions(-) diff --git a/base b/base index b1b035069..6fa062f20 160000 --- a/base +++ b/base @@ -1 +1 @@ -Subproject commit b1b0350697750565f1dae9be88dd59fc1ee79446 +Subproject commit 6fa062f20cf2a7bafaaf4bd215c145c496643fc1 diff --git a/defaults.lua b/defaults.lua index 865788d5a..7a1780ffe 100644 --- a/defaults.lua +++ b/defaults.lua @@ -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 diff --git a/frontend/apps/reader/modules/readerpaging.lua b/frontend/apps/reader/modules/readerpaging.lua index 73d78d1d9..f8fc54ad9 100644 --- a/frontend/apps/reader/modules/readerpaging.lua +++ b/frontend/apps/reader/modules/readerpaging.lua @@ -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) diff --git a/frontend/apps/reader/modules/readerzooming.lua b/frontend/apps/reader/modules/readerzooming.lua index de6e1a845..915090366 100644 --- a/frontend/apps/reader/modules/readerzooming.lua +++ b/frontend/apps/reader/modules/readerzooming.lua @@ -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() diff --git a/frontend/device/input.lua b/frontend/device/input.lua index 4edccbac7..215f2d32e 100644 --- a/frontend/device/input.lua +++ b/frontend/device/input.lua @@ -88,7 +88,7 @@ local Input = { }, timer_callbacks = {}, - disable_double_tap = DGESDETECT_DISABLE_DOUBLE_TAP, + disable_double_tap = true, -- keyboard state: modifiers = { diff --git a/frontend/document/djvudocument.lua b/frontend/document/djvudocument.lua index c85fc582f..145a774d2 100644 --- a/frontend/document/djvudocument.lua +++ b/frontend/document/djvudocument.lua @@ -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) diff --git a/frontend/document/koptinterface.lua b/frontend/document/koptinterface.lua index 1b10fcbea..500919752 100644 --- a/frontend/document/koptinterface.lua +++ b/frontend/document/koptinterface.lua @@ -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 --[[ diff --git a/frontend/document/pdfdocument.lua b/frontend/document/pdfdocument.lua index 7fe9d1008..09b6f8f74 100644 --- a/frontend/document/pdfdocument.lua +++ b/frontend/document/pdfdocument.lua @@ -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) diff --git a/frontend/ui/uimanager.lua b/frontend/ui/uimanager.lua index 4710c3884..6eb3a0863 100644 --- a/frontend/ui/uimanager.lua +++ b/frontend/ui/uimanager.lua @@ -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