lpdf-img.lua /size: 48 Kb    last modification: 2020-07-01 14:35
1
if
not
modules
then
modules
=
{
}
end
modules
[
'
lpdf-img
'
]
=
{
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 9
-- This started as an experiment but has potential for some (cached) optimizations.
10
-- At some point we can also use it for fonts. For small images performance is ok
11
-- with pure lua but for bigger images we can use some helpers. Normally in a
12
-- typesetting workflow non-interlaced images are used. One should convert
13
-- interlaced images to more efficient non-interlaced ones (ok, we can cache
14
-- them if needed).
15
--
16
-- The \LUA\ code is slightly optimized so we could have done with less lines if
17
-- we wanted but best gain a little. The idea is that we collect striped (in stages)
18
-- so that we can play with substitutions.
19 20
local
type
=
type
21
local
concat
,
move
=
table
.
concat
,
table
.
move
22
local
ceil
,
min
=
math
.
ceil
,
math
.
min
23
local
char
,
byte
,
find
,
gmatch
=
string
.
char
,
string
.
byte
,
string
.
find
,
string
.
gmatch
24
local
idiv
=
number
.
idiv
25
local
band
,
rshift
=
bit32
.
band
,
bit32
.
rshift
26 27
local
loaddata
=
io
.
loaddata
28
local
setmetatableindex
=
table
.
setmetatableindex
29
local
formatters
=
string
.
formatters
30 31
local
streams
=
utilities
.
streams
32
local
openstring
=
streams
.
openstring
33
local
readstring
=
streams
.
readstring
34
local
readbytetable
=
streams
.
readbytetable
35 36
local
newreader
=
io
.
newreader
37 38
local
tobytetable
=
string
.
bytetable
39 40
local
lpdf
=
lpdf
or
{
}
41
local
pdfdictionary
=
lpdf
.
dictionary
42
local
pdfarray
=
lpdf
.
array
43
local
pdfconstant
=
lpdf
.
constant
44
local
pdfstring
=
lpdf
.
string
45
local
pdfflushstreamobject
=
lpdf
.
flushstreamobject
46
local
pdfreference
=
lpdf
.
reference
47
local
pdfverbose
=
lpdf
.
verbose
48 49
local
pdfmajorversion
=
lpdf
.
majorversion
50
local
pdfminorversion
=
lpdf
.
minorversion
51 52
local
createimage
=
images
.
create
53 54
local
zlibcompress
=
(
xzip
or
zlib
)
.
compress
55
local
zlibdecompress
=
(
xzip
or
zlib
)
.
decompress
56 57
local
trace
=
false
58 59
local
report_jpg
=
logs
.
reporter
(
"
graphics
"
,
"
jpg
"
)
60
local
report_jp2
=
logs
.
reporter
(
"
graphics
"
,
"
jp2
"
)
61
local
report_png
=
logs
.
reporter
(
"
graphics
"
,
"
png
"
)
62 63
trackers
.
register
(
"
graphics.backend
"
,
function
(
v
)
trace
=
v
end
)
64 65
local
injectors
=
{
}
66
lpdf
.
injectors
=
injectors
67 68
-- todo: load from a virtual file
69 70
local
function
loadcontent
(
filename
,
method
)
71
return
method
=
=
"
string
"
and
filename
or
loaddata
(
filename
)
72
end
73 74
local
function
newcontent
(
filename
,
method
)
75
return
newreader
(
filename
,
method
)
76
end
77 78
--
79 80
local
chars
=
setmetatableindex
(
function
(
t
,
k
)
-- share this one
81
local
v
=
(
k
<
=
0
and
"
\000
"
)
or
(
k
>
=
255
and
"
\255
"
)
or
char
(
k
)
82
t
[
k
]
=
v
83
return
v
84
end
)
85 86
do
87 88
function
injectors
.
jpg
(
specification
,
method
)
89
if
specification
.
error
then
90
return
91
end
92
local
filename
=
specification
.
filename
93
if
not
filename
then
94
return
95
end
96
local
colorspace
=
specification
.
colorspace
or
jpg_gray
97
local
decodearray
=
nil
98
----- procset = colorspace == 0 and "image b" or "image c"
99
if
colorspace
=
=
1
then
100
colorspace
=
"
DeviceGray
"
101
elseif
colorspace
=
=
2
then
102
colorspace
=
"
DeviceRGB
"
103
elseif
colorspace
=
=
3
then
104
colorspace
=
"
DeviceCMYK
"
105
decodearray
=
pdfarray
{
1
,
0
,
1
,
0
,
1
,
0
,
1
,
0
}
106
end
107
-- todo: set filename
108
local
xsize
=
specification
.
xsize
109
local
ysize
=
specification
.
ysize
110
local
colordepth
=
specification
.
colordepth
111
local
content
=
loadcontent
(
filename
,
method
)
112
local
xobject
=
pdfdictionary
{
113
Type
=
pdfconstant
(
"
XObject
"
)
,
114
Subtype
=
pdfconstant
(
"
Image
"
)
,
115
-- BBox = pdfarray { 0, 0, xsize, ysize },
116
Width
=
xsize
,
117
Height
=
ysize
,
118
BitsPerComponent
=
colordepth
,
119
Filter
=
pdfconstant
(
"
DCTDecode
"
)
,
120
ColorSpace
=
pdfconstant
(
colorspace
)
,
121
Decode
=
decodearray
,
122
Length
=
#
content
,
-- specification.length
123
}
+
specification
.
attr
124
if
trace
then
125
report_jpg
(
"
%s: width %i, height %i, colordepth %i, size %i
"
,
filename
,
xsize
,
ysize
,
colordepth
,
#
content
)
126
end
127
return
createimage
{
128
bbox
=
{
0
,
0
,
specification
.
width
/
xsize
,
specification
.
height
/
ysize
}
,
-- mandate
129
transform
=
specification
.
transform
,
130
nolength
=
true
,
131
nobbox
=
true
,
132
notype
=
true
,
133
stream
=
content
,
134
attr
=
xobject
(
)
,
135
}
136
end
137 138
end
139 140
do
141 142
function
injectors
.
jp2
(
specification
,
method
)
143
if
specification
.
error
then
144
return
145
end
146
local
filename
=
specification
.
filename
147
if
not
filename
then
148
return
149
end
150
-- todo: set filename
151
local
xsize
=
specification
.
xsize
152
local
ysize
=
specification
.
ysize
153
local
content
=
loadcontent
(
filename
,
method
)
154
local
xobject
=
pdfdictionary
{
155
Type
=
pdfconstant
(
"
XObject
"
)
,
156
Subtype
=
pdfconstant
(
"
Image
"
)
,
157
BBox
=
pdfarray
{
0
,
0
,
xsize
,
ysize
}
,
158
Width
=
xsize
,
159
Height
=
ysize
,
160
Filter
=
pdfconstant
(
"
JPXDecode
"
)
,
161
Length
=
#
content
,
-- specification.length
162
}
+
specification
.
attr
163
if
trace
then
164
report_jp2
(
"
%s: width %i, height %i, size %i
"
,
filename
,
xsize
,
ysize
,
#
content
)
165
end
166
return
createimage
{
167
bbox
=
{
0
,
0
,
specification
.
width
/
xsize
,
specification
.
height
/
ysize
}
,
-- mandate
168
transform
=
specification
.
transform
,
169
nolength
=
true
,
170
nobbox
=
true
,
171
notype
=
true
,
172
stream
=
content
,
173
attr
=
xobject
(
)
,
174
}
175
end
176 177
end
178 179
do
180 181
-- We don't like interlaced files. You can deinterlace them beforehand because otherwise
182
-- each run you add runtime. Actually, even masked images can best be converted to PDF
183
-- beforehand.
184 185
-- The amount of code is larger that I like and looks somewhat redundant but we sort of
186
-- optimize a few combinations that happen often.
187 188
local
pngapplyfilter
=
pngdecode
.
applyfilter
189
local
pngsplitmask
=
pngdecode
.
splitmask
190
local
pnginterlace
=
pngdecode
.
interlace
191
local
pngexpand
=
pngdecode
.
expand
192
local
pngtocmyk
=
pngdecode
.
tocmyk
193 194
local
filtermask
,
decodemask
,
decodestrip
,
transpose
,
expand
,
tocmyk
195 196
local
newindex
=
lua
.
newindex
197
local
newtable
=
lua
.
newtable
198 199
local
function
newoutput
(
size
)
200
if
newindex
then
201
return
newindex
(
size
,
0
)
202
end
203
local
t
=
newtable
and
newtable
(
size
,
0
)
or
{
}
204
for
i
=
1
,
size
do
205
t
[
i
]
=
0
206
end
207
return
t
208
end
209 210
local
function
convert
(
t
)
211
if
type
(
t
)
=
=
"
table
"
then
212
for
i
=
1
,
#
t
do
213
local
ti
=
t
[
i
]
214
if
ti
~
=
"
"
then
-- soon gone
215
t
[
i
]
=
chars
[
ti
]
216
end
217
end
218
return
concat
(
t
)
219
else
220
return
t
221
end
222
end
223 224
local
function
zero
(
t
,
k
)
225
return
0
226
end
227 228
local
function
applyfilter
(
t
,
xsize
,
ysize
,
bpp
)
229
local
len
=
xsize
*
bpp
+
1
230
local
n
=
1
231
local
m
=
len
-
1
232
for
i
=
1
,
ysize
do
233
local
filter
=
t
[
n
]
234
t
[
n
]
=
"
"
235
if
filter
=
=
0
then
236
elseif
filter
=
=
1
then
237
for
j
=
n
+
bpp
+
1
,
n
+
m
do
238
t
[
j
]
=
(
t
[
j
]
+
t
[
j
-
bpp
]
)
%
256
239
end
240
elseif
filter
=
=
2
then
241
for
j
=
n
+
1
,
n
+
m
do
242
t
[
j
]
=
(
t
[
j
]
+
t
[
j
-
len
]
)
%
256
243
end
244
elseif
filter
=
=
3
then
245
for
j
=
n
+
1
,
n
+
bpp
do
246
t
[
j
]
=
(
t
[
j
]
+
idiv
(
t
[
j
-
len
]
,
2
)
)
%
256
247
end
248
for
j
=
n
+
bpp
+
1
,
n
+
m
do
249
t
[
j
]
=
(
t
[
j
]
+
idiv
(
t
[
j
-
bpp
]
+
t
[
j
-
len
]
,
2
)
)
%
256
250
end
251
elseif
filter
=
=
4
then
252
for
j
=
n
+
1
,
n
+
bpp
do
253
local
p
=
j
-
len
254
local
b
=
t
[
p
]
255
if
b
>
0
then
256
t
[
j
]
=
(
t
[
j
]
+
b
)
%
256
257
end
258
end
259
for
j
=
n
+
bpp
+
1
,
n
+
m
do
260
local
p
=
j
-
len
261
local
a
=
t
[
j
-
bpp
]
262
local
b
=
t
[
p
]
263
local
c
=
t
[
p
-
bpp
]
264
local
pa
=
b
-
c
265
local
pb
=
a
-
c
266
local
pc
=
pa
+
pb
267
if
pa
<
0
then
pa
=
-
pa
end
268
if
pb
<
0
then
pb
=
-
pb
end
269
if
pc
<
0
then
pc
=
-
pc
end
270
t
[
j
]
=
(
t
[
j
]
+
(
(
pa
<
=
pb
and
pa
<
=
pc
and
a
)
or
(
pb
<
=
pc
and
b
)
or
c
)
)
%
256
271
end
272
end
273
n
=
n
+
len
274
end
275
return
t
276
end
277 278
local
filtermask_l
=
function
(
content
,
xsize
,
ysize
,
colordepth
,
colorspace
,
hasfilter
)
279
local
mask
=
{
}
280
local
bytes
=
colordepth
=
=
16
and
2
or
1
281
local
bpp
=
colorspace
=
=
"
DeviceRGB
"
and
3
or
1
282
local
length
=
#
content
283
local
size
=
ysize
*
xsize
*
(
(
bpp
+
1
)
*
bytes
+
(
hasfilter
and
1
or
0
)
)
284
local
n
=
1
285
local
l
=
1
286
if
bytes
=
=
2
then
287
if
bpp
=
=
1
then
288
for
i
=
1
,
ysize
do
289
if
hasfilter
then
290
content
[
n
]
=
"
"
;
n
=
n
+
1
291
end
292
for
j
=
1
,
xsize
do
293
content
[
n
]
=
chars
[
content
[
n
]
]
;
n
=
n
+
1
294
content
[
n
]
=
chars
[
content
[
n
]
]
;
n
=
n
+
1
295
mask
[
l
]
=
chars
[
content
[
n
]
]
;
l
=
l
+
1
296
content
[
n
]
=
"
"
;
n
=
n
+
1
297
mask
[
l
]
=
chars
[
content
[
n
]
]
;
l
=
l
+
1
298
content
[
n
]
=
"
"
;
n
=
n
+
1
299
end
300
end
301
elseif
bpp
=
=
3
then
302
for
i
=
1
,
ysize
do
303
if
hasfilter
then
304
content
[
n
]
=
"
"
;
n
=
n
+
1
305
end
306
for
j
=
1
,
xsize
do
307
content
[
n
]
=
chars
[
content
[
n
]
]
;
n
=
n
+
1
308
content
[
n
]
=
chars
[
content
[
n
]
]
;
n
=
n
+
1
309
content
[
n
]
=
chars
[
content
[
n
]
]
;
n
=
n
+
1
310
content
[
n
]
=
chars
[
content
[
n
]
]
;
n
=
n
+
1
311
content
[
n
]
=
chars
[
content
[
n
]
]
;
n
=
n
+
1
312
content
[
n
]
=
chars
[
content
[
n
]
]
;
n
=
n
+
1
313
mask
[
l
]
=
chars
[
content
[
n
]
]
;
l
=
l
+
1
314
content
[
n
]
=
"
"
;
n
=
n
+
1
315
mask
[
l
]
=
chars
[
content
[
n
]
]
;
l
=
l
+
1
316
content
[
n
]
=
"
"
;
n
=
n
+
1
317
end
318
end
319
else
320
return
"
"
,
"
"
321
end
322
else
323
if
bpp
=
=
1
then
324
for
i
=
1
,
ysize
do
325
if
hasfilter
then
326
content
[
n
]
=
"
"
;
n
=
n
+
1
327
end
328
for
j
=
1
,
xsize
do
329
content
[
n
]
=
chars
[
content
[
n
]
]
;
n
=
n
+
1
330
mask
[
l
]
=
chars
[
content
[
n
]
]
;
l
=
l
+
1
331
content
[
n
]
=
"
"
;
n
=
n
+
1
332
end
333
end
334
elseif
bpp
=
=
3
then
335
for
i
=
1
,
ysize
do
336
if
hasfilter
then
337
content
[
n
]
=
"
"
;
n
=
n
+
1
338
end
339
for
j
=
1
,
xsize
do
340
content
[
n
]
=
chars
[
content
[
n
]
]
;
n
=
n
+
1
341
content
[
n
]
=
chars
[
content
[
n
]
]
;
n
=
n
+
1
342
content
[
n
]
=
chars
[
content
[
n
]
]
;
n
=
n
+
1
343
mask
[
l
]
=
chars
[
content
[
n
]
]
;
l
=
l
+
1
344
content
[
n
]
=
"
"
;
n
=
n
+
1
345
end
346
end
347
else
348
return
"
"
,
"
"
349
end
350
end
351
return
concat
(
content
)
,
concat
(
mask
)
352
end
353 354
local
decodemask_l
=
function
(
content
,
xsize
,
ysize
,
colordepth
,
colorspace
)
355
local
bytes
=
colordepth
=
=
16
and
2
or
1
356
local
bpp
=
colorspace
=
=
"
DeviceRGB
"
and
3
or
1
357
local
slice
=
bytes
*
(
bpp
+
1
)
358
local
length
=
#
content
359
local
size
=
ysize
*
xsize
*
(
(
bpp
+
1
)
*
bytes
+
1
)
-- assume filter
360
content
=
openstring
(
content
)
361
content
=
readbytetable
(
content
,
length
)
362
setmetatableindex
(
content
,
zero
)
363
applyfilter
(
content
,
xsize
,
ysize
,
slice
)
364
content
,
mask
=
filtermask
(
content
,
xsize
,
ysize
,
colordepth
,
colorspace
,
true
)
365
return
content
,
mask
366
end
367 368
local
filtermask_c
=
function
(
content
,
xsize
,
ysize
,
colordepth
,
colorspace
)
369
local
bytes
=
colordepth
=
=
16
and
2
or
1
370
local
bpp
=
colorspace
=
=
"
DeviceRGB
"
and
3
or
1
371
return
pngsplitmask
(
content
,
xsize
,
ysize
,
bpp
,
bytes
)
372
end
373 374
local
decodemask_c
=
function
(
content
,
xsize
,
ysize
,
colordepth
,
colorspace
)
375
local
mask
=
true
376
local
filter
=
false
377
local
bytes
=
colordepth
=
=
16
and
2
or
1
378
local
bpp
=
colorspace
=
=
"
DeviceRGB
"
and
3
or
1
379
local
slice
=
bytes
*
(
bpp
+
1
)
-- always a mask
380
content
=
pngapplyfilter
(
content
,
xsize
,
ysize
,
slice
)
381
return
pngsplitmask
(
content
,
xsize
,
ysize
,
bpp
,
bytes
,
mask
,
filter
)
382
end
383 384
local
function
decodestrip_l
(
s
,
nx
,
ny
,
slice
)
385
local
input
=
readbytetable
(
s
,
ny
*
(
nx
*
slice
+
1
)
)
386
setmetatableindex
(
input
,
zero
)
387
applyfilter
(
input
,
nx
,
ny
,
slice
)
388
return
input
,
true
389
end
390 391
local
function
decodestrip_c
(
s
,
nx
,
ny
,
slice
)
392
local
input
=
readstring
(
s
,
ny
*
(
nx
*
slice
+
1
)
)
393
input
=
pngapplyfilter
(
input
,
nx
,
ny
,
slice
)
394
return
input
,
false
395
end
396 397
local
xstart
=
{
0
,
4
,
0
,
2
,
0
,
1
,
0
}
398
local
ystart
=
{
0
,
0
,
4
,
0
,
2
,
0
,
1
}
399
local
xstep
=
{
8
,
8
,
4
,
4
,
2
,
2
,
1
}
400
local
ystep
=
{
8
,
8
,
8
,
4
,
4
,
2
,
2
}
401 402
local
xblock
=
{
8
,
4
,
4
,
2
,
2
,
1
,
1
}
403
local
yblock
=
{
8
,
8
,
4
,
4
,
2
,
2
,
1
}
404 405
local
function
transpose_l
(
xsize
,
ysize
,
slice
,
pass
,
input
,
output
,
filter
)
406
local
xstart
=
xstart
[
pass
]
407
local
xstep
=
xstep
[
pass
]
408
local
ystart
=
ystart
[
pass
]
409
local
ystep
=
ystep
[
pass
]
410
local
nx
=
idiv
(
xsize
+
xstep
-
xstart
-
1
,
xstep
)
411
local
ny
=
idiv
(
ysize
+
ystep
-
ystart
-
1
,
ystep
)
412
local
offset
=
filter
and
1
or
0
413
local
xstep
=
xstep
*
slice
414
local
xstart
=
xstart
*
slice
415
local
xsize
=
xsize
*
slice
416
local
target
=
ystart
*
xsize
+
xstart
+
1
417
local
ystep
=
ystep
*
xsize
418
local
start
=
1
419
local
plus
=
nx
*
xstep
420
local
step
=
plus
-
xstep
421
if
not
output
then
422
output
=
newoutput
(
xsize
*
(
parts
or
slice
)
*
ysize
)
423
end
424
if
slice
=
=
1
then
425
for
j
=
0
,
ny
-1
do
426
start
=
start
+
offset
427
local
target
=
target
+
j
*
ystep
428
for
target
=
target
,
target
+
step
,
xstep
do
429
output
[
target
]
=
input
[
start
]
430
start
=
start
+
slice
431
end
432
end
433
elseif
slice
=
=
2
then
434
for
j
=
0
,
ny
-1
do
435
start
=
start
+
offset
436
local
target
=
target
+
j
*
ystep
437
for
target
=
target
,
target
+
step
,
xstep
do
438
output
[
target
]
=
input
[
start
]
439
output
[
target
+
1
]
=
input
[
start
+
1
]
440
start
=
start
+
slice
441
end
442
end
443
elseif
slice
=
=
3
then
444
for
j
=
0
,
ny
-1
do
445
start
=
start
+
offset
446
local
target
=
target
+
j
*
ystep
447
for
target
=
target
,
target
+
step
,
xstep
do
448
output
[
target
]
=
input
[
start
]
449
output
[
target
+
1
]
=
input
[
start
+
1
]
450
output
[
target
+
2
]
=
input
[
start
+
2
]
451
start
=
start
+
slice
452
end
453
end
454
elseif
slice
=
=
4
then
455
for
j
=
0
,
ny
-1
do
456
start
=
start
+
offset
457
local
target
=
target
+
j
*
ystep
458
for
target
=
target
,
target
+
step
,
xstep
do
459
output
[
target
]
=
input
[
start
]
460
output
[
target
+
1
]
=
input
[
start
+
1
]
461
output
[
target
+
2
]
=
input
[
start
+
2
]
462
output
[
target
+
3
]
=
input
[
start
+
3
]
463
start
=
start
+
slice
464
end
465
end
466
else
467
local
delta
=
slice
-
1
468
for
j
=
0
,
ny
-1
do
469
start
=
start
+
offset
470
local
target
=
target
+
j
*
ystep
471
for
target
=
target
,
target
+
step
,
xstep
do
472
move
(
input
,
start
,
start
+
delta
,
target
,
output
)
473
start
=
start
+
slice
474
end
475
end
476
end
477
return
output
;
478
end
479 480
local
transpose_c
=
pnginterlace
481 482
-- print(band(rshift(v,4),0x03),extract(v,4,2))
483
-- print(band(rshift(v,6),0x03),extract(v,6,2))
484 485
local
function
expand_l
(
t
,
xsize
,
ysize
,
parts
,
run
,
factor
,
filter
)
486
local
size
=
ysize
*
xsize
+
1
-- a bit of overshoot, needs testing, probably a few bytes us ok
487
local
xline
=
filter
and
(
run
+
1
)
or
run
488
local
f
=
filter
and
1
or
0
489
local
l
=
xline
-
1
490
local
n
=
1
491
local
o
=
newoutput
(
size
)
492
local
k
=
0
493
if
factor
then
494
if
parts
=
=
4
then
495
for
i
=
1
,
ysize
do
496
for
j
=
n
+
f
,
n
+
l
do
497
local
v
=
t
[
j
]
498
if
v
=
=
0
then
499
k
=
k
+
2
500
else
501
k
=
k
+
1
;
o
[
k
]
=
extract4
(
v
,
4
)
*
0x11
502
k
=
k
+
1
;
o
[
k
]
=
extract4
(
v
,
0
)
*
0x11
503
end
504
end
505
k
=
i
*
xsize
506
n
=
n
+
xline
507
end
508
elseif
parts
=
=
2
then
509
for
i
=
1
,
ysize
do
510
for
j
=
n
+
f
,
n
+
l
do
511
local
v
=
t
[
j
]
512
if
v
=
=
0
then
513
k
=
k
+
4
514
else
515
k
=
k
+
1
;
o
[
k
]
=
extract2
(
v
,
6
)
*
0x55
516
k
=
k
+
1
;
o
[
k
]
=
extract2
(
v
,
4
)
*
0x55
517
k
=
k
+
1
;
o
[
k
]
=
extract2
(
v
,
2
)
*
0x55
518
k
=
k
+
1
;
o
[
k
]
=
extract2
(
v
,
0
)
*
0x55
519
end
520
end
521
k
=
i
*
xsize
522
n
=
n
+
xline
523
end
524
else
525
for
i
=
1
,
ysize
do
526
for
j
=
n
+
f
,
n
+
l
do
527
local
v
=
t
[
j
]
528
if
v
=
=
0
then
529
k
=
k
+
8
530
else
531
k
=
k
+
1
;
if
band
(
v
,
0x80
)
~
=
0
then
o
[
k
]
=
0xFF
end
-- o[k] = extract1(v,7) * 0xFF
532
k
=
k
+
1
;
if
band
(
v
,
0x40
)
~
=
0
then
o
[
k
]
=
0xFF
end
-- o[k] = extract1(v,6) * 0xFF
533
k
=
k
+
1
;
if
band
(
v
,
0x20
)
~
=
0
then
o
[
k
]
=
0xFF
end
-- o[k] = extract1(v,5) * 0xFF
534
k
=
k
+
1
;
if
band
(
v
,
0x10
)
~
=
0
then
o
[
k
]
=
0xFF
end
-- o[k] = extract1(v,4) * 0xFF
535
k
=
k
+
1
;
if
band
(
v
,
0x08
)
~
=
0
then
o
[
k
]
=
0xFF
end
-- o[k] = extract1(v,3) * 0xFF
536
k
=
k
+
1
;
if
band
(
v
,
0x04
)
~
=
0
then
o
[
k
]
=
0xFF
end
-- o[k] = extract1(v,2) * 0xFF
537
k
=
k
+
1
;
if
band
(
v
,
0x02
)
~
=
0
then
o
[
k
]
=
0xFF
end
-- o[k] = extract1(v,1) * 0xFF
538
k
=
k
+
1
;
if
band
(
v
,
0x01
)
~
=
0
then
o
[
k
]
=
0xFF
end
-- o[k] = extract1(v,0) * 0xFF
539
end
540
end
541
k
=
i
*
xsize
542
n
=
n
+
xline
543
end
544
end
545
else
546
if
parts
=
=
4
then
547
for
i
=
1
,
ysize
do
548
for
j
=
n
+
f
,
n
+
l
do
549
local
v
=
t
[
j
]
550
if
v
=
=
0
then
551
k
=
k
+
2
552
else
553
k
=
k
+
1
;
o
[
k
]
=
extract4
(
v
,
4
)
554
k
=
k
+
1
;
o
[
k
]
=
extract4
(
v
,
0
)
555
end
556
end
557
k
=
i
*
xsize
558
n
=
n
+
xline
559
end
560
elseif
parts
=
=
2
then
561
for
i
=
1
,
ysize
do
562
for
j
=
n
+
f
,
n
+
l
do
563
local
v
=
t
[
j
]
564
if
v
=
=
0
then
565
k
=
k
+
4
566
else
567
k
=
k
+
1
;
o
[
k
]
=
extract2
(
v
,
6
)
568
k
=
k
+
1
;
o
[
k
]
=
extract2
(
v
,
4
)
569
k
=
k
+
1
;
o
[
k
]
=
extract2
(
v
,
2
)
570
k
=
k
+
1
;
o
[
k
]
=
extract2
(
v
,
0
)
571
end
572
end
573
k
=
i
*
xsize
574
n
=
n
+
xline
575
end
576
else
577
for
i
=
1
,
ysize
do
578
for
j
=
n
+
f
,
n
+
l
do
579
local
v
=
t
[
j
]
580
if
v
=
=
0
then
581
k
=
k
+
8
582
else
583
k
=
k
+
1
;
if
band
(
v
,
0x80
)
~
=
0
then
o
[
k
]
=
1
end
-- o[k] = extract1(v,7)
584
k
=
k
+
1
;
if
band
(
v
,
0x40
)
~
=
0
then
o
[
k
]
=
1
end
-- o[k] = extract1(v,6)
585
k
=
k
+
1
;
if
band
(
v
,
0x20
)
~
=
0
then
o
[
k
]
=
1
end
-- o[k] = extract1(v,5)
586
k
=
k
+
1
;
if
band
(
v
,
0x10
)
~
=
0
then
o
[
k
]
=
1
end
-- o[k] = extract1(v,4)
587
k
=
k
+
1
;
if
band
(
v
,
0x08
)
~
=
0
then
o
[
k
]
=
1
end
-- o[k] = extract1(v,3)
588
k
=
k
+
1
;
if
band
(
v
,
0x04
)
~
=
0
then
o
[
k
]
=
1
end
-- o[k] = extract1(v,2)
589
k
=
k
+
1
;
if
band
(
v
,
0x02
)
~
=
0
then
o
[
k
]
=
1
end
-- o[k] = extract1(v,1)
590
k
=
k
+
1
;
if
band
(
v
,
0x01
)
~
=
0
then
o
[
k
]
=
1
end
-- o[k] = extract1(v,0)
591
end
592
end
593
k
=
i
*
xsize
594
n
=
n
+
xline
595
end
596
end
597
end
598
for
i
=
size
,
xsize
*
ysize
+
1
,
-1
do
599
o
[
i
]
=
nil
600
end
601
return
o
,
false
602
end
603 604
local
expand_c
=
pngexpand
605 606
local
function
analyze
(
colordepth
,
colorspace
,
palette
,
mask
)
607
-- return bytes, parts, factor
608
if
palette
then
609
if
colordepth
=
=
16
then
610
return
2
,
false
,
false
611
elseif
colordepth
=
=
8
then
612
return
1
,
false
,
false
613
elseif
colordepth
=
=
4
then
614
return
1
,
4
,
false
615
elseif
colordepth
=
=
2
then
616
return
1
,
2
,
false
617
elseif
colordepth
=
=
1
then
618
return
1
,
1
,
false
619
end
620
elseif
colorspace
=
=
"
DeviceGray
"
then
621
if
colordepth
=
=
16
then
622
return
mask
and
4
or
2
,
false
,
false
623
elseif
colordepth
=
=
8
then
624
return
mask
and
2
or
1
,
false
,
false
625
elseif
colordepth
=
=
4
then
626
return
1
,
4
,
true
627
elseif
colordepth
=
=
2
then
628
return
1
,
2
,
true
629
elseif
colordepth
=
=
1
then
630
return
1
,
1
,
true
631
end
632
else
633
if
colordepth
=
=
16
then
634
return
mask
and
8
or
6
,
false
,
false
635
elseif
colordepth
=
=
8
then
636
return
mask
and
4
or
3
,
false
,
false
637
elseif
colordepth
=
=
4
then
638
return
3
,
4
,
true
639
elseif
colordepth
=
=
2
then
640
return
3
,
2
,
true
641
elseif
colordepth
=
=
1
then
642
return
3
,
1
,
true
643
end
644
end
645
return
false
,
false
,
false
646
end
647 648
-- 1 6 4 6 2 6 4 6
649
-- 7 7 7 7 7 7 7 7
650
-- 5 6 5 6 5 6 5 6
651
-- 7 7 7 7 7 7 7 7
652
-- 3 6 4 6 3 6 4 6
653
-- 7 7 7 7 7 7 7 7
654
-- 5 6 5 6 5 6 5 6
655
-- 7 7 7 7 7 7 7 7
656 657
local
function
deinterlace
(
content
,
xsize
,
ysize
,
colordepth
,
colorspace
,
palette
,
mask
)
658
local
slice
,
parts
,
factor
=
analyze
(
colordepth
,
colorspace
,
palette
,
mask
)
659
if
slice
then
660
content
=
openstring
(
zlibdecompress
(
content
)
)
661
local
filter
=
false
662
local
output
=
false
663
for
pass
=
1
,
7
do
664
local
xstart
=
xstart
[
pass
]
665
local
xstep
=
xstep
[
pass
]
666
local
ystart
=
ystart
[
pass
]
667
local
ystep
=
ystep
[
pass
]
668
local
nx
=
idiv
(
xsize
+
xstep
-
xstart
-
1
,
xstep
)
669
local
ny
=
idiv
(
ysize
+
ystep
-
ystart
-
1
,
ystep
)
670
if
nx
>
0
and
ny
>
0
then
671
local
input
,
filter
672
if
parts
then
673
local
nxx
=
ceil
(
nx
*
parts
/
8
)
674
input
,
filter
=
decodestrip
(
content
,
nxx
,
ny
,
slice
)
675
input
,
filter
=
expand
(
input
,
nx
,
ny
,
parts
,
nxx
,
factor
,
filter
)
676
else
677
input
,
filter
=
decodestrip
(
content
,
nx
,
ny
,
slice
)
678
end
679
output
=
transpose
(
xsize
,
ysize
,
slice
,
pass
,
input
,
output
,
filter
)
680
end
681
-- if pass == 3 then
682
-- break -- still looks ok, could be nice for a preroll
683
-- end
684
end
685
return
output
,
parts
and
8
or
false
686
end
687
end
688 689
-- 1 (palette used), 2 (color used), and 4 (alpha channel used)
690 691
-- paeth:
692
--
693
-- p = a + b - c
694
-- pa = abs(p - a) => a + b - c - a => b - c
695
-- pb = abs(p - b) => a + b - c - b => a - c
696
-- pc = abs(p - c) => a + b - c - c => a + b - c - c => a - c + b - c => pa + pb
697 698
local
function
full
(
t
,
k
)
local
v
=
"
\xFF
"
t
[
k
]
=
v
return
v
end
699 700
local
function
expandvector
(
transparent
)
701
local
s
=
openstring
(
transparent
)
702
local
n
=
#
transparent
703
local
r
=
{
}
704
for
i
=
0
,
n
-1
do
705
r
[
i
]
=
readstring
(
s
,
1
)
-- readchar
706
end
707
setmetatableindex
(
r
,
full
)
708
return
r
709
end
710 711
local
function
createmask_l
(
content
,
palette
,
transparent
,
xsize
,
ysize
,
colordepth
,
colorspace
)
712
if
palette
then
713
local
r
=
expandvector
(
transparent
)
714
local
size
=
xsize
*
ysize
715
local
len
=
ceil
(
xsize
*
colordepth
/
8
)
+
1
716
local
o
=
newoutput
(
xsize
*
ysize
)
717
local
u
=
setmetatableindex
(
zero
)
718
content
=
zlibdecompress
(
content
)
719
content
=
openstring
(
content
)
720
for
i
=
0
,
ysize
-1
do
721
local
t
=
readbytetable
(
content
,
len
)
722
local
k
=
i
*
xsize
723
local
filter
=
t
[
1
]
724
if
filter
=
=
0
then
725
elseif
filter
=
=
1
then
726
for
j
=
3
,
len
do
727
t
[
j
]
=
(
t
[
j
]
+
t
[
j
-1
]
)
%
256
728
end
729
elseif
filter
=
=
2
then
730
for
j
=
2
,
len
do
731
t
[
j
]
=
(
t
[
j
]
+
u
[
j
]
)
%
256
732
end
733
elseif
filter
=
=
3
then
734
local
j
=
2
735
t
[
j
]
=
(
t
[
j
]
+
idiv
(
u
[
j
]
,
2
)
)
%
256
736
for
j
=
3
,
len
do
737
t
[
j
]
=
(
t
[
j
]
+
idiv
(
t
[
j
-1
]
+
u
[
j
]
,
2
)
)
%
256
738
end
739
elseif
filter
=
=
4
then
740
local
j
=
2
741
local
p
=
j
-
len
742
local
b
=
t
[
p
]
743
if
b
<
0
then
744
b
=
-
b
745
end
746
if
b
>
0
then
747
t
[
j
]
=
(
t
[
j
]
+
b
)
%
256
748
end
749
for
j
=
3
,
len
do
750
local
p
=
j
-
len
751
local
a
=
t
[
j
-1
]
752
local
b
=
t
[
p
]
753
local
c
=
t
[
p
-1
]
754
local
pa
=
b
-
c
755
local
pb
=
a
-
c
756
local
pc
=
pa
+
pb
757
if
pa
<
0
then
pa
=
-
pa
end
758
if
pb
<
0
then
pb
=
-
pb
end
759
if
pc
<
0
then
pc
=
-
pc
end
760
t
[
j
]
=
(
t
[
j
]
+
(
(
pa
<
=
pb
and
pa
<
=
pc
and
a
)
or
(
pb
<
=
pc
and
b
)
or
c
)
)
%
256
761
end
762
end
763
if
colordepth
=
=
8
then
764
for
j
=
2
,
len
do
765
local
v
=
t
[
j
]
766
k
=
k
+
1
;
o
[
k
]
=
r
[
v
]
767
end
768
elseif
colordepth
=
=
4
then
769
for
j
=
2
,
len
do
770
local
v
=
t
[
j
]
771
k
=
k
+
1
;
o
[
k
]
=
r
[
extract4
(
v
,
4
)
]
772
k
=
k
+
1
;
o
[
k
]
=
r
[
extract4
(
v
,
0
)
]
773
end
774
elseif
colordepth
=
=
2
then
775
for
j
=
2
,
len
do
776
local
v
=
t
[
j
]
777
k
=
k
+
1
;
o
[
k
]
=
r
[
extract2
(
v
,
6
)
]
778
k
=
k
+
1
;
o
[
k
]
=
r
[
extract2
(
v
,
4
)
]
779
k
=
k
+
1
;
o
[
k
]
=
r
[
extract2
(
v
,
2
)
]
780
k
=
k
+
1
;
o
[
k
]
=
r
[
extract2
(
v
,
0
)
]
781
end
782
else
783
for
j
=
2
,
len
do
784
local
v
=
t
[
j
]
785
k
=
k
+
1
;
o
[
k
]
=
r
[
extract1
(
v
,
7
)
]
786
k
=
k
+
1
;
o
[
k
]
=
r
[
extract1
(
v
,
6
)
]
787
k
=
k
+
1
;
o
[
k
]
=
r
[
extract1
(
v
,
5
)
]
788
k
=
k
+
1
;
o
[
k
]
=
r
[
extract1
(
v
,
4
)
]
789
k
=
k
+
1
;
o
[
k
]
=
r
[
extract1
(
v
,
3
)
]
790
k
=
k
+
1
;
o
[
k
]
=
r
[
extract1
(
v
,
2
)
]
791
k
=
k
+
1
;
o
[
k
]
=
r
[
extract1
(
v
,
1
)
]
792
k
=
k
+
1
;
o
[
k
]
=
r
[
extract1
(
v
,
0
)
]
793
end
794
end
795
u
=
t
796
end
797
return
concat
(
o
,
"
"
,
1
,
size
)
798
end
799
end
800 801
local
function
createmask_c
(
content
,
palette
,
transparent
,
xsize
,
ysize
,
colordepth
,
colorspace
)
802
if
palette
then
803
local
r
=
expandvector
(
transparent
)
804
local
size
=
xsize
*
ysize
805
local
len
=
ceil
(
xsize
*
colordepth
/
8
)
806
local
o
=
newoutput
(
size
)
807
content
=
zlibdecompress
(
content
)
808
content
=
pngapplyfilter
(
content
,
len
,
ysize
,
1
)
-- nostrip (saves copy)
809
content
=
openstring
(
content
)
810
for
i
=
0
,
ysize
-1
do
811
local
t
=
readbytetable
(
content
,
len
)
812
local
k
=
i
*
xsize
813
if
colordepth
=
=
8
then
814
for
j
=
1
,
len
do
815
local
v
=
t
[
j
]
816
k
=
k
+
1
;
o
[
k
]
=
r
[
v
]
817
end
818
elseif
colordepth
=
=
4
then
819
for
j
=
1
,
len
do
820
local
v
=
t
[
j
]
821
k
=
k
+
1
;
o
[
k
]
=
r
[
extract4
(
v
,
4
)
]
822
k
=
k
+
1
;
o
[
k
]
=
r
[
extract4
(
v
,
0
)
]
823
end
824
elseif
colordepth
=
=
2
then
825
for
j
=
1
,
len
do
826
local
v
=
t
[
j
]
827
k
=
k
+
1
;
o
[
k
]
=
r
[
extract2
(
v
,
6
)
]
828
k
=
k
+
1
;
o
[
k
]
=
r
[
extract2
(
v
,
4
)
]
829
k
=
k
+
1
;
o
[
k
]
=
r
[
extract2
(
v
,
2
)
]
830
k
=
k
+
1
;
o
[
k
]
=
r
[
extract2
(
v
,
0
)
]
831
end
832
else
833
for
j
=
1
,
len
do
834
local
v
=
t
[
j
]
835
k
=
k
+
1
;
o
[
k
]
=
r
[
extract1
(
v
,
7
)
]
836
k
=
k
+
1
;
o
[
k
]
=
r
[
extract1
(
v
,
6
)
]
837
k
=
k
+
1
;
o
[
k
]
=
r
[
extract1
(
v
,
5
)
]
838
k
=
k
+
1
;
o
[
k
]
=
r
[
extract1
(
v
,
4
)
]
839
k
=
k
+
1
;
o
[
k
]
=
r
[
extract1
(
v
,
3
)
]
840
k
=
k
+
1
;
o
[
k
]
=
r
[
extract1
(
v
,
2
)
]
841
k
=
k
+
1
;
o
[
k
]
=
r
[
extract1
(
v
,
1
)
]
842
k
=
k
+
1
;
o
[
k
]
=
r
[
extract1
(
v
,
0
)
]
843
end
844
end
845
end
846
return
concat
(
o
,
"
"
,
1
,
size
)
847
end
848
end
849 850
local
function
tocmyk_l
(
content
,
colordepth
)
851
local
l
=
#
content
852
local
t
=
{
}
853
local
n
=
0
854
if
colordepth
=
=
8
then
855
for
i
=
1
,
l
,
3
do
856
local
r
,
g
,
b
=
byte
(
content
,
i
,
i
+
2
)
857
n
=
n
+
1
;
t
[
n
]
=
char
(
255
-
r
,
255
-
g
,
255
-
b
,
0
)
-- a tad faster than chars[...]
858
end
859
else
860
for
i
=
1
,
l
,
6
do
861
local
r1
,
r2
,
g1
,
g2
,
b1
,
b2
=
byte
(
content
,
i
,
i
+
5
)
862
n
=
n
+
1
;
t
[
n
]
=
char
(
255
-
r1
,
255
-
r2
,
255
-
g1
,
255
-
g2
,
255
-
b1
,
255
-
b2
,
0
,
0
)
863
end
864
end
865
return
concat
(
t
)
866
end
867 868
local
tocmyk_c
=
pngtocmyk
or
tocmyk_l
869 870
local
function
converttocmyk
(
content
,
colorspace
,
colordepth
)
871
if
colorspace
=
=
"
DeviceRGB
"
and
colordepth
=
=
8
or
colordepth
=
=
16
then
872
local
done
=
tocmyk
(
content
,
colordepth
)
873
if
done
then
874
content
=
done
875
colorspace
=
"
DeviceCMYK
"
876
end
877
end
878
return
content
,
colorspace
879
end
880 881
local
function
switch
(
v
)
882
if
v
then
883
filtermask
=
filtermask_l
884
decodemask
=
decodemask_l
885
decodestrip
=
decodestrip_l
886
transpose
=
transpose_l
887
expand
=
expand_l
888
createmask
=
createmask_l
889
tocmyk
=
tocmyk_l
890
else
891
filtermask
=
filtermask_c
892
decodemask
=
decodemask_c
893
decodestrip
=
decodestrip_c
894
transpose
=
transpose_c
895
expand
=
expand_c
896
createmask
=
createmask_c
897
tocmyk
=
tocmyk_c
898
end
899
end
900 901
if
pngapplyfilter
then
902
switch
(
false
)
903
directives
.
register
(
"
graphics.png.purelua
"
,
switch
)
904
else
905
switch
(
true
)
906
end
907 908
local
alwaysdecode
=
false
-- trucky with palettes
909
local
compresslevel
=
3
910 911
directives
.
register
(
"
graphics.png.recompress
"
,
function
(
v
)
912
alwaysdecode
=
v
913
end
)
914 915
directives
.
register
(
"
graphics.png.compresslevel
"
,
function
(
v
)
916
v
=
tonumber
(
v
)
917
if
compresslevel
>
=
0
or
compresslevel
<
=
9
then
918
compresslevel
=
v
919
end
920
end
)
921 922
function
injectors
.
png
(
specification
,
method
)
-- todo: method in specification
923
if
specification
.
error
then
924
return
925
end
926
local
filename
=
specification
.
filename
927
if
not
filename
then
928
return
929
end
930
local
colorspace
=
specification
.
colorspace
931
if
not
colorspace
then
932
return
933
end
934
local
interlace
=
specification
.
interlace
or
0
935
if
interlace
=
=
1
then
936
interlace
=
true
937
elseif
interlace
=
=
0
then
938
interlace
=
false
939
else
940
report_png
(
"
unknown interlacing %i
"
,
interlace
)
941
return
942
end
943
local
tables
=
specification
.
tables
944
if
not
tables
then
945
return
946
end
947
local
idat
=
tables
.
idat
948
if
not
idat
then
949
return
950
end
951
local
pngfile
=
newcontent
(
filename
,
method
)
952
if
not
pngfile
then
953
return
954
end
955
local
content
=
idat
(
pngfile
,
true
)
956
tables
.
idat
=
false
957
--
958
-- if tables.gama then
959
-- report_png("ignoring gamma correction")
960
-- end
961
--
962
local
xsize
=
specification
.
xsize
963
local
ysize
=
specification
.
ysize
964
local
colordepth
=
specification
.
colordepth
or
8
965
local
mask
=
false
966
local
transparent
=
false
967
local
palette
=
false
968
local
enforcecmyk
=
specification
.
enforcecmyk
969
local
colors
=
1
970
if
colorspace
=
=
0
then
-- gray | image b
971
colorspace
=
"
DeviceGray
"
972
transparent
=
true
973
elseif
colorspace
=
=
2
then
-- rgb | image c
974
colorspace
=
"
DeviceRGB
"
975
colors
=
3
976
transparent
=
true
977
elseif
colorspace
=
=
3
then
-- palette | image c+i
978
colorspace
=
"
DeviceRGB
"
979
palette
=
true
980
transparent
=
true
981
elseif
colorspace
=
=
4
then
-- gray | alpha | image b
982
colorspace
=
"
DeviceGray
"
983
mask
=
true
984
elseif
colorspace
=
=
6
then
-- rgb | alpha | image c
985
colorspace
=
"
DeviceRGB
"
986
colors
=
3
987
mask
=
true
988
else
989
report_png
(
"
unknown colorspace %i
"
,
colorspace
)
990
return
991
end
992
--
993
if
transparent
then
994
local
trns
=
tables
.
trns
995
if
trns
then
996
transparent
=
trns
(
pngfile
,
true
)
997
if
transparent
=
=
"
"
then
998
transparent
=
false
999
end
1000
tables
.
trns
=
false
1001
else
1002
transparent
=
false
1003
end
1004
end
1005
--
1006
local
decode
=
alwaysdecode
-- tricky, might go away
1007
local
filter
=
pdfconstant
(
"
FlateDecode
"
)
1008
local
major
=
pdfmajorversion
(
)
1009
local
minor
=
pdfminorversion
(
)
1010
if
major
>
1
then
1011
-- we're okay
1012
elseif
minor
<
5
and
colordepth
=
=
16
then
1013
report_png
(
"
16 bit colordepth not supported in pdf < 1.5
"
)
1014
return
1015
elseif
minor
<
4
and
(
mask
or
transparent
)
then
1016
report_png
(
"
alpha channels not supported in pdf < 1.4
"
)
1017
return
1018
elseif
minor
<
2
then
1019
report_png
(
"
you'd better use a version > 1.2
"
)
1020
return
1021
-- decode = true
1022
end
1023
--
1024
-- todo: compresslevel (or delegate)
1025
--
1026
if
palette
then
1027
local
plte
=
tables
.
plte
1028
if
plte
then
1029
palette
=
plte
(
pngfile
,
true
)
1030
if
palette
=
=
"
"
then
1031
palette
=
false
1032
end
1033
tables
.
plte
=
false
1034
else
1035
palette
=
false
1036
end
1037
end
1038
--
1039
if
interlace
then
1040
local
r
,
p
=
deinterlace
(
content
,
xsize
,
ysize
,
colordepth
,
colorspace
,
palette
,
mask
)
1041
if
not
r
then
1042
return
1043
end
1044
if
p
then
1045
colordepth
=
p
1046
end
1047
if
mask
then
1048
if
not
(
colordepth
=
=
8
or
colordepth
=
=
16
)
then
1049
report_png
(
"
mask can't be split from the image
"
)
1050
return
1051
end
-- get rid of bpp:
1052
content
,
mask
=
filtermask
(
r
,
xsize
,
ysize
,
colordepth
,
colorspace
,
false
)
1053
else
1054
content
=
convert
(
r
)
-- can be in deinterlace if needed
1055
end
1056
if
enforcecmyk
then
1057
content
,
colorspace
=
converttocmyk
(
content
,
colorspace
,
colordepth
)
1058
end
1059
if
compresslevel
>
0
then
1060
content
=
zlibcompress
(
content
,
compresslevel
)
1061
else
1062
filter
=
nil
1063
end
1064
decode
=
true
1065
elseif
mask
then
1066
if
not
(
colordepth
=
=
8
or
colordepth
=
=
16
)
then
1067
report_png
(
"
mask can't be split from the image
"
)
1068
return
1069
end
1070
content
=
zlibdecompress
(
content
)
1071
content
,
mask
=
decodemask
(
content
,
xsize
,
ysize
,
colordepth
,
colorspace
)
1072
if
enforcecmyk
and
not
palette
then
1073
content
,
colorspace
=
converttocmyk
(
content
,
colorspace
,
colordepth
)
1074
end
1075
if
compresslevel
>
0
then
1076
content
=
zlibcompress
(
content
,
compresslevel
)
1077
else
1078
filter
=
nil
1079
end
1080
decode
=
true
-- we don't copy the filter byte
1081
elseif
transparent
then
1082
-- in test suite
1083
-- how about decode/recompress here
1084
if
palette
then
1085
mask
=
createmask
(
content
,
palette
,
transparent
,
xsize
,
ysize
,
colordepth
,
colorspace
)
1086
else
1087
pallette
=
false
1088
end
1089
elseif
decode
or
(
enforcecmyk
and
not
palette
)
then
1090
-- this one needs checking
1091
local
bytes
=
analyze
(
colordepth
,
colorspace
)
1092
if
bytes
then
1093
content
=
zlibdecompress
(
content
)
1094
content
=
decodestrip
(
openstring
(
content
)
,
xsize
,
ysize
,
bytes
)
1095
if
enforcecmyk
and
not
palette
then
1096
content
,
colorspace
=
converttocmyk
(
content
,
colorspace
,
colordepth
)
1097
end
1098
if
compresslevel
>
0
then
1099
content
=
zlibcompress
(
content
,
compresslevel
)
1100
else
1101
filter
=
nil
1102
end
1103
else
1104
return
1105
end
1106
decode
=
true
-- due to enforcecmyk
1107
else
1108
-- print("PASS ON")
1109
end
1110
if
palette
then
1111
local
colorspace
=
"
DeviceRGB
"
1112
local
nofbytes
=
3
1113
if
enforcecmyk
then
1114
palette
=
converttocmyk
(
palette
,
colorspace
,
8
)
1115
colorspace
=
"
DeviceCMYK
"
1116
nofbytes
=
4
1117
end
1118
palette
=
pdfarray
{
1119
pdfconstant
(
"
Indexed
"
)
,
1120
pdfconstant
(
colorspace
)
,
1121
idiv
(
#
palette
,
nofbytes
)
,
1122
pdfreference
(
pdfflushstreamobject
(
palette
)
)
,
1123
}
1124
end
1125
pngfile
:
close
(
)
1126
local
xobject
=
pdfdictionary
{
1127
Type
=
pdfconstant
(
"
XObject
"
)
,
1128
Subtype
=
pdfconstant
(
"
Image
"
)
,
1129
-- BBox = pdfarray { 0, 0, xsize, ysize },
1130
Width
=
xsize
,
1131
Height
=
ysize
,
1132
BitsPerComponent
=
colordepth
,
1133
Filter
=
filter
,
1134
ColorSpace
=
palette
or
pdfconstant
(
colorspace
)
,
1135
Length
=
#
content
,
1136
}
+
specification
.
attr
1137
if
mask
then
1138
local
d
=
pdfdictionary
{
1139
Type
=
pdfconstant
(
"
XObject
"
)
,
1140
Subtype
=
pdfconstant
(
"
Image
"
)
,
1141
Width
=
xsize
,
1142
Height
=
ysize
,
1143
BitsPerComponent
=
palette
and
8
or
colordepth
,
1144
ColorSpace
=
pdfconstant
(
"
DeviceGray
"
)
,
1145
}
1146
xobject
.
SMask
=
pdfreference
(
pdfflushstreamobject
(
mask
,
d
(
)
)
)
1147
end
1148
if
not
decode
then
1149
xobject
.
DecodeParms
=
pdfdictionary
{
1150
Colors
=
colors
,
1151
Columns
=
xsize
,
1152
BitsPerComponent
=
colordepth
,
1153
Predictor
=
15
,
1154
}
1155
end
1156
if
trace
then
1157
report_png
(
"
%s: width %i, height %i, colordepth %i, size %i, palette %l, mask %l, transparent %l, decode %l
"
,
filename
,
xsize
,
ysize
,
colordepth
,
#
content
,
palette
,
mask
,
transparent
,
decode
)
1158
end
1159
if
specification
.
colorref
then
1160
xobject
.
ColorSpace
=
pdfreference
(
specification
.
colorref
)
1161
end
1162
local
width
=
specification
.
width
or
xsize
*
65536
1163
local
height
=
specification
.
height
or
ysize
*
65536
1164
return
createimage
{
1165
bbox
=
{
0
,
0
,
width
/
xsize
,
height
/
ysize
}
,
-- mandate
1166
transform
=
specification
.
transform
,
1167
nolength
=
true
,
1168
nobbox
=
true
,
1169
notype
=
true
,
1170
stream
=
content
,
1171
attr
=
xobject
(
)
,
1172
}
1173
end
1174 1175
end
1176 1177
do
1178 1179
local
function
pack
(
specification
,
what
)
1180
local
t
=
{
}
1181
local
n
=
0
1182
local
s
=
specification
.
colorspace
1183
local
d
=
specification
.
data
1184
local
x
=
specification
.
xsize
1185
local
y
=
specification
.
ysize
1186
if
what
=
=
"
mask
"
then
1187
d
=
specification
.
mask
1188
s
=
1
1189
elseif
what
=
=
"
indexed
"
then
1190
s
=
1
1191
elseif
what
=
=
"
index
"
then
1192
d
=
specification
.
index
1193
s
=
-
s
1194
end
1195
if
s
>
0
then
1196
if
s
=
=
1
then
1197
for
i
=
1
,
y
do
1198
local
r
=
d
[
i
]
1199
for
j
=
1
,
x
do
1200
n
=
n
+
1
;
t
[
n
]
=
chars
[
r
[
j
]
]
1201
end
1202
end
1203
elseif
s
=
=
2
then
1204
for
i
=
1
,
y
do
1205
local
r
=
d
[
i
]
1206
for
j
=
1
,
x
do
1207
local
c
=
r
[
j
]
1208
n
=
n
+
1
;
t
[
n
]
=
chars
[
c
[
1
]
]
1209
n
=
n
+
1
;
t
[
n
]
=
chars
[
c
[
2
]
]
1210
n
=
n
+
1
;
t
[
n
]
=
chars
[
c
[
3
]
]
1211
-- n = n + 1 ; t[n] = char(c[1],c[2],c[3]) -- test this
1212
end
1213
end
1214
elseif
s
=
=
3
then
1215
for
i
=
1
,
y
do
1216
local
r
=
d
[
i
]
1217
for
j
=
1
,
x
do
1218
local
c
=
r
[
j
]
1219
n
=
n
+
1
;
t
[
n
]
=
chars
[
c
[
1
]
]
1220
n
=
n
+
1
;
t
[
n
]
=
chars
[
c
[
2
]
]
1221
n
=
n
+
1
;
t
[
n
]
=
chars
[
c
[
3
]
]
1222
n
=
n
+
1
;
t
[
n
]
=
chars
[
c
[
4
]
]
1223
-- n = n + 1 ; t[n] = char(c[1],c[2],c[3],c[4]) -- test this
1224
end
1225
end
1226
end
1227
return
concat
(
t
)
1228
else
1229
local
z
=
d
[
0
]
and
0
or
1
1230
if
s
=
=
-1
then
1231
local
f
=
formatters
[
"
%02X
"
]
1232
for
i
=
z
,
#
d
do
1233
n
=
n
+
1
;
t
[
n
]
=
f
(
d
[
i
]
)
1234
end
1235
elseif
s
=
=
-2
then
1236
local
f
=
formatters
[
"
%02X%02X%02X
"
]
1237
for
i
=
z
,
#
d
do
1238
local
c
=
d
[
i
]
1239
n
=
n
+
1
;
t
[
n
]
=
f
(
c
[
1
]
,
c
[
2
]
,
c
[
3
]
)
1240
end
1241
elseif
s
=
=
-3
then
1242
local
f
=
formatters
[
"
%02X%02X%02X%02X
"
]
1243
for
i
=
z
,
#
d
do
1244
local
c
=
d
[
i
]
1245
n
=
n
+
1
;
t
[
n
]
=
f
(
c
[
1
]
,
c
[
2
]
,
c
[
3
]
,
c
[
4
]
)
1246
end
1247
end
1248
return
"
<
"
.
.
concat
(
t
,
"
"
)
.
.
"
>
"
1249
end
1250
return
"
"
1251
end
1252 1253
function
injectors
.
bitmap
(
specification
)
1254
local
data
=
specification
.
data
1255
if
not
data
then
1256
return
1257
end
1258
local
xsize
=
specification
.
xsize
or
0
1259
local
ysize
=
specification
.
ysize
or
0
1260
if
xsize
=
=
0
or
ysize
=
=
0
then
1261
return
1262
end
1263
local
colorspace
=
specification
.
colorspace
or
1
1264
if
colorspace
=
=
1
then
1265
colorspace
=
"
DeviceGray
"
1266
elseif
colorspace
=
=
2
then
1267
colorspace
=
"
DeviceRGB
"
1268
elseif
colorspace
=
=
3
then
1269
colorspace
=
"
DeviceCMYK
"
1270
end
1271
local
colordepth
=
(
specification
.
colordepth
or
2
)
=
=
16
or
8
1272
local
index
=
specification
.
index
1273
local
content
=
pack
(
specification
,
index
and
"
indexed
"
or
"
data
"
)
1274
local
mask
=
specification
.
mask
1275
local
colorspace
=
pdfconstant
(
colorspace
)
1276
if
index
then
1277
colorspace
=
pdfarray
{
1278
pdfconstant
(
"
Indexed
"
)
,
1279
colorspace
,
1280
#
index
+
(
index
[
0
]
and
0
or
-1
)
,
-- upper index
1281
pdfverbose
(
pack
(
specification
,
"
index
"
)
)
1282
}
1283
end
1284
local
xobject
=
pdfdictionary
{
1285
Type
=
pdfconstant
(
"
XObject
"
)
,
1286
Subtype
=
pdfconstant
(
"
Image
"
)
,
1287
BBox
=
pdfarray
{
0
,
0
,
xsize
,
ysize
}
,
1288
Width
=
xsize
,
1289
Height
=
ysize
,
1290
BitsPerComponent
=
colordepth
,
1291
ColorSpace
=
colorspace
,
1292
Length
=
#
content
,
-- specification.length
1293
}
1294
if
mask
then
1295
local
d
=
pdfdictionary
{
1296
Type
=
pdfconstant
(
"
XObject
"
)
,
1297
Subtype
=
pdfconstant
(
"
Image
"
)
,
1298
Width
=
xsize
,
1299
Height
=
ysize
,
1300
BitsPerComponent
=
colordepth
,
1301
ColorSpace
=
pdfconstant
(
"
DeviceGray
"
)
,
1302
}
1303
xobject
.
SMask
=
pdfreference
(
pdfflushstreamobject
(
pack
(
specification
,
"
mask
"
)
,
d
(
)
)
)
1304
end
1305
return
createimage
{
1306
bbox
=
{
0
,
0
,
specification
.
width
/
xsize
,
specification
.
height
/
ysize
}
,
-- mandate
1307
-- nolength = true,
1308
nobbox
=
true
,
1309
notype
=
true
,
1310
stream
=
content
,
1311
attr
=
xobject
(
)
,
1312
}
1313
end
1314 1315
backends
.
pdf
.
codeinjections
.
bitmap
=
injectors
.
bitmap
1316 1317
end
1318 1319
-- local function validcompression(data)
1320
-- local d = utilities.streams.openstring(data)
1321
-- local b1 = utilities.streams.readbyte(d)
1322
-- local b2 = utilities.streams.readbyte(d)
1323
-- print(b1,b2)
1324
-- if (b1 * 256 + b2) % 31 ~= 0 then
1325
-- return false, "no zlib compressed file"
1326
-- end
1327
-- local method = band(b1,15)
1328
-- if method ~= 8 then
1329
-- return false, "method 8 expected"
1330
-- end
1331
-- local detail = band(rshift(b1,4),15)
1332
-- if detail > 7 then
1333
-- return false, "window 32 expected"
1334
-- end
1335
-- local preset = band(rshift(b2,5),1)
1336
-- if preset ~= 0 then
1337
-- return false, "unexpected preset dictionary"
1338
-- end
1339
-- return true
1340
-- end
1341