1if not modules then modules = { } end modules ['lpdf-grp'] = {
2 version = 1.001,
3 comment = "companion to lpdf-ini.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9local type, tonumber = type, tonumber
10local formatters, gsub = string.formatters, string.gsub
11local concat, sort = table.concat, table.sort
12local round = math.round
13
14local colors = attributes.colors
15local basepoints = number.dimenfactors.bp
16
17local pdfbackend = backends.registered.pdf
18local nodeinjections = pdfbackend.nodeinjections
19local codeinjections = pdfbackend.codeinjections
20local registrations = pdfbackend.registrations
21
22local lpdf = lpdf
23local pdfdictionary = lpdf.dictionary
24local pdfarray = lpdf.array
25local pdfconstant = lpdf.constant
26local pdfboolean = lpdf.boolean
27local pdfreference = lpdf.reference
28local pdfflushobject = lpdf.flushobject
29
30local createimage = images.create
31local wrapimage = images.wrap
32local embedimage = images.embed
33
34
35
36
37
38
39
40local function shade(stype,name,domain,color_a,color_b,n,colorspace,coordinates,separation,steps,fractions)
41 local func = nil
42
43
44
45
46 domain = pdfarray(domain)
47 n = tonumber(n)
48
49 if steps then
50 local list = pdfarray()
51 local bounds = pdfarray()
52 local encode = pdfarray()
53
54
55 local tmp = { }
56 for i=1,steps do
57 tmp[i] = { fractions[i], color_a[i], color_b[i] }
58 end
59 sort(tmp, function(a,b)
60 return a[1] < b[1]
61 end)
62 for i=1,steps do
63 local t = tmp[i]
64 fractions[i] = t[1]
65 color_a [i] = t[2]
66 color_b [i] = t[3]
67 end
68
69 for i=1,steps do
70 if i < steps then
71 bounds[i] = fractions[i] or 1
72 end
73 encode[2*i-1] = 0
74 encode[2*i] = 1
75 list [i] = pdfdictionary {
76 FunctionType = 2,
77 Domain = domain,
78 C0 = pdfarray(color_a[i]),
79 C1 = pdfarray(color_b[i]),
80 N = n,
81 }
82 end
83 func = pdfdictionary {
84 FunctionType = 3,
85 Bounds = bounds,
86 Encode = encode,
87 Functions = list,
88 Domain = domain,
89 }
90 else
91 func = pdfdictionary {
92 FunctionType = 2,
93 Domain = domain,
94 C0 = pdfarray(color_a),
95 C1 = pdfarray(color_b),
96 N = n,
97 }
98 end
99 separation = separation and registrations.getspotcolorreference(separation)
100 local s = pdfdictionary {
101 ShadingType = stype,
102 ColorSpace = separation and pdfreference(separation) or pdfconstant(colorspace),
103 Domain = domain,
104 Function = pdfreference(pdfflushobject(func)),
105 Coords = pdfarray(coordinates),
106 Extend = pdfarray { true, true },
107 AntiAlias = pdfboolean(true),
108 }
109 lpdf.adddocumentshade(name,pdfreference(pdfflushobject(s)))
110end
111
112function lpdf.circularshade(name,domain,color_a,color_b,n,colorspace,coordinates,separation,steps,fractions)
113 shade(3,name,domain,color_a,color_b,n,colorspace,coordinates,separation,steps,fractions)
114end
115
116function lpdf.linearshade(name,domain,color_a,color_b,n,colorspace,coordinates,separation,steps,fractions)
117 shade(2,name,domain,color_a,color_b,n,colorspace,coordinates,separation,steps,fractions)
118end
119
120
121
122
123
124
125
126
127
128do
129
130 local template = "q BI %s ID %s > EI Q"
131 local factor = 72/300
132
133 local methods = { }
134
135 methods.hex = function(t)
136
137 local xresolution, yresolution = t.xresolution or 0, t.yresolution or 0
138 if xresolution == 0 or yresolution == 0 then
139 return
140 end
141 local colorspace = t.colorspace
142 if colorspace ~= "rgb" and colorspace ~= "cmyk" and colorspace ~= "gray" then
143
144 local d = gsub(t.data,"[^0-9a-f]","")
145 local b = round(#d / (xresolution * yresolution))
146 if b == 2 then
147 colorspace = "gray"
148 elseif b == 6 then
149 colorspace = "rgb"
150 elseif b == 8 then
151 colorspace = "cmyk"
152 end
153 end
154 colorspace = lpdf.colorspaceconstants[colorspace]
155 if not colorspace then
156 return
157 end
158
159 local d = pdfdictionary {
160 W = xresolution,
161 H = yresolution,
162 CS = colorspace,
163 BPC = 8,
164 F = pdfconstant("AHx"),
165
166
167
168 }
169
170 local urx, ury = 1/basepoints, 1/basepoints
171
172
173 local width, height = t.width or 0, t.height or 0
174 if width == 0 and height == 0 then
175 width = factor * xresolution / basepoints
176 height = factor * yresolution / basepoints
177 elseif width == 0 then
178 width = height * xresolution / yresolution
179 elseif height == 0 then
180 height = width * yresolution / xresolution
181 end
182 local a = pdfdictionary {
183 BBox = pdfarray { 0, 0, round(urx * basepoints), round(ury * basepoints) }
184 }
185 local image = createimage {
186 stream = formatters[template](d(),t.data),
187 width = width,
188 height = height,
189 bbox = { 0, 0, round(urx), round(ury) },
190 attr = a(),
191 nobbox = true,
192 }
193 return wrapimage(image)
194 end
195
196
197
198
199 local zlibcompress = xzip.compress
200 local hextocharacters = string.hextocharacters
201 local compresslevel = 3
202
203 methods.png = function(t)
204
205 local xresolution = t.xresolution or 0
206 local yresolution = t.yresolution or 0
207 local data = t.data or ""
208 if xresolution == 0 or yresolution == 0 or data == "" then
209 return
210 end
211 data = hextocharacters(data)
212 if not data then
213 return
214 end
215 local colorspace = t.colorspace
216 local colordepth = 8
217 local colors = 1
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232 if colorspace ~= "rgb" and colorspace ~= "gray" then
233 local b = round(#data / (xresolution * yresolution))
234 if b == 1 then
235 colorspace = "gray"
236 colors = 1
237 elseif b == 3 then
238 colorspace = "rgb"
239 colors = 3
240 elseif b == 4 then
241 return
242 end
243 end
244 colorspace = lpdf.colorspaceconstants[colorspace]
245 if not colorspace then
246 return
247 end
248 local width = t.width
249 local height = t.height
250 if width == 0 and height == 0 then
251 width = factor * xresolution / basepoints
252 height = factor * yresolution / basepoints
253 elseif width == 0 then
254 width = height * xresolution / yresolution
255 elseif height == 0 then
256 height = width * yresolution / xresolution
257 end
258
259 data = zlibcompress(data,compresslevel)
260 local xobject = pdfdictionary {
261 Type = pdfconstant("XObject"),
262 Subtype = pdfconstant("Image"),
263 Width = xresolution,
264 Height = yresolution,
265 BitsPerComponent = 8,
266 ColorSpace = colorspace,
267 Length = #data,
268 Filter = pdfconstant("FlateDecode"),
269 }
270 local image = createimage {
271
272 bbox = { 0, 0, round(width), round(height) },
273 width = round(width),
274 height = round(height),
275 nolength = true,
276 nobbox = true,
277 notype = true,
278 stream = data,
279 attr = xobject(),
280 }
281 return wrapimage(image)
282 end
283
284 function nodeinjections.injectbitmap(t)
285 if t.colorspace == "cmyk" then
286 return methods.hex(t)
287 else
288 return (methods[t.format or "hex"] or methods.hex)(t)
289 end
290 end
291
292end
293
294function codeinjections.setfigurealternative(data,figure)
295 local request = data.request
296 local display = request.display
297 if display and display ~= "" then
298 local nested = figures.push {
299 name = display,
300 page = request.page,
301 size = request.size,
302 prefix = request.prefix,
303 cache = request.cache,
304 width = request.width,
305 height = request.height,
306 }
307 figures.identify()
308 local displayfigure = figures.check()
309 if displayfigure then
310
311 embedimage(figure)
312 local a = pdfarray {
313 pdfdictionary {
314 Image = pdfreference(figure.objnum),
315 DefaultForPrinting = true,
316 }
317 }
318 local d = pdfdictionary {
319 Alternates = pdfreference(pdfflushobject(a)),
320 }
321 displayfigure.attr = d()
322 figures.pop()
323 return displayfigure, nested
324 else
325 figures.pop()
326 end
327 end
328end
329
330function codeinjections.getpreviewfigure(request)
331 local figure = figures.initialize(request)
332 if not figure then
333 return
334 end
335 figure = figures.identify(figure)
336 if not (figure and figure.status and figure.status.fullname) then
337 return
338 end
339 figure = figures.check(figure)
340 if not (figure and figure.status and figure.status.fullname) then
341 return
342 end
343 local image = figure.status.private
344 if image then
345 embedimage(image)
346 end
347 return figure
348end
349
350local masks = {
351 demomask = {
352 { 0, 63, 0 },
353 { 64, 127, 127 },
354 { 128, 195, 195 },
355 { 196, 255, 255 },
356 }
357}
358
359local ranges = {
360
361
362
363}
364
365function codeinjections.registerfiguremask(name,specification)
366 masks[name] = specification
367end
368
369function codeinjections.registerfigurerange(name,specification)
370 ranges[name] = specification
371end
372
373function codeinjections.setfiguremask(data,figure)
374 local request = data.request
375 local mask = request.mask
376 local range = request.range
377 if mask and mask ~= "" then
378 local m = masks[mask]
379 if m then
380 if type(m) == "function" then
381 m = m()
382 end
383 figure.newmask = m
384 else
385 figures.push {
386 name = mask,
387 page = request.page,
388 size = request.size,
389 prefix = request.prefix,
390 cache = request.cache,
391 width = request.width,
392 height = request.height,
393 }
394 mask = figures.identify()
395 mask = figures.check(mask)
396 if mask then
397 local image = mask.status.private
398 if image then
399 figures.include(mask)
400 embedimage(image)
401 local d = pdfdictionary {
402 Interpolate = false,
403 SMask = pdfreference(mask.status.objectnumber),
404 }
405 figure.attr = d()
406 end
407 end
408 figures.pop()
409 end
410 end
411 if range and range ~= "" then
412 local r = ranges[range]
413 if not r then
414 r = tonumber(range)
415 end
416 if type(r) == "function" then
417 r = r()
418 end
419 figure.newranges = r
420 end
421end
422
423
424
425local saveboxresource = tex.boxresources.save
426local nofpatterns = 0
427local f_pattern = formatters["q /Pattern cs /%s scn 0 0 %.6N %.6N re f Q"]
428
429function lpdf.registerpattern(specification)
430 nofpatterns = nofpatterns + 1
431 local d = pdfdictionary {
432 Type = pdfconstant("Pattern"),
433 PatternType = 1,
434 PaintType = 1,
435 TilingType = 2,
436 XStep = (specification.width or 10) * basepoints,
437 YStep = (specification.height or 10) * basepoints,
438 Matrix = {
439 1, 0, 0, 1,
440 (specification.hoffset or 0) * basepoints,
441 (specification.voffset or 0) * basepoints,
442 },
443 }
444
445
446 local resources = lpdf.collectedresources{ patterns = false, serialize = false }
447 local attributes = d
448 local onlybounds = 1
449 local patternobj = saveboxresource(specification.number,attributes,resources,true,onlybounds)
450 lpdf.adddocumentpattern("Pt" .. nofpatterns,lpdf.reference(patternobj ))
451 return nofpatterns
452end
453
454function lpdf.patternstream(n,width,height)
455 return f_pattern("Pt" .. n,width*basepoints,height*basepoints)
456end
457
458codeinjections.registerpattern = lpdf.registerpattern
459 |