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 11 years ago
parent 4945e0ae23
commit 8e4516b824

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

@ -447,6 +447,35 @@ function KoptInterface:getNativeTextBoxesFromScratch(doc, pageno)
end end
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 get word from OCR providing selected word box
--]] --]]

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

@ -274,6 +274,35 @@ function Geom:offsetWithin(rect_b, dx, dy)
end end
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) function Geom:shrinkInside(rect_b, dx, dy)
self:offsetBy(dx, dy) self:offsetBy(dx, dy)
return self:intersect(rect_b) return self:intersect(rect_b)

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

@ -439,6 +439,30 @@ function ReaderView:PanningUpdate(dx, dy)
return true return true
end 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) function ReaderView:onSetScreenMode(new_mode, rotation)
if new_mode == "landscape" or new_mode == "portrait" then if new_mode == "landscape" or new_mode == "portrait" then
self.screen_mode = new_mode 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 end
self.ui.menu:registerToMainMenu(self) self.ui.menu:registerToMainMenu(self)
@ -126,6 +136,24 @@ function ReaderZooming:onPinch(arg, ges)
return true return true
end 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) function ReaderZooming:onSetDimensions(dimensions)
-- we were resized -- we were resized
self.dimen = dimensions self.dimen = dimensions
@ -160,9 +188,9 @@ function ReaderZooming:onSetZoomMode(new_mode)
self.view.zoom_mode = new_mode self.view.zoom_mode = new_mode
if self.zoom_mode ~= new_mode then if self.zoom_mode ~= new_mode then
DEBUG("setting zoom mode to", new_mode) DEBUG("setting zoom mode to", new_mode)
self.ui:handleEvent(Event:new("ZoomModeUpdate", new_mode))
self.zoom_mode = new_mode self.zoom_mode = new_mode
self:setZoom() self:setZoom()
self.ui:handleEvent(Event:new("ZoomModeUpdate", new_mode))
end end
end end
@ -212,15 +240,34 @@ function ReaderZooming:getZoom(pageno)
zoom = zoom_w zoom = zoom_w
elseif self.zoom_mode == "contentheight" or self.zoom_mode == "pageheight" then elseif self.zoom_mode == "contentheight" or self.zoom_mode == "pageheight" then
zoom = zoom_h zoom = zoom_h
elseif self.zoom_mode == "free" then
zoom = self.zoom
end end
return zoom return zoom
end end
function ReaderZooming:setZoom() function ReaderZooming:getRegionalZoomCenter(pageno, pos)
-- nothing to do in free zoom mode local p_pos = self.view:getSinglePagePosition(pos)
if self.zoom_mode == "free" then local page_size = self.ui.document:getNativePageDimensions(pageno)
return 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 end
return 2
end
function ReaderZooming:setZoom()
if not self.dimen then if not self.dimen then
self.dimen = self.ui.dimen self.dimen = self.ui.dimen
end end

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