diff --git a/Makefile b/Makefile index 0f27d4a1a..3789f8461 100644 --- a/Makefile +++ b/Makefile @@ -109,7 +109,9 @@ POPENNSLIB := $(POPENNSDIR)/libpopen_noshell.a all: kpdfview +VERSION?=$(shell git describe HEAD) kpdfview: kpdfview.o einkfb.o pdf.o blitbuffer.o drawcontext.o input.o $(POPENNSLIB) util.o ft.o lfs.o mupdfimg.o $(MUPDFLIBS) $(THIRDPARTYLIBS) $(LUALIB) djvu.o $(DJVULIBS) cre.o $(CRENGINELIBS) + echo $(VERSION) > git-rev $(CC) \ $(CFLAGS) \ kpdfview.o \ @@ -250,7 +252,6 @@ INSTALL_DIR=kindlepdfviewer LUA_FILES=reader.lua -VERSION?=$(shell git describe HEAD) customupdate: all # ensure that build binary is for ARM file kpdfview | grep ARM || exit 1 @@ -258,12 +259,11 @@ customupdate: all rm -f kindlepdfviewer-$(VERSION).zip rm -rf $(INSTALL_DIR) mkdir -p $(INSTALL_DIR)/{history,screenshots} - echo $(VERSION) > $(INSTALL_DIR)/git-rev cp -p README.md COPYING kpdfview kpdf.sh $(LUA_FILES) $(INSTALL_DIR) mkdir $(INSTALL_DIR)/data cp -rpL data/*.css $(INSTALL_DIR)/data cp -rpL fonts $(INSTALL_DIR) - cp -r resources $(INSTALL_DIR) + cp -r git-rev resources $(INSTALL_DIR) cp -rpL frontend $(INSTALL_DIR) mkdir $(INSTALL_DIR)/fonts/host zip -9 -r kindlepdfviewer-$(VERSION).zip $(INSTALL_DIR) launchpad/ kite/ diff --git a/README.md b/README.md index ee48f0504..e23f0b3a0 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Follow these steps: * install popen_noshell sources into subfolder "popen-noshell" * automatically fetch thirdparty sources with Makefile: - * make sure you have wget, unzip, git and svn installed + * make sure you have patch, wget, unzip, git and svn installed * run `make fetchthirdparty`. * adapt Makefile to your needs diff --git a/cre.cpp b/cre.cpp index ef3aca8b1..6277233f4 100644 --- a/cre.cpp +++ b/cre.cpp @@ -575,7 +575,7 @@ int luaopen_cre(lua_State *L) { /* initialize font manager for CREngine */ InitFontManager(lString8()); -#ifdef DEBUG_CRENGINE +#if DEBUG_CRENGINE CRLog::setStdoutLogger(); CRLog::setLogLevel(CRLog::LL_DEBUG); #endif diff --git a/djvu.c b/djvu.c index a34c46bfb..c2ba5a5ca 100644 --- a/djvu.c +++ b/djvu.c @@ -17,6 +17,7 @@ */ #include #include +#include #include #include @@ -85,11 +86,10 @@ static int openDocument(lua_State *L) { ddjvu_cache_set_size(doc->context, (unsigned long)cache_size); doc->doc_ref = ddjvu_document_create_by_filename_utf8(doc->context, filename, TRUE); + if (! doc->doc_ref) + return luaL_error(L, "cannot open DjVu file <%s>", filename); 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->pixelformat = ddjvu_format_create(DDJVU_FORMAT_GREY8, 0, NULL); if (! doc->pixelformat) { @@ -135,17 +135,28 @@ static int walkTableOfContent(lua_State *L, miniexp_t r, int *count, int depth) int length = miniexp_length(r); int counter = 0; - char page_number[6]; + const char* page_name; + int page_number; while(counter < length-1) { lua_pushnumber(L, *count); lua_newtable(L); lua_pushstring(L, "page"); - strcpy(page_number,miniexp_to_str(miniexp_car(miniexp_cdr(miniexp_nth(counter, lista))))); - /* page numbers appear as #11, set # to 0 so strtol works */ - page_number[0]= '0'; - lua_pushnumber(L, strtol(page_number, NULL, 10)); + page_name = miniexp_to_str(miniexp_car(miniexp_cdr(miniexp_nth(counter, lista)))); + if(page_name != NULL && page_name[0] == '#') { + errno = 0; + page_number = strtol(page_name + 1, NULL, 10); + if(!errno) { + lua_pushnumber(L, page_number); + } else { + /* we can not parse this as a number, TODO: parse page names */ + lua_pushnumber(L, -1); + } + } else { + /* something we did not expect here */ + lua_pushnumber(L, -1); + } lua_settable(L, -3); lua_pushstring(L, "depth"); @@ -199,11 +210,10 @@ static int openPage(lua_State *L) { /* djvulibre counts page starts from 0 */ page->page_ref = ddjvu_page_create_by_pageno(doc->doc_ref, pageno - 1); + if (! page->page_ref) + return luaL_error(L, "cannot open page #%d", pageno); while (! ddjvu_page_decoding_done(page->page_ref)) handle(L, doc->context, TRUE); - if (! page->page_ref) { - return luaL_error(L, "cannot open page #%d", pageno); - } page->doc = doc; page->num = pageno; @@ -231,13 +241,10 @@ static int getPageSize(lua_State *L) { /* unsupported so fake it */ static int getUsedBBox(lua_State *L) { - DjvuPage *page = (DjvuPage*) luaL_checkudata(L, 1, "djvupage"); - lua_pushnumber(L, (double)0.01); lua_pushnumber(L, (double)0.01); lua_pushnumber(L, (double)-0.01); lua_pushnumber(L, (double)-0.01); - return 4; } @@ -259,6 +266,63 @@ static int getOriginalPageSize(lua_State *L) { return 2; } +static int getPageInfo(lua_State *L) { + DjvuDocument *doc = (DjvuDocument*) luaL_checkudata(L, 1, "djvudocument"); + int pageno = luaL_checkint(L, 2); + ddjvu_page_t *djvu_page; + int page_width, page_height, page_dpi; + double page_gamma; + ddjvu_page_type_t page_type; + char *page_type_str; + + djvu_page = ddjvu_page_create_by_pageno(doc->doc_ref, pageno - 1); + if (! djvu_page) + return luaL_error(L, "cannot create djvu_page #%d", pageno); + + while (! ddjvu_page_decoding_done(djvu_page)) + handle(L, doc->context, TRUE); + + page_width = ddjvu_page_get_width(djvu_page); + lua_pushnumber(L, page_width); + + page_height = ddjvu_page_get_height(djvu_page); + lua_pushnumber(L, page_height); + + page_dpi = ddjvu_page_get_resolution(djvu_page); + lua_pushnumber(L, page_dpi); + + page_gamma = ddjvu_page_get_gamma(djvu_page); + lua_pushnumber(L, page_gamma); + + page_type = ddjvu_page_get_type(djvu_page); + switch (page_type) { + case DDJVU_PAGETYPE_UNKNOWN: + page_type_str = "UNKNOWN"; + break; + + case DDJVU_PAGETYPE_BITONAL: + page_type_str = "BITONAL"; + break; + + case DDJVU_PAGETYPE_PHOTO: + page_type_str = "PHOTO"; + break; + + case DDJVU_PAGETYPE_COMPOUND: + page_type_str = "COMPOUND"; + break; + + default: + page_type_str = "INVALID"; + break; + } + lua_pushstring(L, page_type_str); + + ddjvu_page_release(djvu_page); + + return 5; +} + /* * Return a table like following: * { @@ -424,13 +488,11 @@ static int drawPage(lua_State *L) { unsigned char adjusted_low[16], adjusted_high[16]; int i, adjust_pixels = 0; ddjvu_rect_t pagerect, renderrect; - uint8_t *imagebuffer = malloc((bb->w)*(bb->h)+1); + int bbsize = (bb->w)*(bb->h)+1; + uint8_t *imagebuffer = malloc(bbsize); /*printf("@page %d, @@zoom:%f, offset: (%d, %d)\n", page->num, dc->zoom, dc->offset_x, dc->offset_y);*/ - /* fill pixel map with white color */ - memset(imagebuffer, 0xFF, (bb->w)*(bb->h)+1); - /* render full page into rectangle specified by pagerect */ pagerect.x = 0; pagerect.y = 0; @@ -461,13 +523,8 @@ static int drawPage(lua_State *L) { * So we don't set rotation here. */ - ddjvu_page_render(page->page_ref, - djvu_render_mode, - &pagerect, - &renderrect, - page->doc->pixelformat, - bb->w, - imagebuffer); + if (!ddjvu_page_render(page->page_ref, djvu_render_mode, &pagerect, &renderrect, page->doc->pixelformat, bb->w, imagebuffer)) + memset(imagebuffer, 0xFF, bbsize); uint8_t *bbptr = bb->data; uint8_t *pmptr = imagebuffer; @@ -535,6 +592,7 @@ static const struct luaL_Reg djvudocument_meth[] = { {"getToc", getTableOfContent}, {"getPageText", getPageText}, {"getOriginalPageSize", getOriginalPageSize}, + {"getPageInfo", getPageInfo}, {"close", closeDocument}, {"getCacheSize", getCacheSize}, {"cleanCache", cleanCache}, diff --git a/frontend/document/djvudocument.lua b/frontend/document/djvudocument.lua index 31d3aa2e9..d8f627e06 100644 --- a/frontend/document/djvudocument.lua +++ b/frontend/document/djvudocument.lua @@ -9,6 +9,11 @@ DjvuDocument = Document:new{ } function DjvuDocument:init() + if not validDjvuFile(self.file) then + self.error_message = "Not a valid DjVu file" + return + end + local ok ok, self._document = pcall(djvu.openDocument, self.file, self.djvulibre_cache_size) if not ok then @@ -20,6 +25,16 @@ function DjvuDocument:init() self:_readMetadata() end +-- check DjVu magic string to validate +function validDjvuFile(filename) + f = io.open(filename, "r") + if not f then return false end + local magic = f:read(8) + f:close() + if not magic or magic ~= "AT&TFORM" then return false end + return true +end + function DjvuDocument:getUsedBBox(pageno) -- djvu does not support usedbbox, so fake it. local used = {} diff --git a/frontend/document/document.lua b/frontend/document/document.lua index 9a173f183..f9ed27091 100644 --- a/frontend/document/document.lua +++ b/frontend/document/document.lua @@ -128,7 +128,7 @@ function Document:getToc() return self._document:getToc() end -function Document:renderPage(pageno, rect, zoom, rotation) +function Document:renderPage(pageno, rect, zoom, rotation, render_mode) local hash = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation local page_size = self:getPageDimensions(pageno, zoom, rotation) -- this will be the size we actually render @@ -172,7 +172,7 @@ function Document:renderPage(pageno, rect, zoom, rotation) -- render local page = self._document:openPage(pageno) - page:draw(dc, tile.bb, size.x, size.y) + page:draw(dc, tile.bb, size.x, size.y, render_mode) page:close() Cache:insert(hash, tile) @@ -185,7 +185,7 @@ function Document:hintPage(pageno, zoom, rotation) self:renderPage(pageno, nil, zoom, rotation) end -function Document:drawPage(target, x, y, rect, pageno, zoom, rotation) +function Document:drawPage(target, x, y, rect, pageno, zoom, rotation, render_mode) local hash_full_page = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation local hash_excerpt = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..tostring(rect) local tile = Cache:check(hash_full_page) @@ -193,7 +193,7 @@ function Document:drawPage(target, x, y, rect, pageno, zoom, rotation) tile = Cache:check(hash_excerpt) if not tile then DEBUG("rendering") - tile = self:renderPage(pageno, rect, zoom, rotation) + tile = self:renderPage(pageno, rect, zoom, rotation, render_mode) end end DEBUG("now painting", tile) diff --git a/frontend/ui/reader/readerview.lua b/frontend/ui/reader/readerview.lua index 1beaf1581..6f9c1ce94 100644 --- a/frontend/ui/reader/readerview.lua +++ b/frontend/ui/reader/readerview.lua @@ -9,8 +9,9 @@ ReaderView = WidgetContainer:new{ offset = {}, bbox = nil, }, - outer_page_color = 7, + -- DjVu page rendering mode (used in djvu.c:drawPage()) + render_mode = 0, -- default to COLOR visible_area = Geom:new{x = 0, y = 0}, page_area = Geom:new{}, @@ -41,7 +42,8 @@ function ReaderView:paintTo(bb, x, y) self.visible_area, self.state.page, self.state.zoom, - self.state.rotation) + self.state.rotation, + self.render_mode) else self.ui.document:drawCurrentView( bb, @@ -88,6 +90,10 @@ function ReaderView:onSetDimensions(dimensions) self:recalculate() end +function ReaderView:onReadSettings(config) + self.render_mode = config:readSetting("render_mode") or 0 +end + function ReaderView:onPageUpdate(new_page_no) self.state.page = new_page_no self:recalculate() @@ -108,3 +114,6 @@ function ReaderView:onRotationUpdate(rotation) self:recalculate() end +function ReaderView:onCloseDocument() + self.ui.doc_settings:saveSetting("render_mode", self.render_mode) +end diff --git a/frontend/ui/rendertext.lua b/frontend/ui/rendertext.lua index 743240916..9b4b492a6 100644 --- a/frontend/ui/rendertext.lua +++ b/frontend/ui/rendertext.lua @@ -47,10 +47,11 @@ function getSubTextByWidth(text, face, width, kerning) end function sizeUtf8Text(x, width, face, text, kerning) - if text == nil then + if not text then DEBUG("sizeUtf8Text called without text"); return end + -- may still need more adaptive pen placement when kerning, -- see: http://freetype.org/freetype2/docs/glyphs/glyphs-4.html local pen_x = 0 @@ -61,48 +62,46 @@ function sizeUtf8Text(x, width, face, text, kerning) if pen_x < (width - x) then local charcode = util.utf8charcode(uchar) local glyph = getGlyph(face, charcode) - if kerning and prevcharcode then - local kern = face.ftface:getKerning(prevcharcode, charcode) - pen_x = pen_x + kern - --DEBUG("prev:"..string.char(prevcharcode).." curr:"..string.char(charcode).." kern:"..kern) - else - --DEBUG("curr:"..string.char(charcode)) + if kerning and (prevcharcode ~= 0) then + pen_x = pen_x + face.ftface:getKerning(prevcharcode, charcode) end pen_x = pen_x + glyph.ax pen_y_top = math.max(pen_y_top, glyph.t) pen_y_bottom = math.max(pen_y_bottom, glyph.bb:getHeight() - glyph.t) --DEBUG("ax:"..glyph.ax.." t:"..glyph.t.." r:"..glyph.r.." h:"..glyph.bb:getHeight().." w:"..glyph.bb:getWidth().." yt:"..pen_y_top.." yb:"..pen_y_bottom) prevcharcode = charcode - end - end + end -- if pen_x < (width - x) + end -- for uchar return { x = pen_x, y_top = pen_y_top, y_bottom = pen_y_bottom} end function renderUtf8Text(buffer, x, y, face, text, kerning) - if text == nil then + if not text then DEBUG("renderUtf8Text called without text"); return 0 end + -- may still need more adaptive pen placement when kerning, -- see: http://freetype.org/freetype2/docs/glyphs/glyphs-4.html local pen_x = 0 local prevcharcode = 0 + local buffer_width = buffer:getWidth() for uchar in string.gfind(text, "([%z\1-\127\194-\244][\128-\191]*)") do - if pen_x < buffer:getWidth() then + if pen_x < buffer_width then local charcode = util.utf8charcode(uchar) local glyph = getGlyph(face, charcode) - if kerning and prevcharcode then - local kern = face.ftface:getKerning(prevcharcode, charcode) - pen_x = pen_x + kern - --DEBUG("prev:"..string.char(prevcharcode).." curr:"..string.char(charcode).." pen_x:"..pen_x.." kern:"..kern) - buffer:addblitFrom(glyph.bb, x + pen_x + glyph.l, y - glyph.t, 0, 0, glyph.bb:getWidth(), glyph.bb:getHeight()) - else - --DEBUG(" curr:"..string.char(charcode)) - buffer:blitFrom(glyph.bb, x + pen_x + glyph.l, y - glyph.t, 0, 0, glyph.bb:getWidth(), glyph.bb:getHeight()) + if kerning and (prevcharcode ~= 0) then + pen_x = pen_x + face.ftface:getKerning(prevcharcode, charcode) end + buffer:addblitFrom( + glyph.bb, + x + pen_x + glyph.l, y - glyph.t, + 0, 0, + glyph.bb:getWidth(), glyph.bb:getHeight()) pen_x = pen_x + glyph.ax prevcharcode = charcode - end - end + end -- if pen_x < buffer_width + end -- for uchar + return pen_x end diff --git a/frontend/ui/widget.lua b/frontend/ui/widget.lua index c4ce3713e..630fa0589 100644 --- a/frontend/ui/widget.lua +++ b/frontend/ui/widget.lua @@ -204,6 +204,7 @@ function TextWidget:paintTo(bb, x, y) --self:_render() --end --bb:blitFrom(self._bb, x, y, 0, 0, self._length, self._bb:getHeight()) + --@TODO Don't use kerning for monospaced fonts. (houqp) renderUtf8Text(bb, x, y+self._height*0.7, self.face, self.text, true) end @@ -281,6 +282,8 @@ function TextBoxWidget:_render() for _,l in ipairs(v_list) do pen_x = 0 for _,w in ipairs(l) do + --@TODO Don't use kerning for monospaced fonts. (houqp) + -- refert to cb25029dddc42693cc7aaefbe47e9bd3b7e1a750 in master tree renderUtf8Text(self._bb, pen_x, y*0.8, self.face, w.word, true) pen_x = pen_x + w.width + space_w end diff --git a/reader.lua b/reader.lua index e8e06ccc5..d6ae51c9a 100755 --- a/reader.lua +++ b/reader.lua @@ -121,6 +121,8 @@ local last_file = G_reader_settings:readSetting("lastfile") Screen:updateRotationMode() Screen.native_rotation_mode = Screen.cur_rotation_mode +--@TODO we can read version here, refer to commit in master tree: (houqp) +--87712cf0e43fed624f8a9f610be42b1fe174b9fe if ARGV[optind] then