summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/grph-chk.lua
blob: 6356755aab0196769ccf3ac30f34fee2e30e2b88 (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
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
if not modules then modules = { } end modules ['grph-inc'] = {
    version   = 1.001,
    comment   = "companion to grph-inc.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

local xpcall, pcall = xpcall, pcall

local bpfactor          = number.dimenfactors.bp

local report            = logs.reporter("graphics")
local report_inclusion  = logs.reporter("graphics","inclusion")
local report_bitmap     = logs.reporter("graphics","bitmap")

local checkers          = figures.checkers

local placeholder       = graphics.bitmaps.placeholder

-- This is an experiment. The following method uses Lua to handle the embedding
-- using the epdf library. This feature will be used when we make the transition
-- from the pre 1.10 epdf library (using an unsuported low level poppler api) to a
-- new (lightweight, small and statically compiled) library. More on that later.
--
-- The method implemented below has the same performance as the hard coded inclusion
-- but opens up some possibilities (like merging fonts) that I will look into some
-- day.

local function pdf_checker(data)
    local request = data.request
    local used    = data.used
    if request and used and not request.scanimage then
        local image    = lpdf.epdf.image
        local openpdf  = image.open
        local closepdf = image.close
        local querypdf = image.query
        local copypage = image.copy
        local pdfdoc   = nil
        request.scanimage = function(t)
            pdfdoc = openpdf(t.filename,request.userpassword,request.ownerpassword)
            if pdfdoc then
                --
                pdfdoc.nofcopiedpages = 0
                --
                local info = querypdf(pdfdoc,request.page,request.size)
                if info then
                    local bbox     = info and info.boundingbox or { 0, 0, 0, 0 }
                    local height   = bbox[4] - bbox[2]
                    local width    = bbox[3] - bbox[1]
                    local rotation = info.rotation or 0
                    if rotation == 90 then
                        rotation, height, width = 3, width, height
                    elseif rotation == 180 then
                        rotation = 2
                    elseif rotation == 270 then
                        rotation, height, width = 1, width, height
                    elseif rotation == 1 or rotation == 3 then
                        height, width = width, height
                    else
                        rotation = 0
                    end
                    return {
                        filename    = filename,
                     -- page        = 1,
                        pages       = pdfdoc.nofpages,
                        width       = width,
                        height      = height,
                        depth       = 0,
                        colordepth  = 0,
                        xres        = 0,
                        yres        = 0,
                        xsize       = width,
                        ysize       = height,
                        rotation    = rotation,
                        pdfdoc      = pdfdoc,
                    }
                end
            end
        end
        request.copyimage = function(t)
            if not pdfdoc then
                pdfdoc = t.pdfdoc
            end
            if pdfdoc then
                local result = copypage(pdfdoc,request.page,nil,request.compact,request.width,request.height,request.attr)
                pdfdoc.nofcopiedpages = pdfdoc.nofcopiedpages + 1
                if pdfdoc.nofcopiedpages >= pdfdoc.nofpages then
                    closepdf(pdfdoc)
                    pdfdoc = nil
                    t.pdfdoc = nil
                end
                return result
            else
                -- message, should not happen as we always first scan so that reopens
            end
        end
    end
    return checkers.generic(data)
end

local function wrappedidentify(identify,filename)
    local wrapup    = function() report_inclusion("fatal error reading %a",filename) end
    local _, result = xpcall(identify,wrapup,filename)
    if result then
        local xsize = result.xsize or 0
        local ysize = result.ysize or 0
        local xres  = result.xres or 0
        local yres  = result.yres or 0
        if xres == 0 or yres == 0 then
            xres = 300
            yres = 300
        end
        result.xsize       = xsize
        result.ysize       = ysize
        result.xres        = xres
        result.yres        = yres
        result.width       = result.width  or ((72/xres) * xsize / bpfactor)
        result.height      = result.height or ((72/yres) * ysize / bpfactor)
        result.depth       = result.depth  or 0
        result.filename    = filename
        result.colordepth  = result.colordepth or 0
        result.colorspace  = result.colorspace or 0
        result.rotation    = result.rotation or 0
        result.orientation = result.orientation or 0
        result.transform   = result.transform or 0
        return result
    else
        return { error = "fatal error" }
    end
end

local function jpg_checker(data)
    local request = data.request
    local used    = data.used
    if request and used and not request.scanimage then
        local identify = graphics.identify
        local inject   = lpdf.injectors.jpg
        local found    = false
        request.scanimage = function(t)
            local result = wrappedidentify(identify,t.filename)
            found = not result.error
            return {
                filename    = result.filename,
                width       = result.width,
                height      = result.height,
                depth       = result.depth,
                colordepth  = result.colordepth,
                xres        = result.xres,
                yres        = result.yres,
                xsize       = result.xsize,
                ysize       = result.ysize,
                colorspace  = result.colorspace,
                rotation    = result.rotation,
                orientation = result.orientation,
                transform   = result.transform,
            }
        end
        request.copyimage = function(t)
            if found then
                found = false
                return inject(t)
            end
        end
    end
    return checkers.generic(data)
end

local function jp2_checker(data) -- idem as jpg
    local request = data.request
    local used    = data.used
    if request and used and not request.scanimage then
        local identify = graphics.identify
        local inject   = lpdf.injectors.jp2
        local found    = false
        request.scanimage = function(t)
            local result = wrappedidentify(identify,t.filename)
            found = not result.error
            return {
                filename    = result.filename,
                width       = result.width,
                height      = result.height,
                depth       = result.depth,
                colordepth  = result.colordepth,
                xres        = result.xres,
                yres        = result.yres,
                xsize       = result.xsize,
                ysize       = result.ysize,
                rotation    = result.rotation,
                colorspace  = result.colorspace,
                orientation = result.orientation,
                transform   = result.transform,
            }
        end
        request.copyimage = function(t)
            if found then
                found = false
                return inject(t)
            end
        end
    end
    return checkers.generic(data)
end

local function png_checker(data) -- same as jpg (for now)
    local request = data.request
    local used    = data.used
    if request and used and not request.scanimage then
        local identify = graphics.identify
        local inject   = lpdf.injectors.png
        local found    = false
        request.scanimage = function(t)
            local result = wrappedidentify(identify,t.filename)
            found = not result.error
            return {
                filename    = result.filename,
                width       = result.width,
                height      = result.height,
                depth       = result.depth,
                colordepth  = result.colordepth,
                xres        = result.xres,
                yres        = result.yres,
                xsize       = result.xsize,
                ysize       = result.ysize,
                rotation    = result.rotation,
                colorspace  = result.colorspace,
                tables      = result.tables,
                interlace   = result.interlace,
                filter      = result.filter,
                orientation = result.orientation,
                transform   = result.transform,
            }
        end
        request.copyimage = function(t)
            t.colorref = used.colorref -- this is a bit of a hack
            if found then
                found = false
                local ok, result = pcall(inject,t)
                if ok then
                    return result
                else
                    report_inclusion("bad bitmap image")
                    return placeholder()
                end
            end
        end
    end
    return checkers.generic(data)
end


if CONTEXTLMTXMODE then

    checkers.pdf = pdf_checker
    checkers.jpg = jpg_checker
    checkers.jp2 = jp2_checker
    checkers.png = png_checker

else

    -- yes or no ...

    directives.register("graphics.pdf.uselua",function(v)
        checkers.pdf = v and pdf_checker or nil
        report("%s Lua based PDF inclusion",v and "enabling" or "disabling")
    end)

 -- directives.register("graphics.uselua",function(v)
 --     checkers.pdf = v and pdf_checker or nil
 --     checkers.jpg = v and jpg_checker or nil
 --     checkers.jp2 = v and jp2_checker or nil
 --     checkers.png = v and png_checker or nil
 --  -- report("%s Lua based PDF, PNG, JPG and JP2 inclusion",v and "enabling" or "disabling")
 -- end)

end