mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
Merge pull request #163 from chrox/ocr_language
add document language option in config dialog
This commit is contained in:
@@ -34,13 +34,20 @@ DKOPTREADER_CONFIG_DETECT_INDENT = 1 -- 1 = enable, 0 = disable
|
||||
DKOPTREADER_CONFIG_DEFECT_SIZE = 1.0 -- range from 0.0 to 3.0
|
||||
DKOPTREADER_CONFIG_PAGE_MARGIN = 0.10 -- range from 0.0 to 1.0
|
||||
DKOPTREADER_CONFIG_LINE_SPACING = 1.2 -- range from 0.5 to 2.0
|
||||
DKOPTREADER_CONFIG_WORD_SAPCING = 0.15 -- range from 0.05 to 0.5
|
||||
DKOPTREADER_CONFIG_RENDER_QUALITY = 0.8 -- range from 0.5 to 1.0
|
||||
DKOPTREADER_CONFIG_AUTO_STRAIGHTEN = 0 -- range from 0 to 10
|
||||
DKOPTREADER_CONFIG_JUSTIFICATION = -1 -- -1 = auto, 0 = left, 1 = center, 2 = right, 3 = full
|
||||
DKOPTREADER_CONFIG_MAX_COLUMNS = 2 -- range from 1 to 4
|
||||
DKOPTREADER_CONFIG_CONTRAST = 1.0 -- range from 0.2 to 2.0
|
||||
|
||||
-- word spacing for reflow
|
||||
DKOPTREADER_CONFIG_WORD_SAPCINGS = {0.05, 0.15, 0.375} -- range from 0.05 to 0.5
|
||||
DKOPTREADER_CONFIG_DEFAULT_WORD_SAPCING = 0.15 -- range from 0.05 to 0.5
|
||||
-- document languages for OCR
|
||||
DKOPTREADER_CONFIG_DOC_LANGS_TEXT = {"English", "Chinese_S", "Chinese_T"}
|
||||
DKOPTREADER_CONFIG_DOC_LANGS_CODE = {"eng", "chi_sim", "chi_tra"} -- ISO 639-3 language string,
|
||||
DKOPTREADER_CONFIG_DOC_DEFAULT_LANG_CODE = "eng" -- and make sure you have corresponding training data
|
||||
|
||||
|
||||
-- ####################################################################
|
||||
-- following features are not supported right now
|
||||
|
||||
@@ -62,6 +62,7 @@ function KoptInterface:createContext(doc, pageno, bbox)
|
||||
kc:setDefectSize(doc.configurable.defect_size)
|
||||
kc:setLineSpacing(doc.configurable.line_spacing)
|
||||
kc:setWordSpacing(doc.configurable.word_spacing)
|
||||
kc:setLanguage(doc.configurable.doc_language)
|
||||
kc:setBBox(bbox.x0, bbox.y0, bbox.x1, bbox.y1)
|
||||
if Dbg.is_on then kc:setDebug() end
|
||||
return kc
|
||||
@@ -75,9 +76,11 @@ function KoptInterface:getContextHash(doc, pageno, bbox)
|
||||
end
|
||||
|
||||
function KoptInterface:getAutoBBox(doc, pageno)
|
||||
local native_size = Document.getNativePageDimensions(doc, pageno)
|
||||
local bbox = {
|
||||
x0 = 0, y0 = 0,
|
||||
x1 = 0, y1 = 0,
|
||||
x1 = native_size.w,
|
||||
y1 = native_size.h,
|
||||
}
|
||||
local context_hash = self:getContextHash(doc, pageno, bbox)
|
||||
local hash = "autobbox|"..context_hash
|
||||
@@ -129,6 +132,13 @@ function KoptInterface:getReflewTextBoxes(doc, pageno)
|
||||
local cached = Cache:check(kctx_hash)
|
||||
if cached then
|
||||
local kc = self:waitForContext(cached.kctx)
|
||||
--kc:setDebug()
|
||||
local lang = doc.configurable.doc_language
|
||||
if lang == "chi_sim" or lang == "chi_tra" or
|
||||
lang == "jpn" or lang == "kor" then
|
||||
kc:setCJKChar()
|
||||
end
|
||||
kc:setLanguage(lang)
|
||||
local fullwidth, fullheight = kc:getPageDim()
|
||||
local boxes = kc:getWordBoxes(0, 0, fullwidth, fullheight)
|
||||
Cache:insert(hash, CacheItem:new{ rfpgboxes = boxes })
|
||||
@@ -146,6 +156,12 @@ function KoptInterface:getTextBoxes(doc, pageno)
|
||||
local kc_hash = "kctx|"..doc.file.."|"..pageno
|
||||
local kc = KOPTContext.new()
|
||||
kc:setDebug()
|
||||
local lang = doc.configurable.doc_language
|
||||
if lang == "chi_sim" or lang == "chi_tra" or
|
||||
lang == "jpn" or lang == "kor" then
|
||||
kc:setCJKChar()
|
||||
end
|
||||
kc:setLanguage(lang)
|
||||
local page = doc._document:openPage(pageno)
|
||||
page:getPagePix(kc)
|
||||
local fullwidth, fullheight = kc:getPageDim()
|
||||
@@ -167,6 +183,7 @@ function KoptInterface:getReflewOCRWord(doc, pageno, rect)
|
||||
local dummy = KOPTContext.new()
|
||||
Cache:insert(ocrengine, OCREngine:new{ ocrengine = dummy })
|
||||
end
|
||||
self.ocr_lang = doc.configurable.doc_language
|
||||
local bbox = doc:getPageBBox(pageno)
|
||||
local context_hash = self:getContextHash(doc, pageno, bbox)
|
||||
local hash = "rfocrword|"..context_hash..rect.x..rect.y..rect.w..rect.h
|
||||
@@ -197,6 +214,7 @@ function KoptInterface:getOCRWord(doc, pageno, rect)
|
||||
local dummy = KOPTContext.new()
|
||||
Cache:insert(ocrengine, OCREngine:new{ ocrengine = dummy })
|
||||
end
|
||||
self.ocr_lang = doc.configurable.doc_language
|
||||
local hash = "ocrword|"..doc.file.."|"..pageno..rect.x..rect.y..rect.w..rect.h
|
||||
local cached = Cache:check(hash)
|
||||
if not cached then
|
||||
|
||||
@@ -160,6 +160,15 @@ KoptOptions = {
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
name="doc_language",
|
||||
name_text = DOC_LANG_STR,
|
||||
toggle = DKOPTREADER_CONFIG_DOC_LANGS_TEXT,
|
||||
values = DKOPTREADER_CONFIG_DOC_LANGS_CODE,
|
||||
default_value = DKOPTREADER_CONFIG_DOC_DEFAULT_LANG_CODE,
|
||||
event = "DocLangUpdate",
|
||||
args = DKOPTREADER_CONFIG_DOC_LANGS_CODE,
|
||||
},
|
||||
{
|
||||
name="screen_rotation",
|
||||
name_text = VERTICAL_TEXT_STR,
|
||||
@@ -171,8 +180,8 @@ KoptOptions = {
|
||||
name = "word_spacing",
|
||||
name_text = WORD_GAP_STR,
|
||||
toggle = {SMALL_STR, MEDIUM_STR, LARGE_STR},
|
||||
values = {0.05, 0.15, 0.375},
|
||||
default_value = DKOPTREADER_CONFIG_WORD_SAPCING,
|
||||
values = DKOPTREADER_CONFIG_WORD_SAPCINGS,
|
||||
default_value = DKOPTREADER_CONFIG_DEFAULT_WORD_SAPCING,
|
||||
},
|
||||
{
|
||||
name = "defect_size",
|
||||
@@ -195,6 +204,7 @@ KoptOptions = {
|
||||
toggle = {ZERO_DEG_STR, FIVE_DEG_STR, TEN_DEG_STR},
|
||||
values = {0, 5, 10},
|
||||
default_value = DKOPTREADER_CONFIG_AUTO_STRAIGHTEN,
|
||||
show = false,
|
||||
},
|
||||
{
|
||||
name = "detect_indent",
|
||||
|
||||
@@ -10,6 +10,7 @@ TEXT_ALIGN_STR = _("Text Align")
|
||||
FONTSIZE_FINE_TUNING_STR = _("Fine Tuning")
|
||||
CONTRAST_STR = _("Contrast")
|
||||
REFLOW_STR = _("Reflow")
|
||||
DOC_LANG_STR = _("Document Language")
|
||||
VERTICAL_TEXT_STR = _("Vertical Text")
|
||||
WORD_GAP_STR = _("Word Gap")
|
||||
DEFECT_SIZE_STR = _("Defect Size")
|
||||
|
||||
@@ -6,7 +6,8 @@ function Configurable:hash(sep)
|
||||
local hash = ""
|
||||
local excluded = {multi_threads = true,}
|
||||
for key,value in pairs(self) do
|
||||
if type(value) == "number" and not excluded[key] then
|
||||
if type(value) == "number" or type(value) == "string"
|
||||
and not excluded[key] then
|
||||
hash = hash..sep..value
|
||||
end
|
||||
end
|
||||
@@ -28,8 +29,9 @@ end
|
||||
|
||||
function Configurable:loadSettings(settings, prefix)
|
||||
for key,value in pairs(self) do
|
||||
if type(value) == "number" or type(value) == "table" then
|
||||
saved_value = settings:readSetting(prefix..key)
|
||||
if type(value) == "number" or type(value) == "string"
|
||||
or type(value) == "table" then
|
||||
local saved_value = settings:readSetting(prefix..key)
|
||||
self[key] = (saved_value == nil) and self[key] or saved_value
|
||||
--Debug("Configurable:loadSettings", "key", key, "saved value", saved_value,"Configurable.key", self[key])
|
||||
end
|
||||
@@ -39,7 +41,8 @@ end
|
||||
|
||||
function Configurable:saveSettings(settings, prefix)
|
||||
for key,value in pairs(self) do
|
||||
if type(value) == "number" or type(value) == "table" then
|
||||
if type(value) == "number" or type(value) == "string"
|
||||
or type(value) == "table" then
|
||||
settings:saveSetting(prefix..key, value)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -165,22 +165,42 @@ function ReaderHighlight:onHoldPan(arg, ges)
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderHighlight:lookup(selected_word)
|
||||
-- if we extracted text directly
|
||||
if selected_word.word then
|
||||
self.ui:handleEvent(Event:new("LookupWord", selected_word.word))
|
||||
-- or we will do OCR
|
||||
else
|
||||
local word_box = selected_word.box
|
||||
--word_box.x = word_box.x - math.floor(word_box.h * 0.1)
|
||||
--word_box.y = word_box.y - math.floor(word_box.h * 0.2)
|
||||
--word_box.w = word_box.w + math.floor(word_box.h * 0.2)
|
||||
--word_box.h = word_box.h + math.floor(word_box.h * 0.4)
|
||||
local word = self.ui.document:getOCRWord(self.hold_pos.page, word_box)
|
||||
DEBUG("OCRed word:", word)
|
||||
self.ui:handleEvent(Event:new("LookupWord", word))
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderHighlight:translate(selected_text)
|
||||
if selected_text.text ~= "" then
|
||||
self.ui:handleEvent(Event:new("LookupWord", selected_text.text))
|
||||
-- or we will do OCR
|
||||
else
|
||||
local text_box = selected_text.boxes[1]
|
||||
--text_box.x = text_box.x - math.floor(text_box.h * 0.1)
|
||||
text_box.y = text_box.y - math.floor(text_box.h * 0.2)
|
||||
--text_box.w = text_box.w + math.floor(text_box.h * 0.2)
|
||||
text_box.h = text_box.h + math.floor(text_box.h * 0.4)
|
||||
local text = self.ui.document:getOCRWord(self.hold_pos.page, text_box)
|
||||
DEBUG("OCRed text:", text)
|
||||
self.ui:handleEvent(Event:new("LookupWord", text))
|
||||
end
|
||||
end
|
||||
|
||||
function ReaderHighlight:onHoldRelease(arg, ges)
|
||||
if self.selected_word then
|
||||
-- if we extracted text directly
|
||||
if self.selected_word.word then
|
||||
self.ui:handleEvent(Event:new("LookupWord", self.selected_word.word))
|
||||
-- or we will do OCR
|
||||
else
|
||||
local word_box = self.selected_word.box
|
||||
word_box.x = word_box.x - math.floor(word_box.h * 0.1)
|
||||
word_box.y = word_box.y - math.floor(word_box.h * 0.2)
|
||||
word_box.w = word_box.w + math.floor(word_box.h * 0.2)
|
||||
word_box.h = word_box.h + math.floor(word_box.h * 0.4)
|
||||
local word = self.ui.document:getOCRWord(self.hold_pos.page, word_box)
|
||||
DEBUG("OCRed word:", word)
|
||||
self.ui:handleEvent(Event:new("LookupWord", word))
|
||||
end
|
||||
self:lookup(self.selected_word)
|
||||
self.selected_word = nil
|
||||
elseif self.selected_text then
|
||||
DEBUG("show highlight dialog")
|
||||
@@ -206,6 +226,14 @@ function ReaderHighlight:onHoldRelease(arg, ges)
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
text = _("Translate"),
|
||||
callback = function()
|
||||
self:translate(self.selected_text)
|
||||
UIManager:close(self.highlight_dialog)
|
||||
self.ui:handleEvent(Event:new("Tap"))
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Share"),
|
||||
enabled = false,
|
||||
@@ -215,6 +243,8 @@ function ReaderHighlight:onHoldRelease(arg, ges)
|
||||
self.ui:handleEvent(Event:new("Tap"))
|
||||
end,
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
text = _("More"),
|
||||
enabled = false,
|
||||
|
||||
@@ -49,3 +49,12 @@ function ReaderKoptListener:onZoomUpdate(zoom)
|
||||
end
|
||||
end
|
||||
|
||||
-- misc koptoption handler
|
||||
function ReaderKoptListener:onDocLangUpdate(lang)
|
||||
if lang == "chi_sim" or lang == "chi_tra" or
|
||||
lang == "jpn" or lang == "kor" then
|
||||
self.document.configurable.word_spacing = DKOPTREADER_CONFIG_WORD_SAPCINGS[1]
|
||||
else
|
||||
self.document.configurable.word_spacing = DKOPTREADER_CONFIG_WORD_SAPCINGS[3]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -204,6 +204,16 @@ function ConfigOption:init()
|
||||
end
|
||||
-- make current index according to configurable table
|
||||
local current_item = nil
|
||||
local function value_diff(val1, val2, name)
|
||||
if type(val1) ~= type(val2) then
|
||||
error("different data types in option", name)
|
||||
end
|
||||
if type(val1) == "number" then
|
||||
return math.abs(val1 - val2)
|
||||
elseif type(val1) == "string" then
|
||||
return val1 == val2 and 0 or 1
|
||||
end
|
||||
end
|
||||
if self.options[c].name then
|
||||
if self.options[c].values then
|
||||
-- check if current value is stored in configurable or calculated in runtime
|
||||
@@ -211,18 +221,18 @@ function ConfigOption:init()
|
||||
or self.config.configurable[self.options[c].name]
|
||||
local min_diff = nil
|
||||
if type(val) == "table" then
|
||||
min_diff = math.abs(val[1] - self.options[c].values[1][1])
|
||||
min_diff = value_diff(val[1], self.options[c].values[1][1])
|
||||
else
|
||||
min_diff = math.abs(val - self.options[c].values[1])
|
||||
min_diff = value_diff(val, self.options[c].values[1])
|
||||
end
|
||||
|
||||
local diff = nil
|
||||
for index, val_ in pairs(self.options[c].values) do
|
||||
local diff = nil
|
||||
if type(val) == "table" then
|
||||
diff = math.abs(val[1] - val_[1])
|
||||
diff = value_diff(val[1], val_[1])
|
||||
else
|
||||
diff = math.abs(val - val_)
|
||||
diff = value_diff(val, val_)
|
||||
end
|
||||
if val == val_ then
|
||||
current_item = index
|
||||
@@ -492,6 +502,7 @@ end
|
||||
function ConfigDialog:onConfigEvent(option_event, option_arg)
|
||||
--DEBUG("config option event", option_event, option_arg)
|
||||
self.ui:handleEvent(Event:new(option_event, option_arg))
|
||||
self:onShowConfigPanel(self.panel_index)
|
||||
end
|
||||
|
||||
function ConfigDialog:closeDialog()
|
||||
|
||||
Submodule koreader-base updated: 7de326340e...d45c0ac4b1
Reference in New Issue
Block a user