From dc3ea10fd9d4aa755d53fc75f7965940c013e6ca Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Wed, 29 Feb 2012 22:49:52 +0800 Subject: [PATCH 01/27] initial commit for djvu --- reader.lua | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/reader.lua b/reader.lua index cdc5983f6..62d4dee64 100755 --- a/reader.lua +++ b/reader.lua @@ -107,9 +107,12 @@ if lfs.attributes(ARGV[optind], "mode") == "directory" then 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() + --PDFReader:open(ARGV[optind], optarg["p"]) + --PDFReader:goto(tonumber(optarg["g"]) or tonumber(PDFReader.settings:readsetting("last_page") or 1)) + --PDFReader:inputloop() + DJVUReader:open("/home/dave/documents/code/kindle/djvu/test-djvu/test.djvu") + DJVUReader:goto(1) + DJVUReader:inputloop() end -- save reader settings From c4d0cd26ae6abf317194637981cc9a18d685d05a Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Thu, 1 Mar 2012 21:04:46 +0800 Subject: [PATCH 02/27] half done djvu support --- Makefile | 14 +- djvu.c | 414 +++++++++++++++++++++++++++++++++++++++++ djvu.h | 28 +++ djvureader.lua | 496 +++++++++++++++++++++++++++++++++++++++++++++++++ kpdfview.c | 1 + pdfreader.lua | 1 - reader.lua | 57 +++--- 7 files changed, 981 insertions(+), 30 deletions(-) create mode 100644 djvu.c create mode 100644 djvu.h create mode 100644 djvureader.lua diff --git a/Makefile b/Makefile index 5f9de89ee..d07ac5267 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ LUADIR=lua MUPDFDIR=mupdf +DJVUDIR=djvulibre-3.5.24 MUPDFTARGET=build/debug MUPDFLIBDIR=$(MUPDFDIR)/$(MUPDFTARGET) @@ -43,6 +44,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)/libdjvulibre.a THIRDPARTYLIBS := $(MUPDFLIBDIR)/libfreetype.a \ $(MUPDFLIBDIR)/libjpeg.a \ $(MUPDFLIBDIR)/libopenjpeg.a \ @@ -55,11 +57,12 @@ 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) \ +kpdfview: kpdfview.o einkfb.o pdf.o djvu.o blitbuffer.o input.o util.o ft.o $(SQLITE3OBJS) lfs.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) + $(CC) -lm -ldl -ldjvulibre $(EMU_LDFLAGS) $(SQLITE3LDFLAGS) \ kpdfview.o \ einkfb.o \ pdf.o \ + djvu.o \ blitbuffer.o \ input.o \ util.o \ @@ -80,6 +83,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 $@ + sqlite3.o: $(SQLITE3DIR)/sqlite3.c $(CC) -c $(CFLAGS) $(SQLITE3DIR)/sqlite3.c -o $@ @@ -123,6 +129,10 @@ $(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): + #cd $(DJVUDIR) && ./configure --enable-desktopfiles=no + #make -c $() + $(LUALIB): make -C lua/src CC="$(CC)" CFLAGS="$(CFLAGS)" MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E" liblua.a diff --git a/djvu.c b/djvu.c new file mode 100644 index 000000000..86d5e5566 --- /dev/null +++ b/djvu.c @@ -0,0 +1,414 @@ +/* + 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 "blitbuffer.h" +#include "djvu.h" + +typedef struct DjvuDocument { + ddjvu_context_t *context; + ddjvu_document_t *doc_ref; + int pages; +} DjvuDocument; + +typedef struct DjvuPage { + int num; + ddjvu_page_t *page; + ddjvu_pageinfo_t info; + DjvuDocument *doc; +} DjvuPage; + +typedef struct DrawContext { + int rotate; + double zoom; + double gamma; + int offset_x; + int offset_y; + ddjvu_format_t *pixelformat; +} 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); + 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); + unsigned int format_mask[4]; + + 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; + + format_mask[0] = 0x00ff0000; + format_mask[1] = 0x0000ff00; + format_mask[2] = 0x000000ff; + format_mask[3] = 0xff000000; + dc->pixelformat = ddjvu_format_create(DDJVU_FORMAT_RGBMASK32, 4, format_mask); + ddjvu_format_set_row_order(dc->pixelformat, 1); + ddjvu_format_set_y_direction(dc->pixelformat, 1); + /*ddjvu_format_set_ditherbits(dc->pixelformat, 2);*/ + + 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) { + 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 = ddjvu_page_create_by_pageno(doc->doc_ref, pageno - 1); + while (! ddjvu_page_decoding_done(page->page)) + handle(L, doc->context, TRUE); + if(! page->page) { + return luaL_error(L, "cannot open page #%d", pageno); + } + + page->doc = doc; + + /* @TODO:handle failure here */ + ddjvu_document_get_pageinfo(doc->doc_ref, pageno, &(page->info)); + + return 1; +} + +static int getPageSize(lua_State *L) { + /*fz_matrix ctm;*/ + /*fz_rect bbox;*/ + DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage"); + DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext"); + + /*ctm = fz_translate(0, -page->page->mediabox.y1);*/ + /*ctm = fz_concat(ctm, fz_scale(dc->zoom, -dc->zoom));*/ + /*ctm = fz_concat(ctm, fz_rotate(page->page->rotate));*/ + /*ctm = fz_concat(ctm, fz_rotate(dc->rotate));*/ + /*bbox = fz_transform_rect(ctm, page->page->mediabox);*/ + + /*lua_pushnumber(L, bbox.x1-bbox.x0);*/ + /*lua_pushnumber(L, bbox.y1-bbox.y0);*/ + + /*lua_pushnumber(L, page->info.width);*/ + /*lua_pushnumber(L, page->info.height);*/ + + lua_pushnumber(L, ddjvu_page_get_width(page)); + lua_pushnumber(L, ddjvu_page_get_height(page)); + + 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 != NULL) {*/ + /*pdf_free_page(page->doc->xref, page->page);*/ + /*page->page = NULL;*/ + /*}*/ + return 0; +} + +static int drawPage(lua_State *L) { + /*fz_pixmap *pix;*/ + /*fz_device *dev;*/ + /*fz_matrix ctm;*/ + /*fz_bbox bbox;*/ + ddjvu_rect_t pagerect, renderrect; + char imagebuffer[600*800*4+1]; + memset(imagebuffer, 0, 600*800*4+1); + + + DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage"); + DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext"); + BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 3, "blitbuffer"); + /*rect.x0 = luaL_checkint(L, 4);*/ + /*rect.y0 = luaL_checkint(L, 5);*/ + /*rect.x1 = rect.x0 + bb->w;*/ + /*rect.y1 = rect.y0 + bb->h;*/ + + /* render page into rectangle specified by pagerect */ + pagerect.x = luaL_checkint(L, 4); + pagerect.y = luaL_checkint(L, 5); + pagerect.w = bb->w - pagerect.x; + pagerect.h = bb->h - pagerect.y; + + /* copy pixels area from pagerect specified by renderrect */ + renderrect.x = dc->offset_x; + renderrect.y = dc->offset_y; + renderrect.w = bb->w - renderrect.x; + renderrect.h = bb->h - renderrect.y; + + /*fz_clear_pixmap_with_value(page->doc->context, pix, 0xff);*/ + + /*ctm = fz_scale(dc->zoom, dc->zoom);*/ + /*ctm = fz_concat(ctm, fz_rotate(page->page->rotate));*/ + /*ctm = fz_concat(ctm, fz_rotate(dc->rotate));*/ + /*ctm = fz_concat(ctm, fz_translate(dc->offset_x, dc->offset_y));*/ + /*dev = fz_new_draw_device(page->doc->context, pix);*/ + + printf("%d, %d\n", bb->w, bb->h); + ddjvu_page_render(page->page, + DDJVU_FORMAT_RGBMASK32, + &pagerect, + &renderrect, + dc->pixelformat, + (bb->w)*4, + imagebuffer); + + /*if(dc->gamma >= 0.0) {*/ + /*fz_gamma_pixmap(page->doc->context, pix, dc->gamma);*/ + /*}*/ + + uint8_t *bbptr = (uint8_t*)bb->data; + uint16_t *pmptr = (uint16_t*)imagebuffer; + int x, y; + + for(y = 0; y < bb->h; y++) { + for(x = 0; x < (bb->w / 2); x++) { + bbptr[x] = (((pmptr[x*2 + 1] & 0xF0) >> 4) | (pmptr[x*2] & 0xF0)) ^ 0xFF; + } + if(bb->w & 1) { + bbptr[x] = pmptr[x*2] & 0xF0; + } + bbptr += bb->pitch; + pmptr += bb->w; + } + + 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..0aeb7dec5 --- /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_pdf(lua_State *L); + +#define True 1 +#endif diff --git a/djvureader.lua b/djvureader.lua new file mode 100644 index 000000000..37ab6dcc0 --- /dev/null +++ b/djvureader.lua @@ -0,0 +1,496 @@ +require "keys" +require "settings" +require "selectmenu" + +DJVUReader = { + -- "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, + + 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 + + -- keep track of input state: + shiftmode = false, -- shift pressed + altmode = false, -- alt pressed + + -- the djvu document: + doc = nil, + -- the document's setting store: + settings = nil, + + -- we will use this one often, so keep it "static": + nulldc = djvu.newDC(), + + -- 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 = {}, +} + +-- guarantee that we have enough memory in cache +function DJVUReader: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 DJVUReader: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 DJVUReader: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 DJVUReader:clearcache() + self.cache = {} + self.cache_current_memsize = 0 +end + +-- open a DJVU file and its settings store +function DJVUReader:open(filename, password) + self.doc = djvu.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 DJVUReader:setzoom(page) + local dc = djvu.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 + 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 + + -- 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 DJVUReader: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 + +-- change current page and cache next page after rendering +function DJVUReader: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 + --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 == self.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 = self.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]] + + 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 DJVUReader: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 DJVUReader:setglobalzoommode(newzoommode) + if self.globalzoommode ~= newzoommode then + self.globalzoommode = newzoommode + self:goto(self.pageno) + end +end + +-- adjust zoom state and trigger re-rendering +function DJVUReader:setglobalzoom(zoom) + if self.globalzoom ~= zoom then + self.globalzoommode = self.ZOOM_BY_VALUE + self.globalzoom = zoom + self:goto(self.pageno) + end +end + +function DJVUReader:setrotate(rotate) + self.globalrotate = rotate + self:goto(self.pageno) +end + +function DJVUReader: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 DJVUReader: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 DJVUReader:inputloop() + while 1 do + local ev = input.waitForEvent() + if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then + local secs, usecs = util.gettime() + if ev.code == KEY_SHIFT then + self.shiftmode = true + elseif ev.code == KEY_ALT then + self.altmode = true + elseif ev.code == KEY_PGFWD or ev.code == KEY_LPGFWD then + if self.shiftmode then + self:setglobalzoom(self.globalzoom*1.2) + elseif self.altmode then + self:setglobalzoom(self.globalzoom*1.1) + else + self:goto(self.pageno + 1) + end + elseif ev.code == KEY_PGBCK or ev.code == KEY_LPGBCK then + if self.shiftmode then + self:setglobalzoom(self.globalzoom*0.8) + elseif self.altmode then + self:setglobalzoom(self.globalzoom*0.9) + else + self:goto(self.pageno - 1) + end + elseif ev.code == KEY_BACK then + if self.altmode then + -- altmode, exit djvureader + 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 + 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 self.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 self.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 self.shiftmode then + self:setglobalzoommode(self.ZOOM_FIT_TO_CONTENT_HEIGHT) + else + self:setglobalzoommode(self.ZOOM_FIT_TO_PAGE_HEIGHT) + end + elseif ev.code == KEY_T then + self:showTOC() + elseif ev.code == KEY_B then + self:showJumpStack() + elseif ev.code == KEY_J then + self:setrotate( self.globalrotate + 10 ) + elseif ev.code == KEY_K then + self:setrotate( self.globalrotate - 10 ) + end + + if self.globalzoommode == self.ZOOM_BY_VALUE then + local x + local y + + if self.shiftmode then -- shift always moves in small steps + x = self.shift_x / 2 + y = self.shift_y / 2 + elseif self.altmode then + x = self.shift_x / 5 + y = self.shift_y / 5 + elseif self.pan_by_page then + x = self.width - 5; -- small overlap when moving by page + y = self.height - 5; + 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 + end + elseif ev.code == KEY_FW_RIGHT then + self.offset_x = self.offset_x - x + if 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 + 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 self.shiftmode then + self.offset_x = 0 + self.offset_y = 0 + else + self.pan_by_page = not self.pan_by_page + 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) + elseif ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_RELEASE and ev.code == KEY_SHIFT then + print "shift haha" + self.shiftmode = false + elseif ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_RELEASE and ev.code == KEY_ALT then + self.altmode = false + end + end +end + + diff --git a/kpdfview.c b/kpdfview.c index 9e5fa60ad..ab28e653d 100644 --- a/kpdfview.c +++ b/kpdfview.c @@ -53,6 +53,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); diff --git a/pdfreader.lua b/pdfreader.lua index ef9a7ab58..eddf0beaa 100644 --- a/pdfreader.lua +++ b/pdfreader.lua @@ -1,6 +1,5 @@ require "keys" require "settings" ---require "tocmenu" require "selectmenu" PDFReader = { diff --git a/reader.lua b/reader.lua index 62d4dee64..17cb1224d 100755 --- a/reader.lua +++ b/reader.lua @@ -19,6 +19,7 @@ require "alt_getopt" require "pdfreader" +require "djvureader" require "filechooser" require "settings" @@ -52,6 +53,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,33 +93,34 @@ if r_cfont ~=nil then FontChooser.cfont = r_cfont end +DJVUReader:open("/home/dave/documents/code/kindle/djvu/test-djvu/test.djvu") +DJVUReader:goto(1) +DJVUReader:inputloop() -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)) - PDFReader:inputloop() - end - 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() - DJVUReader:open("/home/dave/documents/code/kindle/djvu/test-djvu/test.djvu") - DJVUReader:goto(1) - DJVUReader:inputloop() -end --- save reader settings -reader_settings:savesetting("cfont", FontChooser.cfont) -reader_settings:close() +--[[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)) + --PDFReader:inputloop() + --end + --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() +--end -input.closeAll() -os.execute('test -e /proc/keypad && echo "send '..KEY_HOME..'" > /proc/keypad ') +---- save reader settings +--reader_settings:savesetting("cfont", FontChooser.cfont) +--reader_settings:close() + +--input.closeAll() +--[[os.execute('test -e /proc/keypad && echo "send '..KEY_HOME..'" > /proc/keypad ')]] From 581684d3bd0119cce75fcbdba6e4c396277a30c5 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sat, 3 Mar 2012 13:26:12 +0800 Subject: [PATCH 03/27] first demo on emu mode :-) --- djvu.c | 39 +++++++++++++++++++-------------------- djvureader.lua | 2 ++ 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/djvu.c b/djvu.c index 86d5e5566..7dac4d292 100644 --- a/djvu.c +++ b/djvu.c @@ -28,7 +28,7 @@ typedef struct DjvuDocument { typedef struct DjvuPage { int num; - ddjvu_page_t *page; + ddjvu_page_t *page_ref; ddjvu_pageinfo_t info; DjvuDocument *doc; } DjvuPage; @@ -119,7 +119,6 @@ static int newDrawContext(lua_State *L) { 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); - unsigned int format_mask[4]; DrawContext *dc = (DrawContext*) lua_newuserdata(L, sizeof(DrawContext)); dc->rotate = rotate; @@ -128,11 +127,8 @@ static int newDrawContext(lua_State *L) { /*dc->offset_y = offset_y;*/ dc->gamma = gamma; - format_mask[0] = 0x00ff0000; - format_mask[1] = 0x0000ff00; - format_mask[2] = 0x000000ff; - format_mask[3] = 0xff000000; - dc->pixelformat = ddjvu_format_create(DDJVU_FORMAT_RGBMASK32, 4, format_mask); + /*dc->pixelformat = ddjvu_format_create(DDJVU_FORMAT_RGBMASK32, 4, format_mask);*/ + dc->pixelformat = ddjvu_format_create(DDJVU_FORMAT_GREY8, 0, NULL); ddjvu_format_set_row_order(dc->pixelformat, 1); ddjvu_format_set_y_direction(dc->pixelformat, 1); /*ddjvu_format_set_ditherbits(dc->pixelformat, 2);*/ @@ -205,14 +201,15 @@ static int openPage(lua_State *L) { luaL_getmetatable(L, "djvupage"); lua_setmetatable(L, -2); - page->page = ddjvu_page_create_by_pageno(doc->doc_ref, pageno - 1); - while (! ddjvu_page_decoding_done(page->page)) + 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) { + if(! page->page_ref) { return luaL_error(L, "cannot open page #%d", pageno); } page->doc = doc; + page->num = pageno; /* @TODO:handle failure here */ ddjvu_document_get_pageinfo(doc->doc_ref, pageno, &(page->info)); @@ -238,8 +235,8 @@ static int getPageSize(lua_State *L) { /*lua_pushnumber(L, page->info.width);*/ /*lua_pushnumber(L, page->info.height);*/ - lua_pushnumber(L, ddjvu_page_get_width(page)); - lua_pushnumber(L, ddjvu_page_get_height(page)); + lua_pushnumber(L, ddjvu_page_get_width(page->page_ref) * dc->zoom); + lua_pushnumber(L, ddjvu_page_get_height(page->page_ref) * dc->zoom); return 2; } @@ -288,8 +285,8 @@ static int drawPage(lua_State *L) { /*fz_matrix ctm;*/ /*fz_bbox bbox;*/ ddjvu_rect_t pagerect, renderrect; - char imagebuffer[600*800*4+1]; - memset(imagebuffer, 0, 600*800*4+1); + char imagebuffer[600*800+1]; + memset(imagebuffer, 0, 600*800+1); DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage"); @@ -321,12 +318,12 @@ static int drawPage(lua_State *L) { /*dev = fz_new_draw_device(page->doc->context, pix);*/ printf("%d, %d\n", bb->w, bb->h); - ddjvu_page_render(page->page, - DDJVU_FORMAT_RGBMASK32, + ddjvu_page_render(page->page_ref, + DDJVU_RENDER_COLOR, &pagerect, &renderrect, dc->pixelformat, - (bb->w)*4, + bb->w, imagebuffer); /*if(dc->gamma >= 0.0) {*/ @@ -334,16 +331,18 @@ static int drawPage(lua_State *L) { /*}*/ uint8_t *bbptr = (uint8_t*)bb->data; - uint16_t *pmptr = (uint16_t*)imagebuffer; + uint8_t *pmptr = (uint8_t*)imagebuffer; int x, y; for(y = 0; y < bb->h; y++) { + /* render every line */ for(x = 0; x < (bb->w / 2); x++) { - bbptr[x] = (((pmptr[x*2 + 1] & 0xF0) >> 4) | (pmptr[x*2] & 0xF0)) ^ 0xFF; + bbptr[x] = 255 - (((pmptr[x*2 + 1] & 0xF0) >> 4) | (pmptr[x*2] & 0xF0)); } if(bb->w & 1) { - bbptr[x] = pmptr[x*2] & 0xF0; + bbptr[x] = 255 - (pmptr[x*2] & 0xF0); } + /* go to next line */ bbptr += bb->pitch; pmptr += bb->w; } diff --git a/djvureader.lua b/djvureader.lua index 37ab6dcc0..10cf5087d 100644 --- a/djvureader.lua +++ b/djvureader.lua @@ -100,7 +100,9 @@ function DJVUReader:draworcache(no, zoom, offset_x, offset_y, width, height, gam -- and draw the page local page = self.doc:openPage(no) local dc = self:setzoom(page, hash) + --print("--drawing page : "..no) page:draw(dc, self.cache[hash].bb, 0, 0) + --print("--page draught: "..no) page:close() else -- we have the page in our cache, From 755567d7ba9b2bcc977998a0b9bb307eaf1fad00 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sat, 3 Mar 2012 16:52:24 +0800 Subject: [PATCH 04/27] mod: zoom feature finished --- djvu.c | 83 +++++++++++++++++++++++++------------------------- djvureader.lua | 36 +++++----------------- 2 files changed, 49 insertions(+), 70 deletions(-) diff --git a/djvu.c b/djvu.c index 7dac4d292..9f36b4879 100644 --- a/djvu.c +++ b/djvu.c @@ -20,6 +20,11 @@ #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; @@ -217,24 +222,11 @@ static int openPage(lua_State *L) { return 1; } +/* this returns the original page size, seldom used. */ static int getPageSize(lua_State *L) { - /*fz_matrix ctm;*/ - /*fz_rect bbox;*/ DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage"); DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext"); - /*ctm = fz_translate(0, -page->page->mediabox.y1);*/ - /*ctm = fz_concat(ctm, fz_scale(dc->zoom, -dc->zoom));*/ - /*ctm = fz_concat(ctm, fz_rotate(page->page->rotate));*/ - /*ctm = fz_concat(ctm, fz_rotate(dc->rotate));*/ - /*bbox = fz_transform_rect(ctm, page->page->mediabox);*/ - - /*lua_pushnumber(L, bbox.x1-bbox.x0);*/ - /*lua_pushnumber(L, bbox.y1-bbox.y0);*/ - - /*lua_pushnumber(L, page->info.width);*/ - /*lua_pushnumber(L, page->info.height);*/ - lua_pushnumber(L, ddjvu_page_get_width(page->page_ref) * dc->zoom); lua_pushnumber(L, ddjvu_page_get_height(page->page_ref) * dc->zoom); @@ -284,38 +276,39 @@ static int drawPage(lua_State *L) { /*fz_device *dev;*/ /*fz_matrix ctm;*/ /*fz_bbox bbox;*/ - ddjvu_rect_t pagerect, renderrect; - char imagebuffer[600*800+1]; - memset(imagebuffer, 0, 600*800+1); - - DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage"); DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext"); BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 3, "blitbuffer"); - /*rect.x0 = luaL_checkint(L, 4);*/ - /*rect.y0 = luaL_checkint(L, 5);*/ - /*rect.x1 = rect.x0 + bb->w;*/ - /*rect.y1 = rect.y0 + bb->h;*/ - /* render page into rectangle specified by pagerect */ - pagerect.x = luaL_checkint(L, 4); - pagerect.y = luaL_checkint(L, 5); - pagerect.w = bb->w - pagerect.x; - pagerect.h = bb->h - pagerect.y; + 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); + + /* 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 = bb->w * dc->zoom; + pagerect.h = bb->h * dc->zoom; + /*printf("@@@zoom:%f::: %d, y: %d, w: %d, h: %d.\n", 0, 0, dc->zoom, pagerect.w, pagerect.h);*/ /* copy pixels area from pagerect specified by renderrect */ - renderrect.x = dc->offset_x; - renderrect.y = dc->offset_y; - renderrect.w = bb->w - renderrect.x; - renderrect.h = bb->h - renderrect.y; + /* ddjvulibre does not support negative offset, + * we need to handle negative offset manually when copying buffer. + * if offset is negative, we are moving towards down and right*/ + 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);*/ - /*fz_clear_pixmap_with_value(page->doc->context, pix, 0xff);*/ - - /*ctm = fz_scale(dc->zoom, dc->zoom);*/ /*ctm = fz_concat(ctm, fz_rotate(page->page->rotate));*/ /*ctm = fz_concat(ctm, fz_rotate(dc->rotate));*/ /*ctm = fz_concat(ctm, fz_translate(dc->offset_x, dc->offset_y));*/ - /*dev = fz_new_draw_device(page->doc->context, pix);*/ printf("%d, %d\n", bb->w, bb->h); ddjvu_page_render(page->page_ref, @@ -333,20 +326,26 @@ static int drawPage(lua_State *L) { 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 y_offset = MAX(0, MAX(0, dc->offset_y)); + int x_offset = MAX(0, MAX(0, dc->offset_x)); - for(y = 0; y < bb->h; y++) { - /* render every line */ - for(x = 0; x < (bb->w / 2); x++) { - bbptr[x] = 255 - (((pmptr[x*2 + 1] & 0xF0) >> 4) | (pmptr[x*2] & 0xF0)); + for(y = y_offset; y < bb->h; y++) { + for(x = x_offset; 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; + bbptr += bb->pitch + y_offset; + pmptr += bb->w + y_offset; } + free(imagebuffer); + pmptr = imagebuffer = NULL; + return 0; } diff --git a/djvureader.lua b/djvureader.lua index 10cf5087d..7cf625cec 100644 --- a/djvureader.lua +++ b/djvureader.lua @@ -143,27 +143,6 @@ function DJVUReader:setzoom(page) local dc = djvu.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 @@ -191,12 +170,13 @@ function DJVUReader:setzoom(page) self.offset_y = -1 * y0 * self.globalzoom end 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 + --self.fullwidth, self.fullheight = page:getSize(dc) + self.min_offset_x = fb.bb:getWidth() * (1 - self.globalzoom) + self.min_offset_y = fb.bb:getHeight() * (1 - self.globalzoom) if(self.min_offset_x > 0) then self.min_offset_x = 0 end @@ -362,17 +342,17 @@ function DJVUReader:inputloop() self.altmode = true elseif ev.code == KEY_PGFWD or ev.code == KEY_LPGFWD then if self.shiftmode then - self:setglobalzoom(self.globalzoom*1.2) + self:setglobalzoom(self.globalzoom + 0.2) elseif self.altmode then - self:setglobalzoom(self.globalzoom*1.1) + self:setglobalzoom(self.globalzoom + 0.1) else self:goto(self.pageno + 1) end elseif ev.code == KEY_PGBCK or ev.code == KEY_LPGBCK then if self.shiftmode then - self:setglobalzoom(self.globalzoom*0.8) + self:setglobalzoom(self.globalzoom - 0.2) elseif self.altmode then - self:setglobalzoom(self.globalzoom*0.9) + self:setglobalzoom(self.globalzoom - 0.1) else self:goto(self.pageno - 1) end From bcc86f260a464f85e77b727c7d3ba6178fb55804 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sat, 3 Mar 2012 17:04:31 +0800 Subject: [PATCH 05/27] mod: add set gamma --- djvu.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/djvu.c b/djvu.c index 9f36b4879..56788b2e8 100644 --- a/djvu.c +++ b/djvu.c @@ -128,8 +128,8 @@ static int newDrawContext(lua_State *L) { 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->offset_x = offset_x; + dc->offset_y = offset_y; dc->gamma = gamma; /*dc->pixelformat = ddjvu_format_create(DDJVU_FORMAT_RGBMASK32, 4, format_mask);*/ @@ -185,6 +185,7 @@ static int dcGetZoom(lua_State *L) { static int dcSetGamma(lua_State *L) { DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); dc->gamma = luaL_checknumber(L, 2); + ddjvu_format_set_gamma(dc->pixelformat, dc->gamma); return 0; } @@ -272,10 +273,6 @@ static int closePage(lua_State *L) { } static int drawPage(lua_State *L) { - /*fz_pixmap *pix;*/ - /*fz_device *dev;*/ - /*fz_matrix ctm;*/ - /*fz_bbox bbox;*/ DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage"); DrawContext *dc = (DrawContext*) luaL_checkudata(L, 2, "drawcontext"); BlitBuffer *bb = (BlitBuffer*) luaL_checkudata(L, 3, "blitbuffer"); From e258371134ed042ae009c6cd7ac95cacb98797b4 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sat, 3 Mar 2012 17:17:35 +0800 Subject: [PATCH 06/27] mod: add closePage and demo for filechooser --- djvu.c | 8 ++++---- djvureader.lua | 34 +++++++++++++--------------------- filechooser.lua | 4 +++- reader.lua | 23 +++++++++++++++++++---- 4 files changed, 39 insertions(+), 30 deletions(-) diff --git a/djvu.c b/djvu.c index 56788b2e8..14a93b835 100644 --- a/djvu.c +++ b/djvu.c @@ -265,10 +265,10 @@ static int getPageSize(lua_State *L) { static int closePage(lua_State *L) { DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage"); - /*if(page->page != NULL) {*/ - /*pdf_free_page(page->doc->xref, page->page);*/ - /*page->page = NULL;*/ - /*}*/ + if(page->page_ref != NULL) { + ddjvu_page_release(page->page_ref); + page->page_ref = NULL; + } return 0; } diff --git a/djvureader.lua b/djvureader.lua index 7cf625cec..967d74547 100644 --- a/djvureader.lua +++ b/djvureader.lua @@ -334,30 +334,27 @@ end function DJVUReader:inputloop() 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_SHIFT then - self.shiftmode = true - elseif ev.code == KEY_ALT then - self.altmode = true - elseif ev.code == KEY_PGFWD or ev.code == KEY_LPGFWD then - if self.shiftmode then + if ev.code == KEY_PGFWD or ev.code == KEY_LPGFWD then + if Keys.shiftmode then self:setglobalzoom(self.globalzoom + 0.2) - elseif self.altmode then + elseif Keys.altmode then self:setglobalzoom(self.globalzoom + 0.1) else self:goto(self.pageno + 1) end elseif ev.code == KEY_PGBCK or ev.code == KEY_LPGBCK then - if self.shiftmode then + if Keys.shiftmode then self:setglobalzoom(self.globalzoom - 0.2) - elseif self.altmode then + elseif Keys.altmode then self:setglobalzoom(self.globalzoom - 0.1) else self:goto(self.pageno - 1) end elseif ev.code == KEY_BACK then - if self.altmode then + if Keys.altmode then -- altmode, exit djvureader self:clearcache() if self.doc ~= nil then @@ -380,19 +377,19 @@ function DJVUReader:inputloop() elseif ev.code == KEY_VMINUS then self:modify_gamma( 0.8 ) elseif ev.code == KEY_A then - if self.shiftmode 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 self.shiftmode 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 self.shiftmode then + if Keys.shiftmode then self:setglobalzoommode(self.ZOOM_FIT_TO_CONTENT_HEIGHT) else self:setglobalzoommode(self.ZOOM_FIT_TO_PAGE_HEIGHT) @@ -411,10 +408,10 @@ function DJVUReader:inputloop() local x local y - if self.shiftmode then -- shift always moves in small steps + if Keys.shiftmode then -- shift always moves in small steps x = self.shift_x / 2 y = self.shift_y / 2 - elseif self.altmode then + elseif Keys.altmode then x = self.shift_x / 5 y = self.shift_y / 5 elseif self.pan_by_page then @@ -450,7 +447,7 @@ function DJVUReader:inputloop() self.offset_y = self.min_offset_y end elseif ev.code == KEY_FW_PRESS then - if self.shiftmode then + if Keys.shiftmode then self.offset_x = 0 self.offset_y = 0 else @@ -466,11 +463,6 @@ function DJVUReader:inputloop() 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) - elseif ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_RELEASE and ev.code == KEY_SHIFT then - print "shift haha" - self.shiftmode = false - elseif ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_RELEASE and ev.code == KEY_ALT then - self.altmode = false end end end diff --git a/filechooser.lua b/filechooser.lua index d2ca88b5c..b7bd6f1bf 100644 --- a/filechooser.lua +++ b/filechooser.lua @@ -41,7 +41,9 @@ 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 + --@TODO search for all files 03.03 2012 + elseif string.match(f, ".+%.[dD][jJ][vV][uU]$")then table.insert(self.files, f) end end diff --git a/reader.lua b/reader.lua index 887e5482f..469ea0c6f 100755 --- a/reader.lua +++ b/reader.lua @@ -93,9 +93,25 @@ if r_cfont ~=nil then FontChooser.cfont = r_cfont end -DJVUReader:open("/home/dave/documents/code/kindle/djvu/test-djvu/test.djvu") -DJVUReader:goto(1) -DJVUReader:inputloop() +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 DJVUReader:open(pdffile,"") then + DJVUReader:goto(1) + DJVUReader:inputloop() + end + else + running = false + end + end +else + DJVUReader:open(ARGV[optind], optarg["p"]) + DJVUReader:goto(tonumber(optarg["g"]) or tonumber(PDFReader.settings:readsetting("last_page") or 1)) + DJVUReader:inputloop() +end --[[if lfs.attributes(ARGV[optind], "mode") == "directory" then]] @@ -122,7 +138,6 @@ DJVUReader:inputloop() --reader_settings:savesetting("cfont", FontChooser.cfont) --reader_settings:close() ---input.closeAll() input.closeAll() --os.execute('test -e /proc/keypad && echo "send '..KEY_HOME..'" > /proc/keypad ') if optarg["d"] ~= "emu" then From 516e32bc4604b0b7acae7df0ee51a6d411b31dc3 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sat, 3 Mar 2012 19:51:49 +0800 Subject: [PATCH 07/27] mod: call different reader in reader.lua call PDFReader or DJVUReader according to filetype --- djvu.c | 22 +++++------ djvureader.lua | 99 +++++++++++++++++++++---------------------------- filechooser.lua | 4 +- reader.lua | 56 ++++++++++++---------------- 4 files changed, 77 insertions(+), 104 deletions(-) diff --git a/djvu.c b/djvu.c index 14a93b835..b27524582 100644 --- a/djvu.c +++ b/djvu.c @@ -44,7 +44,6 @@ typedef struct DrawContext { double gamma; int offset_x; int offset_y; - ddjvu_format_t *pixelformat; } DrawContext; @@ -132,11 +131,6 @@ static int newDrawContext(lua_State *L) { dc->offset_y = offset_y; dc->gamma = gamma; - /*dc->pixelformat = ddjvu_format_create(DDJVU_FORMAT_RGBMASK32, 4, format_mask);*/ - dc->pixelformat = ddjvu_format_create(DDJVU_FORMAT_GREY8, 0, NULL); - ddjvu_format_set_row_order(dc->pixelformat, 1); - ddjvu_format_set_y_direction(dc->pixelformat, 1); - /*ddjvu_format_set_ditherbits(dc->pixelformat, 2);*/ luaL_getmetatable(L, "drawcontext"); lua_setmetatable(L, -2); @@ -185,7 +179,6 @@ static int dcGetZoom(lua_State *L) { static int dcSetGamma(lua_State *L) { DrawContext *dc = (DrawContext*) luaL_checkudata(L, 1, "drawcontext"); dc->gamma = luaL_checknumber(L, 2); - ddjvu_format_set_gamma(dc->pixelformat, dc->gamma); return 0; } @@ -277,6 +270,7 @@ static int drawPage(lua_State *L) { 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; @@ -284,6 +278,12 @@ static int drawPage(lua_State *L) { /* 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);*/ + /* render full page into rectangle specified by pagerect */ /*pagerect.x = luaL_checkint(L, 4);*/ /*pagerect.y = luaL_checkint(L, 5);*/ @@ -307,19 +307,14 @@ static int drawPage(lua_State *L) { /*ctm = fz_concat(ctm, fz_rotate(dc->rotate));*/ /*ctm = fz_concat(ctm, fz_translate(dc->offset_x, dc->offset_y));*/ - printf("%d, %d\n", bb->w, bb->h); ddjvu_page_render(page->page_ref, DDJVU_RENDER_COLOR, &pagerect, &renderrect, - dc->pixelformat, + pixelformat, bb->w, imagebuffer); - /*if(dc->gamma >= 0.0) {*/ - /*fz_gamma_pixmap(page->doc->context, pix, dc->gamma);*/ - /*}*/ - uint8_t *bbptr = (uint8_t*)bb->data; uint8_t *pmptr = (uint8_t*)imagebuffer; int x, y; @@ -342,6 +337,7 @@ static int drawPage(lua_State *L) { free(imagebuffer); pmptr = imagebuffer = NULL; + ddjvu_format_release(pixelformat); return 0; } diff --git a/djvureader.lua b/djvureader.lua index 967d74547..b0ce85aae 100644 --- a/djvureader.lua +++ b/djvureader.lua @@ -40,10 +40,6 @@ DJVUReader = { shift_y = 50, pan_by_page = false, -- using shift_[xy] or width/height - -- keep track of input state: - shiftmode = false, -- shift pressed - altmode = false, -- alt pressed - -- the djvu document: doc = nil, -- the document's setting store: @@ -101,7 +97,7 @@ function DJVUReader:draworcache(no, zoom, offset_x, offset_y, width, height, gam local page = self.doc:openPage(no) local dc = self:setzoom(page, hash) --print("--drawing page : "..no) - page:draw(dc, self.cache[hash].bb, 0, 0) + page:draw(dc, self.cache[hash].bb) --print("--page draught: "..no) page:close() else @@ -125,14 +121,14 @@ function DJVUReader:clearcache() end -- open a DJVU file and its settings store -function DJVUReader:open(filename, password) - self.doc = djvu.openDocument(filename, password or "") +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 + self.settings = DocSettings:open(filename) + local gamma = self.settings:readsetting("gamma") + if gamma then + self.globalgamma = gamma + end return true end return false @@ -219,44 +215,44 @@ function DJVUReader:goto(no) return end - --[[ -- for jump_stack]] - --if self.pageno and math.abs(self.pageno - no) > 1 then - --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 == self.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 = self.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]] + -- for jump_stack + if self.pageno and math.abs(self.pageno - no) > 1 then + 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 == self.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 = self.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 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]] + 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 @@ -283,11 +279,6 @@ function DJVUReader:setglobalzoom(zoom) end end -function DJVUReader:setrotate(rotate) - self.globalrotate = rotate - self:goto(self.pageno) -end - function DJVUReader:showTOC() toc = self.doc:getTOC() local menu_items = {} @@ -398,10 +389,6 @@ function DJVUReader:inputloop() self:showTOC() elseif ev.code == KEY_B then self:showJumpStack() - elseif ev.code == KEY_J then - self:setrotate( self.globalrotate + 10 ) - elseif ev.code == KEY_K then - self:setrotate( self.globalrotate - 10 ) end if self.globalzoommode == self.ZOOM_BY_VALUE then diff --git a/filechooser.lua b/filechooser.lua index b7bd6f1bf..68c14d263 100644 --- a/filechooser.lua +++ b/filechooser.lua @@ -41,9 +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]$") or string.match(f, ".+%.[dD][jJ][vV][uU]$")then - --@TODO search for all files 03.03 2012 - elseif 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 diff --git a/reader.lua b/reader.lua index 469ea0c6f..5e3e41191 100755 --- a/reader.lua +++ b/reader.lua @@ -31,6 +31,22 @@ longopts = { device = "d", help = "h" } + +function openFile(filename) + local file_type = string.lower(string.match(filename, ".+%.(.+)")) + if file_type == "djvu" then + if DJVUReader:open(filename) then + DJVUReader:goto(tonumber(DJVUReader.settings:readsetting("last_page")) or 1) + DJVUReader:inputloop() + end + elseif file_type == "pdf" then + if PDFReader:open(filename,"") then -- TODO: query for password + PDFReader:goto(tonumber(PDFReader.settings:readsetting("last_page") or 1)) + 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") @@ -93,50 +109,26 @@ if r_cfont ~=nil then FontChooser.cfont = r_cfont end +-- 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 DJVUReader:open(pdffile,"") then - DJVUReader:goto(1) - DJVUReader:inputloop() - end + local file = FileChooser:choose(0,height) + if file ~= nil then + openFile(file) else running = false end end else - DJVUReader:open(ARGV[optind], optarg["p"]) - DJVUReader:goto(tonumber(optarg["g"]) or tonumber(PDFReader.settings:readsetting("last_page") or 1)) - DJVUReader:inputloop() + openFile(ARGV[optind], optarg["p"]) end ---[[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)) - --PDFReader:inputloop() - --end - --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() ---end - ----- save reader settings ---reader_settings:savesetting("cfont", FontChooser.cfont) ---reader_settings:close() +-- save reader settings +reader_settings:savesetting("cfont", FontChooser.cfont) +reader_settings:close() input.closeAll() --os.execute('test -e /proc/keypad && echo "send '..KEY_HOME..'" > /proc/keypad ') From 41c46313eff5949d016673f299fd96e8e859d8cb Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sat, 3 Mar 2012 22:56:07 +0800 Subject: [PATCH 08/27] mod: adapt makefile to build djvu library --- Makefile | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index dcd4a6eb5..074d59c62 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,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:=-O0 -g @@ -24,6 +26,7 @@ CFLAGS:=-O0 -g ifdef EMULATE_READER CC:=$(HOSTCC) +CXX:=$(HOSTCXX) EMULATE_READER_W?=824 EMULATE_READER_H?=1200 EMU_CFLAGS?=$(shell sdl-config --cflags) @@ -44,7 +47,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)/libdjvulibre.a +DJVULIBS := $(DJVUDIR)/build/libdjvu/.libs/libdjvulibre.a THIRDPARTYLIBS := $(MUPDFLIBDIR)/libfreetype.a \ $(MUPDFLIBDIR)/libjpeg.a \ $(MUPDFLIBDIR)/libopenjpeg.a \ @@ -57,8 +60,8 @@ 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) $(THIRDPARTYLIBS) $(LUALIB) - $(CC) -lm -ldl -ldjvulibre $(EMU_LDFLAGS) $(SQLITE3LDFLAGS) \ +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.o \ einkfb.o \ pdf.o \ @@ -70,6 +73,7 @@ kpdfview: kpdfview.o einkfb.o pdf.o djvu.o blitbuffer.o input.o util.o ft.o $(SQ $(SQLITE3OBJS) \ lfs.o \ $(MUPDFLIBS) \ + $(DJVULIBS) \ $(THIRDPARTYLIBS) \ $(LUALIB) \ -o kpdfview @@ -101,12 +105,15 @@ fetchthirdparty: -rm -Rf lsqlite3_svn08* -rm -Rf sqlite-amalgamation-3070900* -rm -Rf luafilesystem* + -rm -Rf djvulibre.tar.gz + -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 + wget http://sourceforge.net/projects/djvu/files/latest/download\?source\=files -O djvulibre.tar.gz && tar xvzf djvulibre.tar.gz clean: -rm -f *.o kpdfview @@ -114,6 +121,7 @@ clean: cleanthirdparty: make -C $(LUADIR) clean make -C $(MUPDFDIR) clean + -rm -rf $(DJVUDIR)/build -rm $(MUPDFDIR)/fontdump.host -rm $(MUPDFDIR)/cmapdump.host @@ -132,13 +140,23 @@ $(MUPDFLIBS) $(THIRDPARTYLIBS): $(MUPDFDIR)/cmapdump.host $(MUPDFDIR)/fontdump.h CFLAGS="$(CFLAGS)" make -C mupdf CC="$(CC)" CMAPDUMP=cmapdump.host FONTDUMP=fontdump.host MUPDF= XPS_APPS= $(DJVULIBS): - #cd $(DJVUDIR) && ./configure --enable-desktopfiles=no - #make -c $() + -mkdir $(DJVUDIR)/build +ifdef EMULATE_READER + cd $(DJVUDIR)/build && ../configure --enable-desktopfiles=no +else + cd $(DJVUDIR)/build && ../configure --enable-desktopfiles=no --host=arm +endif + make -C $(DJVUDIR)/build CXX="$(CXX)" +ifdef EMULATE_READER + cd $(DJVUDIR)/build/libdjvu/.libs && ar -cvq libdjvulibre.a *.o +else + cd $(DJVUDIR)/build/libdjvu/ && ar -cvq libdjvulibre.a *.o +endif $(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 From 2f9a44bfc617a7cfed1137d1b8b1338b809097c3 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sat, 3 Mar 2012 22:56:54 +0800 Subject: [PATCH 09/27] code clean up for first demo --- djvu.c | 10 +++++++++- djvureader.lua | 5 ++--- filesearcher.lua | 10 +++------- reader.lua | 6 ++++-- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/djvu.c b/djvu.c index b27524582..327b97ced 100644 --- a/djvu.c +++ b/djvu.c @@ -17,6 +17,7 @@ */ #include +#include "string.h" #include "blitbuffer.h" #include "djvu.h" @@ -107,6 +108,13 @@ static int closeDocument(lua_State *L) { } 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; } } @@ -276,7 +284,7 @@ static int drawPage(lua_State *L) { imagebuffer = malloc((bb->w)*(bb->h)+1); /* fill pixel map with white color */ - memset(imagebuffer, 0xFF, (bb->w)*(bb->h)+1); + memset((void *)imagebuffer, 0xFF, (bb->w)*(bb->h)+1); pixelformat = ddjvu_format_create(DDJVU_FORMAT_GREY8, 0, NULL); ddjvu_format_set_row_order(pixelformat, 1); diff --git a/djvureader.lua b/djvureader.lua index b0ce85aae..03084ee46 100644 --- a/djvureader.lua +++ b/djvureader.lua @@ -337,8 +337,7 @@ function DJVUReader:inputloop() 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) + if Keys.shiftmode then self:setglobalzoom(self.globalzoom - 0.2) elseif Keys.altmode then self:setglobalzoom(self.globalzoom - 0.1) else @@ -386,7 +385,7 @@ function DJVUReader:inputloop() self:setglobalzoommode(self.ZOOM_FIT_TO_PAGE_HEIGHT) end elseif ev.code == KEY_T then - self:showTOC() + --self:showTOC() elseif ev.code == KEY_B then self:showJumpStack() end diff --git a/filesearcher.lua b/filesearcher.lua index 55ef1892e..e0f41d8de 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) @@ -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/reader.lua b/reader.lua index 5e3e41191..61817638f 100755 --- a/reader.lua +++ b/reader.lua @@ -36,12 +36,14 @@ function openFile(filename) local file_type = string.lower(string.match(filename, ".+%.(.+)")) if file_type == "djvu" then if DJVUReader:open(filename) then - DJVUReader:goto(tonumber(DJVUReader.settings:readsetting("last_page")) or 1) + 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 - PDFReader:goto(tonumber(PDFReader.settings:readsetting("last_page") or 1)) + page_num = PDFReader.settings:readsetting("last_page") or 1 + PDFReader:goto(tonumber(page_num)) PDFReader:inputloop() end end From f987ed33c33cd9e6b7bac296980f084903b7ca9c Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 4 Mar 2012 00:30:49 +0800 Subject: [PATCH 10/27] fix: bug in zoomming --- djvu.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/djvu.c b/djvu.c index 327b97ced..420774ab3 100644 --- a/djvu.c +++ b/djvu.c @@ -224,13 +224,12 @@ static int openPage(lua_State *L) { return 1; } -/* this returns the original page size, seldom used. */ 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, ddjvu_page_get_width(page->page_ref) * dc->zoom); - lua_pushnumber(L, ddjvu_page_get_height(page->page_ref) * dc->zoom); + lua_pushnumber(L, page->info.width); + lua_pushnumber(L, page->info.height); return 2; } @@ -284,7 +283,7 @@ static int drawPage(lua_State *L) { imagebuffer = malloc((bb->w)*(bb->h)+1); /* fill pixel map with white color */ - memset((void *)imagebuffer, 0xFF, (bb->w)*(bb->h)+1); + memset(imagebuffer, 0xFF, (bb->w)*(bb->h)+1); pixelformat = ddjvu_format_create(DDJVU_FORMAT_GREY8, 0, NULL); ddjvu_format_set_row_order(pixelformat, 1); @@ -292,14 +291,17 @@ static int drawPage(lua_State *L) { ddjvu_format_set_gamma(pixelformat, dc->gamma); /*ddjvu_format_set_ditherbits(dc->pixelformat, 2);*/ + /*printf("@page %d, @@zoom:%f\n", page->num, dc->zoom);*/ + /* 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 = bb->w * dc->zoom; - pagerect.h = bb->h * dc->zoom; - /*printf("@@@zoom:%f::: %d, y: %d, w: %d, h: %d.\n", 0, 0, dc->zoom, pagerect.w, pagerect.h);*/ + 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 does not support negative offset, @@ -309,11 +311,10 @@ static int drawPage(lua_State *L) { 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);*/ - /*ctm = fz_concat(ctm, fz_rotate(page->page->rotate));*/ - /*ctm = fz_concat(ctm, fz_rotate(dc->rotate));*/ - /*ctm = fz_concat(ctm, fz_translate(dc->offset_x, dc->offset_y));*/ + /*@TODO handle rotate 04.03 2012*/ ddjvu_page_render(page->page_ref, DDJVU_RENDER_COLOR, @@ -327,11 +328,13 @@ static int drawPage(lua_State *L) { uint8_t *pmptr = (uint8_t*)imagebuffer; int x, y; /* if offset is positive, we are moving towards up and left. */ - int y_offset = MAX(0, MAX(0, dc->offset_y)); - int x_offset = MAX(0, MAX(0, dc->offset_x)); + 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++) { for(x = x_offset; x < (bb->w / 2); x++) { + /*printf(" --- y: %d, x: %d\n", y, x);*/ bbptr[x] = 255 - (((pmptr[x*2 + 1 - x_offset] & 0xF0) >> 4) | (pmptr[x*2 - x_offset] & 0xF0)); } @@ -339,8 +342,8 @@ static int drawPage(lua_State *L) { bbptr[x] = 255 - (pmptr[x*2] & 0xF0); } /* go to next line */ - bbptr += bb->pitch + y_offset; - pmptr += bb->w + y_offset; + bbptr += bb->pitch; + pmptr += bb->w; } free(imagebuffer); From 84d6bfe3f8ad7bd851b48a82074d6606268a599b Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 4 Mar 2012 00:31:26 +0800 Subject: [PATCH 11/27] fix: bug in setting zomming --- djvureader.lua | 54 +++++++++++++++++++++++--------------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/djvureader.lua b/djvureader.lua index 03084ee46..3b54efa42 100644 --- a/djvureader.lua +++ b/djvureader.lua @@ -20,6 +20,7 @@ DJVUReader = { -- zoom state: globalzoom = 1.0, + globalzoom_orig = 1.0, globalzoommode = -1, -- ZOOM_FIT_TO_PAGE globalrotate = 0, @@ -139,35 +140,30 @@ function DJVUReader:setzoom(page) local dc = djvu.newDC() local pwidth, pheight = page:getSize(self.nulldc) - 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 + 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 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) @@ -330,16 +326,16 @@ function DJVUReader:inputloop() 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) + self:setglobalzoom(self.globalzoom + self.globalzoom_orig*0.2) elseif Keys.altmode then - self:setglobalzoom(self.globalzoom + 0.1) + self:setglobalzoom(self.globalzoom + self.globalzoom_orig*0.1) else 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) + if Keys.shiftmode then self:setglobalzoom(self.globalzoom - self.globalzoom_orig*0.2) elseif Keys.altmode then - self:setglobalzoom(self.globalzoom - 0.1) + self:setglobalzoom(self.globalzoom - self.globalzoom_orig*0.1) else self:goto(self.pageno - 1) end From f1fdd9a18c3fe49750b7ebbb139287161d8fee76 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 4 Mar 2012 01:11:34 +0800 Subject: [PATCH 12/27] fix: two bugs in zomming --- djvu.c | 14 ++++++++------ djvureader.lua | 8 +++++--- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/djvu.c b/djvu.c index 420774ab3..8c06270f1 100644 --- a/djvu.c +++ b/djvu.c @@ -224,12 +224,13 @@ static int openPage(lua_State *L) { 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, page->info.width); - lua_pushnumber(L, page->info.height); + lua_pushnumber(L, dc->zoom * page->info.width); + lua_pushnumber(L, dc->zoom * page->info.height); return 2; } @@ -291,7 +292,7 @@ static int drawPage(lua_State *L) { ddjvu_format_set_gamma(pixelformat, dc->gamma); /*ddjvu_format_set_ditherbits(dc->pixelformat, 2);*/ - /*printf("@page %d, @@zoom:%f\n", page->num, dc->zoom);*/ + 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);*/ @@ -301,7 +302,7 @@ static int drawPage(lua_State *L) { 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);*/ + 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 does not support negative offset, @@ -312,7 +313,7 @@ static int drawPage(lua_State *L) { 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);*/ + printf("--renderrect--- (%d, %d), w:%d, h:%d\n", renderrect.x, renderrect.y, renderrect.w, renderrect.h); /*@TODO handle rotate 04.03 2012*/ @@ -333,7 +334,8 @@ static int drawPage(lua_State *L) { bbptr += bb->pitch * y_offset; for(y = y_offset; y < bb->h; y++) { - for(x = x_offset; x < (bb->w / 2); x++) { + /* bbptr's width is half of pmptr's */ + for(x = x_offset/2; x < (bb->w / 2); x++) { /*printf(" --- y: %d, x: %d\n", y, x);*/ bbptr[x] = 255 - (((pmptr[x*2 + 1 - x_offset] & 0xF0) >> 4) | (pmptr[x*2 - x_offset] & 0xF0)); diff --git a/djvureader.lua b/djvureader.lua index 3b54efa42..c3fa7b995 100644 --- a/djvureader.lua +++ b/djvureader.lua @@ -147,6 +147,8 @@ function DJVUReader:setzoom(page) self.offset_y = (height - (self.globalzoom * pheight)) / 2 if height / pheight < self.globalzoom then self.globalzoom = height / pheight + print "adf" + print(width, (self.globalzoom * pwidth)) self.offset_x = (width - (self.globalzoom * pwidth)) / 2 self.offset_y = 0 end @@ -166,9 +168,9 @@ function DJVUReader:setzoom(page) 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() * (1 - self.globalzoom) - self.min_offset_y = fb.bb:getHeight() * (1 - self.globalzoom) + 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 From b638d083f191390f706dd500f535cf9f298e6131 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 4 Mar 2012 01:19:20 +0800 Subject: [PATCH 13/27] mod: clean up debug printf --- djvu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/djvu.c b/djvu.c index 8c06270f1..3d009881a 100644 --- a/djvu.c +++ b/djvu.c @@ -292,7 +292,7 @@ static int drawPage(lua_State *L) { 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); + /*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);*/ @@ -302,7 +302,7 @@ static int drawPage(lua_State *L) { 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); + /*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 does not support negative offset, @@ -313,7 +313,7 @@ static int drawPage(lua_State *L) { 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); + /*printf("--renderrect--- (%d, %d), w:%d, h:%d\n", renderrect.x, renderrect.y, renderrect.w, renderrect.h);*/ /*@TODO handle rotate 04.03 2012*/ From f1cfbded5de86cbcfb5becdcdc430f9aac041e4e Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 4 Mar 2012 01:39:47 +0800 Subject: [PATCH 14/27] mod: clean up code, no FIT_TO_CONTENT support --- djvureader.lua | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/djvureader.lua b/djvureader.lua index c3fa7b995..c71e61df2 100644 --- a/djvureader.lua +++ b/djvureader.lua @@ -140,8 +140,7 @@ function DJVUReader:setzoom(page) local dc = djvu.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 + 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 @@ -152,13 +151,11 @@ function DJVUReader:setzoom(page) 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 + 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 - or self.globalzoommode == self.ZOOM_FIT_TO_CONTENT_HEIGHT then + 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 From 6af5b42961dc56ed859ca3c4c2e2b94b61d12587 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 4 Mar 2012 01:40:31 +0800 Subject: [PATCH 15/27] mod: clean up debug code --- djvureader.lua | 4 ---- 1 file changed, 4 deletions(-) diff --git a/djvureader.lua b/djvureader.lua index c71e61df2..ceb587853 100644 --- a/djvureader.lua +++ b/djvureader.lua @@ -8,9 +8,6 @@ DJVUReader = { 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, GAMMA_NO_GAMMA = 1.0, @@ -146,7 +143,6 @@ function DJVUReader:setzoom(page) self.offset_y = (height - (self.globalzoom * pheight)) / 2 if height / pheight < self.globalzoom then self.globalzoom = height / pheight - print "adf" print(width, (self.globalzoom * pwidth)) self.offset_x = (width - (self.globalzoom * pwidth)) / 2 self.offset_y = 0 From a808f9936b7704a156fdcb2fd7847c3f385fbee6 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 4 Mar 2012 02:03:42 +0800 Subject: [PATCH 16/27] mod: add djvulibre --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 100e46616..0ffcc182f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,6 @@ sqlite-amalgamation* mupdf/ luafilesystem/ kpdfview +djvulibre* From dbdae773c372c78cc2dc420da77a76a176274f2f Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 4 Mar 2012 11:39:53 +0800 Subject: [PATCH 17/27] fix: handle failure for document get pageinfo --- djvu.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/djvu.c b/djvu.c index 3d009881a..e106058cc 100644 --- a/djvu.c +++ b/djvu.c @@ -197,6 +197,7 @@ static int dcGetGamma(lua_State *L) { } static int openPage(lua_State *L) { + ddjvu_status_t r; DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument"); int pageno = luaL_checkint(L, 2); @@ -218,8 +219,10 @@ static int openPage(lua_State *L) { page->doc = doc; page->num = pageno; - /* @TODO:handle failure here */ - ddjvu_document_get_pageinfo(doc->doc_ref, pageno, &(page->info)); + 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; } From 5f5f5341e0f9a2a80ac18bab1312d6ec89a6b5e0 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 4 Mar 2012 14:52:59 +0800 Subject: [PATCH 18/27] mod: update comment in djvu.c --- djvu.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/djvu.c b/djvu.c index e106058cc..cf7f2e326 100644 --- a/djvu.c +++ b/djvu.c @@ -307,10 +307,17 @@ static int drawPage(lua_State *L) { /*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 does not support negative offset, - * we need to handle negative offset manually when copying buffer. - * if offset is negative, we are moving towards down and right*/ + + /* 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); @@ -318,7 +325,7 @@ static int drawPage(lua_State *L) { /*printf("--renderrect--- (%d, %d), w:%d, h:%d\n", renderrect.x, renderrect.y, renderrect.w, renderrect.h);*/ - /*@TODO handle rotate 04.03 2012*/ + /*@TODO handle rotate here 04.03 2012*/ ddjvu_page_render(page->page_ref, DDJVU_RENDER_COLOR, @@ -337,9 +344,8 @@ static int drawPage(lua_State *L) { bbptr += bb->pitch * y_offset; for(y = y_offset; y < bb->h; y++) { - /* bbptr's width is half of pmptr's */ + /* bbptr's line width is half of pmptr's */ for(x = x_offset/2; x < (bb->w / 2); x++) { - /*printf(" --- y: %d, x: %d\n", y, x);*/ bbptr[x] = 255 - (((pmptr[x*2 + 1 - x_offset] & 0xF0) >> 4) | (pmptr[x*2 - x_offset] & 0xF0)); } From 0f0aee11b7042ab4ea936835533f5a9823c1020a Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 4 Mar 2012 15:22:54 +0800 Subject: [PATCH 19/27] mod: add comments for rotation support --- djvu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/djvu.c b/djvu.c index cf7f2e326..f7b244755 100644 --- a/djvu.c +++ b/djvu.c @@ -325,7 +325,10 @@ static int drawPage(lua_State *L) { /*printf("--renderrect--- (%d, %d), w:%d, h:%d\n", renderrect.x, renderrect.y, renderrect.w, renderrect.h);*/ - /*@TODO handle rotate here 04.03 2012*/ + /* 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, From 56470a75b067b6c6641d8fe4921d28b03b58cdab Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 4 Mar 2012 19:32:49 +0800 Subject: [PATCH 20/27] add: unireader class Add unireader class for better code reuse. Now pdfreader and djvureader are subclass of unireader. Every subclass needs to have a init() method that will be called in reader.lua. --- unireader.lua | 465 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 465 insertions(+) create mode 100644 unireader.lua diff --git a/unireader.lua b/unireader.lua new file mode 100644 index 000000000..ec766c578 --- /dev/null +++ b/unireader.lua @@ -0,0 +1,465 @@ +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, + 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, + + -- we will use this one often, so keep it "static": + --nulldc = pdf.newDC(), + nulldc = nil, -- you have to initialize it in specific reader + + -- 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) + return nil +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() + 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 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 + 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 ) + 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 + 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 +end + + From e4e0eb45eecf58eb72a973e59a14d1840bb1ccd6 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 4 Mar 2012 19:34:19 +0800 Subject: [PATCH 21/27] mod: adapt pdfreader and djvureader to unireader --- djvureader.lua | 387 +------------------------------------------ pdfreader.lua | 442 +------------------------------------------------ reader.lua | 4 + 3 files changed, 12 insertions(+), 821 deletions(-) diff --git a/djvureader.lua b/djvureader.lua index ceb587853..4ca820657 100644 --- a/djvureader.lua +++ b/djvureader.lua @@ -1,121 +1,9 @@ -require "keys" -require "settings" -require "selectmenu" +require "unireader" -DJVUReader = { - -- "constants": - ZOOM_BY_VALUE = 0, - ZOOM_FIT_TO_PAGE = -1, - ZOOM_FIT_TO_PAGE_WIDTH = -2, - ZOOM_FIT_TO_PAGE_HEIGHT = -3, +DJVUReader = UniReader:new{} - 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 - - -- the djvu document: - doc = nil, - -- the document's setting store: - settings = nil, - - -- we will use this one often, so keep it "static": - nulldc = djvu.newDC(), - - -- 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 = {}, -} - --- guarantee that we have enough memory in cache -function DJVUReader: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 DJVUReader: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) - --print("--drawing page : "..no) - page:draw(dc, self.cache[hash].bb) - --print("--page draught: "..no) - 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 DJVUReader: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 DJVUReader:clearcache() - self.cache = {} - self.cache_current_memsize = 0 +function DJVUReader:init() + self.nulldc = djvu.newDC() end -- open a DJVU file and its settings store @@ -178,270 +66,3 @@ function DJVUReader:setzoom(page) end return dc end - --- render and blit a page -function DJVUReader: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 - --- change current page and cache next page after rendering -function DJVUReader: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 - 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 == self.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 = self.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 - - 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 DJVUReader: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 DJVUReader:setglobalzoommode(newzoommode) - if self.globalzoommode ~= newzoommode then - self.globalzoommode = newzoommode - self:goto(self.pageno) - end -end - --- adjust zoom state and trigger re-rendering -function DJVUReader:setglobalzoom(zoom) - if self.globalzoom ~= zoom then - self.globalzoommode = self.ZOOM_BY_VALUE - self.globalzoom = zoom - self:goto(self.pageno) - end -end - -function DJVUReader: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 DJVUReader: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 DJVUReader:inputloop() - 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 - 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 - self:goto(self.pageno - 1) - end - elseif ev.code == KEY_BACK then - if Keys.altmode then - -- altmode, exit djvureader - 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 - 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_T then - --self:showTOC() - elseif ev.code == KEY_B then - self:showJumpStack() - 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 = self.width - 5; -- small overlap when moving by page - y = self.height - 5; - 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 - end - elseif ev.code == KEY_FW_RIGHT then - self.offset_x = self.offset_x - x - if 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 - 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 - self.offset_x = 0 - self.offset_y = 0 - else - self.pan_by_page = not self.pan_by_page - 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 -end - - diff --git a/pdfreader.lua b/pdfreader.lua index 35fea5692..7712f1f8b 100644 --- a/pdfreader.lua +++ b/pdfreader.lua @@ -1,125 +1,10 @@ -require "keys" -require "settings" -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, +PDFReader = UniReader:new{} - 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 = pdf.newDC(), - - -- 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 = {}, -} - --- 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 = pdf.newDC() end -- open a PDF file and its settings store @@ -222,322 +107,3 @@ function PDFReader:setzoom(page) 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) - 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() - 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 - 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 - 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 ) - 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 - 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 -end - - diff --git a/reader.lua b/reader.lua index 61817638f..5ad66dcdd 100755 --- a/reader.lua +++ b/reader.lua @@ -111,6 +111,10 @@ 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 From f370842a883e0b59a1b122f0e8c44c262b3d7421 Mon Sep 17 00:00:00 2001 From: Qingping Hou Date: Sun, 4 Mar 2012 19:47:17 +0800 Subject: [PATCH 22/27] mod: record self.globalzoom_orig to help zoom in/out see: https://github.com/hwhw/kindlepdfviewer/issues/24 --- djvureader.lua | 2 ++ pdfreader.lua | 4 ++++ unireader.lua | 9 +++++---- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/djvureader.lua b/djvureader.lua index 4ca820657..0e64c1081 100644 --- a/djvureader.lua +++ b/djvureader.lua @@ -46,7 +46,9 @@ function DJVUReader:setzoom(page) 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) diff --git a/pdfreader.lua b/pdfreader.lua index 7712f1f8b..e965094e0 100644 --- a/pdfreader.lua +++ b/pdfreader.lua @@ -86,7 +86,11 @@ function PDFReader:setzoom(page) 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) diff --git a/unireader.lua b/unireader.lua index ec766c578..80ac95281 100644 --- a/unireader.lua +++ b/unireader.lua @@ -21,6 +21,7 @@ UniReader = { -- zoom state: globalzoom = 1.0, + globalzoom_orig = 1.0, globalzoommode = -1, -- ZOOM_FIT_TO_PAGE globalrotate = 0, @@ -295,9 +296,9 @@ function UniReader:inputloop() 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) + self:setglobalzoom(self.globalzoom+self.globalzoom_orig*0.2) elseif Keys.altmode then - self:setglobalzoom(self.globalzoom+0.1) + self:setglobalzoom(self.globalzoom+self.globalzoom_orig*0.1) else if self.pan_by_page then self.offset_x = self.pan_x @@ -307,9 +308,9 @@ function UniReader:inputloop() end elseif ev.code == KEY_PGBCK or ev.code == KEY_LPGBCK then if Keys.shiftmode then - self:setglobalzoom(self.globalzoom-0.2) + self:setglobalzoom(self.globalzoom-self.globalzoom_orig*0.2) elseif Keys.altmode then - self:setglobalzoom(self.globalzoom-0.1) + self:setglobalzoom(self.globalzoom-self.globalzoom_orig*0.1) else if self.pan_by_page then self.offset_x = self.pan_x From 2b0a17e0348fb6d687516cacc57ce50b7f31c160 Mon Sep 17 00:00:00 2001 From: Dobrica Pavlinusic Date: Sun, 4 Mar 2012 14:10:44 +0100 Subject: [PATCH 23/27] switch to git djvulibre since 3.5.24 fails #26 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I'm using gcc version 4.6.3 (Debian 4.6.3-1) and git does compile while version 3.5.24 fails with: In file included from ../../libdjvu/GContainer.h:67:0, from ../../libdjvu/GContainer.cpp:63: ../../libdjvu/GSmartPointer.h:492:30: error: ‘size_t’ does not name a type ../../libdjvu/GSmartPointer.h:492:37: error: ISO C++ forbids declaration of ‘n’ with no type [-fpermissive] --- Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 074d59c62..8faea98d0 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ LUADIR=lua MUPDFDIR=mupdf -DJVUDIR=djvulibre-3.5.24 +DJVUDIR=djvulibre MUPDFTARGET=build/debug MUPDFLIBDIR=$(MUPDFDIR)/$(MUPDFTARGET) @@ -105,7 +105,6 @@ fetchthirdparty: -rm -Rf lsqlite3_svn08* -rm -Rf sqlite-amalgamation-3070900* -rm -Rf luafilesystem* - -rm -Rf djvulibre.tar.gz -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 ) @@ -113,7 +112,7 @@ fetchthirdparty: 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 - wget http://sourceforge.net/projects/djvu/files/latest/download\?source\=files -O djvulibre.tar.gz && tar xvzf djvulibre.tar.gz + git clone git://djvu.git.sourceforge.net/gitroot/djvu/djvulibre.git clean: -rm -f *.o kpdfview From c9064411f72a68afcb4cd093a7724ec91719144d Mon Sep 17 00:00:00 2001 From: Dobrica Pavlinusic Date: Sun, 4 Mar 2012 15:31:15 +0100 Subject: [PATCH 24/27] build only static djvulibre and fix cross-compile #26 --- Makefile | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 8faea98d0..078011392 100644 --- a/Makefile +++ b/Makefile @@ -141,16 +141,11 @@ $(MUPDFLIBS) $(THIRDPARTYLIBS): $(MUPDFDIR)/cmapdump.host $(MUPDFDIR)/fontdump.h $(DJVULIBS): -mkdir $(DJVUDIR)/build ifdef EMULATE_READER - cd $(DJVUDIR)/build && ../configure --enable-desktopfiles=no + cd $(DJVUDIR)/build && ../configure --disable-desktopfiles --disable-shared --enable-static else - cd $(DJVUDIR)/build && ../configure --enable-desktopfiles=no --host=arm -endif - make -C $(DJVUDIR)/build CXX="$(CXX)" -ifdef EMULATE_READER - cd $(DJVUDIR)/build/libdjvu/.libs && ar -cvq libdjvulibre.a *.o -else - cd $(DJVUDIR)/build/libdjvu/ && ar -cvq libdjvulibre.a *.o + 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 From df101d19faad4c445c847508a7893feb72b8899a Mon Sep 17 00:00:00 2001 From: traycold Date: Sun, 4 Mar 2012 23:01:27 +0100 Subject: [PATCH 25/27] added eclipse files and some libs folder --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 0ffcc182f..b5e821476 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,8 @@ kpdfview djvulibre* +/.cproject +/.project +/.reader.kpdfview +/luafilesystem +/mupdf From 9fb0fcadd8cbae7ad2018e36bf33bcf5a705871c Mon Sep 17 00:00:00 2001 From: traycold Date: Sun, 4 Mar 2012 23:01:41 +0100 Subject: [PATCH 26/27] fixed small type; set compiler variables when using scratchbox --- Makefile | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 078011392..f916d6bc6 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,10 @@ LFSDIR=luafilesystem CC:=arm-unknown-linux-gnueabi-gcc CXX:=arm-unknown-linux-gnueabi-g++ +ifdef SBOX_UNAME_MACHINE + CC:=gcc + CXX:=g++ +endif HOSTCC:=gcc HOSTCXX:=g++ @@ -25,16 +29,15 @@ CFLAGS:=-O0 -g # in that case. ifdef EMULATE_READER -CC:=$(HOSTCC) -CXX:=$(HOSTCXX) -EMULATE_READER_W?=824 -EMULATE_READER_H?=1200 -EMU_CFLAGS?=$(shell sdl-config --cflags) -EMU_CFLAGS+= -DEMULATE_READER \ - -DEMULATE_READER_W=$(EMULATE_READER_W) \ - -DEMULATE_READER_H=$(EMULATE_READER_H) \ - -EMU_LDFLAGS?=$(shell sdl-config --libs) + CC:=$(HOSTCC) + CXX:=$(HOSTCXX) + EMULATE_READER_W?=824 + EMULATE_READER_H?=1200 + EMU_CFLAGS?=$(shell sdl-config --cflags) + EMU_CFLAGS+= -DEMULATE_READER \ + -DEMULATE_READER_W=$(EMULATE_READER_W) \ + -DEMULATE_READER_H=$(EMULATE_READER_H) \ + EMU_LDFLAGS?=$(shell sdl-config --libs) endif # standard includes @@ -150,7 +153,7 @@ endif $(LUALIB): make -C lua/src CC="$(CC)" CFLAGS="$(CFLAGS)" MYCFLAGS=-DLUA_USE_LINUX MYLIBS="-Wl,-E" liblua.a -thirdparty: $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIBS) $(DJVULIBS) +thirdparty: $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) $(DJVULIBS) INSTALL_DIR=kindlepdfviewer From 04184a59501b75bb07431fc2bf6d2c701b2d11db Mon Sep 17 00:00:00 2001 From: traycold Date: Sun, 4 Mar 2012 23:03:04 +0100 Subject: [PATCH 27/27] improved filechooser; enable "single file" mode of kindlepdfviewer with this mode it's possible to start kindlepdfviewer opening last viewed file, bypassing filechooser --- filechooser.lua | 60 +++++++++++++++++++++++++++++++++++++---------- launchpad/kpdf.sh | 2 +- reader.lua | 29 ++++++++++++++++------- 3 files changed, 68 insertions(+), 23 deletions(-) diff --git a/filechooser.lua b/filechooser.lua index 68c14d263..d9b4e7f2c 100644 --- a/filechooser.lua +++ b/filechooser.lua @@ -33,13 +33,37 @@ FileChooser = { page = 1, current = 1, oldcurrent = 0, + exception_message = nil } +function getAbsolutePath(aPath) + local abs_path + if not aPath then + abs_path = aPath + elseif aPath:match('^//') then + abs_path = aPath:sub(2) + elseif aPath:match('^/') then + abs_path = aPath + elseif #aPath == 0 then + abs_path = '/' + else + local curr_dir = lfs.currentdir() + abs_path = aPath + if lfs.chdir(aPath) then + abs_path = lfs.currentdir() + lfs.chdir(curr_dir) + end + --print("rel: '"..aPath.."' abs:'"..abs_path.."'") + end + return abs_path +end + function FileChooser:readdir() self.dirs = {} self.files = {} for f in lfs.dir(self.path) do - if lfs.attributes(self.path.."/"..f, "mode") == "directory" and f ~= "." and not string.match(f, "^%.[^.]") then + 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 table.insert(self.files, f) @@ -51,15 +75,22 @@ function FileChooser:readdir() end function FileChooser:setPath(newPath) - self.path = newPath - self:readdir() - self.items = #self.dirs + #self.files - if self.items == 0 then - return nil + local curr_path = self.path + self.path = getAbsolutePath(newPath) + local readdir_ok, exc = pcall(self.readdir,self) + if(not readdir_ok) then + print("readdir error: "..tostring(exc)) + self.exception_message = exc + return self:setPath(curr_path) + else + self.items = #self.dirs + #self.files + if self.items == 0 then + return nil + end + self.page = 1 + self.current = 1 + return true end - self.page = 1 - self.current = 1 - return true end function FileChooser:updateFont() @@ -74,7 +105,7 @@ function FileChooser:updateFont() end function FileChooser:choose(ypos, height) - local perpage = math.floor(height / self.spacing) - 1 + local perpage = math.floor(height / self.spacing) - 2 local pagedirty = true local markerdirty = false @@ -122,8 +153,11 @@ function FileChooser:choose(ypos, height) renderUtf8Text(fb.bb, 50, ypos + self.spacing*c, self.face, self.fhash, self.files[i-#self.dirs], true) end end - renderUtf8Text(fb.bb, 39, ypos + self.spacing * perpage + 32, self.fface, self.ffhash, - "Page "..self.page.." of "..(math.floor(self.items / perpage)+1), true) + renderUtf8Text(fb.bb, 5, ypos + self.spacing * perpage + 42, self.fface, self.ffhash, + "Page "..self.page.." of "..(math.floor(self.items / perpage)+1), true) + local msg = self.exception_message and self.exception_message:match("[^%:]+:%d+: (.*)") or "Path: "..self.path + self.exception_message = nil + renderUtf8Text(fb.bb, 5, ypos + self.spacing * (perpage+1) + 27, self.fface, self.ffhash, msg, true) markerdirty = true end if markerdirty then @@ -146,7 +180,7 @@ function FileChooser:choose(ypos, height) end local ev = input.waitForEvent() - print("key code:"..ev.code) + --print("key code:"..ev.code) ev.code = adjustKeyEvents(ev) if ev.type == EV_KEY and ev.value == EVENT_VALUE_KEY_PRESS then if ev.code == KEY_FW_UP then diff --git a/launchpad/kpdf.sh b/launchpad/kpdf.sh index e89a329fd..d493b9739 100755 --- a/launchpad/kpdf.sh +++ b/launchpad/kpdf.sh @@ -2,5 +2,5 @@ echo unlock > /proc/keypad echo unlock > /proc/fiveway cd /mnt/us/kindlepdfviewer/ -./reader.lua /mnt/us/documents +./reader.lua $1 echo 1 > /proc/eink_fb/update_display diff --git a/reader.lua b/reader.lua index 5ad66dcdd..1c2b1fee8 100755 --- a/reader.lua +++ b/reader.lua @@ -39,20 +39,21 @@ function openFile(filename) page_num = DJVUReader.settings:readsetting("last_page") or 1 DJVUReader:goto(tonumber(page_num)) DJVUReader:inputloop() + reader_settings:savesetting("lastfile", filename) 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) 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") - print("Read PDFs on your E-Ink reader") +function showusage() + print("usage: ./reader.lua [OPTION] ... path") + print("Read PDFs and DJVUs on your E-Ink reader") print("") print("-p, --password=PASSWORD set password for reading PDF document") print("-g, --goto=page start reading on page") @@ -63,14 +64,21 @@ if optarg["h"] or ARGV[optind] == nil then print(" \"emu\" (DXG emulation)") print("-h, --help show this usage help") print("") - print("If you give the name of a directory instead of a path, a file") - print("chooser will show up and let you select a PDF file") + print("If you give the name of a directory instead of a file path, a file") + print("chooser will show up and let you select a PDF|DJVU file") + print("") + print("If you don't pass any path, the last viewed document will be opened") print("") print("This software is licensed under the GPLv3.") print("See http://github.com/hwhw/kindlepdfviewer for more info.") return end +optarg, optind = alt_getopt.get_opts(ARGV, "p:G:hg:d:", longopts) +if optarg["h"] then + return showusage() +end + if optarg["d"] == "k3" then -- for now, the only difference is the additional input device @@ -116,9 +124,10 @@ PDFReader:init() DJVUReader:init() -- display directory or open file -if lfs.attributes(ARGV[optind], "mode") == "directory" then +local patharg = ARGV[optind] or reader_settings:readsetting("lastfile") +if patharg and lfs.attributes(patharg, "mode") == "directory" then local running = true - FileChooser:setPath(ARGV[optind]) + FileChooser:setPath(patharg) while running do local file = FileChooser:choose(0,height) if file ~= nil then @@ -127,8 +136,10 @@ if lfs.attributes(ARGV[optind], "mode") == "directory" then running = false end end +elseif patharg then + openFile(patharg, optarg["p"]) else - openFile(ARGV[optind], optarg["p"]) + return showusage() end