diff --git a/pdf.c b/pdf.c index 780b33dd7..d20a12b86 100644 --- a/pdf.c +++ b/pdf.c @@ -492,9 +492,9 @@ static int getUsedBBox(lua_State *L) { return luaL_error(L, "cannot calculate bbox for page"); } - lua_pushnumber(L, ((double)result.x0)/100); + 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.x1)/100); lua_pushnumber(L, ((double)result.y1)/100); return 4; @@ -577,6 +577,59 @@ static int cleanCache(lua_State *L) { return 0; } + +static int getPageLinks(lua_State *L) { + fz_link *page_links; + fz_link *link; + + int link_count; + + PdfPage *page = (PdfPage*) luaL_checkudata(L, 1, "pdfpage"); + + page_links = fz_load_links(page->doc->xref, page->page); // page->doc->xref? + + lua_newtable(L); // all links + + link_count = 0; + + for (link = page_links; link; link = link->next) { + lua_newtable(L); // new link + + lua_pushstring(L, "x0"); + lua_pushinteger(L, link->rect.x0); + lua_settable(L, -3); + lua_pushstring(L, "y0"); + lua_pushinteger(L, link->rect.y0); + lua_settable(L, -3); + lua_pushstring(L, "x1"); + lua_pushinteger(L, link->rect.x1); + lua_settable(L, -3); + lua_pushstring(L, "y1"); + lua_pushinteger(L, link->rect.y1); + lua_settable(L, -3); + + if (link->dest.kind == FZ_LINK_URI) { + lua_pushstring(L, "uri"); + lua_pushstring(L, link->dest.ld.uri.uri); + lua_settable(L, -3); + } else if (link->dest.kind == FZ_LINK_GOTO) { + lua_pushstring(L, "page"); + lua_pushinteger(L, link->dest.ld.gotor.page); // FIXME page+1? + lua_settable(L, -3); + } else { + printf("ERROR: unkown link kind: %x", link->dest.kind); + } + + lua_rawseti(L, -2, ++link_count); + } + + printf("## getPageLinks found %d links in document\n", link_count); + + fz_drop_link(page->doc->context, page_links); + + return 1; +} + static const struct luaL_Reg pdf_func[] = { {"openDocument", openDocument}, {NULL, NULL} @@ -599,6 +652,7 @@ static const struct luaL_Reg pdfpage_meth[] = { {"getSize", getPageSize}, {"getUsedBBox", getUsedBBox}, {"getPageText", getPageText}, + {"getPageLinks", getPageLinks}, {"close", closePage}, {"__gc", closePage}, {"draw", drawPage}, diff --git a/pdfreader.lua b/pdfreader.lua index b14d0a94a..12961d438 100644 --- a/pdfreader.lua +++ b/pdfreader.lua @@ -45,3 +45,16 @@ function PDFReader:getText(pageno) page:close() return text end + +function PDFReader:getPageLinks(pageno) + local ok, page = pcall(self.doc.openPage, self.doc, pageno) + if not ok then + -- TODO: error handling + return nil + end + local links = page:getPageLinks() + Debug("## page:getPageLinks ", links) + page:close() + return links +end + diff --git a/unireader.lua b/unireader.lua index 1c58c7872..ed8393e16 100644 --- a/unireader.lua +++ b/unireader.lua @@ -1389,6 +1389,17 @@ function UniReader:show(no) self:toggleTextHighLight(self.highlight[no]) end + -- draw links on page + local links = self:getPageLinks( no ) + if links ~= nil then + for i, link in ipairs(links) do + if link.page then -- skip non-page links + local x,y,w,h = self:zoomedRectCoordTransform( link.x0,link.y0, link.x1,link.y1 ) + fb.bb:invertRect(x,y+h-2, w,1) + end + end + end + if self.rcount >= self.rcountmax then Debug("full refresh") self.rcount = 0 @@ -2070,6 +2081,11 @@ function UniReader:searchHighLight(search) end +function UniReader:getPageLinks(pageno) + Debug("getPageLinks not supported in this format") + return nil +end + -- used in UniReader:showMenu() function UniReader:_drawReadingInfo() local width, height = G_width, G_height @@ -2865,6 +2881,117 @@ function UniReader:addAllCommands() end end ) + self.commands:add(KEY_L, nil, "L", + "page links", + function(unireader) + local links = unireader:getPageLinks( unireader.pageno ) + if links == nil or next(links) == nil then + showInfoMsgWithDelay("No links on this page", 2000, 1) + else + local font_size = math.ceil( (links[1].y1 - links[1].y0 - 2) * unireader.globalzoom ) + Debug("font_size",font_size) + Debug("shortcuts",SelectMenu.item_shortcuts) + local face = Font:getFace("rifont", font_size) + + local page_links = 0 + + for i, link in ipairs(links) do + if link.page then + local x,y,w,h = self:zoomedRectCoordTransform( link.x0,link.y0, link.x1,link.y1 ) + fb.bb:dimRect(x,y,w,h) -- black 50% + fb.bb:dimRect(x,y,w,h) -- black 25% + page_links = page_links + 1 + end + end + + if page_links == 0 then + showInfoMsgWithDelay("No links on this page", 2000, 1) + return + end + + Screen:saveCurrentBB() -- save dimmed links + + local shortcut_offset = 0 + local shortcut_map + + local render_shortcuts = function() + Screen:restoreFromSavedBB() + + local shortcut_nr = 1 + shortcut_map = {} + + for i = 1, #SelectMenu.item_shortcuts, 1 do + local link = links[ i + shortcut_offset ] + if link == nil then break end + Debug("link", i, shortcut_offset, link) + if link.page then + local x,y,w,h = self:zoomedRectCoordTransform( link.x0,link.y0, link.x1,link.y1 ) + renderUtf8Text(fb.bb, x, y + font_size - 1, face, SelectMenu.item_shortcuts[shortcut_nr]) + shortcut_map[shortcut_nr] = i + shortcut_offset + shortcut_nr = shortcut_nr + 1 + end + end + + Debug("shortcut_map", shortcut_map) + + fb:refresh(1) + end + + render_shortcuts() + + local goto_page = nil + + while not goto_page do + + local ev = input.saveWaitForEvent() + ev.code = adjustKeyEvents(ev) + Debug("ev",ev) + + local link = nil + + if ev.type == EV_KEY and ev.value ~= EVENT_VALUE_KEY_RELEASE then + if ev.code >= KEY_Q and ev.code <= KEY_P then + link = ev.code - KEY_Q + 1 + elseif ev.code >= KEY_A and ev.code <= KEY_L then + link = ev.code - KEY_A + 11 + elseif ev.code == KEY_SLASH then + link = 20 + elseif ev.code >= KEY_Z and ev.code <= KEY_M then + link = ev.code - KEY_Z + 21 + elseif ev.code == KEY_DOT then + link = 28 + elseif ev.code == KEY_SYM then + link = 29 + elseif ev.code == KEY_ENTER then + link = 30 + elseif ev.code == KEY_BACK then + goto_page = unireader.pageno + elseif ( ev.code == KEY_FW_RIGHT or ev.code == KEY_FW_DOWN ) and shortcut_offset <= #links - 30 then + shortcut_offset = shortcut_offset + 30 + render_shortcuts() + elseif ( ev.code == KEY_FW_LEFT or ev.code == KEY_FW_UP ) and shortcut_offset >= 30 then + shortcut_offset = shortcut_offset - 30 + render_shortcuts() + end + end + + if link then + link = shortcut_map[link] + if links[link] ~= nil and links[link].page ~= nil then + goto_page = links[link].page + 1 + else + Debug("missing link", link) + end + end + + Debug("goto_page", goto_page, "now on", unireader.pageno, "link", link) + end + + unireader:goto(goto_page) + + end + end + ) self.commands:add(KEY_BACK,MOD_ALT,"Back", "close document", function(unireader)