diff --git a/Makefile b/Makefile index cc8b946db..b87f4ff62 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,10 @@ customupdate: all 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 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/* cp -rpL $(KOR_BASE)/data/*.css $(INSTALL_DIR)/data cp -rpL $(KOR_BASE)/fonts $(INSTALL_DIR) diff --git a/frontend/document/djvudocument.lua b/frontend/document/djvudocument.lua index 5d7808f8a..2c386a3be 100644 --- a/frontend/document/djvudocument.lua +++ b/frontend/document/djvudocument.lua @@ -47,6 +47,25 @@ function validDjvuFile(filename) return true 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) -- djvu does not support usedbbox, so fake it. local used = {} diff --git a/frontend/document/document.lua b/frontend/document/document.lua index 77e3f035b..5e53ecb8f 100644 --- a/frontend/document/document.lua +++ b/frontend/document/document.lua @@ -184,6 +184,14 @@ function Document:getToc() return self._document:getToc() 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) local hash = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..gamma.."|"..render_mode local page_size = self:getPageDimensions(pageno, zoom, rotation) diff --git a/frontend/document/koptinterface.lua b/frontend/document/koptinterface.lua index 88f40ddd7..e1af67ef7 100644 --- a/frontend/document/koptinterface.lua +++ b/frontend/document/koptinterface.lua @@ -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 + +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 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: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. +--[[ +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 diff --git a/frontend/document/pdfdocument.lua b/frontend/document/pdfdocument.lua index c5fe50c7d..78f633b1a 100644 --- a/frontend/document/pdfdocument.lua +++ b/frontend/document/pdfdocument.lua @@ -44,6 +44,28 @@ function PdfDocument:unlock(password) return self:_readMetadata() 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) local hash = "pgubbox|"..self.file.."|"..pageno local cached = Cache:check(hash) diff --git a/frontend/ui/reader/readerdictionary.lua b/frontend/ui/reader/readerdictionary.lua new file mode 100644 index 000000000..992f33fb4 --- /dev/null +++ b/frontend/ui/reader/readerdictionary.lua @@ -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 diff --git a/frontend/ui/reader/readerhighlight.lua b/frontend/ui/reader/readerhighlight.lua new file mode 100644 index 000000000..dbdc7cd44 --- /dev/null +++ b/frontend/ui/reader/readerhighlight.lua @@ -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 diff --git a/frontend/ui/reader/readerkopt.lua b/frontend/ui/reader/readerkopt.lua index 74582c762..479f65fda 100644 --- a/frontend/ui/reader/readerkopt.lua +++ b/frontend/ui/reader/readerkopt.lua @@ -41,3 +41,11 @@ end function ReaderKoptListener:onFineTuningFontSize(delta) self.document.configurable.font_size = self.document.configurable.font_size + delta 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 + diff --git a/frontend/ui/reader/readerview.lua b/frontend/ui/reader/readerview.lua index 641e56108..d92d6c350 100644 --- a/frontend/ui/reader/readerview.lua +++ b/frontend/ui/reader/readerview.lua @@ -16,6 +16,10 @@ ReaderView = OverlapGroup:new{ bbox = nil, }, outer_page_color = 0, + -- hightlight + highlight = { + drawer = "marker" -- show as inverted block instead of underline + }, -- PDF/DjVu continuous paging page_scroll = nil, page_bgcolor = 0, @@ -96,6 +100,11 @@ function ReaderView:paintTo(bb, x, y) self.dim_area.w, self.dim_area.h ) end + + -- draw highlight + if self.highlight.rect then + self:drawHightlight(bb, x, y, self.highlight.rect) + end -- paint dogear if self.dogear_visible then @@ -113,6 +122,32 @@ function ReaderView:paintTo(bb, x, y) self.ui:handleEvent(Event:new("StopActivityIndicator")) 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) bb:paintRect(x, y, self.dimen.w, self.dimen.h, self.page_bgcolor) end @@ -155,6 +190,40 @@ function ReaderView:drawScrollPages(bb, x, y) 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) if self.scroll_mode == "vertical" then 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 +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) self.ui.document:drawCurrentViewByPage( bb, @@ -197,6 +288,26 @@ function ReaderView:drawScrollView(bb, x, y) self.state.pos) 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) if self.use_bbox then return self.ui.document:getUsedBBoxDimensions(page, zoom, rotation) diff --git a/frontend/ui/readerui.lua b/frontend/ui/readerui.lua index a041893fa..d4eb54025 100644 --- a/frontend/ui/readerui.lua +++ b/frontend/ui/readerui.lua @@ -14,8 +14,10 @@ require "ui/reader/readercropping" require "ui/reader/readerkopt" require "ui/reader/readercopt" require "ui/reader/readerhinting" +require "ui/reader/readerhighlight" require "ui/reader/readerscreenshot" require "ui/reader/readerfrontlight" +require "ui/reader/readerdictionary" require "ui/reader/readerhyphenation" require "ui/reader/readeractivityindicator" @@ -96,6 +98,22 @@ function ReaderUI:init() ui = self } 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 local reader_ss = ReaderScreenshot:new{ dialog = self.dialog, diff --git a/koreader.sh b/koreader.sh index a7348b2d7..e364de239 100755 --- a/koreader.sh +++ b/koreader.sh @@ -9,6 +9,9 @@ test -e $PROC_FIVEWAY && echo unlock > $PROC_FIVEWAY # we're always starting from our working directory cd /mnt/us/koreader/ +# export trained OCR data directory +export TESSDATA_PREFIX="data" + # bind-mount system fonts if ! grep /mnt/us/koreader/fonts/host /proc/mounts; then mount -o bind /usr/java/lib/fonts /mnt/us/koreader/fonts/host