summaryrefslogtreecommitdiff
path: root/tex/context/base/lpdf-epa.lua
blob: c8d23a6182509930fcaee4184ccbe101f4ec31a8 (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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
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, gsub = string.format, string.gsub

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

local report_link = logs.reporter("backend","merging")

local backends, lpdf = backends, lpdf

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

local layerspec = { -- predefining saves time
    "epdflinks"
}

local function makenamespace(filename)
    return format("lpdf-epa-%s-",file.removesuffix(file.basename(filename)))
end

local function add_link(x,y,w,h,destination,what)
    if trace_links then
        report_link("dx: % 4i, dy: % 4i, wd: % 4i, ht: % 4i, destination: %s, type: %s",x,y,w,h,destination,what)
    end
    local locationspec = { -- predefining saves time
        x      = x .. "bp",
        y      = y .. "bp",
        preset = "leftbottom",
    }
    local buttonspec = {
        width  = w .. "bp",
        height = h .. "bp",
        offset = variables.overlay,
        frame  = trace_links and variables.on or variables.off,
    }
    context.setlayer (
        layerspec,
        locationspec,
        function() context.button ( buttonspec, "", { destination } ) end
     -- context.nested.button(buttonspec, "", { destination }) -- time this
    )
end

local function link_goto(x,y,w,h,document,annotation,pagedata,namespace)
    local destination = annotation.A.D -- [ 18 0 R /Fit ]
    local what = "page"
    if type(destination) == "string" then
        local destinations = document.destinations
        local wanted = destinations[destination]
        destination = wanted and wanted.D
        if destination then what = "named" end
    end
    local pagedata = destination and destination[1]
    if pagedata then
        local destinationpage = pagedata.number
        if destinationpage then
            add_link(x,y,w,h,namespace .. destinationpage,what)
        end
    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.epdf.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 pagedata    = document.pages[pagenumber]
            local annotations = pagedata.Annots
            local namespace   = format("lpdf-epa-%s-",file.removesuffix(file.basename(fullname)))
            local reference   = namespace .. pagenumber
            if annotations.n > 0 then
                local mediabox = pagedata.MediaBox
                local llx, lly, urx, ury = mediabox[1], mediabox[2], mediabox[3], mediabox[4]
                local width, height = xscale * (urx - llx), yscale * (ury - lly) -- \\overlaywidth, \\overlayheight
                context.definelayer( { "epdflinks" }, { height = height.."bp" , width = width.."bp" })
                for i=1,annotations.n do
                    local annotation = annotations[i]
                    local subtype = annotation.Subtype
                    local rectangle = annotation.Rect
                    local a_llx, a_lly, a_urx, a_ury = rectangle[1], rectangle[2], rectangle[3], rectangle[4]
                    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,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
                context.setgvalue("figurereference",reference) -- global
                if trace_links then
                    report_link("setting figure reference to '%s'",reference)
                end
                specification.reference = reference
                return namespace
            end
        end
    end
    return ""-- no namespace, empty, not nil
end

function codeinjections.mergeviewerlayers(specification)
    -- todo: parse included page for layers
    if true then
        return
    end
    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.epdf.load(fullname)
        if document then
            local namespace = format("lpdf:epa:%s:",file.removesuffix(file.basename(fullname)))
            local layers = document.layers
            if layers then
                for i=1,layers.n do
                    local tag = namespace .. gsub(layers[i]," ",":")
                    local title = tag
                    if trace_links then
                        report_link("using layer '%s'",tag)
                    end
                    attributes.viewerlayers.define { -- also does some cleaning
                        tag       = tag, -- todo: #3A or so
                        title     = title,
                        visible   = variables.start,
                        editable  = variables.yes,
                        printable = variables.yes,
                    }
                    codeinjections.useviewerlayer(tag)
                end
            end
        end
    end
end