mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
add text highlight in both reflow and non-reflow mode
This commit is contained in:
@@ -1,9 +1,23 @@
|
||||
require "dbg"
|
||||
require "cache"
|
||||
require "ui/geometry"
|
||||
require "ui/device"
|
||||
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)
|
||||
-- if koptcontext is being processed in background thread
|
||||
@@ -12,10 +26,13 @@ function KoptInterface:waitForContext(kc)
|
||||
DEBUG("waiting for background rendering")
|
||||
util.usleep(100000)
|
||||
end
|
||||
return kc
|
||||
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.
|
||||
-- So there is no need to check background context when creating new context.
|
||||
local kc = KOPTContext.new()
|
||||
@@ -37,6 +54,7 @@ function KoptInterface:getKOPTContext(doc, pageno, bbox)
|
||||
kc:setLineSpacing(doc.configurable.line_spacing)
|
||||
kc:setWordSpacing(doc.configurable.word_spacing)
|
||||
kc:setBBox(bbox.x0, bbox.y0, bbox.x1, bbox.y1)
|
||||
if Dbg.is_on then kc:setDebug() end
|
||||
return kc
|
||||
end
|
||||
|
||||
@@ -47,17 +65,6 @@ function KoptInterface:getContextHash(doc, pageno, bbox)
|
||||
return doc.file.."|"..pageno.."|"..doc.configurable:hash("|").."|"..bbox_hash.."|"..screen_size_hash
|
||||
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)
|
||||
local bbox = {
|
||||
x0 = 0, y0 = 0,
|
||||
@@ -68,26 +75,68 @@ function KoptInterface:getAutoBBox(doc, pageno)
|
||||
local cached = Cache:check(hash)
|
||||
if not cached then
|
||||
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)
|
||||
DEBUG("Auto detected bbox", bbox)
|
||||
page:close()
|
||||
Cache:insert(hash, CacheItem:new{ bbox = bbox })
|
||||
Cache:insert(hash, CacheItem:new{ autobbox = bbox })
|
||||
return bbox
|
||||
else
|
||||
return cached.bbox
|
||||
return cached.autobbox
|
||||
end
|
||||
end
|
||||
|
||||
-- get reflowed page dimension from a cached context. wait for background thread
|
||||
-- if necessary.
|
||||
function KoptInterface:getReflowedDim(kctx)
|
||||
self:waitForContext(kctx)
|
||||
return kctx:getPageDim()
|
||||
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
|
||||
|
||||
-- get cached koptcontext for centain page. if context doesn't exist in cache make
|
||||
-- new context and reflow the src page immediatly.
|
||||
function KoptInterface:getOCRWord(doc, pageno, rect)
|
||||
local bbox = doc:getPageBBox(pageno)
|
||||
local context_hash = self:getContextHash(doc, pageno, bbox)
|
||||
local hash = "ocrword|"..context_hash..rect.x..rect.y..rect.w..rect.h
|
||||
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
|
||||
|
||||
--[[
|
||||
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)
|
||||
local bbox = doc:getPageBBox(pageno)
|
||||
local context_hash = self:getContextHash(doc, pageno, bbox)
|
||||
@@ -95,7 +144,7 @@ function KoptInterface:getCachedContext(doc, pageno)
|
||||
local cached = Cache:check(kctx_hash)
|
||||
if not cached then
|
||||
-- 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)
|
||||
-- reflow page
|
||||
--local secs, usecs = util.gettime()
|
||||
@@ -107,22 +156,27 @@ function KoptInterface:getCachedContext(doc, pageno)
|
||||
--self:logReflowDuration(pageno, dur)
|
||||
local fullwidth, fullheight = kc:getPageDim()
|
||||
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
|
||||
else
|
||||
return cached.kctx
|
||||
-- wait for background thread
|
||||
return self:waitForContext(cached.kctx)
|
||||
end
|
||||
end
|
||||
|
||||
-- get reflowed page dimensions
|
||||
--[[
|
||||
get reflowed page dimensions
|
||||
--]]
|
||||
function KoptInterface:getPageDimensions(doc, pageno, zoom, rotation)
|
||||
local kctx = self:getCachedContext(doc, pageno)
|
||||
local fullwidth, fullheight = self:getReflowedDim(kctx)
|
||||
local kc = self:getCachedContext(doc, pageno)
|
||||
local fullwidth, fullheight = kc:getPageDim()
|
||||
return Geom:new{ w = fullwidth, h = fullheight }
|
||||
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)
|
||||
doc.render_mode = render_mode
|
||||
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)
|
||||
if not cached then
|
||||
-- do the real reflowing if kctx is not been cached yet
|
||||
local kctx = self:getCachedContext(doc, pageno)
|
||||
local fullwidth, fullheight = self:getReflowedDim(kctx)
|
||||
local kc = self:getCachedContext(doc, pageno)
|
||||
local fullwidth, fullheight = kc:getPageDim()
|
||||
if not Cache:willAccept(fullwidth * fullheight / 2) then
|
||||
-- whole page won't fit into cache
|
||||
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,
|
||||
bb = Blitbuffer.new(fullwidth, fullheight)
|
||||
}
|
||||
page:rfdraw(kctx, tile.bb)
|
||||
page:rfdraw(kc, tile.bb)
|
||||
page:close()
|
||||
-- free dst bitmap in kctx as soon as we draw the bitmap to blitbuffer
|
||||
kctx:free()
|
||||
Cache:insert(renderpg_hash, tile)
|
||||
return tile
|
||||
else
|
||||
@@ -157,29 +209,33 @@ function KoptInterface:renderPage(doc, pageno, rect, zoom, rotation, render_mode
|
||||
end
|
||||
end
|
||||
|
||||
-- inherited from common document interface
|
||||
-- render reflowed page into cache in background thread. this method returns immediatly
|
||||
-- leaving the precache flag on in context. subsequent usage of this context should
|
||||
-- wait for the precache flag off by calling self:waitForContext(kctx)
|
||||
--[[
|
||||
inherited from common document interface
|
||||
render reflowed page into cache in background thread. this method returns immediatly
|
||||
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)
|
||||
local bbox = doc:getPageBBox(pageno)
|
||||
local context_hash = self:getContextHash(doc, pageno, bbox)
|
||||
local kctx_hash = "kctx|"..context_hash
|
||||
local cached = Cache:check(kctx_hash)
|
||||
if not cached then
|
||||
local kc = self:getKOPTContext(doc, pageno, bbox)
|
||||
local kc = self:createContext(doc, pageno, bbox)
|
||||
local page = doc._document:openPage(pageno)
|
||||
DEBUG("hinting page", pageno, "in background")
|
||||
-- reflow will return immediately and running in background thread
|
||||
kc:setPreCache()
|
||||
page:reflow(kc, 0)
|
||||
page:close()
|
||||
Cache:insert(kctx_hash, CacheItem:new{ kctx = kc })
|
||||
Cache:insert(kctx_hash, ContextCacheItem:new{ kctx = kc })
|
||||
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)
|
||||
local tile = self:renderPage(doc, pageno, rect, zoom, rotation, render_mode)
|
||||
--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.w, rect.h)
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user