add regional zoom mode in pdf/djvu page

In regional zoom mode double tap will zoom to the tapped
region(paragraph or column, etc., detected optically via libk2pdfopt).
As the first demo, this feature is only turned on in flipping mode by
tapping the top-left corner of the screen. Eventually we may incorporate
this feature in "free" zoom mode.
pull/427/head
chrox 10 years ago
parent 4945e0ae23
commit 8e4516b824

@ -80,6 +80,10 @@ function DjvuDocument:getOCRText(pageno, tboxes)
return self.koptinterface:getOCRText(self, pageno, tboxes)
end
function DjvuDocument:getPageRegions(pageno)
return self.koptinterface:getPageRegions(self, pageno)
end
function DjvuDocument:getUsedBBox(pageno)
-- djvu does not support usedbbox, so fake it.
local used = {}

@ -447,6 +447,35 @@ function KoptInterface:getNativeTextBoxesFromScratch(doc, pageno)
end
end
--[[
get page regions in native page via optical method,
--]]
function KoptInterface:getPageRegions(doc, pageno)
local bbox = doc:getPageBBox(pageno)
local context_hash = self:getContextHash(doc, pageno, bbox)
local hash = "pageregions|"..context_hash
local cached = Cache:check(hash)
if not cached then
local page_size = Document.getNativePageDimensions(doc, pageno)
local bbox = {
x0 = 0, y0 = 0,
x1 = page_size.w,
y1 = page_size.h,
}
local kc = self:createContext(doc, pageno, bbox)
kc:setZoom(1.0)
local page = doc._document:openPage(pageno)
page:getPagePix(kc)
local regions = kc:getPageRegions()
Cache:insert(hash, CacheItem:new{ pageregions = regions })
page:close()
kc:free()
return regions
else
return cached.pageregions
end
end
--[[
get word from OCR providing selected word box
--]]

@ -70,6 +70,10 @@ function PdfDocument:getOCRText(pageno, tboxes)
return self.koptinterface:getOCRText(self, pageno, tboxes)
end
function PdfDocument:getPageRegions(pageno)
return self.koptinterface:getPageRegions(self, pageno)
end
function PdfDocument:getUsedBBox(pageno)
local hash = "pgubbox|"..self.file.."|"..pageno
local cached = Cache:check(hash)

@ -274,6 +274,35 @@ function Geom:offsetWithin(rect_b, dx, dy)
end
end
--[[
center the current rectangle at position x and y of a given rectangle
]]--
function Geom:centerWithin(rect_b, x, y)
-- check size constraints and shrink us when we're too big
if self.w > rect_b.w then
self.w = rect_b.w
end
if self.h > rect_b.h then
self.h = rect_b.h
end
-- place to center
self.x = x - self.w/2
self.y = y - self.h/2
-- check boundary
if self.x < rect_b.x then
self.x = rect_b.x
end
if self.y < rect_b.y then
self.y = rect_b.y
end
if self.x + self.w > rect_b.x + rect_b.w then
self.x = rect_b.x + rect_b.w - self.w
end
if self.y + self.h > rect_b.y + rect_b.h then
self.y = rect_b.y + rect_b.h - self.h
end
end
function Geom:shrinkInside(rect_b, dx, dy)
self:offsetBy(dx, dy)
return self:intersect(rect_b)

@ -209,16 +209,26 @@ function ReaderPaging:enterFlippingMode()
self.orig_reflow_mode = self.view.document.configurable.text_wrap
self.orig_footer_mode = self.view.footer_visible
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 = false
self.view.footer_visible = true
Input.disable_double_tap = false
DGESDETECT_DISABLE_DOUBLE_TAP = false
self.ui:handleEvent(Event:new("SetZoomMode", "page"))
end
function ReaderPaging:exitFlippingMode()
self.view.document.configurable.text_wrap = self.orig_reflow_mode
self.view.page_scroll = self.orig_scroll_mode
self.view.footer_visible = self.orig_footer_mode
DGESDETECT_DISABLE_DOUBLE_TAP = self.DGESDETECT_DISABLE_DOUBLE_TAP
Input.disable_double_tap = DGESDETECT_DISABLE_DOUBLE_TAP
DEBUG("restore zoom mode", self.orig_zoom_mode)
self.ui:handleEvent(Event:new("SetZoomMode", self.orig_zoom_mode))
end
function ReaderPaging:updateOriginalPage(page)
@ -268,7 +278,11 @@ end
function ReaderPaging:onPan(arg, ges)
if self.flipping_mode then
self:flipping(self.flipping_page, ges)
if self.view.zoom_mode == "page" then
self:flipping(self.flipping_page, ges)
else
self.view:PanningStart(-ges.relative.x, -ges.relative.y)
end
elseif ges.direction == "north" or ges.direction == "south" then
self:onPanningRel(self.last_pan_relative_y - ges.relative.y)
self.last_pan_relative_y = ges.relative.y
@ -278,7 +292,11 @@ end
function ReaderPaging:onPanRelease(arg, ges)
if self.flipping_mode then
self:updateFlippingPage(self.current_page)
if self.view.zoom_mode == "page" then
self:updateFlippingPage(self.current_page)
else
self.view:PanningStop()
end
else
self.last_pan_relative_y = 0
UIManager.full_refresh = true
@ -588,7 +606,9 @@ function ReaderPaging:onGotoPageRel(diff)
local new_va = self.visible_area:copy()
local x_pan_off, y_pan_off = 0, 0
if self.zoom_mode:find("width") then
if self.zoom_mode == "free" then
-- do nothing in free zoom mode
elseif self.zoom_mode:find("width") then
y_pan_off = self.visible_area.h * diff
elseif self.zoom_mode:find("height") then
x_pan_off = self.visible_area.w * diff

@ -439,6 +439,30 @@ function ReaderView:PanningUpdate(dx, dy)
return true
end
function ReaderView:PanningStart(x, y)
DEBUG("panning start", x, y)
if not self.panning_visible_area then
self.panning_visible_area = self.visible_area:copy()
end
self.visible_area = self.panning_visible_area:copy()
self.visible_area:offsetWithin(self.page_area, x, y)
self.ui:handleEvent(Event:new("ViewRecalculate", self.visible_area, self.page_area))
UIManager:setDirty(self.dialog)
end
function ReaderView:PanningStop()
self.panning_visible_area = nil
end
function ReaderView:SetZoomCenter(x, y)
local old = self.visible_area:copy()
self.visible_area:centerWithin(self.page_area, x, y)
if self.visible_area ~= old then
self.ui:handleEvent(Event:new("ViewRecalculate", self.visible_area, self.page_area))
UIManager:setDirty(self.dialog)
end
end
function ReaderView:onSetScreenMode(new_mode, rotation)
if new_mode == "landscape" or new_mode == "portrait" then
self.screen_mode = new_mode

@ -84,6 +84,16 @@ function ReaderZooming:init()
}
}
},
ToggleFreeZoom = {
GestureRange:new{
ges = "double_tap",
range = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight(),
}
}
},
}
end
self.ui.menu:registerToMainMenu(self)
@ -126,6 +136,24 @@ function ReaderZooming:onPinch(arg, ges)
return true
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)
self.ui:handleEvent(Event:new("SetZoomMode", "free"))
if xpos == nil or ypos == nil then
xpos = ges.pos.x * self.zoom / self.orig_zoom
ypos = ges.pos.y * self.zoom / self.orig_zoom
end
self.view:SetZoomCenter(xpos, ypos)
else
self.ui:handleEvent(Event:new("SetZoomMode", self.orig_zoom_mode or "page"))
end
end
function ReaderZooming:onSetDimensions(dimensions)
-- we were resized
self.dimen = dimensions
@ -160,9 +188,9 @@ function ReaderZooming:onSetZoomMode(new_mode)
self.view.zoom_mode = new_mode
if self.zoom_mode ~= new_mode then
DEBUG("setting zoom mode to", new_mode)
self.ui:handleEvent(Event:new("ZoomModeUpdate", new_mode))
self.zoom_mode = new_mode
self:setZoom()
self.ui:handleEvent(Event:new("ZoomModeUpdate", new_mode))
end
end
@ -212,15 +240,34 @@ function ReaderZooming:getZoom(pageno)
zoom = zoom_w
elseif self.zoom_mode == "contentheight" or self.zoom_mode == "pageheight" then
zoom = zoom_h
elseif self.zoom_mode == "free" then
zoom = self.zoom
end
return zoom
end
function ReaderZooming:setZoom()
-- nothing to do in free zoom mode
if self.zoom_mode == "free" then
return
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 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
end
return 2
end
function ReaderZooming:setZoom()
if not self.dimen then
self.dimen = self.ui.dimen
end

@ -1 +1 @@
Subproject commit 8b9989a5f91d1e708a285c3e660009232ad14a08
Subproject commit bf3ef2a6c9002a665b8c224632eba744e6147fe0
Loading…
Cancel
Save