diff --git a/.gitmodules b/.gitmodules index faaef3ef7..e924e9edf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "koreader-base"] path = base - url = https://github.com/koreader/koreader-base.git + url = https://github.com/kerivin/koreader-base.git [submodule "platform/android/luajit-launcher"] path = platform/android/luajit-launcher url = https://github.com/koreader/android-luajit-launcher.git diff --git a/base b/base index 63f95f0f2..003e635a5 160000 --- a/base +++ b/base @@ -1 +1 @@ -Subproject commit 63f95f0f2a8d87ce2b0c1a32e9f9774e2d80b556 +Subproject commit 003e635a56c38d0530a69fa628b7395780837884 diff --git a/defaults.lua b/defaults.lua index 306d4483a..2ae8d1a92 100644 --- a/defaults.lua +++ b/defaults.lua @@ -83,6 +83,8 @@ DKOPTREADER_CONFIG_AUTO_STRAIGHTEN = 0, -- range from 0 to 10 DKOPTREADER_CONFIG_JUSTIFICATION = 3, -- -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 +DKOPTREADER_CONFIG_BLACK_HEX = 0x000000, -- color defined blackness +DKOPTREADER_CONFIG_WHITE_HEX = 0xFFFFFF, -- color defined whiteness -- word spacing for reflow DKOPTREADER_CONFIG_WORD_SPACINGS = {0.05, -0.2, 0.375}, -- range from (+/-)0.05 to (+/-)0.5 diff --git a/frontend/apps/reader/modules/readerhinting.lua b/frontend/apps/reader/modules/readerhinting.lua index 4dee4f112..7a2e8283c 100644 --- a/frontend/apps/reader/modules/readerhinting.lua +++ b/frontend/apps/reader/modules/readerhinting.lua @@ -18,7 +18,9 @@ function ReaderHinting:onHintPage() self.view.state.page + i, self.zoom:getZoom(self.view.state.page + i), self.view.state.rotation, - self.view.state.gamma) + self.view.state.gamma, + self.view.state.black_hex, + self.view.state.white_hex) end end return true diff --git a/frontend/apps/reader/modules/readerkoptlistener.lua b/frontend/apps/reader/modules/readerkoptlistener.lua index 6afac570c..2e8345de4 100644 --- a/frontend/apps/reader/modules/readerkoptlistener.lua +++ b/frontend/apps/reader/modules/readerkoptlistener.lua @@ -22,6 +22,8 @@ function ReaderKoptListener:onReadSettings(config) self.normal_zoom_mode = normal_zoom_mode self:setZoomMode(normal_zoom_mode) self.ui:handleEvent(Event:new("GammaUpdate", self.document.configurable.contrast, true)) -- no notification + self.ui:handleEvent(Event:new("BlackLevelUpdate", self.document.configurable.black_hex, true)) -- no notification + self.ui:handleEvent(Event:new("WhiteLevelUpdate", self.document.configurable.white_hex, true)) -- no notification -- since K2pdfopt v2.21 negative value of word spacing is also used, for config -- compatibility we should manually change previous -1 to a more reasonable -0.2 if self.document.configurable.word_spacing == -1 then diff --git a/frontend/apps/reader/modules/readerpaging.lua b/frontend/apps/reader/modules/readerpaging.lua index edc760e56..577ea40f0 100644 --- a/frontend/apps/reader/modules/readerpaging.lua +++ b/frontend/apps/reader/modules/readerpaging.lua @@ -705,6 +705,20 @@ function ReaderPaging:onUpdateScrollPageGamma(gamma) return true end +function ReaderPaging:onUpdateScrollPageBlackLevel(black_hex) + for _, state in ipairs(self.view.page_states) do + state.black_hex = black_hex + end + return true +end + +function ReaderPaging:onUpdateScrollPageWhiteLevel(white_hex) + for _, state in ipairs(self.view.page_states) do + state.white_hex = white_hex + end + return true +end + function ReaderPaging:getNextPageState(blank_area, image_offset) local page_area = self.view:getPageArea( self.view.state.page, diff --git a/frontend/apps/reader/modules/readerview.lua b/frontend/apps/reader/modules/readerview.lua index 3b8161040..f111018bc 100644 --- a/frontend/apps/reader/modules/readerview.lua +++ b/frontend/apps/reader/modules/readerview.lua @@ -1092,6 +1092,26 @@ function ReaderView:onGammaUpdate(gamma, no_notification) end end +function ReaderView:onBlackLevelUpdate(black_hex, no_notification) + self.state.black_hex = black_hex + if self.page_scroll then + self.ui:handleEvent(Event:new("UpdateScrollPageBlackLevel", black_hex)) + end + if not no_notification then + Notification:notify(T(_("Black level set to: %1."), black_hex)) + end +end + +function ReaderView:onWhiteLevelUpdate(white_hex, no_notification) + self.state.white_hex = white_hex + if self.page_scroll then + self.ui:handleEvent(Event:new("UpdateScrollPageWhiteLevel", white_hex)) + end + if not no_notification then + Notification:notify(T(_("White level set to: %1."), white_hex)) + end +end + -- For ReaderKOptListener function ReaderView:onDitheringUpdate() -- Do the device cap checks again, to avoid snafus when sharing configs between devices diff --git a/frontend/document/djvudocument.lua b/frontend/document/djvudocument.lua index dda72e572..076890736 100644 --- a/frontend/document/djvudocument.lua +++ b/frontend/document/djvudocument.lua @@ -136,16 +136,16 @@ function DjvuDocument:findAllText(pattern, case_insensitive, nb_context_words, m return self.koptinterface:findAllText(self, pattern, case_insensitive, nb_context_words, max_hits) end -function DjvuDocument:renderPage(pageno, rect, zoom, rotation, gamma, hinting) - return self.koptinterface:renderPage(self, pageno, rect, zoom, rotation, gamma, hinting) +function DjvuDocument:renderPage(pageno, rect, zoom, rotation, gamma, black_hex, white_hex, hinting) + return self.koptinterface:renderPage(self, pageno, rect, zoom, rotation, gamma, black_hex, white_hex, hinting) end -function DjvuDocument:hintPage(pageno, zoom, rotation, gamma) - return self.koptinterface:hintPage(self, pageno, zoom, rotation, gamma) +function DjvuDocument:hintPage(pageno, zoom, rotation, gamma, black_hex, white_hex) + return self.koptinterface:hintPage(self, pageno, zoom, rotation, gamma, black_hex, white_hex) end -function DjvuDocument:drawPage(target, x, y, rect, pageno, zoom, rotation, gamma) - return self.koptinterface:drawPage(self, target, x, y, rect, pageno, zoom, rotation, gamma) +function DjvuDocument:drawPage(target, x, y, rect, pageno, zoom, rotation, gamma, black_hex, white_hex) + return self.koptinterface:drawPage(self, target, x, y, rect, pageno, zoom, rotation, gamma, black_hex, white_hex) end function DjvuDocument:register(registry) diff --git a/frontend/document/document.lua b/frontend/document/document.lua index 1308e0630..0e9e80b10 100644 --- a/frontend/document/document.lua +++ b/frontend/document/document.lua @@ -390,31 +390,33 @@ function Document:resetTileCacheValidity() self.tile_cache_validity_ts = os.time() end -function Document:getFullPageHash(pageno, zoom, rotation, gamma) +function Document:getFullPageHash(pageno, zoom, rotation, gamma, black_hex, white_hex) return "renderpg|"..self.file.."|"..self.mod_time.."|"..pageno.."|" ..zoom.."|" - ..rotation.."|"..gamma.."|"..self.render_mode..(self.render_color and "|color" or "|bw") + ..rotation.."|"..gamma.."|"..black_hex.."|"..white_hex + ..self.render_mode..(self.render_color and "|color" or "|bw") ..(self.reflowable_font_size and "|"..self.reflowable_font_size or "") end -function Document:getPagePartHash(pageno, zoom, rotation, gamma, rect) +function Document:getPagePartHash(pageno, zoom, rotation, gamma, black_hex, white_hex, rect) return "renderpgpart|"..self.file.."|"..self.mod_time.."|"..pageno.."|" ..tostring(rect).."|"..zoom.."|"..tostring(rect.scaled_rect).."|" - ..rotation.."|"..gamma.."|"..self.render_mode..(self.render_color and "|color" or "|bw") + ..rotation.."|"..gamma.."|"..black_hex.."|"..white_hex + ..self.render_mode..(self.render_color and "|color" or "|bw") ..(self.reflowable_font_size and "|"..self.reflowable_font_size or "") end -function Document:renderPage(pageno, rect, zoom, rotation, gamma, hinting) +function Document:renderPage(pageno, rect, zoom, rotation, gamma, black_hex, white_hex, hinting) -- If rect contains a nested scaled_rect object, our caller handled scaling itself (e.g., drawPagePart) local is_prescaled = rect and rect.scaled_rect ~= nil or false local hash, hash_excerpt, tile if is_prescaled then - hash = self:getPagePartHash(pageno, zoom, rotation, gamma, rect) + hash = self:getPagePartHash(pageno, zoom, rotation, gamma, black_hex, white_hex, rect) tile = DocCache:check(hash, TileCacheItem) else - hash = self:getFullPageHash(pageno, zoom, rotation, gamma) + hash = self:getFullPageHash(pageno, zoom, rotation, gamma, black_hex, white_hex) tile = DocCache:check(hash, TileCacheItem) @@ -502,6 +504,9 @@ function Document:renderPage(pageno, rect, zoom, rotation, gamma, hinting) dc:setGamma(gamma) end + dc:setBlackHex(black_hex) + dc:setWhiteHex(white_hex) + -- And finally, render the page in our BB local page = self._document:openPage(pageno) page:draw(dc, tile.bb, size.x, size.y, self.render_mode) @@ -516,9 +521,9 @@ end -- a hint for the cache engine to paint a full page to the cache --- @todo this should trigger a background operation -function Document:hintPage(pageno, zoom, rotation, gamma) +function Document:hintPage(pageno, zoom, rotation, gamma, black_hex, white_hex) logger.dbg("hinting page", pageno) - self:renderPage(pageno, nil, zoom, rotation, gamma, true) + self:renderPage(pageno, nil, zoom, rotation, gamma, black_hex, white_hex, true) end --[[ @@ -529,8 +534,8 @@ Draw page content to blitbuffer. @target: target blitbuffer @rect: visible_area inside document page --]] -function Document:drawPage(target, x, y, rect, pageno, zoom, rotation, gamma) - local tile = self:renderPage(pageno, rect, zoom, rotation, gamma) +function Document:drawPage(target, x, y, rect, pageno, zoom, rotation, gamma, black_hex, white_hex) + local tile = self:renderPage(pageno, rect, zoom, rotation, gamma, black_hex, white_hex) -- Enable SW dithering if requested (only available in koptoptions) if self.sw_dithering then target:ditherblitFrom(tile.bb, @@ -570,7 +575,7 @@ function Document:drawPagePart(pageno, native_rect, rotation) rect.scaled_rect = scaled_rect -- Enable SMP via the hinting flag - local tile = self:renderPage(pageno, rect, zoom, rotation, 1.0, true) + local tile = self:renderPage(pageno, rect, zoom, rotation, 1.0, 0x000000, 0xFFFFFF, true) return tile.bb, rotate end diff --git a/frontend/document/koptinterface.lua b/frontend/document/koptinterface.lua index e97d7b058..12520f153 100644 --- a/frontend/document/koptinterface.lua +++ b/frontend/document/koptinterface.lua @@ -99,6 +99,8 @@ function KoptInterface:setDefaultConfigurable(configurable) configurable.page_margin = G_defaults:readSetting("DKOPTREADER_CONFIG_PAGE_MARGIN") configurable.quality = G_defaults:readSetting("DKOPTREADER_CONFIG_RENDER_QUALITY") configurable.contrast = G_defaults:readSetting("DKOPTREADER_CONFIG_CONTRAST") + configurable.black_hex = G_defaults:readSetting("DKOPTREADER_CONFIG_BLACK_HEX") + configurable.white_hex = G_defaults:readSetting("DKOPTREADER_CONFIG_WHITE_HEX") configurable.defect_size = G_defaults:readSetting("DKOPTREADER_CONFIG_DEFECT_SIZE") configurable.line_spacing = G_defaults:readSetting("DKOPTREADER_CONFIG_LINE_SPACING") configurable.word_spacing = G_defaults:readSetting("DKOPTREADER_CONFIG_DEFAULT_WORD_SPACING") @@ -150,6 +152,8 @@ function KoptInterface:createContext(doc, pageno, bbox) kc:setQuality(doc.configurable.quality) -- k2pdfopt (for reflowing) and mupdf use different algorithms to apply gamma when rendering kc:setContrast(1 / doc.configurable.contrast) + kc:setForegroundHex(doc.configurable.black_hex) + kc:setBackgroundHex(doc.configurable.white_hex) kc:setDefectSize(doc.configurable.defect_size) kc:setLineSpacing(doc.configurable.line_spacing) kc:setWordSpacing(doc.configurable.word_spacing) @@ -384,19 +388,19 @@ function KoptInterface:getCoverPageImage(doc) local native_size = Document.getNativePageDimensions(doc, 1) local canvas_size = CanvasContext:getSize() local zoom = math.min(canvas_size.w / native_size.w, canvas_size.h / native_size.h) - local tile = Document.renderPage(doc, 1, nil, zoom, 0, 1.0) + local tile = Document.renderPage(doc, 1, nil, zoom, 0, 1.0, 0x000000, 0xFFFFFF) if tile then return tile.bb:copy() end end -function KoptInterface:renderPage(doc, pageno, rect, zoom, rotation, gamma, hinting) +function KoptInterface:renderPage(doc, pageno, rect, zoom, rotation, gamma, black_hex, white_hex, hinting) if doc.configurable.text_wrap == 1 then return self:renderReflowedPage(doc, pageno, rect, zoom, rotation, hinting) elseif doc.configurable.page_opt == 1 or doc.configurable.auto_straighten > 0 then return self:renderOptimizedPage(doc, pageno, rect, zoom, rotation, hinting) else - return Document.renderPage(doc, pageno, rect, zoom, rotation, gamma, hinting) + return Document.renderPage(doc, pageno, rect, zoom, rotation, gamma, black_hex, white_hex, hinting) end end @@ -491,16 +495,16 @@ function KoptInterface:renderOptimizedPage(doc, pageno, rect, zoom, rotation, hi end end -function KoptInterface:hintPage(doc, pageno, zoom, rotation, gamma) +function KoptInterface:hintPage(doc, pageno, zoom, rotation, gamma, black_hex, white_hex) --- @note: Crappy safeguard around memory issues like in #7627: if we're eating too much RAM, drop half the cache... DocCache:memoryPressureCheck() if doc.configurable.text_wrap == 1 then - self:hintReflowedPage(doc, pageno, zoom, rotation, gamma, true) + self:hintReflowedPage(doc, pageno, zoom, rotation, gamma, black_hex, white_hex, true) elseif doc.configurable.page_opt == 1 or doc.configurable.auto_straighten > 0 then - self:renderOptimizedPage(doc, pageno, nil, zoom, rotation, gamma, true) + self:renderOptimizedPage(doc, pageno, nil, zoom, rotation, gamma, black_hex, white_hex, true) else - Document.hintPage(doc, pageno, zoom, rotation, gamma) + Document.hintPage(doc, pageno, zoom, rotation, gamma, black_hex, white_hex) end end diff --git a/frontend/document/pdfdocument.lua b/frontend/document/pdfdocument.lua index 40399939a..2b3640d6a 100644 --- a/frontend/document/pdfdocument.lua +++ b/frontend/document/pdfdocument.lua @@ -344,16 +344,16 @@ function PdfDocument:findAllText(pattern, case_insensitive, nb_context_words, ma return self.koptinterface:findAllText(self, pattern, case_insensitive, nb_context_words, max_hits) end -function PdfDocument:renderPage(pageno, rect, zoom, rotation, gamma, hinting) - return self.koptinterface:renderPage(self, pageno, rect, zoom, rotation, gamma, hinting) +function PdfDocument:renderPage(pageno, rect, zoom, rotation, gamma, black_hex, white_hex, hinting) + return self.koptinterface:renderPage(self, pageno, rect, zoom, rotation, gamma, black_hex, white_hex, hinting) end -function PdfDocument:hintPage(pageno, zoom, rotation, gamma) - return self.koptinterface:hintPage(self, pageno, zoom, rotation, gamma) +function PdfDocument:hintPage(pageno, zoom, rotation, gamma, black_hex, white_hex) + return self.koptinterface:hintPage(self, pageno, zoom, rotation, gamma, black_hex, white_hex) end -function PdfDocument:drawPage(target, x, y, rect, pageno, zoom, rotation, gamma) - return self.koptinterface:drawPage(self, target, x, y, rect, pageno, zoom, rotation, gamma) +function PdfDocument:drawPage(target, x, y, rect, pageno, zoom, rotation, gamma, black_hex, white_hex) + return self.koptinterface:drawPage(self, target, x, y, rect, pageno, zoom, rotation, gamma, black_hex, white_hex) end function PdfDocument:register(registry) diff --git a/frontend/ui/data/koptoptions.lua b/frontend/ui/data/koptoptions.lua index 8385f4029..d9b5b0ca8 100644 --- a/frontend/ui/data/koptoptions.lua +++ b/frontend/ui/data/koptoptions.lua @@ -501,6 +501,34 @@ Some of the other settings are only available when reflow mode is enabled.]]), precision = "%.1f", }, }, + { + name = "black_hex", + name_text = _("Black Level"), + buttonprogress = true, + -- For pdf reflowing mode (kopt_contrast): + values = {0x808080, 0x606060, 0x404040, 0x202020, 0x000000}, + default_pos = 2, + default_value = G_defaults:readSetting("DKOPTREADER_CONFIG_BLACK_HEX"), + event = "BlackLevelUpdate", + -- For pdf non-reflowing mode (mupdf): + args = {0x808080, 0x606060, 0x404040, 0x202020, 0x000000}, + labels = { #808080, #606060, #404040, #202020, #000000}, + name_text_hold_callback = optionsutil.showValues, + }, + { + name = "white_hex", + name_text = _("White Level"), + buttonprogress = true, + -- For pdf reflowing mode (kopt_contrast): + values = {0xFFFFFF, 0xE0E0E0, 0xC0C0C0, 0xA0A0A0, 0x808080}, + default_pos = 2, + default_value = G_defaults:readSetting("DKOPTREADER_CONFIG_WHITE_HEX"), + event = "WhiteLevelUpdate", + -- For pdf non-reflowing mode (mupdf): + args = {0xFFFFFF, 0xE0E0E0, 0xC0C0C0, 0xA0A0A0, 0x808080}, + labels = { #FFFFFF, #E0E0E0, #C0C0C0, #A0A0A0, #808080}, + name_text_hold_callback = optionsutil.showValues, + }, { name = "page_opt", name_text = _("Dewatermark"), diff --git a/spec/unit/cache_spec.lua b/spec/unit/cache_spec.lua index 2a7ca50b0..632507a90 100644 --- a/spec/unit/cache_spec.lua +++ b/spec/unit/cache_spec.lua @@ -20,7 +20,7 @@ describe("Cache module", function() it("should serialize blitbuffer", function() for pageno = 1, math.min(max_page, doc.info.number_of_pages) do - doc:renderPage(pageno, nil, 1, 0, 1.0) + doc:renderPage(pageno, nil, 1, 0, 1.0, 0x000000, 0xFFFFFF) DocCache:serialize() end DocCache:clear() @@ -28,7 +28,7 @@ describe("Cache module", function() it("should deserialize blitbuffer", function() for pageno = 1, math.min(max_page, doc.info.number_of_pages) do - doc:hintPage(pageno, 1, 0, 1.0, 0) + doc:hintPage(pageno, 1, 0, 1.0, 0x000000, 0xFFFFFF) end DocCache:clear() end) @@ -36,7 +36,7 @@ describe("Cache module", function() it("should serialize koptcontext", function() doc.configurable.text_wrap = 1 for pageno = 1, math.min(max_page, doc.info.number_of_pages) do - doc:renderPage(pageno, nil, 1, 0, 1.0) + doc:renderPage(pageno, nil, 1, 0, 1.0, 0x000000, 0xFFFFFF) doc:getPageDimensions(pageno) DocCache:serialize() end @@ -46,7 +46,7 @@ describe("Cache module", function() it("should deserialize koptcontext", function() for pageno = 1, math.min(max_page, doc.info.number_of_pages) do - doc:renderPage(pageno, nil, 1, 0, 1.0) + doc:renderPage(pageno, nil, 1, 0, 1.0, 0x000000, 0xFFFFFF) end DocCache:clear() end) diff --git a/spec/unit/pdf_bench.lua b/spec/unit/pdf_bench.lua index a7356e4fa..1631dc4cc 100644 --- a/spec/unit/pdf_bench.lua +++ b/spec/unit/pdf_bench.lua @@ -23,7 +23,7 @@ describe("PDF benchmark:", function() end for pageno = 1, math.min(9, doc.info.number_of_pages) do local secs, usecs = util.gettime() - assert.truthy(doc:renderPage(pageno, nil, 1, 0, 1.0)) + assert.truthy(doc:renderPage(pageno, nil, 1, 0, 1.0, , 0x000000, 0xFFFFFF)) local nsecs, nusecs = util.gettime() local dur = nsecs - secs + (nusecs - usecs) / 1000000 logDuration(logfile, pageno, dur)