Merge pull request #91 from chrox/master

add hightlight/dictionary lookup in scanned pdf/djvu
pull/93/head
{Qingping,Dave} Hou 11 years ago
commit 80586c4a2a

@ -66,7 +66,7 @@ customupdate: all
mkdir -p $(INSTALL_DIR)/{history,screenshots,clipboard,libs}
cp -p README.md COPYING $(KOR_BASE)/{koreader-base,extr,sdcv} koreader.sh $(LUA_FILES) $(INSTALL_DIR)
$(STRIP) --strip-unneeded $(INSTALL_DIR)/koreader-base $(INSTALL_DIR)/extr $(INSTALL_DIR)/sdcv
mkdir $(INSTALL_DIR)/data
mkdir $(INSTALL_DIR)/data $(INSTALL_DIR)/data/dict $(INSTALL_DIR)/data/tessdata
cp -L koreader-base/$(DJVULIB) $(KOR_BASE)/$(CRELIB) \
$(KOR_BASE)/$(LUALIB) $(KOR_BASE)/$(K2PDFOPTLIB) \
$(KOR_BASE)/$(LEPTONICALIB) $(KOR_BASE)/$(TESSERACTLIB) \

@ -47,22 +47,24 @@ function validDjvuFile(filename)
return true
end
function DjvuDocument:getPageText(pageno)
function DjvuDocument:getTextBoxes(pageno)
if self.configurable.text_wrap == 1 then
return self.koptinterface:getPageText(self, pageno)
return self.koptinterface:getReflewTextBoxes(self, pageno)
else
return self._document:getPageText(pageno)
local text = self._document:getPageText(pageno)
if not text or #text == 0 then
return self.koptinterface:getTextBoxes(self, pageno)
else
return text
end
end
end
function DjvuDocument:getOCRWord(pageno, rect)
if self.configurable.text_wrap == 1 then
return self.koptinterface:getOCRWord(self, pageno, rect)
return self.koptinterface:getReflewOCRWord(self, pageno, rect)
else
--local page = self._document:openPage(pageno)
--local word = page:getOCRWord(rect)
--page:close()
--return word
return self.koptinterface:getOCRWord(self, pageno, rect)
end
end

@ -184,7 +184,7 @@ function Document:getToc()
return self._document:getToc()
end
function Document:getPageText(pageno)
function Document:getTextBoxes(pageno)
return nil
end

@ -95,10 +95,10 @@ function KoptInterface:getAutoBBox(doc, pageno)
end
end
function KoptInterface:getPageText(doc, pageno)
function KoptInterface:getReflewTextBoxes(doc, pageno)
local bbox = doc:getPageBBox(pageno)
local context_hash = self:getContextHash(doc, pageno, bbox)
local hash = "pgtext|"..context_hash
local hash = "rfpgboxes|"..context_hash
local cached = Cache:check(hash)
if not cached then
local kctx_hash = "kctx|"..context_hash
@ -106,16 +106,38 @@ function KoptInterface:getPageText(doc, pageno)
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
local boxes = kc:getWordBoxes(0, 0, fullwidth, fullheight)
Cache:insert(hash, CacheItem:new{ rfpgboxes = boxes })
return boxes
end
else
return cached.pgtext
return cached.rfpgboxes
end
end
function KoptInterface:getOCRWord(doc, pageno, rect)
function KoptInterface:getTextBoxes(doc, pageno)
local hash = "pgboxes|"..doc.file.."|"..pageno
local cached = Cache:check(hash)
if not cached then
local kc_hash = "kctx|"..doc.file.."|"..pageno
local kc = KOPTContext.new()
kc:setDebug()
local page = doc._document:openPage(pageno)
page:getPagePix(kc)
local fullwidth, fullheight = kc:getPageDim()
local boxes = kc:getWordBoxes(0, 0, fullwidth, fullheight)
Cache:insert(hash, CacheItem:new{ pgboxes = boxes })
Cache:insert(kc_hash, ContextCacheItem:new{ kctx = kc })
return boxes
else
return cached.pgboxes
end
end
--[[
get word from OCR in reflew page
--]]
function KoptInterface:getReflewOCRWord(doc, pageno, rect)
local ocrengine = "ocrengine"
if not Cache:check(ocrengine) then
local dummy = KOPTContext.new()
@ -123,14 +145,43 @@ function KoptInterface:getOCRWord(doc, pageno, rect)
end
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 hash = "rfocrword|"..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.getTOCRWord, kc,
rect.x, rect.y, rect.w, rect.h,
self.tessocr_data, self.ocr_lang, self.ocr_type, 0, 1)
Cache:insert(hash, CacheItem:new{ rfocrword = word })
return word
end
else
return cached.rfocrword
end
end
--[[
get word from OCR in non-reflew page
--]]
function KoptInterface:getOCRWord(doc, pageno, rect)
local ocrengine = "ocrengine"
if not Cache:check(ocrengine) then
local dummy = KOPTContext.new()
Cache:insert(ocrengine, OCREngine:new{ ocrengine = dummy })
end
local hash = "ocrword|"..doc.file.."|"..pageno..rect.x..rect.y..rect.w..rect.h
local cached = Cache:check(hash)
if not cached then
local pgboxes_hash = "pgboxes|"..doc.file.."|"..pageno
local pgboxes_cached = Cache:check(pgboxes_hash)
local kc_hash = "kctx|"..doc.file.."|"..pageno
local kc_cashed = Cache:check(kc_hash)
if pgboxes_cached and kc_cashed then
local kc = kc_cashed.kctx
local ok, word = pcall(
kc.getTOCRWord, kc,
rect.x, rect.y, rect.w, rect.h,

@ -44,25 +44,26 @@ function PdfDocument:unlock(password)
return self:_readMetadata()
end
function PdfDocument:getPageText(pageno)
function PdfDocument:getTextBoxes(pageno)
if self.configurable.text_wrap == 1 then
return self.koptinterface:getPageText(self, pageno)
return self.koptinterface:getReflewTextBoxes(self, pageno)
else
local page = self._document:openPage(pageno)
local text = page:getPageText()
page:close()
return text
if not text or #text == 0 then
return self.koptinterface:getTextBoxes(self, pageno)
else
return text
end
end
end
function PdfDocument:getOCRWord(pageno, rect)
if self.configurable.text_wrap == 1 then
return self.koptinterface:getOCRWord(self, pageno, rect)
return self.koptinterface:getReflewOCRWord(self, pageno, rect)
else
--local page = self._document:openPage(pageno)
--local word = page:getOCRWord(rect)
--page:close()
--return word
return self.koptinterface:getOCRWord(self, pageno, rect)
end
end

@ -39,7 +39,8 @@ end
function ReaderDictionary:stardictLookup(word)
DEBUG("lookup word:", word)
if word then
local std_out = io.popen("./sdcv -nj "..'\"'..word..'\"', "r")
-- escape quotes and other funny characters in word
local std_out = io.popen("./sdcv -nj "..("%q"):format(word), "r")
local results_str = std_out:read("*all")
if results_str then
--DEBUG("result str:", word, results_str)

@ -54,17 +54,34 @@ 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)
local text_boxes = self.ui.document:getTextBoxes(self.pos.page)
--DEBUG("page text", text_boxes)
if not text or #text == 0 then
DEBUG("no text extracted")
if not text_boxes or #text_boxes == 0 then
DEBUG("no text box detected")
return true
end
self.word_info = self:getWordFromText(text, self.pos)
self.word_info = self:getWordFromBoxes(text_boxes, self.pos)
DEBUG("hold word info in page", self.word_info)
if self.word_info then
-- 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.2)
word_box.y = word_box.y - math.floor(word_box.h * 0.4)
word_box.w = word_box.w + math.floor(word_box.h * 0.4)
word_box.h = word_box.h + math.floor(word_box.h * 0.6)
local word = self.ui.document:getOCRWord(self.pos.page, word_box)
DEBUG("OCRed word:", word)
self.ui:handleEvent(Event:new("LookupWord", word))
end)
end
local screen_rect = self.view:pageToScreenTransform(self.pos.page, self.word_info.box)
DEBUG("highlight word rect", screen_rect)
if screen_rect then
@ -74,28 +91,12 @@ function ReaderHighlight:onHold(arg, ges)
screen_rect.h = screen_rect.h + screen_rect.h * 0.4
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.2)
word_box.y = word_box.y - math.floor(word_box.h * 0.4)
word_box.w = word_box.w + math.floor(word_box.h * 0.4)
word_box.h = word_box.h + math.floor(word_box.h * 0.6)
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)
function ReaderHighlight:getWordFromBoxes(boxes, 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
@ -106,12 +107,12 @@ function ReaderHighlight:getWordFromText(text, pos)
return false
end
for i = 1, #text do
local l = text[i]
for i = 1, #boxes do
local l = boxes[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]
for j = 1, #boxes[i] do
local w = boxes[i][j]
if ges_inside(w.x0, w.y0, w.x1, w.y1) then
local box = Geom:new{
x = w.x0, y = w.y0,

@ -213,11 +213,13 @@ 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
local trans_p = rect_p:copy()
trans_p:transformByScale(state.zoom, state.zoom)
if page == state.page and state.visible_area:contains(trans_p) then
rect_s.x = rect_s.x + state.offset.x + trans_p.x - state.visible_area.x
rect_s.y = rect_s.y + state.offset.y + trans_p.y - state.visible_area.y
rect_s.w = trans_p.w
rect_s.h = trans_p.h
return rect_s
end
rect_s.y = rect_s.y + state.visible_area.h + self.page_gap.height
@ -261,11 +263,13 @@ 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
local trans_p = rect_p:copy()
trans_p:transformByScale(self.state.zoom, self.state.zoom)
if self.visible_area:contains(trans_p) then
rect_s.x = self.state.offset.x + trans_p.x - self.visible_area.x
rect_s.y = self.state.offset.y + trans_p.y - self.visible_area.y
rect_s.w = trans_p.w
rect_s.h = trans_p.h
return rect_s
end
end
@ -425,14 +429,15 @@ function ReaderView:onReadSettings(config)
self.state.gamma = config:readSetting("gamma") or 1.0
local full_screen = config:readSetting("kopt_full_screen")
if full_screen == nil then
self.footer_visible = self.document.info.has_pages
self.document.configurable.full_screen = self.footer_visible and 0 or 1
else
self.footer_visible = full_screen == 0 and true or false
full_screen = self.document.configurable.full_screen
end
self.footer_visible = full_screen == 0 and true or false
self:resetLayout()
local page_scroll = config:readSetting("kopt_page_scroll")
self.page_scroll = (page_scroll == nil or page_scroll == 1) and true or false
if page_scroll == nil then
page_scroll = self.document.configurable.page_scroll
end
self.page_scroll = page_scroll == 1 and true or false
end
function ReaderView:onPageUpdate(new_page_no)

@ -1 +1 @@
Subproject commit 519cfc9d75b7b578bdd8796670e7a51d34d13023
Subproject commit 9b16a6975d2cbc795a89bfd14ab3c162a4e26245
Loading…
Cancel
Save