From c11e10070ac1993e431e50463f7fbd87f9d89a8f Mon Sep 17 00:00:00 2001 From: Dobrica Pavlinusic Date: Sat, 3 Mar 2012 19:55:26 +0100 Subject: [PATCH 01/31] dump debugging output --- pdfreader.lua | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pdfreader.lua b/pdfreader.lua index 2050d06aa..1228c3ae1 100644 --- a/pdfreader.lua +++ b/pdfreader.lua @@ -219,6 +219,8 @@ function PDFReader:setzoom(page) self.min_offset_y = 0 end + print("globalzoom:"..self.globalzoom.." globalrotate:"..self.globalrotate.." offset:"..self.offset_x.."*"..self.offset_y.." pagesize:"..self.fullwidth.."*"..self.fullheight.." min_offset:"..self.min_offset_x.."*"..self.min_offset_y) + -- set gamma here, we don't have any other good place for this right now: if self.globalgamma ~= self.GAMMA_NO_GAMMA then print("gamma correction: "..self.globalgamma) From b8cc9c9a363914fa0feb8507a6b4f1e320432f02 Mon Sep 17 00:00:00 2001 From: Dobrica Pavlinusic Date: Sun, 4 Mar 2012 13:06:35 +0100 Subject: [PATCH 02/31] exit reader on HOME key --- keys.lua | 1 + pdfreader.lua | 2 ++ 2 files changed, 3 insertions(+) diff --git a/keys.lua b/keys.lua index 3c4c25568..0ad6c2a81 100644 --- a/keys.lua +++ b/keys.lua @@ -113,6 +113,7 @@ end function set_emu_keycodes() KEY_PGFWD = 117 KEY_PGBCK = 112 + KEY_HOME = 110 -- home KEY_BACK = 22 -- backspace KEY_DEL = 119 -- Delete KEY_MENU = 67 -- F1 diff --git a/pdfreader.lua b/pdfreader.lua index a22dae717..42557af31 100644 --- a/pdfreader.lua +++ b/pdfreader.lua @@ -453,6 +453,8 @@ function PDFReader:inputloop() self:setrotate( self.globalrotate + 10 ) elseif ev.code == KEY_K then self:setrotate( self.globalrotate - 10 ) + elseif ev.code == KEY_HOME then + os.exit(0); end if self.globalzoommode == self.ZOOM_BY_VALUE then From 2c48d4a107aed8a220487415dc7d47b17302b66f Mon Sep 17 00:00:00 2001 From: Dobrica Pavlinusic Date: Sun, 4 Mar 2012 13:28:55 +0100 Subject: [PATCH 03/31] handle invalid bounding boxes from mupdf, closes #25 --- pdfreader.lua | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/pdfreader.lua b/pdfreader.lua index 42557af31..97185474e 100644 --- a/pdfreader.lua +++ b/pdfreader.lua @@ -141,6 +141,15 @@ end function PDFReader:setzoom(page) local dc = pdf.newDC() local pwidth, pheight = page:getSize(self.nulldc) + print("# page::getSize "..pwidth.."*"..pheight); + local x0, y0, x1, y1 = page:getUsedBBox() + if x0 == 0.01 and y0 == 0.01 and x1 == -0.01 and y1 == -0.01 then + x0 = 0 + y0 = 0 + x1 = pwidth + y2 = pheight + end + print("# page::getUsedBBox "..x0.."*"..y0.." "..x1.."*"..y1); if self.globalzoommode == self.ZOOM_FIT_TO_PAGE or self.globalzoommode == self.ZOOM_FIT_TO_CONTENT then @@ -164,7 +173,6 @@ function PDFReader:setzoom(page) self.offset_y = 0 end if self.globalzoommode == self.ZOOM_FIT_TO_CONTENT then - local x0, y0, x1, y1 = page:getUsedBBox() if (x1 - x0) < pwidth then self.globalzoom = width / (x1 - x0) self.offset_x = -1 * x0 * self.globalzoom @@ -176,21 +184,18 @@ function PDFReader:setzoom(page) end end elseif self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_WIDTH then - local x0, y0, x1, y1 = page:getUsedBBox() if (x1 - x0) < pwidth then self.globalzoom = width / (x1 - x0) self.offset_x = -1 * x0 * self.globalzoom self.offset_y = -1 * y0 * self.globalzoom + (height - (self.globalzoom * (y1 - y0))) / 2 end elseif self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_HEIGHT then - local x0, y0, x1, y1 = page:getUsedBBox() if (y1 - y0) < pheight then self.globalzoom = height / (y1 - y0) self.offset_x = -1 * x0 * self.globalzoom + (width - (self.globalzoom * (x1 - x0))) / 2 self.offset_y = -1 * y0 * self.globalzoom end elseif self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH then - local x0, y0, x1, y1 = page:getUsedBBox() self.globalzoom = width / (x1 - x0 + self.pan_margin) self.offset_x = -1 * x0 * self.globalzoom * 2 + self.pan_margin self.globalzoom = height / (y1 - y0) @@ -215,7 +220,7 @@ function PDFReader:setzoom(page) self.min_offset_y = 0 end - print("globalzoom:"..self.globalzoom.." globalrotate:"..self.globalrotate.." offset:"..self.offset_x.."*"..self.offset_y.." pagesize:"..self.fullwidth.."*"..self.fullheight.." min_offset:"..self.min_offset_x.."*"..self.min_offset_y) + print("# PDFReader:setzoom globalzoom:"..self.globalzoom.." globalrotate:"..self.globalrotate.." offset:"..self.offset_x.."*"..self.offset_y.." pagesize:"..self.fullwidth.."*"..self.fullheight.." min_offset:"..self.min_offset_x.."*"..self.min_offset_y) -- set gamma here, we don't have any other good place for this right now: if self.globalgamma ~= self.GAMMA_NO_GAMMA then From b7d0e657a8ad8ff8ebc324bd9f275b63952f9eb3 Mon Sep 17 00:00:00 2001 From: HW Date: Sun, 4 Mar 2012 15:36:17 +0100 Subject: [PATCH 04/31] disabled debug symbol output, enabled optimization --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 141af1b03..d9a325acc 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,9 @@ LFSDIR=luafilesystem CC:=arm-unknown-linux-gnueabi-gcc HOSTCC:=gcc -CFLAGS:=-O0 -g +CFLAGS:=-O3 -march=armv6 +# use this for debugging: +#CFLAGS:=-O0 -g # you can configure an emulation for the (eink) framebuffer here. # the application won't use the framebuffer (and the special e-ink ioctls) From 357da594d405dae76539fafd5c2de8f2ba5d4761 Mon Sep 17 00:00:00 2001 From: HW Date: Sun, 4 Mar 2012 16:56:19 +0100 Subject: [PATCH 05/31] disable ARM specific CFLAGS when in emu mode --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index d9a325acc..21e189d1d 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,8 @@ LFSDIR=luafilesystem CC:=arm-unknown-linux-gnueabi-gcc HOSTCC:=gcc -CFLAGS:=-O3 -march=armv6 +CFLAGS:=-O3 +ARM_CFLAGS:=-march=armv6 # use this for debugging: #CFLAGS:=-O0 -g @@ -33,6 +34,8 @@ EMU_CFLAGS+= -DEMULATE_READER \ -DEMULATE_READER_H=$(EMULATE_READER_H) \ EMU_LDFLAGS?=$(shell sdl-config --libs) +else +CFLAGS+= $(ARM_CFLAGS) endif # standard includes From 788eb90455d21ee57abcb96f96ab69cbe73f97e5 Mon Sep 17 00:00:00 2001 From: HW Date: Sun, 4 Mar 2012 17:29:19 +0100 Subject: [PATCH 06/31] added simple serializer, use lua instead of SQLite --- settings.lua | 70 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/settings.lua b/settings.lua index b7a446202..c324b8975 100644 --- a/settings.lua +++ b/settings.lua @@ -1,38 +1,66 @@ DocSettings = {} function DocSettings:open(docfile) - local new = {} - new.docdb, errno, errstr = sqlite3.open(docfile..".kpdfview") - if new.docdb ~= nil then - new.docdb:exec("CREATE TABLE IF NOT EXISTS settings (key TEXT PRIMARY KEY, value TEXT);") - new.stmt_readsetting = new.docdb:prepare("SELECT value FROM settings WHERE key = ?;") - new.stmt_savesetting = new.docdb:prepare("INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?);") + local new = { file = docfile..".kpdfview.lua", data = {} } + local ok, stored = pcall(dofile,new.file) + if ok then + new.data = stored end return setmetatable(new, { __index = DocSettings}) end function DocSettings:readsetting(key) - if self.docdb ~= nil then - self.stmt_readsetting:reset() - self.stmt_readsetting:bind_values(key) - local result = self.stmt_readsetting:step() - if result == sqlite3.ROW then - return self.stmt_readsetting:get_value(0) + return self.data[key] +end + +function DocSettings:savesetting(key, value) + self.data[key] = value +end + +-- simple serialization function, won't do uservalues, functions, loops +function DocSettings:_serialize(what, outt, indent) + if type(what) == "table" then + local didrun = false + table.insert(outt, "{") + for k, v in pairs(what) do + if didrun then + table.insert(outt, ",") + end + table.insert(outt, "\n") + table.insert(outt, string.rep("\t", indent+1)) + table.insert(outt, "[") + self:_serialize(k, outt, indent+1) + table.insert(outt, "] = ") + self:_serialize(v, outt, indent+1) + didrun = true end + if didrun then + table.insert(outt, "\n") + table.insert(outt, string.rep("\t", indent)) + end + table.insert(outt, "}") + elseif type(what) == "string" then + table.insert(outt, string.format("%q", what)) + elseif type(what) == "number" or type(what) == "boolean" then + table.insert(outt, tostring(what)) end end -function DocSettings:savesetting(key, value) - if self.docdb ~= nil then - self.stmt_savesetting:reset() - self.stmt_savesetting:bind_values(key, value) - self.stmt_savesetting:step() +function DocSettings:flush() + -- write a serialized version of the data table + if not self.file then + return + end + local f_out = io.open(self.file, "w") + if f_out ~= nil then + local out = {"-- we can read Lua syntax here!\nreturn "} + self:_serialize(self.data, out, 0) + table.insert(out, "\n") + f_out:write(table.concat(out)) + f_out:close() end end function DocSettings:close() - if self.docdb ~= nil then - self.docdb:close() - self.docdb = nil - end + self:flush() end From 8816285ec79055ba695470ff4735cd5a794d42d1 Mon Sep 17 00:00:00 2001 From: HW Date: Sun, 4 Mar 2012 17:50:25 +0100 Subject: [PATCH 07/31] removed SQLite and lsqlite for the moment --- Makefile | 19 +------------------ kpdfview.c | 4 ---- 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 21e189d1d..be3831d07 100644 --- a/Makefile +++ b/Makefile @@ -5,8 +5,6 @@ MUPDFDIR=mupdf MUPDFTARGET=build/debug MUPDFLIBDIR=$(MUPDFDIR)/$(MUPDFTARGET) -SQLITE3DIR=sqlite-amalgamation-3070900 -LSQLITE3DIR=lsqlite3_svn08 FREETYPEDIR=$(MUPDFDIR)/thirdparty/freetype-2.4.8 LFSDIR=luafilesystem @@ -54,14 +52,10 @@ THIRDPARTYLIBS := $(MUPDFLIBDIR)/libfreetype.a \ $(MUPDFLIBDIR)/libjbig2dec.a \ $(MUPDFLIBDIR)/libz.a -# comment this out to build without sqlite3 -SQLITE3OBJS := lsqlite3.o sqlite3.o -SQLITE3LDFLAGS := -lpthread - LUALIB := $(LUADIR)/src/liblua.a kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o input.o util.o ft.o $(SQLITE3OBJS) lfs.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) - $(CC) -lm -ldl $(EMU_LDFLAGS) $(SQLITE3LDFLAGS) \ + $(CC) -lm -ldl $(EMU_LDFLAGS) \ kpdfview.o \ einkfb.o \ pdf.o \ @@ -69,7 +63,6 @@ kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o input.o util.o ft.o $(SQLITE3OB input.o \ util.o \ ft.o \ - $(SQLITE3OBJS) \ lfs.o \ $(MUPDFLIBS) \ $(THIRDPARTYLIBS) \ @@ -85,26 +78,16 @@ ft.o: %.o: %.c kpdfview.o pdf.o blitbuffer.o util.o: %.o: %.c $(CC) -c $(KPDFREADER_CFLAGS) -I$(LFSDIR)/src $< -o $@ -sqlite3.o: $(SQLITE3DIR)/sqlite3.c - $(CC) -c $(CFLAGS) $(SQLITE3DIR)/sqlite3.c -o $@ - -lsqlite3.o: $(LSQLITE3DIR)/lsqlite3.c - $(CC) -c $(CFLAGS) -I$(LUADIR)/src -I$(SQLITE3DIR) $(LSQLITE3DIR)/lsqlite3.c -o $@ - lfs.o: $(LFSDIR)/src/lfs.c $(CC) -c $(CFLAGS) -I$(LUADIR)/src -I$(LFSDIR)/src $(LFSDIR)/src/lfs.c -o $@ fetchthirdparty: -rm -Rf mupdf -rm -Rf lua lua-5.1.4* - -rm -Rf lsqlite3_svn08* - -rm -Rf sqlite-amalgamation-3070900* -rm -Rf luafilesystem* git clone git://git.ghostscript.com/mupdf.git ( cd mupdf ; wget http://www.mupdf.com/download/mupdf-thirdparty.zip && unzip mupdf-thirdparty.zip ) wget http://www.lua.org/ftp/lua-5.1.4.tar.gz && tar xvzf lua-5.1.4.tar.gz && ln -s lua-5.1.4 lua - wget "http://lua.sqlite.org/index.cgi/zip/lsqlite3_svn08.zip?uuid=svn_8" && unzip "lsqlite3_svn08.zip?uuid=svn_8" - wget "http://sqlite.org/sqlite-amalgamation-3070900.zip" && unzip sqlite-amalgamation-3070900.zip git clone https://github.com/keplerproject/luafilesystem.git clean: diff --git a/kpdfview.c b/kpdfview.c index 9e5fa60ad..69282f82a 100644 --- a/kpdfview.c +++ b/kpdfview.c @@ -32,9 +32,6 @@ #include "lfs.h" -/* forward declaration for luasqlite3: */ -LUALIB_API int luaopen_lsqlite3(lua_State *L); - lua_State *L; int main(int argc, char **argv) { @@ -57,7 +54,6 @@ int main(int argc, char **argv) { luaopen_util(L); luaopen_ft(L); - luaopen_lsqlite3(L); luaopen_lfs(L); lua_newtable(L); From 0e3c91931de5a419ecf736dfd7b7ed1a6f4dc38e Mon Sep 17 00:00:00 2001 From: Dobrica Pavlinusic Date: Sun, 4 Mar 2012 23:16:38 +0800 Subject: [PATCH 08/31] fix bottom y for getUsedBBox #25 --- pdfreader.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pdfreader.lua b/pdfreader.lua index 97185474e..a825f569c 100644 --- a/pdfreader.lua +++ b/pdfreader.lua @@ -147,7 +147,7 @@ function PDFReader:setzoom(page) x0 = 0 y0 = 0 x1 = pwidth - y2 = pheight + y1 = pheight end print("# page::getUsedBBox "..x0.."*"..y0.." "..x1.."*"..y1); From 3c56f50cae98edb18d3ea8580dd9bb2fd715f658 Mon Sep 17 00:00:00 2001 From: HW Date: Sun, 4 Mar 2012 18:59:50 +0100 Subject: [PATCH 09/31] switched TOC entry sanitizing to Lua code --- pdf.c | 10 ---------- pdfreader.lua | 2 +- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/pdf.c b/pdf.c index c375f93e1..2551be985 100644 --- a/pdf.c +++ b/pdf.c @@ -105,16 +105,6 @@ static int walkTableOfContent(lua_State *L, fz_outline* ol, int *count, int dept lua_settable(L, -3); lua_pushstring(L, "title"); - /* workaround for misplaced carriage ret in toc entry */ - int i = 0; - while (ol->title[i]) { - if (ol->title[i] == 0x0d) { - ol->title[i] = ' '; - } - /*printf("%x|", ol->title[i]);*/ - i++; - } - lua_pushstring(L, ol->title); lua_settable(L, -3); diff --git a/pdfreader.lua b/pdfreader.lua index a825f569c..e162c28de 100644 --- a/pdfreader.lua +++ b/pdfreader.lua @@ -336,7 +336,7 @@ function PDFReader:showTOC() -- build menu items for _k,_v in ipairs(toc) do table.insert(menu_items, - (" "):rep(_v.depth-1).._v.title) + (" "):rep(_v.depth-1) .. _v.title:gsub("\13", "")) end toc_menu = SelectMenu:new{ menu_title = "Table of Contents", From 13ec6e42b58f9cd2c8089d7994d048d604827d75 Mon Sep 17 00:00:00 2001 From: Dobrica Pavlinusic Date: Sun, 4 Mar 2012 19:40:22 +0100 Subject: [PATCH 10/31] moving to right column should take margin into account to provenet skipping columns #27 --- pdfreader.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pdfreader.lua b/pdfreader.lua index a825f569c..0737fb32b 100644 --- a/pdfreader.lua +++ b/pdfreader.lua @@ -498,8 +498,9 @@ function PDFReader:inputloop() self.offset_y = self.min_offset_y end elseif ev.code == KEY_FW_RIGHT then + print("# FW RIGHT "..self.offset_x.." - "..x.." < "..self.min_offset_x); self.offset_x = self.offset_x - x - if self.offset_x < self.min_offset_x then + if self.offset_x < self.min_offset_x - self.pan_margin then self.offset_x = self.min_offset_x if self.pan_by_page and self.pageno < self.doc:getPages() then self.offset_x = self.pan_x From 7efdbaf215e1d61b3c714551ff8344007a1cb649 Mon Sep 17 00:00:00 2001 From: HW Date: Sun, 4 Mar 2012 21:18:09 +0100 Subject: [PATCH 11/31] clamp fit-to-content to page dimensions (BBox) --- pdfreader.lua | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pdfreader.lua b/pdfreader.lua index e162c28de..f63b576f1 100644 --- a/pdfreader.lua +++ b/pdfreader.lua @@ -149,6 +149,12 @@ function PDFReader:setzoom(page) x1 = pwidth y1 = pheight end + -- clamp to page BBox + if x0 < 0 then x0 = 0 end + if x1 > pwidth then x1 = pwidth end + if y0 < 0 then y0 = 0 end + if y1 > pheight then y1 = pheight end + print("# page::getUsedBBox "..x0.."*"..y0.." "..x1.."*"..y1); if self.globalzoommode == self.ZOOM_FIT_TO_PAGE From 4f46f9fa7a27440e8981e1b2aed6953b9cbe0356 Mon Sep 17 00:00:00 2001 From: HW Date: Sun, 4 Mar 2012 21:39:34 +0100 Subject: [PATCH 12/31] proper exit when pressing HOME, store settings etc --- pdfreader.lua | 28 +++++++++++++++++----------- reader.lua | 2 +- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/pdfreader.lua b/pdfreader.lua index 9988f593d..b40d6218e 100644 --- a/pdfreader.lua +++ b/pdfreader.lua @@ -380,6 +380,7 @@ end -- wait for input and handle it function PDFReader:inputloop() + local keep_running = true while 1 do local ev = input.waitForEvent() ev.code = adjustKeyEvents(ev) @@ -412,16 +413,7 @@ function PDFReader:inputloop() elseif ev.code == KEY_BACK then if Keys.altmode then -- altmode, exit pdfreader - self:clearcache() - if self.doc ~= nil then - self.doc:close() - end - if self.settings ~= nil then - self.settings:savesetting("last_page", self.pageno) - self.settings:savesetting("gamma", self.globalgamma) - self.settings:close() - end - return + break else -- not altmode, back to last jump if #self.jump_stack ~= 0 then @@ -465,7 +457,9 @@ function PDFReader:inputloop() elseif ev.code == KEY_K then self:setrotate( self.globalrotate - 10 ) elseif ev.code == KEY_HOME then - os.exit(0); + -- signal quit + keep_running = false + break end if self.globalzoommode == self.ZOOM_BY_VALUE then @@ -555,6 +549,18 @@ function PDFReader:inputloop() print("E: T="..ev.type.." V="..ev.value.." C="..ev.code.." DUR="..dur) end end + + self:clearcache() + if self.doc ~= nil then + self.doc:close() + end + if self.settings ~= nil then + self.settings:savesetting("last_page", self.pageno) + self.settings:savesetting("gamma", self.globalgamma) + self.settings:close() + end + + return keep_running end diff --git a/reader.lua b/reader.lua index c25ea7ec0..1863eae8c 100755 --- a/reader.lua +++ b/reader.lua @@ -100,7 +100,7 @@ if lfs.attributes(ARGV[optind], "mode") == "directory" then if pdffile ~= nil then if PDFReader:open(pdffile,"") then -- TODO: query for password PDFReader:goto(tonumber(PDFReader.settings:readsetting("last_page") or 1)) - PDFReader:inputloop() + running = PDFReader:inputloop() end else running = false From 1b1fc2b3aeb39f1abb875c7fc85374666cf4b6fd Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 4 Mar 2012 23:23:01 +0100 Subject: [PATCH 13/31] integrate djvu support --- Makefile | 28 ++- djvu.c | 430 +++++++++++++++++++++++++++++++++++++++++++++++ djvu.h | 28 +++ filechooser.lua | 2 +- filesearcher.lua | 2 +- kpdfview.c | 1 + 6 files changed, 486 insertions(+), 5 deletions(-) create mode 100644 djvu.c create mode 100644 djvu.h diff --git a/Makefile b/Makefile index be3831d07..4a95b15f8 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ LUADIR=lua MUPDFDIR=mupdf MUPDFTARGET=build/debug MUPDFLIBDIR=$(MUPDFDIR)/$(MUPDFTARGET) +DJVUDIR=djvulibre FREETYPEDIR=$(MUPDFDIR)/thirdparty/freetype-2.4.8 LFSDIR=luafilesystem @@ -11,7 +12,9 @@ LFSDIR=luafilesystem # set this to your ARM cross compiler: CC:=arm-unknown-linux-gnueabi-gcc +CXX:=arm-unknown-linux-gnueabi-g++ HOSTCC:=gcc +HOSTCXX:=g++ CFLAGS:=-O3 ARM_CFLAGS:=-march=armv6 @@ -24,6 +27,7 @@ ARM_CFLAGS:=-march=armv6 ifdef EMULATE_READER CC:=$(HOSTCC) +CXX:=$(HOSTCXX) EMULATE_READER_W?=824 EMULATE_READER_H?=1200 EMU_CFLAGS?=$(shell sdl-config --cflags) @@ -46,6 +50,7 @@ KPDFREADER_CFLAGS=$(CFLAGS) -I$(LUADIR)/src -I$(MUPDFDIR)/ # for now, all dependencies except for the libc are compiled into the final binary: MUPDFLIBS := $(MUPDFLIBDIR)/libfitz.a +DJVULIBS := $(DJVUDIR)/build/libdjvu/.libs/libdjvulibre.a THIRDPARTYLIBS := $(MUPDFLIBDIR)/libfreetype.a \ $(MUPDFLIBDIR)/libjpeg.a \ $(MUPDFLIBDIR)/libopenjpeg.a \ @@ -54,8 +59,8 @@ THIRDPARTYLIBS := $(MUPDFLIBDIR)/libfreetype.a \ LUALIB := $(LUADIR)/src/liblua.a -kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o input.o util.o ft.o $(SQLITE3OBJS) lfs.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) - $(CC) -lm -ldl $(EMU_LDFLAGS) \ +kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o input.o util.o ft.o $(SQLITE3OBJS) lfs.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) $(DJVULIBS) djvu.o + $(CC) -lm -ldl $(EMU_LDFLAGS) -lstdc++ \ kpdfview.o \ einkfb.o \ pdf.o \ @@ -67,6 +72,8 @@ kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o input.o util.o ft.o $(SQLITE3OB $(MUPDFLIBS) \ $(THIRDPARTYLIBS) \ $(LUALIB) \ + djvu.o \ + $(DJVULIBS) \ -o kpdfview einkfb.o input.o: %.o: %.c @@ -78,6 +85,9 @@ ft.o: %.o: %.c kpdfview.o pdf.o blitbuffer.o util.o: %.o: %.c $(CC) -c $(KPDFREADER_CFLAGS) -I$(LFSDIR)/src $< -o $@ +djvu.o: %.o: %.c + $(CC) -c $(KPDFREADER_CFLAGS) -I$(DJVUDIR)/ $< -o $@ + lfs.o: $(LFSDIR)/src/lfs.c $(CC) -c $(CFLAGS) -I$(LUADIR)/src -I$(LFSDIR)/src $(LFSDIR)/src/lfs.c -o $@ @@ -85,10 +95,12 @@ fetchthirdparty: -rm -Rf mupdf -rm -Rf lua lua-5.1.4* -rm -Rf luafilesystem* + -rm -Rf $(DJVUDIR) git clone git://git.ghostscript.com/mupdf.git ( cd mupdf ; wget http://www.mupdf.com/download/mupdf-thirdparty.zip && unzip mupdf-thirdparty.zip ) wget http://www.lua.org/ftp/lua-5.1.4.tar.gz && tar xvzf lua-5.1.4.tar.gz && ln -s lua-5.1.4 lua git clone https://github.com/keplerproject/luafilesystem.git + git clone git://djvu.git.sourceforge.net/gitroot/djvu/djvulibre.git clean: -rm -f *.o kpdfview @@ -96,6 +108,7 @@ clean: cleanthirdparty: make -C $(LUADIR) clean make -C $(MUPDFDIR) clean + -rm -rf $(DJVUDIR)/build -rm $(MUPDFDIR)/fontdump.host -rm $(MUPDFDIR)/cmapdump.host @@ -113,10 +126,19 @@ $(MUPDFLIBS) $(THIRDPARTYLIBS): $(MUPDFDIR)/cmapdump.host $(MUPDFDIR)/fontdump.h # build only thirdparty libs, libfitz and pdf utils, which will care for libmupdf.a being built CFLAGS="$(CFLAGS)" make -C mupdf CC="$(CC)" CMAPDUMP=cmapdump.host FONTDUMP=fontdump.host MUPDF= XPS_APPS= +$(DJVULIBS): + -mkdir $(DJVUDIR)/build +ifdef EMULATE_READER + cd $(DJVUDIR)/build && ../configure --disable-desktopfiles --disable-shared --enable-static +else + cd $(DJVUDIR)/build && ../configure --disable-desktopfiles --disable-shared --enable-static --host=arm-kindle-linux-gnueabi +endif + make -C $(DJVUDIR)/build + $(LUALIB): make -C lua/src CC="$(CC)" CFLAGS="$(CFLAGS)" MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E" liblua.a -thirdparty: $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIBS) +thirdparty: $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIBS) $(DJVULIBS) INSTALL_DIR=kindlepdfviewer diff --git a/djvu.c b/djvu.c new file mode 100644 index 000000000..f7b244755 --- /dev/null +++ b/djvu.c @@ -0,0 +1,430 @@ +/* + KindlePDFViewer: MuPDF abstraction for Lua + Copyright (C) 2011 Hans-Werner Hilse + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include + +#include "string.h" +#include "blitbuffer.h" +#include "djvu.h" + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +/*@TODO check all the close method, ensure memories are freed 03.03 2012*/ + +typedef struct DjvuDocument { + ddjvu_context_t *context; + ddjvu_document_t *doc_ref; + int pages; +} DjvuDocument; + +typedef struct DjvuPage { + int num; + ddjvu_page_t *page_ref; + ddjvu_pageinfo_t info; + DjvuDocument *doc; +} DjvuPage; + +typedef struct DrawContext { + int rotate; + double zoom; + double gamma; + int offset_x; + int offset_y; +} DrawContext; + + +static int handle(lua_State *L, ddjvu_context_t *ctx, int wait) +{ + const ddjvu_message_t *msg; + if (!ctx) + return; + if (wait) + msg = ddjvu_message_wait(ctx); + while ((msg = ddjvu_message_peek(ctx))) + { + switch(msg->m_any.tag) + { + case DDJVU_ERROR: + if (msg->m_error.filename) { + return luaL_error(L, "ddjvu: %s\nddjvu: '%s:%d'\n", + msg->m_error.message, msg->m_error.filename, + msg->m_error.lineno); + } else { + return luaL_error(L, "ddjvu: %s\n", msg->m_error.message); + } + default: + break; + } + ddjvu_message_pop(ctx); + } + + return 0; +} + +static int openDocument(lua_State *L) { + const char *filename = luaL_checkstring(L, 1); + /*const char *password = luaL_checkstring(L, 2);*/ + + DjvuDocument *doc = (DjvuDocument*) lua_newuserdata(L, sizeof(DjvuDocument)); + luaL_getmetatable(L, "djvudocument"); + lua_setmetatable(L, -2); + + doc->context = ddjvu_context_create("DJVUReader"); + if (! doc->context) { + return luaL_error(L, "cannot create context."); + } + + doc->doc_ref = ddjvu_document_create_by_filename(doc->context, filename, TRUE); + while (! ddjvu_document_decoding_done(doc->doc_ref)) + handle(L, doc->context, True); + if (! doc->doc_ref) { + return luaL_error(L, "cannot open DJVU file <%s>", filename); + } + + doc->pages = ddjvu_document_get_pagenum(doc->doc_ref); + return 1; +} + +static int closeDocument(lua_State *L) { + DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument"); + if(doc->doc_ref != NULL) { + ddjvu_document_release(doc->doc_ref); + doc->doc_ref = NULL; + } + if(doc->context != NULL) { + ddjvu_context_release(doc->context); + + /*@TODO fix this! 03.03 2012 + * it works fine in EMU mode, but if I don't + * add this printf after context_release, kpfview + * simply exit after this function call! */ + printf("remeber to fix this bug!\n"); + + doc->context = NULL; + } +} + +static int getNumberOfPages(lua_State *L) { + DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument"); + lua_pushinteger(L, doc->pages); + return 1; +} + +static int newDrawContext(lua_State *L) { + int rotate = luaL_optint(L, 1, 0); + double zoom = luaL_optnumber(L, 2, (double) 1.0); + int offset_x = luaL_optint(L, 3, 0); + int offset_y = luaL_optint(L, 4, 0); + double gamma = luaL_optnumber(L, 5, (double) -1.0); + + DrawContext *dc = (DrawContext*) lua_newuserdata(L, sizeof(DrawContext)); + dc->rotate = rotate; + dc->zoom = zoom; + dc->offset_x = offset_x; + dc->offset_y = offset_y; + dc->gamma = gamma; + + + luaL_getmetatable(L, "drawcontext"); + lua_setmetatable(L, -2); + + return 1; +} + +static int dcSetOffset(lua_State *L) { + DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); + dc->offset_x = luaL_checkint(L, 2); + dc->offset_y = luaL_checkint(L, 3); + return 0; +} + +static int dcGetOffset(lua_State *L) { + DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); + lua_pushinteger(L, dc->offset_x); + lua_pushinteger(L, dc->offset_y); + return 2; +} + +static int dcSetRotate(lua_State *L) { + DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); + dc->rotate = luaL_checkint(L, 2); + return 0; +} + +static int dcSetZoom(lua_State *L) { + DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); + dc->zoom = luaL_checknumber(L, 2); + return 0; +} + +static int dcGetRotate(lua_State *L) { + DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); + lua_pushinteger(L, dc->rotate); + return 1; +} + +static int dcGetZoom(lua_State *L) { + DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); + lua_pushnumber(L, dc->zoom); + return 1; +} + +static int dcSetGamma(lua_State *L) { + DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); + dc->gamma = luaL_checknumber(L, 2); + return 0; +} + +static int dcGetGamma(lua_State *L) { + DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); + lua_pushnumber(L, dc->gamma); + return 1; +} + +static int openPage(lua_State *L) { + ddjvu_status_t r; + DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument"); + int pageno = luaL_checkint(L, 2); + + if(pageno < 1 || pageno > doc->pages) { + return luaL_error(L, "cannot open page #%d, out of range (1-%d)", pageno, doc->pages); + } + + DjvuPage *page = (DjvuPage*) lua_newuserdata(L, sizeof(DjvuPage)); + luaL_getmetatable(L, "djvupage"); + lua_setmetatable(L, -2); + + page->page_ref = ddjvu_page_create_by_pageno(doc->doc_ref, pageno - 1); + while (! ddjvu_page_decoding_done(page->page_ref)) + handle(L, doc->context, TRUE); + if(! page->page_ref) { + return luaL_error(L, "cannot open page #%d", pageno); + } + + page->doc = doc; + page->num = pageno; + + while((r=ddjvu_document_get_pageinfo(doc->doc_ref, pageno, &(page->info)))context, TRUE); + if (r>=DDJVU_JOB_FAILED) + return luaL_error(L, "cannot get page #%d information", pageno); + + return 1; +} + +/* get page size after zoomed */ +static int getPageSize(lua_State *L) { + DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage"); + DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext"); + + lua_pushnumber(L, dc->zoom * page->info.width); + lua_pushnumber(L, dc->zoom * page->info.height); + + return 2; +} + +/*static int getUsedBBox(lua_State *L) {*/ + /*fz_bbox result;*/ + /*fz_matrix ctm;*/ + /*fz_device *dev;*/ + /*DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage");*/ + + /*[> returned BBox is in centi-point (n * 0.01 pt) <]*/ + /*ctm = fz_scale(100, 100);*/ + /*ctm = fz_concat(ctm, fz_rotate(page->page->rotate));*/ + + /*fz_try(page->doc->context) {*/ + /*dev = fz_new_bbox_device(page->doc->context, &result);*/ + /*pdf_run_page(page->doc->xref, page->page, dev, ctm, NULL);*/ + /*}*/ + /*fz_always(page->doc->context) {*/ + /*fz_free_device(dev);*/ + /*}*/ + /*fz_catch(page->doc->context) {*/ + /*return luaL_error(L, "cannot calculate bbox for page");*/ + /*}*/ + + /*lua_pushnumber(L, ((double)result.x0)/100);*/ + /*lua_pushnumber(L, ((double)result.y0)/100);*/ + /*lua_pushnumber(L, ((double)result.x1)/100);*/ + /*lua_pushnumber(L, ((double)result.y1)/100);*/ + + /*return 4;*/ +/*}*/ + +static int closePage(lua_State *L) { + DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage"); + if(page->page_ref != NULL) { + ddjvu_page_release(page->page_ref); + page->page_ref = NULL; + } + return 0; +} + +static int drawPage(lua_State *L) { + DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage"); + DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext"); + BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 3, "blitbuffer"); + + ddjvu_format_t *pixelformat; + ddjvu_rect_t pagerect, renderrect; + uint8_t *imagebuffer = NULL; + + imagebuffer = malloc((bb->w)*(bb->h)+1); + /* fill pixel map with white color */ + memset(imagebuffer, 0xFF, (bb->w)*(bb->h)+1); + + pixelformat = ddjvu_format_create(DDJVU_FORMAT_GREY8, 0, NULL); + ddjvu_format_set_row_order(pixelformat, 1); + ddjvu_format_set_y_direction(pixelformat, 1); + ddjvu_format_set_gamma(pixelformat, dc->gamma); + /*ddjvu_format_set_ditherbits(dc->pixelformat, 2);*/ + + /*printf("@page %d, @@zoom:%f, offset: (%d, %d)\n", page->num, dc->zoom, dc->offset_x, dc->offset_y);*/ + + /* render full page into rectangle specified by pagerect */ + /*pagerect.x = luaL_checkint(L, 4);*/ + /*pagerect.y = luaL_checkint(L, 5);*/ + pagerect.x = 0; + pagerect.y = 0; + pagerect.w = page->info.width * dc->zoom; + pagerect.h = page->info.height * dc->zoom; + + /*printf("--pagerect--- (x: %d, y: %d), w: %d, h: %d.\n", 0, 0, pagerect.w, pagerect.h);*/ + + + /* copy pixels area from pagerect specified by renderrect. + + * ddjvulibre library does not support negative offset, positive offset + * means moving towards right and down. + * + * However, djvureader.lua handles offset differently. It use negative + * offset to move right and down while positive offset to move left + * and up. So we need to handle positive offset manually when copying + * imagebuffer to blitbuffer (framebuffer). + */ + renderrect.x = MAX(-dc->offset_x, 0); + renderrect.y = MAX(-dc->offset_y, 0); + renderrect.w = MIN(pagerect.w - renderrect.x, bb->w); + renderrect.h = MIN(pagerect.h - renderrect.y, bb->h); + + /*printf("--renderrect--- (%d, %d), w:%d, h:%d\n", renderrect.x, renderrect.y, renderrect.w, renderrect.h);*/ + + /* ddjvulibre library only supports rotation of 0, 90, 180 and 270 degrees. + * This four kinds of rotations can already be achieved by native system. + * So we don't set rotation here. + */ + + ddjvu_page_render(page->page_ref, + DDJVU_RENDER_COLOR, + &pagerect, + &renderrect, + pixelformat, + bb->w, + imagebuffer); + + uint8_t *bbptr = (uint8_t*)bb->data; + uint8_t *pmptr = (uint8_t*)imagebuffer; + int x, y; + /* if offset is positive, we are moving towards up and left. */ + int x_offset = MAX(0, dc->offset_x); + int y_offset = MAX(0, dc->offset_y); + + bbptr += bb->pitch * y_offset; + for(y = y_offset; y < bb->h; y++) { + /* bbptr's line width is half of pmptr's */ + for(x = x_offset/2; x < (bb->w / 2); x++) { + bbptr[x] = 255 - (((pmptr[x*2 + 1 - x_offset] & 0xF0) >> 4) | + (pmptr[x*2 - x_offset] & 0xF0)); + } + if(bb->w & 1) { + bbptr[x] = 255 - (pmptr[x*2] & 0xF0); + } + /* go to next line */ + bbptr += bb->pitch; + pmptr += bb->w; + } + + free(imagebuffer); + pmptr = imagebuffer = NULL; + ddjvu_format_release(pixelformat); + + return 0; +} + +static const struct luaL_reg djvu_func[] = { + {"openDocument", openDocument}, + {"newDC", newDrawContext}, + {NULL, NULL} +}; + +static const struct luaL_reg djvudocument_meth[] = { + {"openPage", openPage}, + {"getPages", getNumberOfPages}, + /*{"getTOC", getTableOfContent},*/ + {"close", closeDocument}, + {"__gc", closeDocument}, + {NULL, NULL} +}; + +static const struct luaL_reg djvupage_meth[] = { + {"getSize", getPageSize}, + /*{"getUsedBBox", getUsedBBox},*/ + {"close", closePage}, + {"__gc", closePage}, + {"draw", drawPage}, + {NULL, NULL} +}; + +static const struct luaL_reg drawcontext_meth[] = { + {"setRotate", dcSetRotate}, + {"getRotate", dcGetRotate}, + {"setZoom", dcSetZoom}, + {"getZoom", dcGetZoom}, + {"setOffset", dcSetOffset}, + {"getOffset", dcGetOffset}, + {"setGamma", dcSetGamma}, + {"getGamma", dcGetGamma}, + {NULL, NULL} +}; + +int luaopen_djvu(lua_State *L) { + luaL_newmetatable(L, "djvudocument"); + lua_pushstring(L, "__index"); + lua_pushvalue(L, -2); + lua_settable(L, -3); + luaL_register(L, NULL, djvudocument_meth); + lua_pop(L, 1); + + luaL_newmetatable(L, "djvupage"); + lua_pushstring(L, "__index"); + lua_pushvalue(L, -2); + lua_settable(L, -3); + luaL_register(L, NULL, djvupage_meth); + lua_pop(L, 1); + + luaL_newmetatable(L, "drawcontext"); + lua_pushstring(L, "__index"); + lua_pushvalue(L, -2); + lua_settable(L, -3); + luaL_register(L, NULL, drawcontext_meth); + lua_pop(L, 1); + + luaL_register(L, "djvu", djvu_func); + return 1; +} diff --git a/djvu.h b/djvu.h new file mode 100644 index 000000000..a42068448 --- /dev/null +++ b/djvu.h @@ -0,0 +1,28 @@ +/* + KindlePDFViewer: MuPDF abstraction for Lua + Copyright (C) 2011 Hans-Werner Hilse + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifndef _DJVU_H +#define _DJVU_H + +#include +#include +#include + +int luaopen_djvu(lua_State *L); + +#define True 1 +#endif diff --git a/filechooser.lua b/filechooser.lua index d2ca88b5c..d2f25a4ff 100644 --- a/filechooser.lua +++ b/filechooser.lua @@ -41,7 +41,7 @@ function FileChooser:readdir() for f in lfs.dir(self.path) do if lfs.attributes(self.path.."/"..f, "mode") == "directory" and f ~= "." and not string.match(f, "^%.[^.]") then table.insert(self.dirs, f) - elseif string.match(f, ".+%.[pP][dD][fF]$") then + elseif string.match(f, ".+%.[pP][dD][fF]$") or string.match(f, ".+%.[dD][jJ][vV][uU]$") then table.insert(self.files, f) end end diff --git a/filesearcher.lua b/filesearcher.lua index 55ef1892e..815a26603 100644 --- a/filesearcher.lua +++ b/filesearcher.lua @@ -46,7 +46,7 @@ function FileSearcher:readdir() if lfs.attributes(d.."/"..f, "mode") == "directory" and f ~= "." and f~= ".." and not string.match(f, "^%.[^.]") then table.insert(new_dirs, d.."/"..f) - elseif string.match(f, ".+%.[pP][dD][fF]$") then + elseif string.match(f, ".+%.[pP][dD][fF]$") or string.match(f, ".+%.[dD][jJ][vV][uU]$") then file_entry = {dir=d, name=f,} table.insert(self.files, file_entry) --print("file:"..d.."/"..f) diff --git a/kpdfview.c b/kpdfview.c index 69282f82a..9ce45652c 100644 --- a/kpdfview.c +++ b/kpdfview.c @@ -50,6 +50,7 @@ int main(int argc, char **argv) { luaopen_blitbuffer(L); luaopen_einkfb(L); luaopen_pdf(L); + luaopen_djvu(L); luaopen_input(L); luaopen_util(L); luaopen_ft(L); From efe2ef7efe07678bc07956f6acc171c71cc5e901 Mon Sep 17 00:00:00 2001 From: Dobrica Pavlinusic Date: Mon, 5 Mar 2012 00:17:46 +0100 Subject: [PATCH 14/31] integrate djvu into PDFReader, alternative to #26 This code is based on current master but doesn't include unireader, but leaves all names to old PDFReader to preserve compatilbity --- djvu.c | 41 ++++++++++++----------------------------- pdfreader.lua | 22 +++++++++++++++++++--- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/djvu.c b/djvu.c index f7b244755..7429b92fd 100644 --- a/djvu.c +++ b/djvu.c @@ -238,34 +238,17 @@ static int getPageSize(lua_State *L) { return 2; } -/*static int getUsedBBox(lua_State *L) {*/ - /*fz_bbox result;*/ - /*fz_matrix ctm;*/ - /*fz_device *dev;*/ - /*DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage");*/ - - /*[> returned BBox is in centi-point (n * 0.01 pt) <]*/ - /*ctm = fz_scale(100, 100);*/ - /*ctm = fz_concat(ctm, fz_rotate(page->page->rotate));*/ - - /*fz_try(page->doc->context) {*/ - /*dev = fz_new_bbox_device(page->doc->context, &result);*/ - /*pdf_run_page(page->doc->xref, page->page, dev, ctm, NULL);*/ - /*}*/ - /*fz_always(page->doc->context) {*/ - /*fz_free_device(dev);*/ - /*}*/ - /*fz_catch(page->doc->context) {*/ - /*return luaL_error(L, "cannot calculate bbox for page");*/ - /*}*/ - - /*lua_pushnumber(L, ((double)result.x0)/100);*/ - /*lua_pushnumber(L, ((double)result.y0)/100);*/ - /*lua_pushnumber(L, ((double)result.x1)/100);*/ - /*lua_pushnumber(L, ((double)result.y1)/100);*/ - - /*return 4;*/ -/*}*/ +/* unsupported so fake it */ +static int getUsedBBox(lua_State *L) { + DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage"); + + lua_pushnumber(L, (double)0.01); + lua_pushnumber(L, (double)0.01); + lua_pushnumber(L, (double)-0.01); + lua_pushnumber(L, (double)-0.01); + + return 4; +} static int closePage(lua_State *L) { DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage"); @@ -384,7 +367,7 @@ static const struct luaL_reg djvudocument_meth[] = { static const struct luaL_reg djvupage_meth[] = { {"getSize", getPageSize}, - /*{"getUsedBBox", getUsedBBox},*/ + {"getUsedBBox", getUsedBBox}, {"close", closePage}, {"__gc", closePage}, {"draw", drawPage}, diff --git a/pdfreader.lua b/pdfreader.lua index b40d6218e..9db9d0f1d 100644 --- a/pdfreader.lua +++ b/pdfreader.lua @@ -51,7 +51,8 @@ PDFReader = { settings = nil, -- we will use this one often, so keep it "static": - nulldc = pdf.newDC(), + nulldc = nil, + newDC = nil, -- tile cache configuration: cache_max_memsize = 1024*1024*5, -- 5MB tile cache @@ -125,7 +126,22 @@ end -- open a PDF file and its settings store function PDFReader:open(filename, password) - self.doc = pdf.openDocument(filename, password or "") + if string.match(filename, ".+%.[dD][jJ][vV][uU]$") then + self.doc = djvu.openDocument(filename) + self.newDC = function() + print("djvu.newDC") + return djvu.newDC() + end + else + self.doc = pdf.openDocument(filename, password or "") + self.newDC = function() + print("pdf.newDC") + return pdf.newDC() + end + end + + self.nulldc = self.newDC(); + if self.doc ~= nil then self.settings = DocSettings:open(filename) local gamma = self.settings:readsetting("gamma") @@ -139,7 +155,7 @@ end -- set viewer state according to zoom state function PDFReader:setzoom(page) - local dc = pdf.newDC() + local dc = self.newDC() local pwidth, pheight = page:getSize(self.nulldc) print("# page::getSize "..pwidth.."*"..pheight); local x0, y0, x1, y1 = page:getUsedBBox() From bd02f93d50f00951a153cf0d8ea45f5b429c0150 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 5 Mar 2012 08:58:11 +0800 Subject: [PATCH 15/31] mod: remove sqlite in kpdfview dependence --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4a95b15f8..939df0afe 100644 --- a/Makefile +++ b/Makefile @@ -59,7 +59,7 @@ THIRDPARTYLIBS := $(MUPDFLIBDIR)/libfreetype.a \ LUALIB := $(LUADIR)/src/liblua.a -kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o input.o util.o ft.o $(SQLITE3OBJS) lfs.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) $(DJVULIBS) djvu.o +kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o input.o util.o ft.o lfs.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) $(DJVULIBS) djvu.o $(CC) -lm -ldl $(EMU_LDFLAGS) -lstdc++ \ kpdfview.o \ einkfb.o \ From 145d7006853feea2d742a040007c84f9ec4819b9 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 5 Mar 2012 09:04:00 +0800 Subject: [PATCH 16/31] mod: add fake toc method in djvu.c --- djvu.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/djvu.c b/djvu.c index 7429b92fd..4361561e5 100644 --- a/djvu.c +++ b/djvu.c @@ -125,6 +125,18 @@ static int getNumberOfPages(lua_State *L) { return 1; } +/* not supported yet, so return empty table */ +static int getTableOfContent(lua_State *L) { + /*int count = 1;*/ + + DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument"); + /*ol = djvu_load_outline(doc->doc_ref);*/ + + lua_newtable(L); + /*walkTableOfContent(L, ol, &count, 0);*/ + return 1; +} + static int newDrawContext(lua_State *L) { int rotate = luaL_optint(L, 1, 0); double zoom = luaL_optnumber(L, 2, (double) 1.0); @@ -359,7 +371,7 @@ static const struct luaL_reg djvu_func[] = { static const struct luaL_reg djvudocument_meth[] = { {"openPage", openPage}, {"getPages", getNumberOfPages}, - /*{"getTOC", getTableOfContent},*/ + {"getTOC", getTableOfContent}, {"close", closeDocument}, {"__gc", closeDocument}, {NULL, NULL} From b318ca08e3c891070a4115dc5d72dc4cd19affed Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 5 Mar 2012 09:46:16 +0800 Subject: [PATCH 17/31] mod: merge djvu branch with master --- djvureader.lua | 75 ++++++ filesearcher.lua | 8 +- pdfreader.lua | 574 +--------------------------------------------- reader.lua | 39 +++- unireader.lua | 582 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 698 insertions(+), 580 deletions(-) create mode 100644 djvureader.lua create mode 100644 unireader.lua diff --git a/djvureader.lua b/djvureader.lua new file mode 100644 index 000000000..f34c434f0 --- /dev/null +++ b/djvureader.lua @@ -0,0 +1,75 @@ +require "unireader" + +DJVUReader = UniReader:new{ + newDC = function() + print("djvu.newDC") + return djvu.newDC() + end, +} + +function DJVUReader:init() + self.nulldc = self.newDC() +end + +-- open a DJVU file and its settings store +function DJVUReader:open(filename) + self.doc = djvu.openDocument(filename) + if self.doc ~= nil then + self.settings = DocSettings:open(filename) + local gamma = self.settings:readsetting("gamma") + if gamma then + self.globalgamma = gamma + end + return true + end + return false +end + +--set viewer state according to zoom state +function DJVUReader:setzoom(page) + local dc = self.newDC() + local pwidth, pheight = page:getSize(self.nulldc) + + if self.globalzoommode == self.ZOOM_FIT_TO_PAGE then + self.globalzoom = width / pwidth + self.offset_x = 0 + self.offset_y = (height - (self.globalzoom * pheight)) / 2 + if height / pheight < self.globalzoom then + self.globalzoom = height / pheight + print(width, (self.globalzoom * pwidth)) + self.offset_x = (width - (self.globalzoom * pwidth)) / 2 + self.offset_y = 0 + end + elseif self.globalzoommode == self.ZOOM_FIT_TO_PAGE_WIDTH then + self.globalzoom = width / pwidth + self.offset_x = 0 + self.offset_y = (height - (self.globalzoom * pheight)) / 2 + elseif self.globalzoommode == self.ZOOM_FIT_TO_PAGE_HEIGHT then + self.globalzoom = height / pheight + self.offset_x = (width - (self.globalzoom * pwidth)) / 2 + self.offset_y = 0 + end + + dc:setZoom(self.globalzoom) + -- record globalzoom for manual zoom in/out + self.globalzoom_orig = self.globalzoom + + dc:setRotate(self.globalrotate); + dc:setOffset(self.offset_x, self.offset_y) + self.fullwidth, self.fullheight = page:getSize(dc) + self.min_offset_x = fb.bb:getWidth() - self.fullwidth + self.min_offset_y = fb.bb:getHeight() - self.fullheight + if(self.min_offset_x > 0) then + self.min_offset_x = 0 + end + if(self.min_offset_y > 0) then + self.min_offset_y = 0 + end + + -- set gamma here, we don't have any other good place for this right now: + if self.globalgamma ~= self.GAMMA_NO_GAMMA then + print("gamma correction: "..self.globalgamma) + dc:setGamma(self.globalgamma) + end + return dc +end diff --git a/filesearcher.lua b/filesearcher.lua index 815a26603..e0f41d8de 100644 --- a/filesearcher.lua +++ b/filesearcher.lua @@ -261,12 +261,8 @@ function FileSearcher:choose(ypos, height, keywords) pagedirty = true elseif ev.code == KEY_ENTER or ev.code == KEY_FW_PRESS then file_entry = self.result[perpage*(self.page-1)+self.current] - file_path = file_entry.dir .. "/" .. file_entry.name - - if PDFReader:open(file_path,"") then -- TODO: query for password - PDFReader:goto(tonumber(PDFReader.settings:readsetting("last_page") or 1)) - PDFReader:inputloop() - end + file_full_path = file_entry.dir .. "/" .. file_entry.name + openFile(file_full_path) pagedirty = true elseif ev.code == KEY_BACK then diff --git a/pdfreader.lua b/pdfreader.lua index 9db9d0f1d..8973cfadf 100644 --- a/pdfreader.lua +++ b/pdfreader.lua @@ -1,147 +1,19 @@ -require "keys" -require "settings" ---require "tocmenu" -require "selectmenu" +require "unireader" -PDFReader = { - -- "constants": - ZOOM_BY_VALUE = 0, - ZOOM_FIT_TO_PAGE = -1, - ZOOM_FIT_TO_PAGE_WIDTH = -2, - ZOOM_FIT_TO_PAGE_HEIGHT = -3, - ZOOM_FIT_TO_CONTENT = -4, - ZOOM_FIT_TO_CONTENT_WIDTH = -5, - ZOOM_FIT_TO_CONTENT_HEIGHT = -6, - ZOOM_FIT_TO_CONTENT_HALF_WIDTH = -7, - - GAMMA_NO_GAMMA = 1.0, - - -- framebuffer update policy state: - rcount = 5, - rcountmax = 5, - - -- zoom state: - globalzoom = 1.0, - globalzoommode = -1, -- ZOOM_FIT_TO_PAGE - - globalrotate = 0, - - -- gamma setting: - globalgamma = 1.0, -- GAMMA_NO_GAMMA - - -- size of current page for current zoom level in pixels - fullwidth = 0, - fullheight = 0, - offset_x = 0, - offset_y = 0, - min_offset_x = 0, - min_offset_y = 0, - - -- set panning distance - shift_x = 100, - shift_y = 50, - pan_by_page = false, -- using shift_[xy] or width/height - pan_x = 0, -- top-left offset of page when pan activated - pan_y = 0, - pan_margin = 20, - - -- the pdf document: - doc = nil, - -- the document's setting store: - settings = nil, - - -- we will use this one often, so keep it "static": - nulldc = nil, - newDC = nil, - - -- tile cache configuration: - cache_max_memsize = 1024*1024*5, -- 5MB tile cache - cache_item_max_pixels = 1024*1024*2, -- max. size of rendered tiles - cache_max_ttl = 20, -- time to live - -- tile cache state: - cache_current_memsize = 0, - cache = {}, - jump_stack = {}, +PDFReader = UniReader:new{ + newDC = function() + print("pdf.newDC") + return pdf.newDC() + end, } --- guarantee that we have enough memory in cache -function PDFReader:cacheclaim(size) - if(size > self.cache_max_memsize) then - -- we're not allowed to claim this much at all - error("too much memory claimed") - return false - end - while self.cache_current_memsize + size > self.cache_max_memsize do - -- repeat this until we have enough free memory - for k, _ in pairs(self.cache) do - if self.cache[k].ttl > 0 then - -- reduce ttl - self.cache[k].ttl = self.cache[k].ttl - 1 - else - -- cache slot is at end of life, so kick it out - self.cache_current_memsize = self.cache_current_memsize - self.cache[k].size - self.cache[k] = nil - end - end - end - self.cache_current_memsize = self.cache_current_memsize + size - return true -end - -function PDFReader:draworcache(no, zoom, offset_x, offset_y, width, height, gamma, rotate) - -- hash draw state - local hash = self:cachehash(no, zoom, offset_x, offset_y, width, height, gamma, rotate) - if self.cache[hash] == nil then - -- not in cache, so prepare cache slot... - self:cacheclaim(width * height / 2); - self.cache[hash] = { - ttl = self.cache_max_ttl, - size = width * height / 2, - bb = Blitbuffer.new(width, height) - } - -- and draw the page - local page = self.doc:openPage(no) - local dc = self:setzoom(page, hash) - page:draw(dc, self.cache[hash].bb, 0, 0) - page:close() - else - -- we have the page in our cache, - -- so give it more ttl. - self.cache[hash].ttl = self.cache_max_ttl - end - return hash -end - --- calculate a hash for our current state -function PDFReader:cachehash(no, zoom, offset_x, offset_y, width, height, gamma, rotate) - -- TODO (?): make this a "real" hash... - return no..'_'..zoom..'_'..offset_x..','..offset_y..'-'..width..'x'..height..'_'..gamma..'_'..rotate -end - --- blank the cache -function PDFReader:clearcache() - self.cache = {} - self.cache_current_memsize = 0 +function PDFReader:init() + self.nulldc = self.newDC(); end -- open a PDF file and its settings store function PDFReader:open(filename, password) - if string.match(filename, ".+%.[dD][jJ][vV][uU]$") then - self.doc = djvu.openDocument(filename) - self.newDC = function() - print("djvu.newDC") - return djvu.newDC() - end - else - self.doc = pdf.openDocument(filename, password or "") - self.newDC = function() - print("pdf.newDC") - return pdf.newDC() - end - end - - self.nulldc = self.newDC(); - + self.doc = pdf.openDocument(filename, password or "") if self.doc ~= nil then self.settings = DocSettings:open(filename) local gamma = self.settings:readsetting("gamma") @@ -152,431 +24,3 @@ function PDFReader:open(filename, password) end return false end - --- set viewer state according to zoom state -function PDFReader:setzoom(page) - local dc = self.newDC() - local pwidth, pheight = page:getSize(self.nulldc) - print("# page::getSize "..pwidth.."*"..pheight); - local x0, y0, x1, y1 = page:getUsedBBox() - if x0 == 0.01 and y0 == 0.01 and x1 == -0.01 and y1 == -0.01 then - x0 = 0 - y0 = 0 - x1 = pwidth - y1 = pheight - end - -- clamp to page BBox - if x0 < 0 then x0 = 0 end - if x1 > pwidth then x1 = pwidth end - if y0 < 0 then y0 = 0 end - if y1 > pheight then y1 = pheight end - - print("# page::getUsedBBox "..x0.."*"..y0.." "..x1.."*"..y1); - - if self.globalzoommode == self.ZOOM_FIT_TO_PAGE - or self.globalzoommode == self.ZOOM_FIT_TO_CONTENT then - self.globalzoom = width / pwidth - self.offset_x = 0 - self.offset_y = (height - (self.globalzoom * pheight)) / 2 - if height / pheight < self.globalzoom then - self.globalzoom = height / pheight - self.offset_x = (width - (self.globalzoom * pwidth)) / 2 - self.offset_y = 0 - end - elseif self.globalzoommode == self.ZOOM_FIT_TO_PAGE_WIDTH - or self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_WIDTH then - self.globalzoom = width / pwidth - self.offset_x = 0 - self.offset_y = (height - (self.globalzoom * pheight)) / 2 - elseif self.globalzoommode == self.ZOOM_FIT_TO_PAGE_HEIGHT - or self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_HEIGHT then - self.globalzoom = height / pheight - self.offset_x = (width - (self.globalzoom * pwidth)) / 2 - self.offset_y = 0 - end - if self.globalzoommode == self.ZOOM_FIT_TO_CONTENT then - if (x1 - x0) < pwidth then - self.globalzoom = width / (x1 - x0) - self.offset_x = -1 * x0 * self.globalzoom - self.offset_y = -1 * y0 * self.globalzoom + (height - (self.globalzoom * (y1 - y0))) / 2 - if height / (y1 - y0) < self.globalzoom then - self.globalzoom = height / (y1 - y0) - self.offset_x = -1 * x0 * self.globalzoom + (width - (self.globalzoom * (x1 - x0))) / 2 - self.offset_y = -1 * y0 * self.globalzoom - end - end - elseif self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_WIDTH then - if (x1 - x0) < pwidth then - self.globalzoom = width / (x1 - x0) - self.offset_x = -1 * x0 * self.globalzoom - self.offset_y = -1 * y0 * self.globalzoom + (height - (self.globalzoom * (y1 - y0))) / 2 - end - elseif self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_HEIGHT then - if (y1 - y0) < pheight then - self.globalzoom = height / (y1 - y0) - self.offset_x = -1 * x0 * self.globalzoom + (width - (self.globalzoom * (x1 - x0))) / 2 - self.offset_y = -1 * y0 * self.globalzoom - end - elseif self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH then - self.globalzoom = width / (x1 - x0 + self.pan_margin) - self.offset_x = -1 * x0 * self.globalzoom * 2 + self.pan_margin - self.globalzoom = height / (y1 - y0) - self.offset_y = -1 * y0 * self.globalzoom * 2 + self.pan_margin - self.globalzoom = width / (x1 - x0 + self.pan_margin) * 2 - print("column mode offset:"..self.offset_x.."*"..self.offset_y.." zoom:"..self.globalzoom); - self.globalzoommode = self.ZOOM_BY_VALUE -- enable pan mode - self.pan_x = self.offset_x - self.pan_y = self.offset_y - self.pan_by_page = true - end - dc:setZoom(self.globalzoom) - dc:setRotate(self.globalrotate); - dc:setOffset(self.offset_x, self.offset_y) - self.fullwidth, self.fullheight = page:getSize(dc) - self.min_offset_x = fb.bb:getWidth() - self.fullwidth - self.min_offset_y = fb.bb:getHeight() - self.fullheight - if(self.min_offset_x > 0) then - self.min_offset_x = 0 - end - if(self.min_offset_y > 0) then - self.min_offset_y = 0 - end - - print("# PDFReader:setzoom globalzoom:"..self.globalzoom.." globalrotate:"..self.globalrotate.." offset:"..self.offset_x.."*"..self.offset_y.." pagesize:"..self.fullwidth.."*"..self.fullheight.." min_offset:"..self.min_offset_x.."*"..self.min_offset_y) - - -- set gamma here, we don't have any other good place for this right now: - if self.globalgamma ~= self.GAMMA_NO_GAMMA then - print("gamma correction: "..self.globalgamma) - dc:setGamma(self.globalgamma) - end - return dc -end - --- render and blit a page -function PDFReader:show(no) - local slot - if self.globalzoommode ~= self.ZOOM_BY_VALUE then - slot = self:draworcache(no,self.globalzoommode,self.offset_x,self.offset_y,width,height,self.globalgamma,self.globalrotate) - else - slot = self:draworcache(no,self.globalzoom,self.offset_x,self.offset_y,width,height,self.globalgamma,self.globalrotate) - end - fb.bb:blitFullFrom(self.cache[slot].bb) - if self.rcount == self.rcountmax then - print("full refresh") - self.rcount = 1 - fb:refresh(0) - else - print("partial refresh") - self.rcount = self.rcount + 1 - fb:refresh(1) - end - self.slot_visible = slot; -end - -function PDFReader:add_jump(pageno) - local jump_item = nil - -- add current page to jump_stack if no in - for _t,_v in ipairs(self.jump_stack) do - if _v.page == pageno then - jump_item = _v - table.remove(self.jump_stack, _t) - elseif _v.page == no then - -- the page we jumped to should not be show in stack - table.remove(self.jump_stack, _t) - end - end - -- create a new one if not found - if not jump_item then - jump_item = { - page = pageno, - datetime = os.date("%Y-%m-%d %H:%M:%S"), - } - end - -- insert at the start - table.insert(self.jump_stack, 1, jump_item) - if #self.jump_stack > 10 then - -- remove the last element to keep the size less than 10 - table.remove(self.jump_stack) - end -end - --- change current page and cache next page after rendering -function PDFReader:goto(no) - if no < 1 or no > self.doc:getPages() then - return - end - - -- for jump_stack - if self.pageno and math.abs(self.pageno - no) > 1 then - self:add_jump(self.pageno) - end - - self.pageno = no - self:show(no) - if no < self.doc:getPages() then - if self.globalzoommode ~= self.ZOOM_BY_VALUE then - -- pre-cache next page - self:draworcache(no+1,self.globalzoommode,self.offset_x,self.offset_y,width,height,self.globalgamma,self.globalrotate) - else - self:draworcache(no,self.globalzoom,self.offset_x,self.offset_y,width,height,self.globalgamma,self.globalrotate) - end - end -end - --- adjust global gamma setting -function PDFReader:modify_gamma(factor) - print("modify_gamma, gamma="..self.globalgamma.." factor="..factor) - self.globalgamma = self.globalgamma * factor; - self:goto(self.pageno) -end - --- adjust zoom state and trigger re-rendering -function PDFReader:setglobalzoommode(newzoommode) - if self.globalzoommode ~= newzoommode then - self.globalzoommode = newzoommode - self:goto(self.pageno) - end -end - --- adjust zoom state and trigger re-rendering -function PDFReader:setglobalzoom(zoom) - if self.globalzoom ~= zoom then - self.globalzoommode = self.ZOOM_BY_VALUE - self.globalzoom = zoom - self:goto(self.pageno) - end -end - -function PDFReader:setrotate(rotate) - self.globalrotate = rotate - self:goto(self.pageno) -end - -function PDFReader:showTOC() - toc = self.doc:getTOC() - local menu_items = {} - -- build menu items - for _k,_v in ipairs(toc) do - table.insert(menu_items, - (" "):rep(_v.depth-1) .. _v.title:gsub("\13", "")) - end - toc_menu = SelectMenu:new{ - menu_title = "Table of Contents", - item_array = menu_items, - no_item_msg = "This document does not have a Table of Contents.", - } - item_no = toc_menu:choose(0, fb.bb:getHeight()) - if item_no then - self:goto(toc[item_no].page) - else - self:goto(self.pageno) - end -end - -function PDFReader:showJumpStack() - local menu_items = {} - for _k,_v in ipairs(self.jump_stack) do - table.insert(menu_items, - _v.datetime.." -> Page ".._v.page) - end - jump_menu = SelectMenu:new{ - menu_title = "Jump Keeper (current page: "..self.pageno..")", - item_array = menu_items, - no_item_msg = "No jump history.", - } - item_no = jump_menu:choose(0, fb.bb:getHeight()) - if item_no then - local jump_item = self.jump_stack[item_no] - self:goto(jump_item.page) - else - self:goto(self.pageno) - end -end - - --- wait for input and handle it -function PDFReader:inputloop() - local keep_running = true - while 1 do - local ev = input.waitForEvent() - ev.code = adjustKeyEvents(ev) - if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then - local secs, usecs = util.gettime() - if ev.code == KEY_PGFWD or ev.code == KEY_LPGFWD then - if Keys.shiftmode then - self:setglobalzoom(self.globalzoom+0.2) - elseif Keys.altmode then - self:setglobalzoom(self.globalzoom+0.1) - else - if self.pan_by_page then - self.offset_x = self.pan_x - self.offset_y = self.pan_y - end - self:goto(self.pageno + 1) - end - elseif ev.code == KEY_PGBCK or ev.code == KEY_LPGBCK then - if Keys.shiftmode then - self:setglobalzoom(self.globalzoom-0.2) - elseif Keys.altmode then - self:setglobalzoom(self.globalzoom-0.1) - else - if self.pan_by_page then - self.offset_x = self.pan_x - self.offset_y = self.pan_y - end - self:goto(self.pageno - 1) - end - elseif ev.code == KEY_BACK then - if Keys.altmode then - -- altmode, exit pdfreader - break - else - -- not altmode, back to last jump - if #self.jump_stack ~= 0 then - self:goto(self.jump_stack[1].page) - end - end - elseif ev.code == KEY_VPLUS then - self:modify_gamma( 1.25 ) - elseif ev.code == KEY_VMINUS then - self:modify_gamma( 0.8 ) - elseif ev.code == KEY_A then - if Keys.shiftmode then - self:setglobalzoommode(self.ZOOM_FIT_TO_CONTENT) - else - self:setglobalzoommode(self.ZOOM_FIT_TO_PAGE) - end - elseif ev.code == KEY_S then - if Keys.shiftmode then - self:setglobalzoommode(self.ZOOM_FIT_TO_CONTENT_WIDTH) - else - self:setglobalzoommode(self.ZOOM_FIT_TO_PAGE_WIDTH) - end - elseif ev.code == KEY_D then - if Keys.shiftmode then - self:setglobalzoommode(self.ZOOM_FIT_TO_CONTENT_HEIGHT) - else - self:setglobalzoommode(self.ZOOM_FIT_TO_PAGE_HEIGHT) - end - elseif ev.code == KEY_F then - self:setglobalzoommode(self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH) - elseif ev.code == KEY_T then - self:showTOC() - elseif ev.code == KEY_B then - if Keys.shiftmode then - self:add_jump(self.pageno) - else - self:showJumpStack() - end - elseif ev.code == KEY_J then - self:setrotate( self.globalrotate + 10 ) - elseif ev.code == KEY_K then - self:setrotate( self.globalrotate - 10 ) - elseif ev.code == KEY_HOME then - -- signal quit - keep_running = false - break - end - - if self.globalzoommode == self.ZOOM_BY_VALUE then - local x - local y - - if Keys.shiftmode then -- shift always moves in small steps - x = self.shift_x / 2 - y = self.shift_y / 2 - elseif Keys.altmode then - x = self.shift_x / 5 - y = self.shift_y / 5 - elseif self.pan_by_page then - x = width; - y = height - self.pan_margin; -- overlap for lines which didn't fit - else - x = self.shift_x - y = self.shift_y - end - - print("offset "..self.offset_x.."*"..self.offset_x.." shift "..x.."*"..y.." globalzoom="..self.globalzoom) - local old_offset_x = self.offset_x - local old_offset_y = self.offset_y - - if ev.code == KEY_FW_LEFT then - self.offset_x = self.offset_x + x - if self.offset_x > 0 then - self.offset_x = 0 - if self.pan_by_page and self.pageno > 1 then - self.offset_x = self.pan_x - self.offset_y = self.min_offset_y -- bottom - self:goto(self.pageno - 1) - end - end - if self.pan_by_page then - self.offset_y = self.min_offset_y - end - elseif ev.code == KEY_FW_RIGHT then - print("# FW RIGHT "..self.offset_x.." - "..x.." < "..self.min_offset_x); - self.offset_x = self.offset_x - x - if self.offset_x < self.min_offset_x - self.pan_margin then - self.offset_x = self.min_offset_x - if self.pan_by_page and self.pageno < self.doc:getPages() then - self.offset_x = self.pan_x - self.offset_y = self.pan_y - self:goto(self.pageno + 1) - end - end - if self.pan_by_page then - self.offset_y = self.pan_y - end - elseif ev.code == KEY_FW_UP then - self.offset_y = self.offset_y + y - if self.offset_y > 0 then - self.offset_y = 0 - end - elseif ev.code == KEY_FW_DOWN then - self.offset_y = self.offset_y - y - if self.offset_y < self.min_offset_y then - self.offset_y = self.min_offset_y - end - elseif ev.code == KEY_FW_PRESS then - if Keys.shiftmode then - if self.pan_by_page then - self.offset_x = self.pan_x - self.offset_y = self.pan_y - else - self.offset_x = 0 - self.offset_y = 0 - end - else - self.pan_by_page = not self.pan_by_page - if self.pan_by_page then - self.pan_x = self.offset_x - self.pan_y = self.offset_y - end - end - end - if old_offset_x ~= self.offset_x - or old_offset_y ~= self.offset_y then - self:goto(self.pageno) - end - end - - local nsecs, nusecs = util.gettime() - local dur = (nsecs - secs) * 1000000 + nusecs - usecs - print("E: T="..ev.type.." V="..ev.value.." C="..ev.code.." DUR="..dur) - end - end - - self:clearcache() - if self.doc ~= nil then - self.doc:close() - end - if self.settings ~= nil then - self.settings:savesetting("last_page", self.pageno) - self.settings:savesetting("gamma", self.globalgamma) - self.settings:close() - end - - return keep_running -end - - diff --git a/reader.lua b/reader.lua index 1863eae8c..e8adcae54 100755 --- a/reader.lua +++ b/reader.lua @@ -19,6 +19,7 @@ require "alt_getopt" require "pdfreader" +require "djvureader" require "filechooser" require "settings" @@ -30,6 +31,25 @@ longopts = { device = "d", help = "h" } + +function openFile(filename) + local file_type = string.lower(string.match(filename, ".+%.(.+)")) + if file_type == "djvu" then + print "haha" + if DJVUReader:open(filename) then + page_num = DJVUReader.settings:readsetting("last_page") or 1 + DJVUReader:goto(tonumber(page_num)) + DJVUReader:inputloop() + end + elseif file_type == "pdf" then + if PDFReader:open(filename,"") then -- TODO: query for password + page_num = PDFReader.settings:readsetting("last_page") or 1 + PDFReader:goto(tonumber(page_num)) + PDFReader:inputloop() + end + end +end + optarg, optind = alt_getopt.get_opts(ARGV, "p:G:hg:d:", longopts) if optarg["h"] or ARGV[optind] == nil then print("usage: ./reader.lua [OPTION] ... DOCUMENT.PDF") @@ -52,6 +72,7 @@ if optarg["h"] or ARGV[optind] == nil then return end + if optarg["d"] == "k3" then -- for now, the only difference is the additional input device input.open("/dev/input/event0") @@ -91,27 +112,27 @@ if r_cfont ~=nil then FontChooser.cfont = r_cfont end +-- initialize specific readers +PDFReader:init() +DJVUReader:init() +-- display directory or open file if lfs.attributes(ARGV[optind], "mode") == "directory" then local running = true FileChooser:setPath(ARGV[optind]) while running do - local pdffile = FileChooser:choose(0,height) - if pdffile ~= nil then - if PDFReader:open(pdffile,"") then -- TODO: query for password - PDFReader:goto(tonumber(PDFReader.settings:readsetting("last_page") or 1)) - running = PDFReader:inputloop() - end + local file = FileChooser:choose(0,height) + if file ~= nil then + openFile(file) else running = false end end else - PDFReader:open(ARGV[optind], optarg["p"]) - PDFReader:goto(tonumber(optarg["g"]) or tonumber(PDFReader.settings:readsetting("last_page") or 1)) - PDFReader:inputloop() + openFile(ARGV[optind], optarg["p"]) end + -- save reader settings reader_settings:savesetting("cfont", FontChooser.cfont) reader_settings:close() diff --git a/unireader.lua b/unireader.lua new file mode 100644 index 000000000..3d476c2ae --- /dev/null +++ b/unireader.lua @@ -0,0 +1,582 @@ +require "keys" +require "settings" +require "selectmenu" + +UniReader = { + -- "constants": + ZOOM_BY_VALUE = 0, + ZOOM_FIT_TO_PAGE = -1, + ZOOM_FIT_TO_PAGE_WIDTH = -2, + ZOOM_FIT_TO_PAGE_HEIGHT = -3, + ZOOM_FIT_TO_CONTENT = -4, + ZOOM_FIT_TO_CONTENT_WIDTH = -5, + ZOOM_FIT_TO_CONTENT_HEIGHT = -6, + ZOOM_FIT_TO_CONTENT_HALF_WIDTH = -7, + + GAMMA_NO_GAMMA = 1.0, + + -- framebuffer update policy state: + rcount = 5, + rcountmax = 5, + + -- zoom state: + globalzoom = 1.0, + globalzoom_orig = 1.0, + globalzoommode = -1, -- ZOOM_FIT_TO_PAGE + + globalrotate = 0, + + -- gamma setting: + globalgamma = 1.0, -- GAMMA_NO_GAMMA + + -- size of current page for current zoom level in pixels + fullwidth = 0, + fullheight = 0, + offset_x = 0, + offset_y = 0, + min_offset_x = 0, + min_offset_y = 0, + + -- set panning distance + shift_x = 100, + shift_y = 50, + pan_by_page = false, -- using shift_[xy] or width/height + pan_x = 0, -- top-left offset of page when pan activated + pan_y = 0, + pan_margin = 20, + + -- the document: + doc = nil, + -- the document's setting store: + settings = nil, + + -- you have to initialize newDC, nulldc in specific reader + newDC = function() return nil end, + -- we will use this one often, so keep it "static": + nulldc = nil, + + -- tile cache configuration: + cache_max_memsize = 1024*1024*5, -- 5MB tile cache + cache_item_max_pixels = 1024*1024*2, -- max. size of rendered tiles + cache_max_ttl = 20, -- time to live + -- tile cache state: + cache_current_memsize = 0, + cache = {}, + jump_stack = {}, +} + +function UniReader:new(o) + o = o or {} + setmetatable(o, self) + self.__index = self + return o +end + +function UniReader:init() + print("empty initialization method!") +end + +-- guarantee that we have enough memory in cache +function UniReader:cacheclaim(size) + if(size > self.cache_max_memsize) then + -- we're not allowed to claim this much at all + error("too much memory claimed") + return false + end + while self.cache_current_memsize + size > self.cache_max_memsize do + -- repeat this until we have enough free memory + for k, _ in pairs(self.cache) do + if self.cache[k].ttl > 0 then + -- reduce ttl + self.cache[k].ttl = self.cache[k].ttl - 1 + else + -- cache slot is at end of life, so kick it out + self.cache_current_memsize = self.cache_current_memsize - self.cache[k].size + self.cache[k] = nil + end + end + end + self.cache_current_memsize = self.cache_current_memsize + size + return true +end + +function UniReader:draworcache(no, zoom, offset_x, offset_y, width, height, gamma, rotate) + -- hash draw state + local hash = self:cachehash(no, zoom, offset_x, offset_y, width, height, gamma, rotate) + if self.cache[hash] == nil then + -- not in cache, so prepare cache slot... + self:cacheclaim(width * height / 2); + self.cache[hash] = { + ttl = self.cache_max_ttl, + size = width * height / 2, + bb = Blitbuffer.new(width, height) + } + -- and draw the page + local page = self.doc:openPage(no) + local dc = self:setzoom(page, hash) + page:draw(dc, self.cache[hash].bb, 0, 0) + page:close() + else + -- we have the page in our cache, + -- so give it more ttl. + self.cache[hash].ttl = self.cache_max_ttl + end + return hash +end + +-- calculate a hash for our current state +function UniReader:cachehash(no, zoom, offset_x, offset_y, width, height, gamma, rotate) + -- TODO (?): make this a "real" hash... + return no..'_'..zoom..'_'..offset_x..','..offset_y..'-'..width..'x'..height..'_'..gamma..'_'..rotate +end + +-- blank the cache +function UniReader:clearcache() + self.cache = {} + self.cache_current_memsize = 0 +end + +-- open a file and its settings store +function UniReader:open(filename, password) + return false +end + +-- set viewer state according to zoom state +function UniReader:setzoom(page) + local dc = self.newDC() + local pwidth, pheight = page:getSize(self.nulldc) + print("# page::getSize "..pwidth.."*"..pheight); + local x0, y0, x1, y1 = page:getUsedBBox() + if x0 == 0.01 and y0 == 0.01 and x1 == -0.01 and y1 == -0.01 then + x0 = 0 + y0 = 0 + x1 = pwidth + y1 = pheight + end + -- clamp to page BBox + if x0 < 0 then x0 = 0 end + if x1 > pwidth then x1 = pwidth end + if y0 < 0 then y0 = 0 end + if y1 > pheight then y1 = pheight end + + print("# page::getUsedBBox "..x0.."*"..y0.." "..x1.."*"..y1); + + if self.globalzoommode == self.ZOOM_FIT_TO_PAGE + or self.globalzoommode == self.ZOOM_FIT_TO_CONTENT then + self.globalzoom = width / pwidth + self.offset_x = 0 + self.offset_y = (height - (self.globalzoom * pheight)) / 2 + if height / pheight < self.globalzoom then + self.globalzoom = height / pheight + self.offset_x = (width - (self.globalzoom * pwidth)) / 2 + self.offset_y = 0 + end + elseif self.globalzoommode == self.ZOOM_FIT_TO_PAGE_WIDTH + or self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_WIDTH then + self.globalzoom = width / pwidth + self.offset_x = 0 + self.offset_y = (height - (self.globalzoom * pheight)) / 2 + elseif self.globalzoommode == self.ZOOM_FIT_TO_PAGE_HEIGHT + or self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_HEIGHT then + self.globalzoom = height / pheight + self.offset_x = (width - (self.globalzoom * pwidth)) / 2 + self.offset_y = 0 + end + if self.globalzoommode == self.ZOOM_FIT_TO_CONTENT then + if (x1 - x0) < pwidth then + self.globalzoom = width / (x1 - x0) + self.offset_x = -1 * x0 * self.globalzoom + self.offset_y = -1 * y0 * self.globalzoom + (height - (self.globalzoom * (y1 - y0))) / 2 + if height / (y1 - y0) < self.globalzoom then + self.globalzoom = height / (y1 - y0) + self.offset_x = -1 * x0 * self.globalzoom + (width - (self.globalzoom * (x1 - x0))) / 2 + self.offset_y = -1 * y0 * self.globalzoom + end + end + elseif self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_WIDTH then + if (x1 - x0) < pwidth then + self.globalzoom = width / (x1 - x0) + self.offset_x = -1 * x0 * self.globalzoom + self.offset_y = -1 * y0 * self.globalzoom + (height - (self.globalzoom * (y1 - y0))) / 2 + end + elseif self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_HEIGHT then + if (y1 - y0) < pheight then + self.globalzoom = height / (y1 - y0) + self.offset_x = -1 * x0 * self.globalzoom + (width - (self.globalzoom * (x1 - x0))) / 2 + self.offset_y = -1 * y0 * self.globalzoom + end + elseif self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH then + self.globalzoom = width / (x1 - x0 + self.pan_margin) + self.offset_x = -1 * x0 * self.globalzoom * 2 + self.pan_margin + self.globalzoom = height / (y1 - y0) + self.offset_y = -1 * y0 * self.globalzoom * 2 + self.pan_margin + self.globalzoom = width / (x1 - x0 + self.pan_margin) * 2 + print("column mode offset:"..self.offset_x.."*"..self.offset_y.." zoom:"..self.globalzoom); + self.globalzoommode = self.ZOOM_BY_VALUE -- enable pan mode + self.pan_x = self.offset_x + self.pan_y = self.offset_y + self.pan_by_page = true + end + dc:setZoom(self.globalzoom) + dc:setRotate(self.globalrotate); + dc:setOffset(self.offset_x, self.offset_y) + self.fullwidth, self.fullheight = page:getSize(dc) + self.min_offset_x = fb.bb:getWidth() - self.fullwidth + self.min_offset_y = fb.bb:getHeight() - self.fullheight + if(self.min_offset_x > 0) then + self.min_offset_x = 0 + end + if(self.min_offset_y > 0) then + self.min_offset_y = 0 + end + + print("# Reader:setzoom globalzoom:"..self.globalzoom.." globalrotate:"..self.globalrotate.." offset:"..self.offset_x.."*"..self.offset_y.." pagesize:"..self.fullwidth.."*"..self.fullheight.." min_offset:"..self.min_offset_x.."*"..self.min_offset_y) + + -- set gamma here, we don't have any other good place for this right now: + if self.globalgamma ~= self.GAMMA_NO_GAMMA then + print("gamma correction: "..self.globalgamma) + dc:setGamma(self.globalgamma) + end + return dc +end + +-- render and blit a page +function UniReader:show(no) + local slot + if self.globalzoommode ~= self.ZOOM_BY_VALUE then + slot = self:draworcache(no,self.globalzoommode,self.offset_x,self.offset_y,width,height,self.globalgamma,self.globalrotate) + else + slot = self:draworcache(no,self.globalzoom,self.offset_x,self.offset_y,width,height,self.globalgamma,self.globalrotate) + end + fb.bb:blitFullFrom(self.cache[slot].bb) + if self.rcount == self.rcountmax then + print("full refresh") + self.rcount = 1 + fb:refresh(0) + else + print("partial refresh") + self.rcount = self.rcount + 1 + fb:refresh(1) + end + self.slot_visible = slot; +end + +function UniReader:add_jump(pageno) + local jump_item = nil + -- add current page to jump_stack if no in + for _t,_v in ipairs(self.jump_stack) do + if _v.page == pageno then + jump_item = _v + table.remove(self.jump_stack, _t) + elseif _v.page == no then + -- the page we jumped to should not be show in stack + table.remove(self.jump_stack, _t) + end + end + -- create a new one if not found + if not jump_item then + jump_item = { + page = pageno, + datetime = os.date("%Y-%m-%d %H:%M:%S"), + } + end + -- insert at the start + table.insert(self.jump_stack, 1, jump_item) + if #self.jump_stack > 10 then + -- remove the last element to keep the size less than 10 + table.remove(self.jump_stack) + end +end + +-- change current page and cache next page after rendering +function UniReader:goto(no) + if no < 1 or no > self.doc:getPages() then + return + end + + -- for jump_stack + if self.pageno and math.abs(self.pageno - no) > 1 then + self:add_jump(self.pageno) + end + + self.pageno = no + self:show(no) + if no < self.doc:getPages() then + if self.globalzoommode ~= self.ZOOM_BY_VALUE then + -- pre-cache next page + self:draworcache(no+1,self.globalzoommode,self.offset_x,self.offset_y,width,height,self.globalgamma,self.globalrotate) + else + self:draworcache(no,self.globalzoom,self.offset_x,self.offset_y,width,height,self.globalgamma,self.globalrotate) + end + end +end + +-- adjust global gamma setting +function UniReader:modify_gamma(factor) + print("modify_gamma, gamma="..self.globalgamma.." factor="..factor) + self.globalgamma = self.globalgamma * factor; + self:goto(self.pageno) +end + +-- adjust zoom state and trigger re-rendering +function UniReader:setglobalzoommode(newzoommode) + if self.globalzoommode ~= newzoommode then + self.globalzoommode = newzoommode + self:goto(self.pageno) + end +end + +-- adjust zoom state and trigger re-rendering +function UniReader:setglobalzoom(zoom) + if self.globalzoom ~= zoom then + self.globalzoommode = self.ZOOM_BY_VALUE + self.globalzoom = zoom + self:goto(self.pageno) + end +end + +function UniReader:setrotate(rotate) + self.globalrotate = rotate + self:goto(self.pageno) +end + +function UniReader:showTOC() + toc = self.doc:getTOC() + local menu_items = {} + -- build menu items + for _k,_v in ipairs(toc) do + table.insert(menu_items, + (" "):rep(_v.depth-1).._v.title) + end + toc_menu = SelectMenu:new{ + menu_title = "Table of Contents", + item_array = menu_items, + no_item_msg = "This document does not have a Table of Contents.", + } + item_no = toc_menu:choose(0, fb.bb:getHeight()) + if item_no then + self:goto(toc[item_no].page) + else + self:goto(self.pageno) + end +end + +function UniReader:showJumpStack() + local menu_items = {} + for _k,_v in ipairs(self.jump_stack) do + table.insert(menu_items, + _v.datetime.." -> Page ".._v.page) + end + jump_menu = SelectMenu:new{ + menu_title = "Jump Keeper (current page: "..self.pageno..")", + item_array = menu_items, + no_item_msg = "No jump history.", + } + item_no = jump_menu:choose(0, fb.bb:getHeight()) + if item_no then + local jump_item = self.jump_stack[item_no] + self:goto(jump_item.page) + else + self:goto(self.pageno) + end +end + + +-- wait for input and handle it +function UniReader:inputloop() + local keep_running = true + while 1 do + local ev = input.waitForEvent() + ev.code = adjustKeyEvents(ev) + if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then + local secs, usecs = util.gettime() + if ev.code == KEY_PGFWD or ev.code == KEY_LPGFWD then + if Keys.shiftmode then + self:setglobalzoom(self.globalzoom+self.globalzoom_orig*0.2) + elseif Keys.altmode then + self:setglobalzoom(self.globalzoom+self.globalzoom_orig*0.1) + else + if self.pan_by_page then + self.offset_x = self.pan_x + self.offset_y = self.pan_y + end + self:goto(self.pageno + 1) + end + elseif ev.code == KEY_PGBCK or ev.code == KEY_LPGBCK then + if Keys.shiftmode then + self:setglobalzoom(self.globalzoom-self.globalzoom_orig*0.2) + elseif Keys.altmode then + self:setglobalzoom(self.globalzoom-self.globalzoom_orig*0.1) + else + if self.pan_by_page then + self.offset_x = self.pan_x + self.offset_y = self.pan_y + end + self:goto(self.pageno - 1) + end + elseif ev.code == KEY_BACK then + if Keys.altmode then + -- altmode, exit reader + break + else + -- not altmode, back to last jump + if #self.jump_stack ~= 0 then + self:goto(self.jump_stack[1].page) + end + end + elseif ev.code == KEY_VPLUS then + self:modify_gamma( 1.25 ) + elseif ev.code == KEY_VMINUS then + self:modify_gamma( 0.8 ) + elseif ev.code == KEY_A then + if Keys.shiftmode then + self:setglobalzoommode(self.ZOOM_FIT_TO_CONTENT) + else + self:setglobalzoommode(self.ZOOM_FIT_TO_PAGE) + end + elseif ev.code == KEY_S then + if Keys.shiftmode then + self:setglobalzoommode(self.ZOOM_FIT_TO_CONTENT_WIDTH) + else + self:setglobalzoommode(self.ZOOM_FIT_TO_PAGE_WIDTH) + end + elseif ev.code == KEY_D then + if Keys.shiftmode then + self:setglobalzoommode(self.ZOOM_FIT_TO_CONTENT_HEIGHT) + else + self:setglobalzoommode(self.ZOOM_FIT_TO_PAGE_HEIGHT) + end + elseif ev.code == KEY_F then + self:setglobalzoommode(self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH) + elseif ev.code == KEY_T then + self:showTOC() + elseif ev.code == KEY_B then + if Keys.shiftmode then + self:add_jump(self.pageno) + else + self:showJumpStack() + end + elseif ev.code == KEY_J then + self:setrotate( self.globalrotate + 10 ) + elseif ev.code == KEY_K then + self:setrotate( self.globalrotate - 10 ) + elseif ev.code == KEY_HOME then + -- signal quit + keep_running = false + break + end + + if self.globalzoommode == self.ZOOM_BY_VALUE then + local x + local y + + if Keys.shiftmode then -- shift always moves in small steps + x = self.shift_x / 2 + y = self.shift_y / 2 + elseif Keys.altmode then + x = self.shift_x / 5 + y = self.shift_y / 5 + elseif self.pan_by_page then + x = width; + y = height - self.pan_margin; -- overlap for lines which didn't fit + else + x = self.shift_x + y = self.shift_y + end + + print("offset "..self.offset_x.."*"..self.offset_x.." shift "..x.."*"..y.." globalzoom="..self.globalzoom) + local old_offset_x = self.offset_x + local old_offset_y = self.offset_y + + if ev.code == KEY_FW_LEFT then + self.offset_x = self.offset_x + x + if self.offset_x > 0 then + self.offset_x = 0 + if self.pan_by_page and self.pageno > 1 then + self.offset_x = self.pan_x + self.offset_y = self.min_offset_y -- bottom + self:goto(self.pageno - 1) + end + end + if self.pan_by_page then + self.offset_y = self.min_offset_y + end + elseif ev.code == KEY_FW_RIGHT then + print("# FW RIGHT "..self.offset_x.." - "..x.." < "..self.min_offset_x); + self.offset_x = self.offset_x - x + if self.offset_x < self.min_offset_x then + self.offset_x = self.min_offset_x + if self.pan_by_page and self.pageno < self.doc:getPages() then + self.offset_x = self.pan_x + self.offset_y = self.pan_y + self:goto(self.pageno + 1) + end + end + if self.pan_by_page then + self.offset_y = self.pan_y + end + elseif ev.code == KEY_FW_UP then + self.offset_y = self.offset_y + y + if self.offset_y > 0 then + self.offset_y = 0 + end + elseif ev.code == KEY_FW_DOWN then + self.offset_y = self.offset_y - y + if self.offset_y < self.min_offset_y then + self.offset_y = self.min_offset_y + end + elseif ev.code == KEY_FW_PRESS then + if Keys.shiftmode then + if self.pan_by_page then + self.offset_x = self.pan_x + self.offset_y = self.pan_y + else + self.offset_x = 0 + self.offset_y = 0 + end + else + self.pan_by_page = not self.pan_by_page + if self.pan_by_page then + self.pan_x = self.offset_x + self.pan_y = self.offset_y + end + end + end + if old_offset_x ~= self.offset_x + or old_offset_y ~= self.offset_y then + self:goto(self.pageno) + end + end + + local nsecs, nusecs = util.gettime() + local dur = (nsecs - secs) * 1000000 + nusecs - usecs + print("E: T="..ev.type.." V="..ev.value.." C="..ev.code.." DUR="..dur) + end + end + + self:clearcache() + if self.doc ~= nil then + self.doc:close() + end + if self.settings ~= nil then + self.settings:savesetting("last_page", self.pageno) + self.settings:savesetting("gamma", self.globalgamma) + self.settings:close() + end + + return keep_running +end + + + + + + + + + + + + + + From 50d5604c79ea7282a2a94db35e45fb478f0c431f Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 5 Mar 2012 09:58:19 +0800 Subject: [PATCH 18/31] mod: code cleanup for readers closes #26 --- djvureader.lua | 60 ++------------------------------------------------ pdfreader.lua | 10 +-------- unireader.lua | 36 +++++++++++++++++++++++++----- 3 files changed, 34 insertions(+), 72 deletions(-) diff --git a/djvureader.lua b/djvureader.lua index f34c434f0..e929f765d 100644 --- a/djvureader.lua +++ b/djvureader.lua @@ -12,64 +12,8 @@ function DJVUReader:init() end -- open a DJVU file and its settings store +-- DJVU does not support password yet function DJVUReader:open(filename) self.doc = djvu.openDocument(filename) - if self.doc ~= nil then - self.settings = DocSettings:open(filename) - local gamma = self.settings:readsetting("gamma") - if gamma then - self.globalgamma = gamma - end - return true - end - return false -end - ---set viewer state according to zoom state -function DJVUReader:setzoom(page) - local dc = self.newDC() - local pwidth, pheight = page:getSize(self.nulldc) - - if self.globalzoommode == self.ZOOM_FIT_TO_PAGE then - self.globalzoom = width / pwidth - self.offset_x = 0 - self.offset_y = (height - (self.globalzoom * pheight)) / 2 - if height / pheight < self.globalzoom then - self.globalzoom = height / pheight - print(width, (self.globalzoom * pwidth)) - self.offset_x = (width - (self.globalzoom * pwidth)) / 2 - self.offset_y = 0 - end - elseif self.globalzoommode == self.ZOOM_FIT_TO_PAGE_WIDTH then - self.globalzoom = width / pwidth - self.offset_x = 0 - self.offset_y = (height - (self.globalzoom * pheight)) / 2 - elseif self.globalzoommode == self.ZOOM_FIT_TO_PAGE_HEIGHT then - self.globalzoom = height / pheight - self.offset_x = (width - (self.globalzoom * pwidth)) / 2 - self.offset_y = 0 - end - - dc:setZoom(self.globalzoom) - -- record globalzoom for manual zoom in/out - self.globalzoom_orig = self.globalzoom - - dc:setRotate(self.globalrotate); - dc:setOffset(self.offset_x, self.offset_y) - self.fullwidth, self.fullheight = page:getSize(dc) - self.min_offset_x = fb.bb:getWidth() - self.fullwidth - self.min_offset_y = fb.bb:getHeight() - self.fullheight - if(self.min_offset_x > 0) then - self.min_offset_x = 0 - end - if(self.min_offset_y > 0) then - self.min_offset_y = 0 - end - - -- set gamma here, we don't have any other good place for this right now: - if self.globalgamma ~= self.GAMMA_NO_GAMMA then - print("gamma correction: "..self.globalgamma) - dc:setGamma(self.globalgamma) - end - return dc + return self:loadSettings(filename) end diff --git a/pdfreader.lua b/pdfreader.lua index 8973cfadf..5bd12aa73 100644 --- a/pdfreader.lua +++ b/pdfreader.lua @@ -14,13 +14,5 @@ end -- open a PDF file and its settings store function PDFReader:open(filename, password) self.doc = pdf.openDocument(filename, password or "") - if self.doc ~= nil then - self.settings = DocSettings:open(filename) - local gamma = self.settings:readsetting("gamma") - if gamma then - self.globalgamma = gamma - end - return true - end - return false + return self:loadSettings(filename) end diff --git a/unireader.lua b/unireader.lua index 3d476c2ae..812732785 100644 --- a/unireader.lua +++ b/unireader.lua @@ -72,10 +72,41 @@ function UniReader:new(o) return o end +--[[ + For a new specific reader, + you must always overwrite following two methods: + + * self:init() + * self:open() + + overwrite other methods if needed. +--]] function UniReader:init() print("empty initialization method!") end +-- open a file and its settings store +-- tips: you can use self:loadSettings in open() method. +function UniReader:open(filename, password) + return false +end + + + +--[ following are default methods ]-- + +function UniReader:loadSettings(filename) + if self.doc ~= nil then + self.settings = DocSettings:open(filename) + local gamma = self.settings:readsetting("gamma") + if gamma then + self.globalgamma = gamma + end + return true + end + return false +end + -- guarantee that we have enough memory in cache function UniReader:cacheclaim(size) if(size > self.cache_max_memsize) then @@ -136,11 +167,6 @@ function UniReader:clearcache() self.cache_current_memsize = 0 end --- open a file and its settings store -function UniReader:open(filename, password) - return false -end - -- set viewer state according to zoom state function UniReader:setzoom(page) local dc = self.newDC() From 49fa94330635bed0dc2d04c90407af8251c69af1 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 5 Mar 2012 10:02:39 +0800 Subject: [PATCH 19/31] mod: fix typo in comments --- djvu.c | 2 +- djvu.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/djvu.c b/djvu.c index 4361561e5..3da999f88 100644 --- a/djvu.c +++ b/djvu.c @@ -1,5 +1,5 @@ /* - KindlePDFViewer: MuPDF abstraction for Lua + KindlePDFViewer: DjvuLibre abstraction for Lua Copyright (C) 2011 Hans-Werner Hilse This program is free software: you can redistribute it and/or modify diff --git a/djvu.h b/djvu.h index a42068448..00508d973 100644 --- a/djvu.h +++ b/djvu.h @@ -1,5 +1,5 @@ /* - KindlePDFViewer: MuPDF abstraction for Lua + KindlePDFViewer: DjvuLibre abstraction for Lua Copyright (C) 2011 Hans-Werner Hilse This program is free software: you can redistribute it and/or modify From 8cfae790ed8f94acb42959c445b044778399334c Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 5 Mar 2012 10:33:56 +0800 Subject: [PATCH 20/31] mod: clear pan_by_page if not in two column mode --- unireader.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/unireader.lua b/unireader.lua index 812732785..d3525564c 100644 --- a/unireader.lua +++ b/unireader.lua @@ -197,17 +197,21 @@ function UniReader:setzoom(page) self.offset_x = (width - (self.globalzoom * pwidth)) / 2 self.offset_y = 0 end + self.pan_by_page = false elseif self.globalzoommode == self.ZOOM_FIT_TO_PAGE_WIDTH or self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_WIDTH then self.globalzoom = width / pwidth self.offset_x = 0 self.offset_y = (height - (self.globalzoom * pheight)) / 2 + self.pan_by_page = false elseif self.globalzoommode == self.ZOOM_FIT_TO_PAGE_HEIGHT or self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_HEIGHT then self.globalzoom = height / pheight self.offset_x = (width - (self.globalzoom * pwidth)) / 2 self.offset_y = 0 + self.pan_by_page = false end + if self.globalzoommode == self.ZOOM_FIT_TO_CONTENT then if (x1 - x0) < pwidth then self.globalzoom = width / (x1 - x0) From 51dd8472b942ab4a031f50e406eb8b2fa75a3a65 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 5 Mar 2012 10:37:29 +0800 Subject: [PATCH 21/31] mod: bug fix in zooming update self.global_orig after dc:setZoom --- unireader.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/unireader.lua b/unireader.lua index d3525564c..2ff4b3b30 100644 --- a/unireader.lua +++ b/unireader.lua @@ -247,7 +247,10 @@ function UniReader:setzoom(page) self.pan_y = self.offset_y self.pan_by_page = true end + dc:setZoom(self.globalzoom) + self.globalzoom_orig = self.globalzoom + dc:setRotate(self.globalrotate); dc:setOffset(self.offset_x, self.offset_y) self.fullwidth, self.fullheight = page:getSize(dc) From ab2cd3ec8cf7a022751b470d82cd3345be9c94bd Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 5 Mar 2012 10:48:03 +0800 Subject: [PATCH 22/31] mod: save jump_stack after exit --- reader.lua | 1 - unireader.lua | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/reader.lua b/reader.lua index e8adcae54..5ad66dcdd 100755 --- a/reader.lua +++ b/reader.lua @@ -35,7 +35,6 @@ longopts = { function openFile(filename) local file_type = string.lower(string.match(filename, ".+%.(.+)")) if file_type == "djvu" then - print "haha" if DJVUReader:open(filename) then page_num = DJVUReader.settings:readsetting("last_page") or 1 DJVUReader:goto(tonumber(page_num)) diff --git a/unireader.lua b/unireader.lua index 2ff4b3b30..bbd0db7e1 100644 --- a/unireader.lua +++ b/unireader.lua @@ -98,10 +98,15 @@ end function UniReader:loadSettings(filename) if self.doc ~= nil then self.settings = DocSettings:open(filename) + local gamma = self.settings:readsetting("gamma") if gamma then self.globalgamma = gamma end + + local jumpstack = self.settings:readsetting("jumpstack") + self.jump_stack = jumpstack or {} + return true end return false @@ -594,6 +599,7 @@ function UniReader:inputloop() if self.settings ~= nil then self.settings:savesetting("last_page", self.pageno) self.settings:savesetting("gamma", self.globalgamma) + self.settings:savesetting("jumpstack", self.jump_stack) self.settings:close() end From ca3a712521708464c8d87f5bf03cb2d9cc547f62 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 5 Mar 2012 11:25:51 +0800 Subject: [PATCH 23/31] fix: bug in jump stack * remove page to jump from the stack --- unireader.lua | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/unireader.lua b/unireader.lua index bbd0db7e1..732430265 100644 --- a/unireader.lua +++ b/unireader.lua @@ -299,46 +299,60 @@ function UniReader:show(no) self.slot_visible = slot; end +--[[ + @ pageno is the page you want to add to jump_stack +--]] function UniReader:add_jump(pageno) local jump_item = nil - -- add current page to jump_stack if no in + -- move pageno page to jump_stack to jump_stack top if already in for _t,_v in ipairs(self.jump_stack) do if _v.page == pageno then jump_item = _v table.remove(self.jump_stack, _t) - elseif _v.page == no then - -- the page we jumped to should not be show in stack - table.remove(self.jump_stack, _t) + break end end - -- create a new one if not found + -- create a new one if page not found in stack if not jump_item then jump_item = { page = pageno, datetime = os.date("%Y-%m-%d %H:%M:%S"), } end - -- insert at the start + + -- insert item at the start table.insert(self.jump_stack, 1, jump_item) + if #self.jump_stack > 10 then -- remove the last element to keep the size less than 10 table.remove(self.jump_stack) end end +function UniReader:del_jump(pageno) + for _t,_v in ipairs(self.jump_stack) do + if _v.page == pageno then + table.remove(self.jump_stack, _t) + end + end +end + -- change current page and cache next page after rendering function UniReader:goto(no) if no < 1 or no > self.doc:getPages() then return end - -- for jump_stack + -- for jump_stack, distinguish jump from normal page turn if self.pageno and math.abs(self.pageno - no) > 1 then + -- the page we jumped to should not be shown in stack, remove it + self:del_jump(no) self:add_jump(self.pageno) end self.pageno = no self:show(no) + if no < self.doc:getPages() then if self.globalzoommode ~= self.ZOOM_BY_VALUE then -- pre-cache next page From 989e915c8f8c104242e3007ca89ddfb8d9daa843 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 5 Mar 2012 13:15:34 +0800 Subject: [PATCH 24/31] mod: add notes in jumpstack NOTE that the jumpstack maintaining strategy has been changed in this commit compared to commit #15 and #31. Now current viewing page in kept in the stack to preserve the notes. --- unireader.lua | 55 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/unireader.lua b/unireader.lua index 732430265..4852dbfbd 100644 --- a/unireader.lua +++ b/unireader.lua @@ -63,6 +63,7 @@ UniReader = { cache_current_memsize = 0, cache = {}, jump_stack = {}, + toc = nil, } function UniReader:new(o) @@ -302,13 +303,28 @@ end --[[ @ pageno is the page you want to add to jump_stack --]] -function UniReader:add_jump(pageno) +function UniReader:add_jump(pageno, notes) local jump_item = nil - -- move pageno page to jump_stack to jump_stack top if already in + local notes_to_add = notes + if not notes_to_add then + -- no notes given, auto generate from TOC entry + notes_to_add = self:getTOCTitleByPage(self.pageno) + if notes_to_add ~= "" then + notes_to_add = "in "..notes_to_add + end + end + -- move pageno page to jump_stack top if already in for _t,_v in ipairs(self.jump_stack) do if _v.page == pageno then jump_item = _v table.remove(self.jump_stack, _t) + -- if original notes is not empty, probably defined by users, + -- we use the original notes to overwrite auto generated notes + -- from TOC entry + if jump_item.notes ~= "" then + notes_to_add = jump_item.notes + end + jump_item.notes = notes or notes_to_add break end end @@ -317,6 +333,7 @@ function UniReader:add_jump(pageno) jump_item = { page = pageno, datetime = os.date("%Y-%m-%d %H:%M:%S"), + notes = notes_to_add, } end @@ -345,8 +362,6 @@ function UniReader:goto(no) -- for jump_stack, distinguish jump from normal page turn if self.pageno and math.abs(self.pageno - no) > 1 then - -- the page we jumped to should not be shown in stack, remove it - self:del_jump(no) self:add_jump(self.pageno) end @@ -392,11 +407,33 @@ function UniReader:setrotate(rotate) self:goto(self.pageno) end +function UniReader:fillTOC() + self.toc = self.doc:getTOC() +end + +function UniReader:getTOCTitleByPage(pageno) + if not self.toc then + -- build toc when needed. + self:fillTOC() + end + + for _k,_v in ipairs(self.toc) do + if _v.page >= pageno then + --@TODO clean up special characters in title 05.03 2012 + return _v.title + end + end + return "" +end + function UniReader:showTOC() - toc = self.doc:getTOC() + if not self.toc then + -- build toc when needed. + self:fillTOC() + end local menu_items = {} -- build menu items - for _k,_v in ipairs(toc) do + for _k,_v in ipairs(self.toc) do table.insert(menu_items, (" "):rep(_v.depth-1).._v.title) end @@ -407,7 +444,7 @@ function UniReader:showTOC() } item_no = toc_menu:choose(0, fb.bb:getHeight()) if item_no then - self:goto(toc[item_no].page) + self:goto(self.toc[item_no].page) else self:goto(self.pageno) end @@ -417,7 +454,7 @@ function UniReader:showJumpStack() local menu_items = {} for _k,_v in ipairs(self.jump_stack) do table.insert(menu_items, - _v.datetime.." -> Page ".._v.page) + _v.datetime.." -> Page ".._v.page.." ".._v.notes) end jump_menu = SelectMenu:new{ menu_title = "Jump Keeper (current page: "..self.pageno..")", @@ -606,7 +643,9 @@ function UniReader:inputloop() end end + -- do clean up stuff self:clearcache() + self.toc = nil if self.doc ~= nil then self.doc:close() end From 7a2ff94bee1300a55ec91f5a375de86b52e491ac Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 5 Mar 2012 13:38:51 +0800 Subject: [PATCH 25/31] mod: add entries in gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 100e46616..569cf0848 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,9 @@ lua-* lsqlite3* sqlite-amalgamation* mupdf/ +djvulibre/ luafilesystem/ +.reader.kpdfview.lua kpdfview From f50e8d695c46888d678a81a2643a812441ce18b2 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 5 Mar 2012 13:43:23 +0800 Subject: [PATCH 26/31] mod: add UniReader:cleanUpTOCTitle() re-apply the changes introduced by HW in commit: 3c56f50cae98edb18d3ea8580dd9bb2fd715f658 I mistakenly overwrote it when merging from djvu branch. :( Since the title needs to be cleaned in two places, I turn it into a method. --- unireader.lua | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/unireader.lua b/unireader.lua index 4852dbfbd..eb936d131 100644 --- a/unireader.lua +++ b/unireader.lua @@ -407,6 +407,10 @@ function UniReader:setrotate(rotate) self:goto(self.pageno) end +function UniReader:cleanUpTOCTitle(title) + return title:gsub("\13", "") +end + function UniReader:fillTOC() self.toc = self.doc:getTOC() end @@ -419,8 +423,7 @@ function UniReader:getTOCTitleByPage(pageno) for _k,_v in ipairs(self.toc) do if _v.page >= pageno then - --@TODO clean up special characters in title 05.03 2012 - return _v.title + return self:cleanUpTOCTitle(_v.title) end end return "" @@ -435,7 +438,7 @@ function UniReader:showTOC() -- build menu items for _k,_v in ipairs(self.toc) do table.insert(menu_items, - (" "):rep(_v.depth-1).._v.title) + (" "):rep(_v.depth-1)..self:cleanUpTOCTitle(_v.title)) end toc_menu = SelectMenu:new{ menu_title = "Table of Contents", From 2505128128f13ec7243d046e49dde4115b3c461c Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Mon, 5 Mar 2012 14:42:46 +0800 Subject: [PATCH 27/31] fix: add -lpthread for kpdfview target --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 939df0afe..a058d8fbe 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,7 @@ THIRDPARTYLIBS := $(MUPDFLIBDIR)/libfreetype.a \ LUALIB := $(LUADIR)/src/liblua.a kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o input.o util.o ft.o lfs.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) $(DJVULIBS) djvu.o - $(CC) -lm -ldl $(EMU_LDFLAGS) -lstdc++ \ + $(CC) -lm -ldl -lpthread $(EMU_LDFLAGS) -lstdc++ \ kpdfview.o \ einkfb.o \ pdf.o \ From b1ffb5af7e7d1115cb54298fe88c6d10597e8486 Mon Sep 17 00:00:00 2001 From: Dobrica Pavlinusic Date: Mon, 5 Mar 2012 14:05:26 +0100 Subject: [PATCH 28/31] cleanup two column panning It's important for us to take maring into account because rouding error can force us to skip right marging. However, this shouldn't be done when not in pan_by_page mode, so this diff is artifically large --- unireader.lua | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/unireader.lua b/unireader.lua index eb936d131..b25c204b8 100644 --- a/unireader.lua +++ b/unireader.lua @@ -581,31 +581,32 @@ function UniReader:inputloop() local old_offset_y = self.offset_y if ev.code == KEY_FW_LEFT then + print("# KEY_FW_LEFT "..self.offset_x.." + "..x.." > 0"); self.offset_x = self.offset_x + x - if self.offset_x > 0 then - self.offset_x = 0 - if self.pan_by_page and self.pageno > 1 then + if self.pan_by_page then + if self.offset_x > 0 and self.pageno > 1 then self.offset_x = self.pan_x self.offset_y = self.min_offset_y -- bottom self:goto(self.pageno - 1) + else + self.offset_y = self.min_offset_y end - end - if self.pan_by_page then - self.offset_y = self.min_offset_y + elseif self.offset_x > 0 then + self.offset_x = 0 end elseif ev.code == KEY_FW_RIGHT then - print("# FW RIGHT "..self.offset_x.." - "..x.." < "..self.min_offset_x); + print("# KEY_FW_RIGHT "..self.offset_x.." - "..x.." < "..self.min_offset_x); self.offset_x = self.offset_x - x - if self.offset_x < self.min_offset_x then - self.offset_x = self.min_offset_x - if self.pan_by_page and self.pageno < self.doc:getPages() then + if self.pan_by_page then + if self.offset_x < self.min_offset_x - self.pan_margin and self.pageno < self.doc:getPages() then self.offset_x = self.pan_x self.offset_y = self.pan_y self:goto(self.pageno + 1) + else + self.offset_y = self.pan_y end - end - if self.pan_by_page then - self.offset_y = self.pan_y + elseif self.offset_x < self.min_offset_x then + self.offset_x = self.min_offset_x end elseif ev.code == KEY_FW_UP then self.offset_y = self.offset_y + y From bf53b02bd42c58700137010f942bc4cdeb95b332 Mon Sep 17 00:00:00 2001 From: Dobrica Pavlinusic Date: Mon, 5 Mar 2012 14:17:07 +0100 Subject: [PATCH 29/31] new two-colum zoom mode (shift+F) without margins This is especially useful if you want PDF pages which bouding box includes headers or footers which are full page width files like #25 I opted to ignore margins with Shift+F to be consistant with other zoom modes. --- unireader.lua | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/unireader.lua b/unireader.lua index b25c204b8..d59539fcf 100644 --- a/unireader.lua +++ b/unireader.lua @@ -11,7 +11,8 @@ UniReader = { ZOOM_FIT_TO_CONTENT = -4, ZOOM_FIT_TO_CONTENT_WIDTH = -5, ZOOM_FIT_TO_CONTENT_HEIGHT = -6, - ZOOM_FIT_TO_CONTENT_HALF_WIDTH = -7, + ZOOM_FIT_TO_CONTENT_HALF_WIDTH_MARGIN = -7, + ZOOM_FIT_TO_CONTENT_HALF_WIDTH = -8, GAMMA_NO_GAMMA = 1.0, @@ -43,7 +44,8 @@ UniReader = { pan_by_page = false, -- using shift_[xy] or width/height pan_x = 0, -- top-left offset of page when pan activated pan_y = 0, - pan_margin = 20, + pan_margin = 20, -- horizontal margin for two-column zoom + pan_overlap_vertical = 30, -- the document: doc = nil, @@ -241,12 +243,15 @@ function UniReader:setzoom(page) self.offset_x = -1 * x0 * self.globalzoom + (width - (self.globalzoom * (x1 - x0))) / 2 self.offset_y = -1 * y0 * self.globalzoom end - elseif self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH then - self.globalzoom = width / (x1 - x0 + self.pan_margin) - self.offset_x = -1 * x0 * self.globalzoom * 2 + self.pan_margin + elseif self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH + or self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH_MARGIN then + local margin = self.pan_margin + if self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH then margin = 0 end + self.globalzoom = width / (x1 - x0 + margin) + self.offset_x = -1 * x0 * self.globalzoom * 2 + margin self.globalzoom = height / (y1 - y0) - self.offset_y = -1 * y0 * self.globalzoom * 2 + self.pan_margin - self.globalzoom = width / (x1 - x0 + self.pan_margin) * 2 + self.offset_y = -1 * y0 * self.globalzoom * 2 + margin + self.globalzoom = width / (x1 - x0 + margin) * 2 print("column mode offset:"..self.offset_x.."*"..self.offset_y.." zoom:"..self.globalzoom); self.globalzoommode = self.ZOOM_BY_VALUE -- enable pan mode self.pan_x = self.offset_x @@ -539,7 +544,11 @@ function UniReader:inputloop() self:setglobalzoommode(self.ZOOM_FIT_TO_PAGE_HEIGHT) end elseif ev.code == KEY_F then - self:setglobalzoommode(self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH) + if Keys.shiftmode then + self:setglobalzoommode(self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH) + else + self:setglobalzoommode(self.ZOOM_FIT_TO_CONTENT_HALF_WIDTH_MARGIN) + end elseif ev.code == KEY_T then self:showTOC() elseif ev.code == KEY_B then @@ -570,7 +579,7 @@ function UniReader:inputloop() y = self.shift_y / 5 elseif self.pan_by_page then x = width; - y = height - self.pan_margin; -- overlap for lines which didn't fit + y = height - self.pan_overlap_vertical; -- overlap for lines which didn't fit else x = self.shift_x y = self.shift_y From 4a5b12aaa4418ec63273bbfb2b6775c416d3f39a Mon Sep 17 00:00:00 2001 From: Dobrica Pavlinusic Date: Mon, 5 Mar 2012 18:35:54 +0100 Subject: [PATCH 30/31] fix closeDocument return #34 If we don't return 0 lua just exits on us, breaking return to file chooser --- djvu.c | 1 + pdf.c | 1 + 2 files changed, 2 insertions(+) diff --git a/djvu.c b/djvu.c index 3da999f88..d3186cc9a 100644 --- a/djvu.c +++ b/djvu.c @@ -117,6 +117,7 @@ static int closeDocument(lua_State *L) { doc->context = NULL; } + return 0; } static int getNumberOfPages(lua_State *L) { diff --git a/pdf.c b/pdf.c index 2551be985..e079c54b6 100644 --- a/pdf.c +++ b/pdf.c @@ -79,6 +79,7 @@ static int closeDocument(lua_State *L) { fz_free_context(doc->context); doc->context = NULL; } + return 0; } static int getNumberOfPages(lua_State *L) { From 917dc3398592c2acb38ead0382594683658eaa2a Mon Sep 17 00:00:00 2001 From: HW Date: Mon, 5 Mar 2012 19:11:18 +0100 Subject: [PATCH 31/31] put some missing bits into place to fix #34 --- reader.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/reader.lua b/reader.lua index 5ad66dcdd..0efb8dad1 100755 --- a/reader.lua +++ b/reader.lua @@ -38,13 +38,13 @@ function openFile(filename) if DJVUReader:open(filename) then page_num = DJVUReader.settings:readsetting("last_page") or 1 DJVUReader:goto(tonumber(page_num)) - DJVUReader:inputloop() + return DJVUReader:inputloop() end elseif file_type == "pdf" then if PDFReader:open(filename,"") then -- TODO: query for password page_num = PDFReader.settings:readsetting("last_page") or 1 PDFReader:goto(tonumber(page_num)) - PDFReader:inputloop() + return PDFReader:inputloop() end end end @@ -122,7 +122,7 @@ if lfs.attributes(ARGV[optind], "mode") == "directory" then while running do local file = FileChooser:choose(0,height) if file ~= nil then - openFile(file) + running = openFile(file) else running = false end