add text highlight in both reflow and non-reflow mode

pull/85/head
chrox 11 years ago
parent 7f53ddacbe
commit 936dfc6fd1

@ -66,7 +66,10 @@ customupdate: all
cp -p README.md COPYING $(KOR_BASE)/{koreader-base,extr} koreader.sh $(LUA_FILES) $(INSTALL_DIR) cp -p README.md COPYING $(KOR_BASE)/{koreader-base,extr} koreader.sh $(LUA_FILES) $(INSTALL_DIR)
$(STRIP) --strip-unneeded $(INSTALL_DIR)/koreader-base $(INSTALL_DIR)/extr $(STRIP) --strip-unneeded $(INSTALL_DIR)/koreader-base $(INSTALL_DIR)/extr
mkdir $(INSTALL_DIR)/data mkdir $(INSTALL_DIR)/data
cp -L koreader-base/$(DJVULIB) $(KOR_BASE)/$(CRELIB) $(KOR_BASE)/$(LUALIB) $(KOR_BASE)/$(K2PDFOPTLIB) $(INSTALL_DIR)/libs cp -L koreader-base/$(DJVULIB) $(KOR_BASE)/$(CRELIB) \
$(KOR_BASE)/$(LUALIB) $(KOR_BASE)/$(K2PDFOPTLIB) \
$(KOR_BASE)/$(LEPTONICALIB) $(KOR_BASE)/$(TESSERACTLIB) \
$(INSTALL_DIR)/libs
$(STRIP) --strip-unneeded $(INSTALL_DIR)/libs/* $(STRIP) --strip-unneeded $(INSTALL_DIR)/libs/*
cp -rpL $(KOR_BASE)/data/*.css $(INSTALL_DIR)/data cp -rpL $(KOR_BASE)/data/*.css $(INSTALL_DIR)/data
cp -rpL $(KOR_BASE)/fonts $(INSTALL_DIR) cp -rpL $(KOR_BASE)/fonts $(INSTALL_DIR)

@ -47,6 +47,25 @@ function validDjvuFile(filename)
return true return true
end end
function DjvuDocument:getPageText(pageno)
if self.configurable.text_wrap == 1 then
return self.koptinterface:getPageText(self, pageno)
else
return self._document:getPageText(pageno)
end
end
function DjvuDocument:getOCRWord(pageno, rect)
if self.configurable.text_wrap == 1 then
return self.koptinterface:getOCRWord(self, pageno, rect)
else
--local page = self._document:openPage(pageno)
--local word = page:getOCRWord(rect)
--page:close()
--return word
end
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 = {}

@ -184,6 +184,14 @@ function Document:getToc()
return self._document:getToc() return self._document:getToc()
end end
function Document:getPageText(pageno)
return nil
end
function Document:getOCRWord(pageno, rect)
return nil
end
function Document:renderPage(pageno, rect, zoom, rotation, gamma, render_mode) function Document:renderPage(pageno, rect, zoom, rotation, gamma, render_mode)
local hash = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..gamma.."|"..render_mode local hash = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..gamma.."|"..render_mode
local page_size = self:getPageDimensions(pageno, zoom, rotation) local page_size = self:getPageDimensions(pageno, zoom, rotation)

@ -1,9 +1,23 @@
require "dbg"
require "cache" require "cache"
require "ui/geometry" require "ui/geometry"
require "ui/device" require "ui/device"
require "ui/reader/readerconfig" require "ui/reader/readerconfig"
KoptInterface = {} KoptInterface = {
tessocr_data = "data",
ocr_lang = "eng",
ocr_type = 0, -- default, for more accuracy use 3
}
ContextCacheItem = CacheItem:new{}
function ContextCacheItem:onFree()
if self.kctx.free then
DEBUG("free koptcontext", self.kctx)
self.kctx:free()
end
end
function KoptInterface:waitForContext(kc) function KoptInterface:waitForContext(kc)
-- if koptcontext is being processed in background thread -- if koptcontext is being processed in background thread
@ -12,10 +26,13 @@ function KoptInterface:waitForContext(kc)
DEBUG("waiting for background rendering") DEBUG("waiting for background rendering")
util.usleep(100000) util.usleep(100000)
end end
return kc
end end
-- get reflow context --[[
function KoptInterface:getKOPTContext(doc, pageno, bbox) get reflow context
--]]
function KoptInterface:createContext(doc, pageno, bbox)
-- Now koptcontext keeps track of its dst bitmap reflowed by libk2pdfopt. -- Now koptcontext keeps track of its dst bitmap reflowed by libk2pdfopt.
-- So there is no need to check background context when creating new context. -- So there is no need to check background context when creating new context.
local kc = KOPTContext.new() local kc = KOPTContext.new()
@ -37,6 +54,7 @@ function KoptInterface:getKOPTContext(doc, pageno, bbox)
kc:setLineSpacing(doc.configurable.line_spacing) kc:setLineSpacing(doc.configurable.line_spacing)
kc:setWordSpacing(doc.configurable.word_spacing) kc:setWordSpacing(doc.configurable.word_spacing)
kc:setBBox(bbox.x0, bbox.y0, bbox.x1, bbox.y1) kc:setBBox(bbox.x0, bbox.y0, bbox.x1, bbox.y1)
if Dbg.is_on then kc:setDebug() end
return kc return kc
end end
@ -47,17 +65,6 @@ function KoptInterface:getContextHash(doc, pageno, bbox)
return doc.file.."|"..pageno.."|"..doc.configurable:hash("|").."|"..bbox_hash.."|"..screen_size_hash return doc.file.."|"..pageno.."|"..doc.configurable:hash("|").."|"..bbox_hash.."|"..screen_size_hash
end end
function KoptInterface:logReflowDuration(pageno, dur)
local file = io.open("reflowlog.txt", "a+")
if file then
if file:seek("end") == 0 then -- write the header only once
file:write("PAGE\tDUR\n")
end
file:write(string.format("%s\t%s\n", pageno, dur))
file:close()
end
end
function KoptInterface:getAutoBBox(doc, pageno) function KoptInterface:getAutoBBox(doc, pageno)
local bbox = { local bbox = {
x0 = 0, y0 = 0, x0 = 0, y0 = 0,
@ -68,26 +75,68 @@ function KoptInterface:getAutoBBox(doc, pageno)
local cached = Cache:check(hash) local cached = Cache:check(hash)
if not cached then if not cached then
local page = doc._document:openPage(pageno) local page = doc._document:openPage(pageno)
local kc = self:getKOPTContext(doc, pageno, bbox) local kc = self:createContext(doc, pageno, bbox)
bbox.x0, bbox.y0, bbox.x1, bbox.y1 = page:getAutoBBox(kc) bbox.x0, bbox.y0, bbox.x1, bbox.y1 = page:getAutoBBox(kc)
DEBUG("Auto detected bbox", bbox) DEBUG("Auto detected bbox", bbox)
page:close() page:close()
Cache:insert(hash, CacheItem:new{ bbox = bbox }) Cache:insert(hash, CacheItem:new{ autobbox = bbox })
return bbox return bbox
else else
return cached.bbox return cached.autobbox
end
end
function KoptInterface:getPageText(doc, pageno)
local bbox = doc:getPageBBox(pageno)
local context_hash = self:getContextHash(doc, pageno, bbox)
local hash = "pgtext|"..context_hash
local cached = Cache:check(hash)
if not cached then
local kctx_hash = "kctx|"..context_hash
local cached = Cache:check(kctx_hash)
if cached then
local kc = self:waitForContext(cached.kctx)
local fullwidth, fullheight = kc:getPageDim()
local text = kc:getWordBoxes(0, 0, fullwidth, fullheight)
Cache:insert(hash, CacheItem:new{ pgtext = text })
return text
end
else
return cached.pgtext
end end
end end
-- get reflowed page dimension from a cached context. wait for background thread function KoptInterface:getOCRWord(doc, pageno, rect)
-- if necessary. local bbox = doc:getPageBBox(pageno)
function KoptInterface:getReflowedDim(kctx) local context_hash = self:getContextHash(doc, pageno, bbox)
self:waitForContext(kctx) local hash = "ocrword|"..context_hash..rect.x..rect.y..rect.w..rect.h
return kctx:getPageDim() local cached = Cache:check(hash)
if not cached then
local kctx_hash = "kctx|"..context_hash
local cached = Cache:check(kctx_hash)
if cached then
local kc = self:waitForContext(cached.kctx)
local fullwidth, fullheight = kc:getPageDim()
local ok, word = pcall(
kc.getOCRWord, kc,
self.tessocr_data,
self.ocr_lang,
self.ocr_type,
rect.x, rect.y,
rect.w, rect.h)
Cache:insert(hash, CacheItem:new{ ocrword = word })
return word
end
else
return cached.ocrword
end
end end
-- get cached koptcontext for centain page. if context doesn't exist in cache make --[[
-- new context and reflow the src page immediatly. get cached koptcontext for centain page. if context doesn't exist in cache make
new context and reflow the src page immediatly, or wait background thread for
reflowed context.
--]]
function KoptInterface:getCachedContext(doc, pageno) function KoptInterface:getCachedContext(doc, pageno)
local bbox = doc:getPageBBox(pageno) local bbox = doc:getPageBBox(pageno)
local context_hash = self:getContextHash(doc, pageno, bbox) local context_hash = self:getContextHash(doc, pageno, bbox)
@ -95,7 +144,7 @@ function KoptInterface:getCachedContext(doc, pageno)
local cached = Cache:check(kctx_hash) local cached = Cache:check(kctx_hash)
if not cached then if not cached then
-- If kctx is not cached, create one and get reflowed bmp in foreground. -- If kctx is not cached, create one and get reflowed bmp in foreground.
local kc = self:getKOPTContext(doc, pageno, bbox) local kc = self:createContext(doc, pageno, bbox)
local page = doc._document:openPage(pageno) local page = doc._document:openPage(pageno)
-- reflow page -- reflow page
--local secs, usecs = util.gettime() --local secs, usecs = util.gettime()
@ -107,22 +156,27 @@ function KoptInterface:getCachedContext(doc, pageno)
--self:logReflowDuration(pageno, dur) --self:logReflowDuration(pageno, dur)
local fullwidth, fullheight = kc:getPageDim() local fullwidth, fullheight = kc:getPageDim()
DEBUG("reflowed page", pageno, "fullwidth:", fullwidth, "fullheight:", fullheight) DEBUG("reflowed page", pageno, "fullwidth:", fullwidth, "fullheight:", fullheight)
Cache:insert(kctx_hash, CacheItem:new{ kctx = kc }) Cache:insert(kctx_hash, ContextCacheItem:new{ kctx = kc })
return kc return kc
else else
return cached.kctx -- wait for background thread
return self:waitForContext(cached.kctx)
end end
end end
-- get reflowed page dimensions --[[
get reflowed page dimensions
--]]
function KoptInterface:getPageDimensions(doc, pageno, zoom, rotation) function KoptInterface:getPageDimensions(doc, pageno, zoom, rotation)
local kctx = self:getCachedContext(doc, pageno) local kc = self:getCachedContext(doc, pageno)
local fullwidth, fullheight = self:getReflowedDim(kctx) local fullwidth, fullheight = kc:getPageDim()
return Geom:new{ w = fullwidth, h = fullheight } return Geom:new{ w = fullwidth, h = fullheight }
end end
-- inherited from common document interface --[[
-- render reflowed page into tile cache. inherited from common document interface
render reflowed page into tile cache.
--]]
function KoptInterface:renderPage(doc, pageno, rect, zoom, rotation, render_mode) function KoptInterface:renderPage(doc, pageno, rect, zoom, rotation, render_mode)
doc.render_mode = render_mode doc.render_mode = render_mode
local bbox = doc:getPageBBox(pageno) local bbox = doc:getPageBBox(pageno)
@ -132,8 +186,8 @@ function KoptInterface:renderPage(doc, pageno, rect, zoom, rotation, render_mode
local cached = Cache:check(renderpg_hash) local cached = Cache:check(renderpg_hash)
if not cached then if not cached then
-- do the real reflowing if kctx is not been cached yet -- do the real reflowing if kctx is not been cached yet
local kctx = self:getCachedContext(doc, pageno) local kc = self:getCachedContext(doc, pageno)
local fullwidth, fullheight = self:getReflowedDim(kctx) local fullwidth, fullheight = kc:getPageDim()
if not Cache:willAccept(fullwidth * fullheight / 2) then if not Cache:willAccept(fullwidth * fullheight / 2) then
-- whole page won't fit into cache -- whole page won't fit into cache
error("aborting, since we don't have enough cache for this page") error("aborting, since we don't have enough cache for this page")
@ -146,10 +200,8 @@ function KoptInterface:renderPage(doc, pageno, rect, zoom, rotation, render_mode
pageno = pageno, pageno = pageno,
bb = Blitbuffer.new(fullwidth, fullheight) bb = Blitbuffer.new(fullwidth, fullheight)
} }
page:rfdraw(kctx, tile.bb) page:rfdraw(kc, tile.bb)
page:close() page:close()
-- free dst bitmap in kctx as soon as we draw the bitmap to blitbuffer
kctx:free()
Cache:insert(renderpg_hash, tile) Cache:insert(renderpg_hash, tile)
return tile return tile
else else
@ -157,29 +209,33 @@ function KoptInterface:renderPage(doc, pageno, rect, zoom, rotation, render_mode
end end
end end
-- inherited from common document interface --[[
-- render reflowed page into cache in background thread. this method returns immediatly inherited from common document interface
-- leaving the precache flag on in context. subsequent usage of this context should render reflowed page into cache in background thread. this method returns immediatly
-- wait for the precache flag off by calling self:waitForContext(kctx) leaving the precache flag on in context. subsequent usage of this context should
wait for the precache flag off by calling self:waitForContext(kctx)
--]]
function KoptInterface:hintPage(doc, pageno, zoom, rotation, gamma, render_mode) function KoptInterface:hintPage(doc, pageno, zoom, rotation, gamma, render_mode)
local bbox = doc:getPageBBox(pageno) local bbox = doc:getPageBBox(pageno)
local context_hash = self:getContextHash(doc, pageno, bbox) local context_hash = self:getContextHash(doc, pageno, bbox)
local kctx_hash = "kctx|"..context_hash local kctx_hash = "kctx|"..context_hash
local cached = Cache:check(kctx_hash) local cached = Cache:check(kctx_hash)
if not cached then if not cached then
local kc = self:getKOPTContext(doc, pageno, bbox) local kc = self:createContext(doc, pageno, bbox)
local page = doc._document:openPage(pageno) local page = doc._document:openPage(pageno)
DEBUG("hinting page", pageno, "in background") DEBUG("hinting page", pageno, "in background")
-- reflow will return immediately and running in background thread -- reflow will return immediately and running in background thread
kc:setPreCache() kc:setPreCache()
page:reflow(kc, 0) page:reflow(kc, 0)
page:close() page:close()
Cache:insert(kctx_hash, CacheItem:new{ kctx = kc }) Cache:insert(kctx_hash, ContextCacheItem:new{ kctx = kc })
end end
end end
-- inherited from common document interface --[[
-- draw cached tile pixels into target blitbuffer inherited from common document interface
draw cached tile pixels into target blitbuffer.
--]]
function KoptInterface:drawPage(doc, target, x, y, rect, pageno, zoom, rotation, render_mode) function KoptInterface:drawPage(doc, target, x, y, rect, pageno, zoom, rotation, render_mode)
local tile = self:renderPage(doc, pageno, rect, zoom, rotation, render_mode) local tile = self:renderPage(doc, pageno, rect, zoom, rotation, render_mode)
--DEBUG("now painting", tile, rect) --DEBUG("now painting", tile, rect)
@ -189,3 +245,17 @@ function KoptInterface:drawPage(doc, target, x, y, rect, pageno, zoom, rotation,
rect.y - tile.excerpt.y, rect.y - tile.excerpt.y,
rect.w, rect.h) rect.w, rect.h)
end end
--[[
helper functions
--]]
function KoptInterface:logReflowDuration(pageno, dur)
local file = io.open("reflowlog.txt", "a+")
if file then
if file:seek("end") == 0 then -- write the header only once
file:write("PAGE\tDUR\n")
end
file:write(string.format("%s\t%s\n", pageno, dur))
file:close()
end
end

@ -44,6 +44,28 @@ function PdfDocument:unlock(password)
return self:_readMetadata() return self:_readMetadata()
end end
function PdfDocument:getPageText(pageno)
if self.configurable.text_wrap == 1 then
return self.koptinterface:getPageText(self, pageno)
else
local page = self._document:openPage(pageno)
local text = page:getPageText()
page:close()
return text
end
end
function PdfDocument:getOCRWord(pageno, rect)
if self.configurable.text_wrap == 1 then
return self.koptinterface:getOCRWord(self, pageno, rect)
else
--local page = self._document:openPage(pageno)
--local word = page:getOCRWord(rect)
--page:close()
--return word
end
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)

@ -0,0 +1,24 @@
require "ui/device"
ReaderDictionary = EventListener:new{}
function ReaderDictionary:init()
local dev_mod = Device:getModel()
if dev_mod == "KindlePaperWhite" or dev_mod == "KindleTouch" then
require "liblipclua"
self.lipc_handle = lipc.init("com.github.koreader.dictionary")
end
end
function ReaderDictionary:onLookupWord(word)
DEBUG("lookup word:", word)
if self.lipc_handle then
-- start indicator depends on pillow being enabled
self.lipc_handle:set_string_property(
"com.lab126.booklet.kpvbooklet.dict", "lookup", word)
local definitions = self.lipc_handle:get_string_property(
"com.lab126.booklet.kpvbooklet.word", word)
DEBUG("definitions of word:", word, definitions)
end
return true
end

@ -0,0 +1,125 @@
ReaderHighlight = InputContainer:new{}
function ReaderHighlight:init()
if Device:hasKeyboard() then
self.key_events = {
ShowToc = {
{ "." },
doc = _("highlight text") },
}
end
end
function ReaderHighlight:initGesListener()
self.ges_events = {
Tap = {
GestureRange:new{
ges = "tap",
range = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight()
}
}
},
Hold = {
GestureRange:new{
ges = "hold",
range = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight()
}
}
},
}
end
function ReaderHighlight:onSetDimensions(dimen)
-- update listening according to new screen dimen
if Device:isTouchDevice() then
self:initGesListener()
end
end
function ReaderHighlight:onTap(arg, ges)
if self.view.highlight.rect then
self.view.highlight.rect = nil
UIManager:setDirty(self.dialog, "partial")
return true
end
end
function ReaderHighlight:onHold(arg, ges)
self.pos = self.view:screenToPageTransform(ges.pos)
DEBUG("hold position in page", self.pos)
local text = self.ui.document:getPageText(self.pos.page)
--DEBUG("page text", text)
if not text or #text == 0 then
DEBUG("no text extracted")
return true
end
self.word_info = self:getWordFromText(text, self.pos)
DEBUG("hold word info in page", self.word_info)
if self.word_info then
local screen_rect = self.view:pageToScreenTransform(self.pos.page, self.word_info.box)
DEBUG("highlight word rect", screen_rect)
if screen_rect then
self.view.highlight.rect = screen_rect
UIManager:setDirty(self.dialog, "partial")
-- if we extracted text directly
if self.word_info.word then
self.ui:handleEvent(Event:new("LookupWord", self.word_info.word))
-- or we will do OCR
else
UIManager:scheduleIn(0.1, function()
local word_box = self.word_info.box
word_box.x = word_box.x - math.floor(word_box.h * 0.02)
word_box.y = word_box.y - math.floor(word_box.h * 0.02)
word_box.w = word_box.w + math.floor(word_box.h * 0.04)
word_box.h = word_box.h + math.floor(word_box.h * 0.04)
local word = self.ui.document:getOCRWord(self.pos.page, word_box)
DEBUG("OCRed word:", word)
self.ui:handleEvent(Event:new("LookupWord", word))
end)
end
end
end
return true
end
function ReaderHighlight:getWordFromText(text, pos)
local function ges_inside(x0, y0, x1, y1)
local x, y = pos.x, pos.y
if x0 ~= nil and y0 ~= nil and x1 ~= nil and y1 ~= nil then
if x0 <= x and y0 <= y and x1 >= x and y1 >= y then
return true
end
end
return false
end
for i = 1, #text do
local l = text[i]
if ges_inside(l.x0, l.y0, l.x1, l.y1) then
--DEBUG("line box", l.x0, l.y0, l.x1, l.y1)
for j = 1, #text[i] do
local w = text[i][j]
if ges_inside(w.x0, w.y0, w.x1, w.y1) then
local box = Geom:new{
x = w.x0, y = w.y0,
w = w.x1 - w.x0,
h = w.y1 - w.y0,
}
return {
word = w.word,
box = box,
}
end -- end if inside word box
end -- end for each word
end -- end if inside line box
end -- end for each line
end

@ -41,3 +41,11 @@ end
function ReaderKoptListener:onFineTuningFontSize(delta) function ReaderKoptListener:onFineTuningFontSize(delta)
self.document.configurable.font_size = self.document.configurable.font_size + delta self.document.configurable.font_size = self.document.configurable.font_size + delta
end end
function ReaderKoptListener:onZoomUpdate(zoom)
-- an exceptional case is reflow mode
if self.document.configurable.text_wrap == 1 then
self.view.state.zoom = 1.0
end
end

@ -16,6 +16,10 @@ ReaderView = OverlapGroup:new{
bbox = nil, bbox = nil,
}, },
outer_page_color = 0, outer_page_color = 0,
-- hightlight
highlight = {
drawer = "marker" -- show as inverted block instead of underline
},
-- PDF/DjVu continuous paging -- PDF/DjVu continuous paging
page_scroll = nil, page_scroll = nil,
page_bgcolor = 0, page_bgcolor = 0,
@ -96,6 +100,11 @@ function ReaderView:paintTo(bb, x, y)
self.dim_area.w, self.dim_area.h self.dim_area.w, self.dim_area.h
) )
end end
-- draw highlight
if self.highlight.rect then
self:drawHightlight(bb, x, y, self.highlight.rect)
end
-- paint dogear -- paint dogear
if self.dogear_visible then if self.dogear_visible then
@ -113,6 +122,32 @@ function ReaderView:paintTo(bb, x, y)
self.ui:handleEvent(Event:new("StopActivityIndicator")) self.ui:handleEvent(Event:new("StopActivityIndicator"))
end end
--[[
Given coordinates on the screen return position in original page
]]--
function ReaderView:screenToPageTransform(pos)
if self.ui.document.info.has_pages then
if self.page_scroll then
return self:getScrollPagePosition(pos)
else
return self:getSinglePagePosition(pos)
end
end
end
--[[
Given rectangle in original page return rectangle on the screen
]]--
function ReaderView:pageToScreenTransform(page, rect)
if self.ui.document.info.has_pages then
if self.page_scroll then
return self:getScrollPageRect(page, rect)
else
return self:getSinglePageRect(rect)
end
end
end
function ReaderView:drawPageBackground(bb, x, y) function ReaderView:drawPageBackground(bb, x, y)
bb:paintRect(x, y, self.dimen.w, self.dimen.h, self.page_bgcolor) bb:paintRect(x, y, self.dimen.w, self.dimen.h, self.page_bgcolor)
end end
@ -155,6 +190,40 @@ function ReaderView:drawScrollPages(bb, x, y)
end) end)
end end
function ReaderView:getScrollPagePosition(pos)
local x_s, y_s = pos.x, pos.y
local x_p, y_p = nil, nil
for _, state in ipairs(self.page_states) do
if y_s < state.visible_area.h + state.offset.y then
y_p = (state.visible_area.y + y_s - state.offset.y) / state.zoom
x_p = (state.visible_area.x + x_s - state.offset.x) / state.zoom
return {
x = x_p,
y = y_p,
page = state.page,
zoom = state.zoom,
rotation = state.rotation,
}
else
y_s = y_s - state.visible_area.h - self.page_gap.height
end
end
end
function ReaderView:getScrollPageRect(page, rect_p)
local rect_s = Geom:new{}
for _, state in ipairs(self.page_states) do
if page == state.page and state.visible_area:contains(rect_p) then
rect_s.x = rect_s.x + state.offset.x + rect_p.x*state.zoom - state.visible_area.x
rect_s.y = rect_s.y + state.offset.y + rect_p.y*state.zoom - state.visible_area.y
rect_s.w = rect_p.w * state.zoom
rect_s.h = rect_p.h * state.zoom
return rect_s
end
rect_s.y = rect_s.y + state.visible_area.h + self.page_gap.height
end
end
function ReaderView:drawPageGap(bb, x, y) function ReaderView:drawPageGap(bb, x, y)
if self.scroll_mode == "vertical" then if self.scroll_mode == "vertical" then
bb:paintRect(x, y, self.dimen.w, self.page_gap.height, self.page_gap.color) bb:paintRect(x, y, self.dimen.w, self.page_gap.height, self.page_gap.color)
@ -179,6 +248,28 @@ function ReaderView:drawSinglePage(bb, x, y)
end) end)
end end
function ReaderView:getSinglePagePosition(pos)
local x_s, y_s = pos.x, pos.y
return {
x = (self.visible_area.x + x_s - self.state.offset.x) / self.state.zoom,
y = (self.visible_area.y + y_s - self.state.offset.y) / self.state.zoom,
page = self.state.page,
zoom = self.state.zoom,
rotation = self.state.rotation,
}
end
function ReaderView:getSinglePageRect(rect_p)
local rect_s = Geom:new{}
if self.visible_area:contains(rect_p) then
rect_s.x = self.state.offset.x + rect_p.x * self.state.zoom - self.visible_area.x
rect_s.y = self.state.offset.y + rect_p.y * self.state.zoom - self.visible_area.y
rect_s.w = rect_p.w * self.state.zoom
rect_s.h = rect_p.h * self.state.zoom
return rect_s
end
end
function ReaderView:drawPageView(bb, x, y) function ReaderView:drawPageView(bb, x, y)
self.ui.document:drawCurrentViewByPage( self.ui.document:drawCurrentViewByPage(
bb, bb,
@ -197,6 +288,26 @@ function ReaderView:drawScrollView(bb, x, y)
self.state.pos) self.state.pos)
end end
function ReaderView:drawHightlight(bb, x, y, rect)
-- slightly enlarge the highlight box
-- for better viewing experience
local x = rect.x - rect.h * 0.01
local y = rect.y - rect.h * 0.01
local w = rect.w + rect.h * 0.02
local h = rect.h + rect.h * 0.02
self.highlight.drawer = self.highlight.drawer or "underscore"
if self.highlight.drawer == "underscore" then
self.highlight.line_width = self.highlight.line_width or 2
self.highlight.line_color = self.highlight.line_color or 5
bb:paintRect(x, y+h-1, w,
self.highlight.line_width,
self.highlight.line_color)
elseif self.highlight.drawer == "marker" then
bb:invertRect(x, y, w, h)
end
end
function ReaderView:getPageArea(page, zoom, rotation) function ReaderView:getPageArea(page, zoom, rotation)
if self.use_bbox then if self.use_bbox then
return self.ui.document:getUsedBBoxDimensions(page, zoom, rotation) return self.ui.document:getUsedBBoxDimensions(page, zoom, rotation)

@ -14,8 +14,10 @@ require "ui/reader/readercropping"
require "ui/reader/readerkopt" require "ui/reader/readerkopt"
require "ui/reader/readercopt" require "ui/reader/readercopt"
require "ui/reader/readerhinting" require "ui/reader/readerhinting"
require "ui/reader/readerhighlight"
require "ui/reader/readerscreenshot" require "ui/reader/readerscreenshot"
require "ui/reader/readerfrontlight" require "ui/reader/readerfrontlight"
require "ui/reader/readerdictionary"
require "ui/reader/readerhyphenation" require "ui/reader/readerhyphenation"
require "ui/reader/readeractivityindicator" require "ui/reader/readeractivityindicator"
@ -96,6 +98,22 @@ function ReaderUI:init()
ui = self ui = self
} }
table.insert(self, reader_bm) table.insert(self, reader_bm)
-- text highlight
local highlight = ReaderHighlight:new{
dialog = self.dialog,
view = self[1],
ui = self,
document = self.document,
}
table.insert(self, highlight)
-- dictionary
local dict = ReaderDictionary:new{
dialog = self.dialog,
view = self[1],
ui = self,
document = self.document,
}
table.insert(self, dict)
-- screenshot controller -- screenshot controller
local reader_ss = ReaderScreenshot:new{ local reader_ss = ReaderScreenshot:new{
dialog = self.dialog, dialog = self.dialog,

@ -9,6 +9,9 @@ test -e $PROC_FIVEWAY && echo unlock > $PROC_FIVEWAY
# we're always starting from our working directory # we're always starting from our working directory
cd /mnt/us/koreader/ cd /mnt/us/koreader/
# export trained OCR data directory
export TESSDATA_PREFIX="data"
# bind-mount system fonts # bind-mount system fonts
if ! grep /mnt/us/koreader/fonts/host /proc/mounts; then if ! grep /mnt/us/koreader/fonts/host /proc/mounts; then
mount -o bind /usr/java/lib/fonts /mnt/us/koreader/fonts/host mount -o bind /usr/java/lib/fonts /mnt/us/koreader/fonts/host

Loading…
Cancel
Save