1if not modules then modules = { } end modules ['lpdf-fmt'] = {
2 version = 1.001,
3 comment = "companion to lpdf-ini.mkiv",
4 author = "Peter Rolf and Hans Hagen",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files",
7}
8
9
10
11
12
13local tonumber = tonumber
14local lower, gmatch, format, find = string.lower, string.gmatch, string.format, string.find
15local concat, serialize, sortedhash = table.concat, table.serialize, table.sortedhash
16
17local trace_format = false trackers.register("backend.format", function(v) trace_format = v end)
18local trace_variables = false trackers.register("backend.variables", function(v) trace_variables = v end)
19
20local report_backend = logs.reporter("backend","profiles")
21
22local backends, lpdf = backends, lpdf
23
24local codeinjections = backends.pdf.codeinjections
25
26local variables = interfaces.variables
27local viewerlayers = attributes.viewerlayers
28local colors = attributes.colors
29local transparencies = attributes.transparencies
30
31local pdfdictionary = lpdf.dictionary
32local pdfarray = lpdf.array
33local pdfconstant = lpdf.constant
34local pdfreference = lpdf.reference
35local pdfflushobject = lpdf.flushobject
36local pdfstring = lpdf.string
37local pdfverbose = lpdf.verbose
38local pdfflushstreamfileobject = lpdf.flushstreamfileobject
39
40local addtoinfo = lpdf.addtoinfo
41local injectxmpinfo = lpdf.injectxmpinfo
42local insertxmpinfo = lpdf.insertxmpinfo
43
44local settings_to_array = utilities.parsers.settings_to_array
45local settings_to_hash = utilities.parsers.settings_to_hash
46
47
69
70local channels = {
71 gray = 1,
72 grey = 1,
73 rgb = 3,
74 cmyk = 4,
75}
76
77local prefixes = {
78 gray = "DefaultGray",
79 grey = "DefaultGray",
80 rgb = "DefaultRGB",
81 cmyk = "DefaultCMYK",
82}
83
84local formatspecification = nil
85local formatname = nil
86
87
88
89
90
91local formats = utilities.storage.allocate {
92 version = {
93 external_icc_profiles = 1.4,
94 jbig2_compression = 1.4,
95 jpeg2000_compression = 1.5,
96 nchannel_colorspace = 1.6,
97 open_prepress_interface = 1.3,
98 optional_content = 1.5,
99 transparency = 1.4,
100 object_compression = 1.5,
101 attachments = 1.7,
102 },
103 default = {
104 pdf_version = 1.7,
105 format_name = "default",
106 xmp_file = "lpdf-pdx.xml",
107 gray_scale = true,
108 cmyk_colors = true,
109 rgb_colors = true,
110 spot_colors = true,
111 calibrated_rgb_colors = true,
112 cielab_colors = true,
113 nchannel_colorspace = true,
114 internal_icc_profiles = true,
115 external_icc_profiles = true,
116 include_intents = true,
117 open_prepress_interface = true,
118 optional_content = true,
119 transparency = true,
120 jbig2_compression = true,
121 jpeg2000_compression = true,
122 include_cidsets = true,
123 include_charsets = true,
124 attachments = true,
125 inject_metadata = function()
126
127 end
128 },
129 data = {
130 ["pdf/x-1a:2001"] = {
131 pdf_version = 1.3,
132 format_name = "PDF/X-1a:2001",
133 xmp_file = "lpdf-pdx.xml",
134 gts_flag = "GTS_PDFX",
135 gray_scale = true,
136 cmyk_colors = true,
137 spot_colors = true,
138 internal_icc_profiles = true,
139 include_cidsets = true,
140 include_charsets = true,
141 attachments = false,
142 inject_metadata = function()
143 addtoinfo("GTS_PDFXVersion","PDF/X-1a:2001")
144 injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfxid='http://www.npes.org/pdfx/ns/id/'><pdfxid:GTS_PDFXVersion>PDF/X-1a:2001</pdfxid:GTS_PDFXVersion></rdf:Description>",false)
145 end
146 },
147 ["pdf/x-1a:2003"] = {
148 pdf_version = 1.4,
149 format_name = "PDF/X-1a:2003",
150 xmp_file = "lpdf-pdx.xml",
151 gts_flag = "GTS_PDFX",
152 gray_scale = true,
153 cmyk_colors = true,
154 spot_colors = true,
155 internal_icc_profiles = true,
156 include_cidsets = true,
157 include_charsets = true,
158 attachments = false,
159 inject_metadata = function()
160 addtoinfo("GTS_PDFXVersion","PDF/X-1a:2003")
161 injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfxid='http://www.npes.org/pdfx/ns/id/'><pdfxid:GTS_PDFXVersion>PDF/X-1a:2003</pdfxid:GTS_PDFXVersion></rdf:Description>",false)
162 end
163 },
164 ["pdf/x-3:2002"] = {
165 pdf_version = 1.3,
166 format_name = "PDF/X-3:2002",
167 xmp_file = "lpdf-pdx.xml",
168 gts_flag = "GTS_PDFX",
169 gray_scale = true,
170 cmyk_colors = true,
171 rgb_colors = true,
172 calibrated_rgb_colors = true,
173 spot_colors = true,
174 cielab_colors = true,
175 internal_icc_profiles = true,
176 include_intents = true,
177 include_cidsets = true,
178 include_charsets = true,
179 attachments = false,
180 inject_metadata = function()
181 addtoinfo("GTS_PDFXVersion","PDF/X-3:2002")
182 end
183 },
184 ["pdf/x-3:2003"] = {
185 pdf_version = 1.4,
186 format_name = "PDF/X-3:2003",
187 xmp_file = "lpdf-pdx.xml",
188 gts_flag = "GTS_PDFX",
189 gray_scale = true,
190 cmyk_colors = true,
191 rgb_colors = true,
192 calibrated_rgb_colors = true,
193 spot_colors = true,
194 cielab_colors = true,
195 internal_icc_profiles = true,
196 include_intents = true,
197 jbig2_compression = true,
198 include_cidsets = true,
199 include_charsets = true,
200 attachments = false,
201 inject_metadata = function()
202 addtoinfo("GTS_PDFXVersion","PDF/X-3:2003")
203 end
204 },
205 ["pdf/x-4"] = {
206 pdf_version = 1.6,
207 format_name = "PDF/X-4",
208 xmp_file = "lpdf-pdx.xml",
209 gts_flag = "GTS_PDFX",
210 gray_scale = true,
211 cmyk_colors = true,
212 rgb_colors = true,
213 calibrated_rgb_colors = true,
214 spot_colors = true,
215 cielab_colors = true,
216 internal_icc_profiles = true,
217 include_intents = true,
218 optional_content = true,
219 transparency = true,
220 jbig2_compression = true,
221 jpeg2000_compression = true,
222 object_compression = true,
223 include_cidsets = true,
224 include_charsets = true,
225 attachments = false,
226 inject_metadata = function()
227 injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfxid='http://www.npes.org/pdfx/ns/id/'><pdfxid:GTS_PDFXVersion>PDF/X-4</pdfxid:GTS_PDFXVersion></rdf:Description>",false)
228 insertxmpinfo("xml://rdf:Description/xmpMM:InstanceID","<xmpMM:VersionID>1</xmpMM:VersionID>",false)
229 insertxmpinfo("xml://rdf:Description/xmpMM:InstanceID","<xmpMM:RenditionClass>default</xmpMM:RenditionClass>",false)
230 end
231 },
232 ["pdf/x-4p"] = {
233 pdf_version = 1.6,
234 format_name = "PDF/X-4p",
235 xmp_file = "lpdf-pdx.xml",
236 gts_flag = "GTS_PDFX",
237 gray_scale = true,
238 cmyk_colors = true,
239 rgb_colors = true,
240 calibrated_rgb_colors = true,
241 spot_colors = true,
242 cielab_colors = true,
243 internal_icc_profiles = true,
244 external_icc_profiles = true,
245 include_intents = true,
246 optional_content = true,
247 transparency = true,
248 jbig2_compression = true,
249 jpeg2000_compression = true,
250 object_compression = true,
251 include_cidsets = true,
252 include_charsets = true,
253 attachments = false,
254 inject_metadata = function()
255 injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfxid='http://www.npes.org/pdfx/ns/id/'><pdfxid:GTS_PDFXVersion>PDF/X-4p</pdfxid:GTS_PDFXVersion></rdf:Description>",false)
256 insertxmpinfo("xml://rdf:Description/xmpMM:InstanceID","<xmpMM:VersionID>1</xmpMM:VersionID>",false)
257 insertxmpinfo("xml://rdf:Description/xmpMM:InstanceID","<xmpMM:RenditionClass>default</xmpMM:RenditionClass>",false)
258 end
259 },
260 ["pdf/x-5g"] = {
261 pdf_version = 1.6,
262 format_name = "PDF/X-5g",
263 xmp_file = "lpdf-pdx.xml",
264 gts_flag = "GTS_PDFX",
265 gray_scale = true,
266 cmyk_colors = true,
267 rgb_colors = true,
268 calibrated_rgb_colors = true,
269 spot_colors = true,
270 cielab_colors = true,
271 internal_icc_profiles = true,
272 include_intents = true,
273 open_prepress_interface = true,
274 optional_content = true,
275 transparency = true,
276 jbig2_compression = true,
277 jpeg2000_compression = true,
278 object_compression = true,
279 include_cidsets = true,
280 include_charsets = true,
281 attachments = false,
282 inject_metadata = function()
283
284 end
285 },
286 ["pdf/x-5pg"] = {
287 pdf_version = 1.6,
288 format_name = "PDF/X-5pg",
289 xmp_file = "lpdf-pdx.xml",
290 gts_flag = "GTS_PDFX",
291 gray_scale = true,
292 cmyk_colors = true,
293 rgb_colors = true,
294 calibrated_rgb_colors = true,
295 spot_colors = true,
296 cielab_colors = true,
297 internal_icc_profiles = true,
298 external_icc_profiles = true,
299 include_intents = true,
300 open_prepress_interface = true,
301 optional_content = true,
302 transparency = true,
303 jbig2_compression = true,
304 jpeg2000_compression = true,
305 object_compression = true,
306 include_cidsets = true,
307 include_charsets = true,
308 attachments = false,
309 inject_metadata = function()
310
311 end
312 },
313 ["pdf/x-5n"] = {
314 pdf_version = 1.6,
315 format_name = "PDF/X-5n",
316 xmp_file = "lpdf-pdx.xml",
317 gts_flag = "GTS_PDFX",
318 gray_scale = true,
319 cmyk_colors = true,
320 rgb_colors = true,
321 calibrated_rgb_colors = true,
322 spot_colors = true,
323 cielab_colors = true,
324 internal_icc_profiles = true,
325 include_intents = true,
326 optional_content = true,
327 transparency = true,
328 jbig2_compression = true,
329 jpeg2000_compression = true,
330 nchannel_colorspace = true,
331 object_compression = true,
332 include_cidsets = true,
333 include_charsets = true,
334 attachments = false,
335 inject_metadata = function()
336
337 end
338 },
339 ["pdf/a-1a:2005"] = {
340 pdf_version = 1.4,
341 format_name = "pdf/a-1a:2005",
342 xmp_file = "lpdf-pda.xml",
343 gts_flag = "GTS_PDFA1",
344 gray_scale = true,
345 cmyk_colors = true,
346 rgb_colors = true,
347 spot_colors = true,
348 calibrated_rgb_colors = true,
349 cielab_colors = true,
350 include_intents = true,
351 forms = true,
352 tagging = true,
353 internal_icc_profiles = true,
354 include_cidsets = true,
355 include_charsets = true,
356 attachments = false,
357 inject_metadata = function()
358 injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>1</pdfaid:part><pdfaid:conformance>A</pdfaid:conformance></rdf:Description>",false)
359 end
360 },
361 ["pdf/a-1b:2005"] = {
362 pdf_version = 1.4,
363 format_name = "pdf/a-1b:2005",
364 xmp_file = "lpdf-pda.xml",
365 gts_flag = "GTS_PDFA1",
366 gray_scale = true,
367 cmyk_colors = true,
368 rgb_colors = true,
369 spot_colors = true,
370 calibrated_rgb_colors = true,
371 cielab_colors = true,
372 include_intents = true,
373 forms = true,
374 internal_icc_profiles = true,
375 include_cidsets = true,
376 include_charsets = true,
377 attachments = false,
378 inject_metadata = function()
379 injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>1</pdfaid:part><pdfaid:conformance>B</pdfaid:conformance></rdf:Description>",false)
380 end
381 },
382
383
384 ["pdf/a-2a"] = {
385 pdf_version = 1.7,
386 format_name = "pdf/a-2a",
387 xmp_file = "lpdf-pda.xml",
388 gts_flag = "GTS_PDFA1",
389 gray_scale = true,
390 cmyk_colors = true,
391 rgb_colors = true,
392 spot_colors = true,
393 calibrated_rgb_colors = true,
394 cielab_colors = true,
395 include_intents = true,
396 forms = true,
397 tagging = true,
398 internal_icc_profiles = true,
399 transparency = true,
400 jbig2_compression = true,
401 jpeg2000_compression = true,
402 object_compression = true,
403 include_cidsets = false,
404 include_charsets = false,
405 attachments = true,
406 inject_metadata = function()
407 injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>2</pdfaid:part><pdfaid:conformance>A</pdfaid:conformance></rdf:Description>",false)
408 end
409 },
410 ["pdf/a-2b"] = {
411 pdf_version = 1.7,
412 format_name = "pdf/a-2b",
413 xmp_file = "lpdf-pda.xml",
414 gts_flag = "GTS_PDFA1",
415 gray_scale = true,
416 cmyk_colors = true,
417 rgb_colors = true,
418 spot_colors = true,
419 calibrated_rgb_colors = true,
420 cielab_colors = true,
421 include_intents = true,
422 forms = true,
423 tagging = false,
424 internal_icc_profiles = true,
425 transparency = true,
426 jbig2_compression = true,
427 jpeg2000_compression = true,
428 object_compression = true,
429 include_cidsets = false,
430 include_charsets = false,
431 attachments = true,
432 inject_metadata = function()
433 injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>2</pdfaid:part><pdfaid:conformance>B</pdfaid:conformance></rdf:Description>",false)
434 end
435 },
436
437
438 ["pdf/a-2u"] = {
439 pdf_version = 1.7,
440 format_name = "pdf/a-2u",
441 xmp_file = "lpdf-pda.xml",
442 gts_flag = "GTS_PDFA1",
443 gray_scale = true,
444 cmyk_colors = true,
445 rgb_colors = true,
446 spot_colors = true,
447 calibrated_rgb_colors = true,
448 cielab_colors = true,
449 include_intents = true,
450 forms = true,
451 tagging = false,
452 internal_icc_profiles = true,
453 transparency = true,
454 jbig2_compression = true,
455 jpeg2000_compression = true,
456 object_compression = true,
457 include_cidsets = false,
458 include_charsets = false,
459 attachments = true,
460 inject_metadata = function()
461 injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>2</pdfaid:part><pdfaid:conformance>U</pdfaid:conformance></rdf:Description>",false)
462 end
463 },
464
465
466 ["pdf/a-3a"] = {
467 pdf_version = 1.7,
468 format_name = "pdf/a-3a",
469 xmp_file = "lpdf-pda.xml",
470 gts_flag = "GTS_PDFA1",
471 gray_scale = true,
472 cmyk_colors = true,
473 rgb_colors = true,
474 spot_colors = true,
475 calibrated_rgb_colors = true,
476 cielab_colors = true,
477 include_intents = true,
478 forms = true,
479 tagging = true,
480 internal_icc_profiles = true,
481 transparency = true,
482 jbig2_compression = true,
483 jpeg2000_compression = true,
484 object_compression = true,
485 include_cidsets = false,
486 include_charsets = false,
487 attachments = true,
488 inject_metadata = function()
489 injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>3</pdfaid:part><pdfaid:conformance>A</pdfaid:conformance></rdf:Description>",false)
490 end
491 },
492 ["pdf/a-3b"] = {
493 pdf_version = 1.7,
494 format_name = "pdf/a-3b",
495 xmp_file = "lpdf-pda.xml",
496 gts_flag = "GTS_PDFA1",
497 gray_scale = true,
498 cmyk_colors = true,
499 rgb_colors = true,
500 spot_colors = true,
501 calibrated_rgb_colors = true,
502 cielab_colors = true,
503 include_intents = true,
504 forms = true,
505 tagging = false,
506 internal_icc_profiles = true,
507 transparency = true,
508 jbig2_compression = true,
509 jpeg2000_compression = true,
510 object_compression = true,
511 include_cidsets = false,
512 include_charsets = false,
513 attachments = true,
514 inject_metadata = function()
515 injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>3</pdfaid:part><pdfaid:conformance>B</pdfaid:conformance></rdf:Description>",false)
516 end
517 },
518 ["pdf/a-3u"] = {
519 pdf_version = 1.7,
520 format_name = "pdf/a-3u",
521 xmp_file = "lpdf-pda.xml",
522 gts_flag = "GTS_PDFA1",
523 gray_scale = true,
524 cmyk_colors = true,
525 rgb_colors = true,
526 spot_colors = true,
527 calibrated_rgb_colors = true,
528 cielab_colors = true,
529 include_intents = true,
530 forms = true,
531 tagging = false,
532 internal_icc_profiles = true,
533 transparency = true,
534 jbig2_compression = true,
535 jpeg2000_compression = true,
536 object_compression = true,
537 include_cidsets = false,
538 include_charsets = false,
539 attachments = true,
540 inject_metadata = function()
541 injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>3</pdfaid:part><pdfaid:conformance>U</pdfaid:conformance></rdf:Description>",false)
542 end
543 },
544 ["pdf/ua-1"] = {
545 pdf_version = 1.7,
546 format_name = "pdf/ua-1",
547 xmp_file = "lpdf-pua.xml",
548 gray_scale = true,
549 cmyk_colors = true,
550 rgb_colors = true,
551 spot_colors = true,
552 calibrated_rgb_colors = true,
553 cielab_colors = true,
554 include_intents = true,
555 forms = true,
556 tagging = true,
557 internal_icc_profiles = true,
558 transparency = true,
559 jbig2_compression = true,
560 jpeg2000_compression = true,
561 object_compression = true,
562 include_cidsets = true,
563 include_charsets = true,
564 attachments = true,
565 inject_metadata = function()
566 injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfaid='http://www.aiim.org/pdfa/ns/id/'><pdfaid:part>3</pdfaid:part><pdfaid:conformance>A</pdfaid:conformance></rdf:Description>",false)
567 injectxmpinfo("xml://rdf:RDF","<rdf:Description rdf:about='' xmlns:pdfuaid='http://www.aiim.org/pdfua/ns/id/'><pdfuaid:part>1</pdfuaid:part></rdf:Description>",false)
568 end
569 },
570 }
571}
572
573lpdf.formats = formats
574
575local filenames = {
576 "colorprofiles.xml",
577 "colorprofiles.lua",
578}
579
580local function locatefile(filename)
581 local fullname = resolvers.findfile(filename,"icc",1,true)
582 if not fullname or fullname == "" then
583 fullname = resolvers.finders.byscheme("loc",filename)
584 end
585 return fullname or ""
586end
587
588local function loadprofile(name,filename)
589 local profile = false
590 local databases = filename and filename ~= "" and settings_to_array(filename) or filenames
591 for i=1,#databases do
592 local filename = locatefile(databases[i])
593 if filename and filename ~= "" then
594 local suffix = file.suffix(filename)
595 local lname = lower(name)
596 if suffix == "xml" then
597 local xmldata = xml.load(filename)
598 if xmldata then
599 profile = xml.filter(xmldata,format('xml://profiles/profile/(info|filename)[lower(text())=="%s"]/../table()',lname))
600 end
601 elseif suffix == "lua" then
602 local luadata = loadfile(filename)
603 luadata = ludata and luadata()
604 if luadata then
605 profile = luadata[name] or luadata[lname]
606 if not profile then
607 for i=1,#luadata do
608 local li = luadata[i]
609 if lower(li.info) == lname then
610 profile = li
611 break
612 end
613 end
614 end
615 end
616 end
617 if profile then
618 if next(profile) then
619 report_backend("profile specification %a loaded from %a",name,filename)
620 return profile
621 elseif trace_format then
622 report_backend("profile specification %a loaded from %a but empty",name,filename)
623 end
624 return false
625 end
626 end
627 end
628 report_backend("profile specification %a not found in %a",name,concat(filenames, ", "))
629end
630
631local function urls(url)
632 if not url or url == "" then
633 return nil
634 else
635 local u = pdfarray()
636 for url in gmatch(url,"([^, ]+)") do
637 if find(url,"^http") then
638 u[#u+1] = pdfdictionary {
639 FS = pdfconstant("URL"),
640 F = pdfstring(url),
641 }
642 end
643 end
644 return u
645 end
646end
647
648local function profilename(filename)
649 return lower(file.basename(filename))
650end
651
652local internalprofiles = { }
653
654local function handleinternalprofile(s,include)
655 local filename, colorspace = s.filename or "", s.colorspace or ""
656 if filename == "" or colorspace == "" then
657 report_backend("error in internal profile specification: %s",serialize(s,false))
658 else
659 local tag = profilename(filename)
660 local profile = internalprofiles[tag]
661 if not profile then
662 local colorspace = lower(colorspace)
663 if include then
664
665 local fullname = locatefile(filename)
666 local channel = channels[colorspace] or nil
667 if fullname == "" then
668 report_backend("error, couldn't locate profile %a",filename)
669 elseif not channel then
670 report_backend("error, couldn't resolve channel entry for colorspace %a",colorspace)
671 else
672 profile = pdfflushstreamfileobject(fullname,pdfdictionary{ N = channel },false)
673 internalprofiles[tag] = profile
674 if trace_format then
675 report_backend("including %a color profile from %a",colorspace,fullname)
676 end
677 end
678 else
679 internalprofiles[tag] = true
680 if trace_format then
681 report_backend("not including %a color profile %a",colorspace,filename)
682 end
683 end
684 end
685 return profile
686 end
687end
688
689local externalprofiles = { }
690
691local function handleexternalprofile(s,include)
692 local name, url, filename, checksum, version, colorspace =
693 s.info or s.filename or "", s.url or "", s.filename or "", s.checksum or "", s.version or "", s.colorspace or ""
694 if false then
695 local iccprofile = colors.iccprofile(filename)
696 if iccprofile then
697 name = name ~= "" and name or iccprofile.tags.desc.cleaned or ""
698 url = url ~= "" and url or iccprofile.tags.dmnd.cleaned or ""
699 checksum = checksum ~= "" and checksum or file.checksum(iccprofile.fullname) or ""
700 version = version ~= "" and version or iccprofile.header.version or ""
701 colorspace = colorspace ~= "" and colorspace or iccprofile.header.colorspace or ""
702 end
703
704 end
705 if name == "" or url == "" or checksum == "" or version == "" or colorspace == "" or filename == "" then
706 local profile = handleinternalprofile(s)
707 if profile then
708 report_backend("incomplete external profile specification, falling back to internal")
709 else
710 report_backend("error in external profile specification: %s",serialize(s,false))
711 end
712 else
713 local tag = profilename(filename)
714 local profile = externalprofiles[tag]
715 if not profile then
716 local d = pdfdictionary {
717 ProfileName = name,
718 ProfileCS = colorspace,
719 URLs = urls(url),
720 CheckSum = pdfverbose { "<", lower(checksum), ">" },
721 ICCVersion = pdfverbose { "<", version, ">" },
722 }
723 profile = pdfflushobject(d)
724 externalprofiles[tag] = profile
725 end
726 return profile
727 end
728end
729
730local loadeddefaults = { }
731
732local function handledefaultprofile(s,spec)
733 local filename, colorspace = s.filename or "", lower(s.colorspace or "")
734 if filename == "" or colorspace == "" then
735 report_backend("error in default profile specification: %s",serialize(s,false))
736 elseif not loadeddefaults[colorspace] then
737 local tag = profilename(filename)
738 local n = internalprofiles[tag]
739 if n == true then
740 report_backend("no default profile %a for colorspace %a",filename,colorspace)
741 elseif n then
742 local a = pdfarray {
743 pdfconstant("ICCBased"),
744 pdfreference(n),
745 }
746
747 lpdf.adddocumentcolorspace(prefixes[colorspace],pdfreference(pdfflushobject(a)))
748 loadeddefaults[colorspace] = true
749 report_backend("setting %a as default %a color space",filename,colorspace)
750 else
751 report_backend("no default profile %a for colorspace %a",filename,colorspace)
752 end
753 elseif trace_format then
754 report_backend("a default %a colorspace is already in use",colorspace)
755 end
756end
757
758local loadedintents = { }
759local intents = pdfarray()
760
761local function handleoutputintent(s,spec)
762 local url = s.url or ""
763 local filename = s.filename or ""
764 local name = s.info or filename
765 local id = s.id or ""
766 local outputcondition = s.outputcondition or ""
767 local info = s.info or ""
768 if name == "" or id == "" then
769 report_backend("error in output intent specification: %s",serialize(s,false))
770 elseif not loadedintents[name] then
771 local tag = profilename(filename)
772 local internal, external = internalprofiles[tag], externalprofiles[tag]
773 if internal or external then
774 local d = {
775 Type = pdfconstant("OutputIntent"),
776 S = pdfconstant(spec.gts_flag or "GTS_PDFX"),
777 OutputConditionIdentifier = id,
778 RegistryName = url,
779 OutputCondition = outputcondition,
780 Info = info,
781 }
782 if internal and internal ~= true then
783 d.DestOutputProfile = pdfreference(internal)
784 elseif external and external ~= true then
785 d.DestOutputProfileRef = pdfreference(external)
786 else
787 report_backend("omitting reference to profile for intent %a",name)
788 end
789 intents[#intents+1] = pdfreference(pdfflushobject(pdfdictionary(d)))
790 if trace_format then
791 report_backend("setting output intent to %a with id %a for entry %a",name,id,#intents)
792 end
793 else
794 report_backend("invalid output intent %a",name)
795 end
796 loadedintents[name] = true
797 elseif trace_format then
798 report_backend("an output intent with name %a is already in use",name)
799 end
800end
801
802local function handleiccprofile(message,spec,name,filename,how,options,alwaysinclude,gts_flag)
803 if name and name ~= "" then
804 local list = settings_to_array(name)
805 for i=1,#list do
806 local name = list[i]
807 local profile = loadprofile(name,filename)
808 if trace_format then
809 report_backend("handling %s %a",message,name)
810 end
811 if profile then
812 if formatspecification.cmyk_colors then
813 profile.colorspace = profile.colorspace or "CMYK"
814 else
815 profile.colorspace = profile.colorspace or "RGB"
816 end
817 local external = formatspecification.external_icc_profiles
818 local internal = formatspecification.internal_icc_profiles
819 local include = formatspecification.include_intents
820 local always, never = options[variables.always], options[variables.never]
821 if always or alwaysinclude then
822 if trace_format then
823 report_backend("forcing internal profiles")
824 end
825
826 internal, external = not never, false
827 elseif never then
828 if trace_format then
829 report_backend("forcing external profiles")
830 end
831 internal, external = false, true
832 end
833 if external then
834 if trace_format then
835 report_backend("handling external profiles cf. %a",name)
836 end
837 handleexternalprofile(profile,false)
838 else
839 if trace_format then
840 report_backend("handling internal profiles cf. %a",name)
841 end
842 if internal then
843 handleinternalprofile(profile,always or include)
844 else
845 report_backend("no profile inclusion for %a",formatname)
846 end
847 end
848 how(profile,spec)
849 elseif trace_format then
850 report_backend("unknown profile %a",name)
851 end
852 end
853 end
854end
855
856local function flushoutputintents()
857 if #intents > 0 then
858 lpdf.addtocatalog("OutputIntents",pdfreference(pdfflushobject(intents)))
859 end
860end
861
862lpdf.registerdocumentfinalizer(flushoutputintents,2,"output intents")
863
864function codeinjections.setformat(s)
865 local format = s.format or ""
866 local level = tonumber(s.level)
867 local intent = s.intent or ""
868 local profile = s.profile or ""
869 local option = s.option or ""
870 local filename = s.file or ""
871 if format ~= "" then
872 local spec = formats.data[lower(format)]
873 if spec then
874 formatspecification = spec
875 formatname = spec.format_name
876 report_backend("setting format to %a",formatname)
877 local xmp_file = formatspecification.xmp_file or ""
878 if xmp_file == "" then
879
880 else
881 codeinjections.setxmpfile(xmp_file)
882 end
883 if not level then
884 level = 3
885 end
886 local pdf_version = spec.pdf_version * 10
887 local inject_metadata = spec.inject_metadata
888 local majorversion = math.floor(math.div(pdf_version,10))
889 local minorversion = math.floor(math.mod(pdf_version,10))
890 local objectcompression = spec.object_compression and pdf_version >= 15
891 local compresslevel = level or lpdf.compresslevel()
892 local objectcompresslevel = (objectcompression and (level or lpdf.objectcompresslevel())) or 0
893 lpdf.setcompression(compresslevel,objectcompresslevel)
894 lpdf.setversion(majorversion,minorversion)
895 if objectcompression then
896 report_backend("forcing pdf version %s.%s, compression level %s, object compression level %s",
897 majorversion,minorversion,compresslevel,objectcompresslevel)
898 elseif compresslevel > 0 then
899 report_backend("forcing pdf version %s.%s, compression level %s, object compression disabled",
900 majorversion,minorversion,compresslevel)
901 else
902 report_backend("forcing pdf version %s.%s, compression disabled",
903 majorversion,minorversion)
904 end
905
906
907
908
909 lpdf.setomitcidset (formatspecification.include_cidsets == false and 1 or 0)
910 lpdf.setomitcharset(formatspecification.include_charsets == false and 1 or 0)
911
912
913
914 codeinjections.settaggingsupport(formatspecification.tagging)
915 codeinjections.setattachmentsupport(formatspecification.attachments)
916
917
918
919
920
921
922 colors.forcesupport(
923 spec.gray_scale or false,
924 spec.rgb_colors or false,
925 spec.cmyk_colors or false,
926 spec.spot_colors or false,
927 spec.nchannel_colorspace or false
928 )
929 transparencies.forcesupport(
930 spec.transparency or false
931 )
932 viewerlayers.forcesupport(
933 spec.optional_content or false
934 )
935 viewerlayers.setfeatures(
936 spec.has_order or false
937 )
938
939
940
941
942 if type(inject_metadata) == "function" then
943 inject_metadata()
944 end
945 local options = settings_to_hash(option)
946 handleiccprofile("color profile",spec,profile,filename,handledefaultprofile,options,true)
947 handleiccprofile("output intent",spec,intent,filename,handleoutputintent,options,false)
948 if trace_variables then
949 for k, v in sortedhash(formats.default) do
950 local v = formatspecification[k]
951 if type(v) ~= "function" then
952 report_backend("%a = %a",k,v or false)
953 end
954 end
955 end
956 function codeinjections.setformat(noname)
957 if trace_format then
958 report_backend("error, format is already set to %a, ignoring %a",formatname,noname.format)
959 end
960 end
961 else
962 report_backend("error, format %a is not supported",format)
963 end
964 elseif level then
965 lpdf.setcompression(level,level)
966 else
967
968 end
969end
970
971directives.register("backend.format", function(v)
972 local tv = type(v)
973 if tv == "table" then
974 codeinjections.setformat(v)
975 elseif tv == "string" then
976 codeinjections.setformat { format = v }
977 end
978end)
979
980interfaces.implement {
981 name = "setformat",
982 actions = codeinjections.setformat,
983 arguments = { { "*" } }
984}
985
986function codeinjections.getformatoption(key)
987 return formatspecification and formatspecification[key]
988end
989
990
991
992
993
994function codeinjections.supportedformats()
995 local t = { }
996 for k, v in sortedhash(formats.data) do
997 t[#t+1] = k
998 end
999 return t
1000end
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021 |