Merge remote-tracking branch 'hwhw/master' into djvu

pull/2/merge
traycold 12 years ago
commit eba1c2d5ef

2
.gitignore vendored

@ -4,7 +4,9 @@ lua-*
lsqlite3*
sqlite-amalgamation*
mupdf/
djvulibre/
luafilesystem/
.reader.kpdfview.lua
kpdfview
djvulibre*

@ -2,12 +2,10 @@
LUADIR=lua
MUPDFDIR=mupdf
DJVUDIR=djvulibre
MUPDFTARGET=build/debug
MUPDFLIBDIR=$(MUPDFDIR)/$(MUPDFTARGET)
DJVUDIR=djvulibre
SQLITE3DIR=sqlite-amalgamation-3070900
LSQLITE3DIR=lsqlite3_svn08
FREETYPEDIR=$(MUPDFDIR)/thirdparty/freetype-2.4.8
LFSDIR=luafilesystem
@ -22,7 +20,10 @@ endif
HOSTCC:=gcc
HOSTCXX:=g++
CFLAGS:=-O0 -g
CFLAGS:=-O3
ARM_CFLAGS:=-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)
@ -38,6 +39,8 @@ ifdef EMULATE_READER
-DEMULATE_READER_W=$(EMULATE_READER_W) \
-DEMULATE_READER_H=$(EMULATE_READER_H) \
EMU_LDFLAGS?=$(shell sdl-config --libs)
else
CFLAGS+= $(ARM_CFLAGS)
endif
# standard includes
@ -57,28 +60,23 @@ 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 djvu.o blitbuffer.o input.o util.o ft.o $(SQLITE3OBJS) lfs.o $(MUPDFLIBS) $(DJVULIBS) $(THIRDPARTYLIBS) $(LUALIB)
$(CC) -lm -ldl -lstdc++ $(EMU_LDFLAGS) $(SQLITE3LDFLAGS) \
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 -lpthread $(EMU_LDFLAGS) -lstdc++ \
kpdfview.o \
einkfb.o \
pdf.o \
djvu.o \
blitbuffer.o \
input.o \
util.o \
ft.o \
$(SQLITE3OBJS) \
lfs.o \
$(MUPDFLIBS) \
$(DJVULIBS) \
$(THIRDPARTYLIBS) \
$(LUALIB) \
djvu.o \
$(DJVULIBS) \
-o kpdfview
einkfb.o input.o: %.o: %.c
@ -93,27 +91,17 @@ kpdfview.o pdf.o blitbuffer.o util.o: %.o: %.c
djvu.o: %.o: %.c
$(CC) -c $(KPDFREADER_CFLAGS) -I$(DJVUDIR)/ $< -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*
-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
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
git clone git://djvu.git.sourceforge.net/gitroot/djvu/djvulibre.git

@ -1,5 +1,5 @@
/*
KindlePDFViewer: MuPDF abstraction for Lua
KindlePDFViewer: DjvuLibre abstraction for Lua
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
@ -117,6 +117,7 @@ static int closeDocument(lua_State *L) {
doc->context = NULL;
}
return 0;
}
static int getNumberOfPages(lua_State *L) {
@ -125,6 +126,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);
@ -238,34 +251,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");
@ -376,7 +372,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}
@ -384,7 +380,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},

@ -1,5 +1,5 @@
/*
KindlePDFViewer: MuPDF abstraction for Lua
KindlePDFViewer: DjvuLibre abstraction for Lua
Copyright (C) 2011 Hans-Werner Hilse <hilse@web.de>
This program is free software: you can redistribute it and/or modify
@ -22,7 +22,7 @@
#include <lualib.h>
#include <lauxlib.h>
int luaopen_pdf(lua_State *L);
int luaopen_djvu(lua_State *L);
#define True 1
#endif

@ -1,70 +1,19 @@
require "unireader"
DJVUReader = UniReader:new{}
DJVUReader = UniReader:new{
newDC = function()
print("djvu.newDC")
return djvu.newDC()
end,
}
function DJVUReader:init()
self.nulldc = djvu.newDC()
self.nulldc = self.newDC()
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 = djvu.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

@ -65,7 +65,7 @@ function FileChooser:readdir()
if lfs.attributes(self.path.."/"..f, "mode") == "directory" and f ~= "." and not (f==".." and self.path=="/") and not string.match(f, "^%.[^.]") then
--print(self.path.." -> adding: '"..f.."'")
table.insert(self.dirs, f)
elseif string.match(f, ".+%.[pP][dD][fF]$") or string.match(f, ".+%.[dD][jJ][vV][uU]$")then
elseif string.match(f, ".+%.[pP][dD][fF]$") or string.match(f, ".+%.[dD][jJ][vV][uU]$") then
table.insert(self.files, f)
end
end

@ -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

@ -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) {
@ -58,7 +55,6 @@ int main(int argc, char **argv) {
luaopen_util(L);
luaopen_ft(L);
luaopen_lsqlite3(L);
luaopen_lfs(L);
lua_newtable(L);

11
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) {
@ -105,16 +106,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);

@ -1,113 +1,18 @@
require "unireader"
PDFReader = UniReader:new{}
PDFReader = UniReader:new{
newDC = function()
print("pdf.newDC")
return pdf.newDC()
end,
}
function PDFReader:init()
self.nulldc = pdf.newDC()
self.nulldc = self.newDC();
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
end
-- set viewer state according to zoom state
function PDFReader:setzoom(page)
local dc = pdf.newDC()
local pwidth, pheight = page:getSize(self.nulldc)
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
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
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
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)
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)
-- 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

@ -38,15 +38,15 @@ function openFile(filename)
if DJVUReader:open(filename) then
page_num = DJVUReader.settings:readsetting("last_page") or 1
DJVUReader:goto(tonumber(page_num))
DJVUReader:inputloop()
reader_settings:savesetting("lastfile", filename)
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()
reader_settings:savesetting("lastfile", filename)
return PDFReader:inputloop()
end
end
end
@ -124,19 +124,19 @@ PDFReader:init()
DJVUReader:init()
-- display directory or open file
local patharg = ARGV[optind] or reader_settings:readsetting("lastfile")
if patharg and lfs.attributes(patharg, "mode") == "directory" then
local patharg = reader_settings:readsetting("lastfile")
if ARGV[optind] and lfs.attributes(ARGV[optind], "mode") == "directory" then
local running = true
FileChooser:setPath(patharg)
FileChooser:setPath(ARGV[optind])
while running do
local file = FileChooser:choose(0,height)
if file ~= nil then
openFile(file)
running = openFile(file)
else
running = false
end
end
elseif patharg then
elseif patharg and lfs.attributes(patharg, "mode") == "file" then
openFile(patharg, optarg["p"])
else
return showusage()

@ -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

@ -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,16 +44,18 @@ 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,
-- 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 = pdf.newDC(),
nulldc = nil, -- you have to initialize it in specific reader
nulldc = nil,
-- tile cache configuration:
cache_max_memsize = 1024*1024*5, -- 5MB tile cache
@ -62,6 +65,7 @@ UniReader = {
cache_current_memsize = 0,
cache = {},
jump_stack = {},
toc = nil,
}
function UniReader:new(o)
@ -71,10 +75,46 @@ 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
local jumpstack = self.settings:readsetting("jumpstack")
self.jump_stack = jumpstack or {}
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
@ -135,14 +175,113 @@ 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)
return nil
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
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)
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
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 + 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
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)
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
@ -166,46 +305,74 @@ function UniReader:show(no)
self.slot_visible = slot;
end
function UniReader:add_jump(pageno)
--[[
@ pageno is the page you want to add to jump_stack
--]]
function UniReader:add_jump(pageno, notes)
local jump_item = nil
-- add current page to jump_stack if no 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)
elseif _v.page == no then
-- the page we jumped to should not be show in stack
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
-- 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"),
notes = notes_to_add,
}
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
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
@ -245,13 +412,44 @@ 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
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
return self:cleanUpTOCTitle(_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 = {}
local filtered_toc = {}
local curr_page = -1
-- build menu items
for _k,_v in ipairs(toc) do
table.insert(menu_items,
(" "):rep(_v.depth-1).._v.title)
for _k,_v in ipairs(self.toc) do
if(_v.page >= curr_page) then
table.insert(menu_items,
(" "):rep(_v.depth-1)..self:cleanUpTOCTitle(_v.title))
table.insert(filtered_toc,_v.page)
curr_page = _v.page
end
end
toc_menu = SelectMenu:new{
menu_title = "Table of Contents",
@ -260,7 +458,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(filtered_toc[item_no])
else
self:goto(self.pageno)
end
@ -270,7 +468,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..")",
@ -289,6 +487,7 @@ 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)
@ -321,16 +520,7 @@ function UniReader:inputloop()
elseif ev.code == KEY_BACK then
if Keys.altmode then
-- altmode, exit reader
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
@ -360,7 +550,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
@ -373,6 +567,10 @@ function UniReader:inputloop()
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
@ -387,7 +585,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
@ -398,30 +596,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("# 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
@ -461,6 +661,19 @@ function UniReader:inputloop()
print("E: T="..ev.type.." V="..ev.value.." C="..ev.code.." DUR="..dur)
end
end
end
-- do clean up stuff
self:clearcache()
self.toc = nil
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:savesetting("jumpstack", self.jump_stack)
self.settings:close()
end
return keep_running
end

Loading…
Cancel
Save