summaryrefslogtreecommitdiff
path: root/tex/context/base/lpdf-epa.lua
blob: 5709ced3f5aa79a17a36eb54bb1dcc0ded03e531 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
if not modules then modules = { } end modules ['lpdf-epa'] = {
    version   = 1.001,
    comment   = "companion to lpdf-epa.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

-- This is a rather experimental feature and the code will probably
-- change.

local type, tonumber = type, tonumber
local format = string.format

local trace_links = false  trackers.register("figures.links", function(v) trace_links = v end)

local report_link = logs.new("links")

local backends, lpdf = backends, lpdf

local variables      = interfaces.variables
local codeinjections = backends.pdf.codeinjections

local function add_link(x,y,w,h,destination,what)
    if trace_links then
        report_link("dx: %04i, dy: %04i, wd: %04i, ht: %04i, destination: %s, type: %s",x,y,w,h,destination,what)
    end
    context.setlayer (
        { "epdflinks" },
        { x = x .. "bp", y = y .. "bp", preset = "leftbottom" },
        function()
         -- context.blackrule { width = w.."bp", height = h.."bp", depth = "0bp" }
            context.button (
                {
                    width  = w.."bp",
                    height = h.."bp",
                    offset = variables.overlay,
                    frame  = trace_links and variables.on or variables.off,
                },
                "",
                { destination }
            )
        end
    )
end

local function link_goto(x,y,w,h,document,annotation,pagesdata,pagedata,namespace)
 -- print("border",table.unpack(annotation.Border.all))
 -- print("flags",annotation.F)
 -- print("pagenumbers",pagedata.reference.num,destination[1].num)
 -- print("pagerefs",pagedata.number,pagesdata.references[destination[1].num])
    local destination = annotation.A.D -- [ 18 0 R /Fit ]
    local what = "page"
    if type(destination) == "string" then
        local destinations = document.Catalog.Destinations
        local wanted = destinations[destination]
        destination = wanted and wanted.D
        if destination then what = "named" end
    end
    local whereto = destination and destination[1] -- array
    if whereto and whereto.num then
        local currentpage = pagedata.number
        local destinationpage = pagesdata.references[whereto.num]
        add_link(x,y,w,h,namespace .. destinationpage,what)
        return
    end
end

local function link_uri(x,y,w,h,document,annotation)
    local url = annotation.A.URI
    if url then
        add_link(x,y,w,h,format("url(%s)",url),"url")
    end
end

local function link_file(x,y,w,h,document,annotation)
    local filename = annotation.A.F
    if filename then
        local destination = annotation.A.D
        if not destination then
            add_link(x,y,w,h,format("file(%s)",filename),"file")
        elseif type(destination) == "string" then
            add_link(x,y,w,h,format("%s::%s",filename,destination),"file (named)")
        else
            destination = destination[1] -- array
            if tonumber(destination) then
                add_link(x,y,w,h,format("%s::page(%s)",filename,destination),"file (page)")
            else
                add_link(x,y,w,h,format("file(%s)",filename),"file")
            end
        end
    end
end

function codeinjections.mergereferences(specification)
    if figures and not specification then
        specification = figures and figures.current()
        specification = specification and specification.status
    end
    if specification then
        local fullname = specification.fullname
        local document = lpdf.load(fullname)
        if document then
            local pagenumber  = specification.page    or 1
            local xscale      = specification.yscale  or 1
            local yscale      = specification.yscale  or 1
            local size        = specification.size    or "crop" -- todo
            local pagesdata   = document.Catalog.Pages
            local pagedata    = pagesdata[pagenumber]
            local annotations = pagedata.Annots
            local namespace   = format("lpdf-epa-%s-",file.removesuffix(file.basename(fullname)))
            local reference   = namespace .. pagenumber
            if annotations.size > 0 then
                local llx, lly, urx, ury = table.unpack(pagedata.MediaBox.all)
                local width, height = xscale * (urx - llx), yscale * (ury - lly) -- \\overlaywidth, \\overlayheight
                context.definelayer( { "epdflinks" }, { height = height.."bp" , width = width.."bp" })
                for i=1,annotations.size do
                    local annotation = annotations[i]
                    local subtype = annotation.Subtype
                    local a_llx, a_lly, a_urx, a_ury = table.unpack(annotation.Rect.all)
                    local x, y = xscale * (a_llx -   llx), yscale * (a_lly -   lly)
                    local w, h = xscale * (a_urx - a_llx), yscale * (a_ury - a_lly)
                    if subtype  == "Link" then
                        local linktype = annotation.A.S
                        if linktype == "GoTo" then
                            link_goto(x,y,w,h,document,annotation,pagesdata,pagedata,namespace)
                        elseif linktype == "GoToR" then
                            link_file(x,y,w,h,document,annotation)
                        elseif linktype == "URI" then
                            link_uri(x,y,w,h,document,annotation)
                        elseif trace_links then
                            report_link("unsupported link annotation '%s'",linktype)
                        end
                    elseif trace_links then
                        report_link("unsupported annotation '%s'",subtype)
                    end
                end
                context.flushlayer { "epdflinks" }
                context("\\gdef\\figurereference{%s}",reference) -- global
                specification.reference = reference
                return namespace
            end
        end
    end
    return ""-- no namespace, empty, not nil
end

function codeinjections.mergeviewerlayers(specification)
    if not specification then
        specification = figures and figures.current()
        specification = specification and specification.status
    end
    if specification then
        local fullname = specification.fullname
        local document = lpdf.load(fullname)
        if document then
            local pagenumber = specification.page or 1
            local pagesdata  = document.Catalog.Pages
            local pagedata   = pagesdata[pagenumber]
            local resources  = pagedata.Resources
--~             table.print(resources)
--~             local properties = resources.Properties
        end
    end
end