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