%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % pdfbase.sty % % driver independent access to low-level pdf features % % Copyright 2015--\today, Alexander Grahn % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % This package implements commands for the creation of PDF Objects, % Form XObjects, Image XObjects, annotations, links, marked content (BDC/EMC) % and for manipulating the PDF catalog. % % Supported workflows: % % pdflatex, lualatex % latex-->dvips-->ps2pdf or Distiller % latex-->dvipdfmx % xelatex % % Package options: % % xetex % dvipdfmx % dvisvgm (basic support: \pbs_literal:nn, \pbs_pdfannot:nnnn, % \pbs_pdfxform:nnnnn\pbs_pdfrefxform:n) % bigfiles (for embedding large files as stream objects; only relevant for % dvips mode, ignored otherwise) % % Commands defined: % % \pbs_pdfobj:nnn % #1: predefined PDF object ID to be used for the current obj; may be empty % #2: type of object ( dict | array | stream | fstream ) % #3: if #2== % `dict' then PDF key-value dictionary % `stream' then % {stream attributes as PDF key-value dictionary}{content string} % `fstream' then % {stream attributes as PDF key-value dictionary}{file name} % % if #3 && #1 are both empty, an object reference will be reserved for later % use as #1 % % \pbs_pdflastobj: % inserts object ID of PDF object created/processed during most recent call % of \pbs_pdfobj:nnn % % -------- % % \pbs_pdfannot:nnnn % #1: width, #2: height, #3: depth, #4: dictionary (key-value) % % \pbs_pdflastann: % inserts object ID of PDF object created during most recent call of % \pbs_pdfannot:nnnn % % -------- % % \pbs_appendtofields:n % #1 object ID of PDF annotation; annotations of /Subtype/Widget % should be appended to the /Fields array of the global /AcroForm dictionary % % -------- % % \pbs_pdflink:nn % #1: dictionary (key-value), #2: text % % -------- % % \pbs_pdfxform:nnnnn % #1: add pgf/tikz resources (transparency, shading)? (1|0) %dvipdfmx/xetex % #2: used as PDF annotation appearance? (1|0) %dvips/pdftex % #3: additional resources %all BUT dvips % #4: additional dictionary entries % #5: savebox number % creates PDF Form XObject from savebox content % % \pbs_pdflastxform: % inserts object ID of PDF Form XObject created during most recent call of % \pbs_pdfxform:nnnnn % % \pbs_pdfrefxform:n % #1: xform object ID % inserts the PDF Form XObject into the current content stream, that is, % typsets the PDF Form XObject % % -------- % % \pbs_pdfximage:n % #1: bitmap image file name % creates PDF Image XObject from /bitmap/ file for use as bitmap resource % in 3D context % % \pbs_pdflastximage: % inserts object ID of PDF Image XObject created during most recent call of % \pbs_pdfximage:n % % -------- % % \pbs_literal:nn % #1: keyword (empty) | direct | page % #2: raw PDF/Postscript code % implements \pdfliteral{...}, \pdfliteral direct {...}, % \pdfliteral page {...} from pdfTeX, and % \special{" ...} and \special{ps: ...} from dvips % % -------- % % \pbs_pdfcatalog:n % #1: dictionary (key-value) % % -------- % % marked content BDC/EMC operators % \pbs_pdfbdc:nn ... % ... \pbs_pdfemc: % #1: tag, #2: properties dictionary obj ID % % -------- % % alternative \AtEndDvi % \pbs_at_end_dvi:n % #1: \specials or \write to be inserted on the very last page % % -------- % % \pbs_add_form_font: (pdfLaTeX, LuaLaTeX) % adds current font as a resource to the global /AcroForm dict, allowing % the font to be used in PDF Forms (theoretically, see % https://acrobat.uservoice.com/forums/590923-acrobat-for-windows-and-mac/ % suggestions/33077827-bug-in-text-field-forms-embedded-opentype-font ) % % \pbs_last_form_font: (pdfLaTeX, LuaLaTeX) % expands to current font's resource name; to be used in the /DA (...) % entry of the Form dictionary % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License. % % The latest version of this license is in % http://mirrors.ctan.org/macros/latex/base/lppl.txt % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is A. Grahn. \RequirePackage{expl3} \RequirePackage{l3keys2e} \def\g@pbs@date@tl{2019/02/21} \def\g@pbs@version@tl{0.27} \ProvidesExplPackage{pdfbase}{\g@pbs@date@tl}{\g@pbs@version@tl} {driver independent access to low-level PDF features} \int_new:N\g_pbs_page_int %abs. page counter %creating global definitions \cs_new:Npn\pbs@newkey#1#2{\tl_gset:cx{#1}{#2}} \msg_set:nnn{pdfbase}{rerun}{Rerun~to~get~internal~references~right!} %LaTeX2e wrapper \cs_new_nopar:Npn\pbs@seq@push@cx#1#2{ \seq_if_exist:cF{#1}{\seq_new:c{#1}} \seq_gput_right:cx{#1}{#2} } %wrong image file type for Image XObject generation \msg_gset:nnn{pdfbase}{wrong~image~resource}{ Image~resource~file\\~~'#1'\\has~wrong~type.\\\\ Driver~#2~only~accepts~files~of~type\\#3\\ as~image~resources. } %pdfTeX version check \sys_if_engine_pdftex:T{ \int_compare:nT{\pdftexversion<130}{ \msg_interrupt:nnn{pdfbase~error}{pdfTeX,~version~>=~1.30~required.}{} } } % page (bop, eop) hooks \cs_new_protected:Nn\pbs_bop_action:n{\seq_gput_right:Nn\g_pbs_bop_seq{#1}} \cs_new_protected:Nn\pbs_eop_action:n{\seq_gput_right:Nn\g_pbs_eop_seq{#1}} \seq_new:N\g_pbs_bop_seq \seq_new:N\g_pbs_eop_seq % own AtEndDvi implementation \cs_new_protected:Nn\pbs_at_end_dvi:n{\seq_gput_right:Nn\g_pbs_eod_seq{#1}} \seq_new:N\g_pbs_eod_seq \pbs@newkey{pbs@last@page}{0} % AtEndDvi check \AtBeginDocument{ \iow_now:Nx\@mainaux{ \token_to_str:N\providecommand\token_to_str:N\pbs@newkey[2]{} } \iow_now:Nx\@mainaux{ \token_to_str:N\providecommand\token_to_str:N\pbs@seq@push@cx[2]{} } \iow_now:Nx\@mainaux{ \token_to_str:N\providecommand\token_to_str:N\pbs@at@end@dvi@check{} } \iow_now:Nx\@mainaux{\token_to_str:N\pbs@at@end@dvi@check} \cs_new_protected:Npn\pbs@at@end@dvi@check{ \bool_if:nT{ !\tl_if_exist:NTF\pbs@last@page{ \int_compare_p:n{\pbs@last@page=\g_pbs_page_int} }{ \c_false_bool } }{ \cs_if_exist:NF\g_pbs_rerunwarned_tl{ \tl_new:N\g_pbs_rerunwarned_tl \msg_warning:nn{pdfbase}{rerun} } } } } %%%%%%%%%%%%%%%%% %package options %%%%%%%%%%%%%%%%% %unknown package option error message \msg_gset:nnnn{pdfbase}{unknown~package~option}{Unknown~package~option~`#1'.}{ Package option~'#1'~is~unknown;\\ perhaps~it~is~spelled~incorrectly. } \bool_new:N\g_pbs_pkgbigfiles_bool \bool_new:N\g_pbs_dvipdfmx_bool \bool_new:N\g_pbs_dvisvgm_bool \bool_new:N\g_pbs_lscape_bool %if we are inside landscape env \AtBeginDocument{ \cs_if_exist:NT\landscape{% \tl_put_right:Nn\landscape{\bool_gset_true:N\g_pbs_lscape_bool} \tl_put_left:Nn\endlandscape{\bool_gset_false:N\g_pbs_lscape_bool} } } \keys_define:nn{pdfbase}{ xetex .code:n = {}, %dummy, we use engine test instead dvipdfmx .choice:, dvipdfmx / true .code:n = { \bool_gset_true:N\g_pbs_dvipdfmx_bool \bool_gset_false:N\g_pbs_dvisvgm_bool }, dvipdfmx / false .code:n = {\bool_gset_false:N\g_pbs_dvipdfmx_bool}, dvipdfmx .default:n = {true}, dvisvgm .choice:, dvisvgm / true .code:n = { \bool_gset_true:N\g_pbs_dvisvgm_bool \bool_gset_false:N\g_pbs_dvipdfmx_bool }, dvisvgm / false .code:n = {\bool_gset_false:N\g_pbs_dvisvgm_bool}, dvisvgm .default:n = {true}, bigfiles .bool_gset:N = \g_pbs_pkgbigfiles_bool, unknown .code:n = { \msg_error:nnx{pdfbase}{unknown~package~option}{\l_keys_key_tl} } } \ProcessKeysOptions{pdfbase} \sys_if_output_pdf:T{ \bool_gset_false:N\g_pbs_dvipdfmx_bool \bool_gset_false:N\g_pbs_dvisvgm_bool } \sys_if_engine_xetex:T{ \bool_if:NF\g_pbs_dvisvgm_bool{\bool_gset_true:N\g_pbs_dvipdfmx_bool} } \cs_new_nopar:Nn\pbs_first_of_two:nn{#1} %helpers \cs_new_nopar:Nn\pbs_second_of_two:nn{#2} \cs_new_nopar:Nn\pbs_insert_properties_entry:{} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %commands for creating PDF objects, annots etc. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \sys_if_output_pdf:TF{ %in LuaTeX-0.95.0, pdfTeX primitives got new names \bool_lazy_and:nnT{ \sys_if_engine_luatex_p: }{ !\int_compare_p:n{\luatexversion<95} }{ \cs_set_protected:Npn\pdfnames{\pdfextension~names~} \cs_set_protected:Npn\pdfobj{\pdfextension~obj~} \cs_set_protected:Npn\pdfrefobj{\pdfextension~refobj~} \cs_set_protected:Npn\pdfannot{\pdfextension~annot~} \cs_set_protected:Npn\pdfstartlink{\pdfextension~startlink~} \cs_set_protected:Npn\pdfendlink{\pdfextension~endlink\relax} \cs_set_protected:Npn\pdfliteral{\pdfextension~literal~} \cs_set_protected:Npn\pdfcatalog{\pdfextension~catalog~} \cs_set:Npn\pdflastlink{\numexpr\pdffeedback~lastlink\relax} \cs_set:Npn\pdflastobj{\numexpr\pdffeedback~lastobj\relax} \cs_set:Npn\pdflastannot{\numexpr\pdffeedback~lastannot\relax} \cs_set:Npn\pdfpageref{\numexpr\pdffeedback~pageref\relax} \cs_set:Npx\pdfpageresources{\pdfvariable~pageresources} \cs_set_eq:NN\pdfximage\saveimageresource \cs_set_eq:NN\pdfrefximage\useimageresource \cs_set_eq:NN\pdflastximage\lastsavedimageresourceindex \cs_set_eq:NN\pdflastximagepages\lastsavedimageresourcepages \cs_set_eq:NN\pdfxform\saveboxresource \cs_set_eq:NN\pdfrefxform\useboxresource \cs_set_eq:NN\pdflastxform\lastsavedboxresourceindex \cs_set:Npn\pdffontobjnum{\pdffeedback~fontobjnum} } %helper func to remove `0 R' part from pdf obj reference \cs_new_nopar:Nn\pbs_reftonum:n{\_pbs_reftonum:f{#1}} \cs_new_nopar:Nn\_pbs_reftonum:n{\exp_after:wN\_pbs_reftonum:w#1} \cs_generate_variant:Nn\_pbs_reftonum:n{f} \cs_new_nopar:Npn\_pbs_reftonum:w #1~0~R{#1} %literal PDF code into content stream, no saving of graphics state \cs_new_protected_nopar:Nn\pbs_literal:nn{ % #1: empty (`'), `direct' or `page' \str_case:nnF{#1}{ % #2: raw PDF % `direct' inserts raw pdf code without translating origin (0,0) to % current position: origin is lower left page corner {direct}{\pdfliteral~direct~{#2}} % same as above, but closing text object if necessary {page}{\pdfliteral~page~{#2}} }{ % closing text object if necessary and setting current % location's coordinates to (0,0) \pdfliteral{#2} } } \cs_new_protected_nopar:Nn\pbs_pdfobj:nnn{ \tl_clear:N\l_pbs_usenum_tl \tl_if_blank:oF{#1}{ \tl_set:Nx\l_pbs_usenum_tl{useobjnum~\pbs_reftonum:n{#1}} } \bool_if:nTF{\tl_if_blank_p:o{#1}&&\tl_if_blank_p:o{#3}}{ \pdfobj~reserveobjnum }{ \str_case:nn{#2}{ {dict}{\immediate\pdfobj~\l_pbs_usenum_tl~{<<#3>>}} {array}{\immediate\pdfobj~\l_pbs_usenum_tl~{[#3]}} {stream}{\immediate\pdfobj~\l_pbs_usenum_tl~stream~ attr{\pbs_first_of_two:nn#3}~{\pbs_second_of_two:nn#3} } {fstream}{\immediate\pdfobj~\l_pbs_usenum_tl~stream~ attr{\pbs_first_of_two:nn#3}~file~{\pbs_second_of_two:nn#3} } } } \tl_gset:Nx\g_pbs_pdflastobj_tl{\the\pdflastobj\space 0~R} } \cs_new_protected_nopar:Nn\pbs_pdfannot:nnnn{ %dumb dummy Widget, workaround for AR bug; %see https://forums.adobe.com/message/5787612#5787612 \str_if_eq_x:nnF{\cs_if_exist_use:N\ocgbase_insert_oc:}{}{ \immediate\pdfannot~width~3pt~height~3pt~depth~\c_zero_dim { /Ff~65537/FT/Btn/Subtype/Widget } } \immediate\pdfannot~width~#1~height~#2~depth~#3 { \cs_if_exist_use:N\ocgbase_insert_oc:~#4} \tl_gset:Nx\g_pbs_pdflastann_tl{\the\pdflastannot\space 0~R} } \cs_new_protected:Nn\pbs_pdflink:nn{ %dumb dummy Widget, workaround for AR bug; %see https://forums.adobe.com/message/5787612#5787612 \str_if_eq_x:nnF{\cs_if_exist_use:N\ocgbase_insert_oc:}{}{ \immediate\pdfannot~width~3pt~height~3pt~depth~\c_zero_dim { /Ff~65537/FT/Btn/Subtype/Widget } } \immediate\pdfstartlink~user~{ \cs_if_exist_use:N\ocgbase_insert_oc:~#1}#2\pdfendlink } \cs_new_protected_nopar:Nn\pbs_pdfxform:nnnnn{ % #1 not used %additional resources \tl_set:Nx\l_tmpa_tl{\the\pdfpageresources~#3}\tl_trim_spaces:N\l_tmpa_tl %additional dict entries \tl_set:Nx\l_tmpb_tl{#4} \tl_trim_spaces:N\l_tmpb_tl \int_compare:nT{#2>\c_zero}{\immediate} \pdfxform~ \str_if_eq_x:nnF{\l_tmpb_tl}{}{attr~{\l_tmpb_tl}~} \str_if_eq_x:nnF{\l_tmpa_tl}{}{resources~{\l_tmpa_tl}~}#5 \tl_gset:Nx\g_pbs_pdflastxform_tl{\the\pdflastxform\space 0~R} } \cs_new_protected_nopar:Nn\pbs_pdfrefxform:n{% #1: xform obj ID \hbox_overlap_right:n{\smash{\pdfrefxform\pbs_reftonum:n{#1}}} } \cs_new_protected_nopar:Nn\pbs_pdfximage:n{ \filename@parse{#1} \tl_set:Nx\l_pbs_ext_tl{\tl_lower_case:n{\filename@ext}} \bool_if:nTF{ \str_if_eq_p:Vn\l_pbs_ext_tl{png} ||\str_if_eq_p:Vn\l_pbs_ext_tl{jpg} ||\str_if_eq_p:Vn\l_pbs_ext_tl{jpeg} ||\str_if_eq_p:Vn\l_pbs_ext_tl{jbig2} ||\str_if_eq_p:Vn\l_pbs_ext_tl{jb2} }{ \immediate\pdfximage{#1} \tl_gset:Nx\g_pbs_pdflastximage_tl{\the\pdflastximage\space 0~R} }{ \msg_error:nnnnn{pdfbase}{wrong~image~resource}{#1}{pdftex}{ png,~jpeg~and~jbig2 } } } \cs_new_protected_nopar:Nn\pbs_pdfcatalog:n{\pdfcatalog{#1}} \int_new:N\g_pbs_oc_int %object ID for marked content Properties \cs_new_protected_nopar:Nn\pbs_zap_properties:{ %strip /Properties dict from \group_begin: %/pdfpageresources \tl_set:Nx\l_pbs_temp_tl{\group_end: \global\pdfpageresources{ \exp_after:wN\_pbs_zap_properties:w\the\pdfpageresources/Properties<<>>. } }\l_pbs_temp_tl } \cs_new_nopar:Npn\_pbs_zap_properties:w#1/Properties<<#2>>#3{ \bool_if:nTF{\tl_if_empty_p:n{#2}&&\str_if_eq_p:nn{#3}{.}}{#1}{ #1\_pbs_zap_properties:w#3 } } \cs_new_protected_nopar:Nn\pbs_pdfbdc:nn{ \pdfliteral~page~{#1/rm@oc\int_use:N\g_pbs_oc_int\space BDC} %decide whether the current property is to be written to the page %resources or to the xobject resources, depending on whether marked content %is written to a page stream or to an xobject stream (for compatibility with %`xsavebox' package) \bool_if:nTF{ \cs_if_exist:NTF\xsb_count_props:{ \int_compare_p:n{\xsb_count_props:>\c_zero} }{ \c_false_bool } }{ \xsb_addto_props:n{/rm@oc\int_use:N\g_pbs_oc_int\space#2} }{ \iow_shipout_x:Nx\@mainaux{\token_to_str:N\pbs@seq@push@cx{ pbs@props@\exp_not:N\int_use:N\g_pbs_page_int }{/rm@oc\int_use:N\g_pbs_oc_int\space#2}} } \int_gincr:N\g_pbs_oc_int } \cs_new_protected_nopar:Nn\pbs_pdfemc:{\pdfliteral~page~{EMC}} %inserts /Properties <<...>> entry into page resources \cs_gset:Nn\pbs_insert_properties_entry:{ \pbs_zap_properties: %purge those from previous page \tl_set:Nx\l_tmpa_tl{\seq_if_exist:cT{pbs@props@\int_use:N\g_pbs_page_int}{ \seq_use:cn{pbs@props@\int_use:N\g_pbs_page_int}{~}}} \tl_trim_spaces:N\l_tmpa_tl \str_if_eq_x:nnF{\l_tmpa_tl}{}{ \group_begin: \tl_set:Nx\l_pbs_temp_tl{\group_end: \global\pdfpageresources{ \the\pdfpageresources /Properties<<\seq_if_exist:cT{pbs@props@\int_use:N\g_pbs_page_int}{ \seq_use:cn{pbs@props@\int_use:N\g_pbs_page_int}{~} }>> } }\l_pbs_temp_tl } } \cs_new_protected_nopar:Nn\pbs_add_form_font:{ \cs_if_exist:cF{pbs_form_font_\pdffontobjnum\font}{ \tl_new:c{pbs_form_font_\pdffontobjnum\font} \tl_gput_right:Nx\g_pbs_form_fonts_tl{ ~/FormFont\pdffontobjnum\font\space\pdffontobjnum\font\space 0~R } } \tl_gset:Nx\g_pbs_last_form_font_tl{/FormFont\pdffontobjnum\font} } \cs_new_nopar:Nn\pbs_last_form_font:{\g_pbs_last_form_font_tl} }{ %pgf + transparency related settings \bool_new:N\g_pbs_pgfloaded_bool \bool_gset_false:N\g_pbs_pgfloaded_bool \AtBeginDocument{ \@ifpackageloaded{pgf}{\bool_gset_true:N\g_pbs_pgfloaded_bool}{} } \int_new:N\g_pbs_obj_int %object ID \bool_if:NTF\g_pbs_dvipdfmx_bool{ %dvipdfmx/XeTeX %suppress any annotation growth through (x)dvipdfmx option/config var `g' \AtBeginDocument{\special{dvipdfmx:config~g~0}} %literal PDF code into content stream; open text objects are always closed \cs_new_protected_nopar:Nn\pbs_literal:nn{ % #1: empty (`'), `direct' or `page' \str_if_eq:nnTF{#1}{}{ % #2: raw PDF % set current location's coordinates to (0,0), while saving graphics % state before and re-instating after insertion (this is different from % \pdfliteral{...} \special{pdf:content~#2} }{ % `direct' works the same as `page': no origin translation, % no gs saving, but closing open text objects \special{pdf:code~#2} } } \cs_new_protected_nopar:Nn\pbs_pdfobj:nnn{ \tl_if_blank:oTF{#1}{ \tl_set:Nx\l_pbs_usenum_tl{@pbs@obj\int_use:N\g_pbs_obj_int} \int_gincr:N\g_pbs_obj_int }{ \tl_set:Nx\l_pbs_usenum_tl{#1} } \tl_if_blank:oF{#3}{ \str_case:nn{#2}{ {dict}{\special{pdf:obj~\l_pbs_usenum_tl\space<<#3>>}} {array}{\special{pdf:obj~\l_pbs_usenum_tl\space[#3]}} {stream}{\special{pdf:stream~\l_pbs_usenum_tl\space (\pbs_second_of_two:nn#3)<<\pbs_first_of_two:nn#3>> }} {fstream}{ \message{<\pbs_second_of_two:nn#3>} \special{pdf:fstream~\l_pbs_usenum_tl\space (\pbs_second_of_two:nn#3)<<\pbs_first_of_two:nn#3>> } } } } \tl_gset_eq:NN\g_pbs_pdflastobj_tl\l_pbs_usenum_tl } \cs_new_protected_nopar:Nn\pbs_pdfannot:nnnn{ \bool_if:NTF\g_pbs_lscape_bool{ %fix missing annotation rotation of (x)dvipdfmx on landscape pages \box_move_up:nn{\dim_eval:n{#2}}{\vbox:n{ %dumb dummy Widget, workaround for AR bug; %see https://forums.adobe.com/message/5787612#5787612 \str_if_eq_x:nnF{\cs_if_exist_use:N\ocgbase_insert_oc:}{}{ \special{pdf:ann~ width~3pt~height~3pt~depth~0pt~<> } } \special{pdf:ann~@pbs@obj\int_use:N\g_pbs_obj_int\space width~\dim_eval:n{#2+#3}\space height~\dim_eval:n{#1}\space depth~\dim_eval:n{\c_zero_dim}~<< \cs_if_exist_use:N\ocgbase_insert_oc:~#4>> } }} }{ %dumb dummy Widget, workaround for AR bug; %see https://forums.adobe.com/message/5787612#5787612 \str_if_eq_x:nnF{\cs_if_exist_use:N\ocgbase_insert_oc:}{}{ \special{pdf:ann~ width~3pt~height~3pt~depth~0pt~<> } } \special{pdf:ann~@pbs@obj\int_use:N\g_pbs_obj_int\space width~\dim_eval:n{#1}\space height~\dim_eval:n{#2}\space depth~\dim_eval:n{#3}~<<\cs_if_exist_use:N\ocgbase_insert_oc:~#4>> } } \tl_gset:Nx\g_pbs_pdflastann_tl{@pbs@obj\int_use:N\g_pbs_obj_int} \int_gincr:N\g_pbs_obj_int } \cs_new_protected:Nn\pbs_pdflink:nn{ %dumb dummy Widget, workaround for AR bug; %see https://forums.adobe.com/message/5787612#5787612 \str_if_eq_x:nnF{\cs_if_exist_use:N\ocgbase_insert_oc:}{}{ \special{pdf:ann~ width~3pt~height~3pt~depth~0pt~<> } } \special{pdf:bann~<<\cs_if_exist_use:N\ocgbase_insert_oc:~#1>>}#2 \special{pdf:eann} } \cs_new_protected_nopar:Nn\pbs_pdfxform:nnnnn{ % #2 not used \begin{picture}(0,0) \put(0,0){ \special{pdf:bxobj~@pbs@obj\int_use:N\g_pbs_obj_int\space width\space \dim_use:N\box_wd:N#5\space height\space\dim_use:N\box_ht:N#5\space depth\space \dim_use:N\box_dp:N#5 } \box_use:N#5 \tl_clear:N\l_tmpa_tl{} %transparency et al. for PGF \bool_if:nT{\int_compare_p:n{#1>\c_zero} && \g_pbs_pgfloaded_bool}{ \ifpgf@sys@pdf@extgs@exists \tl_set:Nn\l_tmpa_tl{/ExtGState~@pgfextgs} \fi \ifpgf@sys@pdf@patterns@exists \tl_put_right:Nn\l_tmpa_tl{/Pattern~@pgfpatterns} \fi \ifpgf@sys@pdf@colorspaces@exists \tl_put_right:Nn\l_tmpa_tl{/ColorSpace~@pgfcolorspaces} \fi } %additional resources \tl_put_right:Nx\l_tmpa_tl{~#3}\tl_trim_spaces:N\l_tmpa_tl \str_if_eq_x:nnF{\l_tmpa_tl}{}{ \special{pdf:put~@resources~<<\l_tmpa_tl>>} } %additional dict entries \tl_set:Nx\l_tmpa_tl{#4} \tl_trim_spaces:N\l_tmpa_tl \special{pdf:exobj %close form xobject \str_if_eq_x:nnF{\l_tmpa_tl}{}{<<\l_tmpa_tl>>} } } \end{picture} \tl_gset:Nx\g_pbs_pdflastxform_tl{@pbs@obj\int_use:N\g_pbs_obj_int} \int_gincr:N\g_pbs_obj_int } \cs_new_protected_nopar:Nn\pbs_pdfrefxform:n{\special{pdf:uxobj~#1}}% #1: xform obj ID \cs_new_protected_nopar:Nn\pbs_pdfximage:n{ \filename@parse{#1} \tl_set:Nx\l_pbs_ext_tl{\tl_lower_case:n{\filename@ext}} \bool_if:nTF{ \str_if_eq_p:Vn\l_pbs_ext_tl{png} ||\str_if_eq_p:Vn\l_pbs_ext_tl{jpg} ||\str_if_eq_p:Vn\l_pbs_ext_tl{jpeg} }{ \special{pdf:image~@pbs@obj\int_use:N\g_pbs_obj_int\space %move initial display off the page matrix~0.000001~0~0~0.000001~-1000000~-1000000~(#1)} \tl_gset:Nx\g_pbs_pdflastximage_tl{@pbs@obj\int_use:N\g_pbs_obj_int} \int_gincr:N\g_pbs_obj_int }{ \msg_error:nnnnn{pdfbase}{wrong~image~resource}{#1}{dvipdfmx/xetex}{ png~and~jpeg } } } \cs_new_protected_nopar:Nn\pbs_pdfcatalog:n{\special{pdf:put~@catalog~<<#1>>}} \int_new:N\g_pbs_oc_int %object ID \cs_new_protected_nopar:Nn\pbs_pdfbdc:nn{ \special{pdf:code~#1/rm@oc\int_use:N\g_pbs_oc_int\space BDC} \special{pdf:put~@resources~<< /Properties~<>>>} \int_gincr:N\g_pbs_oc_int } \cs_new_nopar:Nn\pbs_pdfemc:{\special{pdf:code~EMC}} }{ \bool_if:NTF\g_pbs_dvisvgm_bool{ \tl_gset:Nx\g_pbs_hash_tl{\token_to_str:N#} %insert literal Postscript code \cs_new_protected_nopar:Nn\pbs_literal:nn{ % #1: empty (`'), `direct' or `page' \str_if_eq:nnTF{#1}{}{ % #2: raw Postscript % set current location's coordinates to (0,0) and set unit vectors to % 1bp right and 1bp upwards; graphics state is saved before and % re-instated after insertion \special{"~#2} }{ % `direct' does the same as `page': no origin translation, % no gs saving \special{ps::~#2} } } \cs_new_protected_nopar:Nn\pbs_pdfannot:nnnn{ \special{dvisvgm:raw~{?nl}} } \cs_new_protected_nopar:Nn\pbs_pdfxform:nnnnn{ \makebox[\c_zero_dim][l]{ \raisebox{\c_zero_dim}[\c_zero_dim][\c_zero_dim]{ \special{dvisvgm:raw~{?nl}{?nl} < g~transform='translate(-{?x},-{?y})'~#4~ id='pbs@obj\int_use:N\g_pbs_obj_int'~class='xform' > } \box_use_drop:N#5 \special{dvisvgm:raw~{?nl}{?nl}} } } \tl_gset:Nx\g_pbs_pdflastxform_tl{\g_pbs_hash_tl pbs@obj\int_use:N\g_pbs_obj_int} \int_gincr:N\g_pbs_obj_int } \cs_new_protected_nopar:Nn\pbs_pdfrefxform:n{ \special{dvisvgm:raw~{?nl}} } }{ %dvips \bool_new:N\g_pbs_powerdot_bool %to cope with some powerdot oddity \@ifclassloaded{powerdot}{\bool_gset_true:N\g_pbs_powerdot_bool}{} \sys_if_engine_pdftex:TF{ \cs_new_nopar:Nn\pbs_filesize:n{\pdffilesize{#1}} \cs_new_nopar:Nn\pbs_filedump:nnn{\pdffiledump~offset~#1~length~#2~{#3}} }{ \sys_if_engine_luatex:T{ \RequirePackage{pdftexcmds} \cs_new_nopar:Nn\pbs_filesize:n{\pdf@filesize{#1}} \cs_new_nopar:Nn\pbs_filedump:nnn{\pdf@filedump{#1}{#2}{#3}} } } \AtBeginDocument{ \@ifpackageloaded{hyperref}{}{ %define `?pdfmark' operator as in file pdfmark.def from package `hyperref' \special{!~ systemdict~/pdfmark~known { userdict~/?pdfmark~systemdict~/exec~get~put }{ userdict~/?pdfmark~systemdict~/pop~get~put~ userdict~/pdfmark~systemdict~/cleartomark~get~put } ifelse } } \special{!~ %keeping track of xform nesting level true~setglobal~globaldict~/pbs@xform@level~0~put~false~setglobal } } \bool_if:NT\g_pbs_pkgbigfiles_bool{ \special{psfile=\jobname.pbsdat} %open auxiliary file \jobname.pbsdat for writing hex encoded streams of %the files to be embedded. This file is inserted into PS during dvips run \iow_new:N\g_pbs_mstreams_stream \iow_open:Nn\g_pbs_mstreams_stream{\jobname.pbsdat} \iow_now:Nn\g_pbs_mstreams_stream{ /M9D~1~dict~def~M9D~begin /o{mark/_objdef}bind~def/O{/type/stream/OBJ~pdfmark}bind~def /m~systemdict/mark~get~def /P{/ASCIIHexDecode~filter/PUT~pdfmark}bind~def /PP{/PUT~pdfmark}bind~def /C{/CLOSE~pdfmark}bind~def~end } } %insert literal Postscript code \cs_new_protected_nopar:Nn\pbs_literal:nn{ % #1: empty (`'), `direct' or `page' \str_if_eq:nnTF{#1}{}{ % #2: raw Postscript % set current location's coordinates to (0,0) and set unit vectors to % 1bp right and 1bp upwards; graphics state is saved before and % re-instated after insertion \special{"~#2} }{ % `direct' does the same as `page': no origin translation, % no gs saving \special{ps::~#2} } } \cs_new_protected_nopar:Nn\pbs_pdfobj:nnn{ \tl_clear:N\l_pbs_usenum_tl \tl_if_blank:oTF{#1}{ \tl_set:Nx\l_pbs_usenum_tl{{pbs@obj\int_use:N\g_pbs_obj_int}} \int_gincr:N\g_pbs_obj_int }{ \tl_set:Nx\l_pbs_usenum_tl{#1} } \tl_if_blank:oF{#3}{ \bool_if:nTF{ \g_pbs_pkgbigfiles_bool && \str_if_eq_p:nn{#2}{fstream} }{ \iow_now:Nx\g_pbs_mstreams_stream{ M9D~begin~o\l_pbs_usenum_tl O } }{ \special{ps:~mark~/_objdef~\l_pbs_usenum_tl\space/type \str_case:nn{#2}{ {dict}{/dict} {array}{/array} {stream}{/stream} {fstream}{/stream} }~ /OBJ~pdfmark } } \str_case:nn{#2}{ {dict}{\special{ps:~mark~\l_pbs_usenum_tl~<<#3>>/PUT~pdfmark}} {array}{ \special{ps:~mark~\l_pbs_usenum_tl~0~[#3]/PUTINTERVAL~pdfmark} } {stream}{\special{ps::[nobreak] ~mark~\l_pbs_usenum_tl~(\pbs_second_of_two:nn#3)/PUT~pdfmark~ ~mark~\l_pbs_usenum_tl~<<\pbs_first_of_two:nn#3>>/PUT~pdfmark }} {fstream}{ \tl_set:Nn\l_pbs_offset_tl{0} \tl_set:Nx\l_pbs_fsize_tl{\pbs_filesize:n{\pbs_second_of_two:nn#3}} \message{<\pbs_second_of_two:nn#3} %embed file in chunks of 32768 Bytes into PS as chunks of %65536 Bytes of HEX code \bool_while_do:nn{ \int_compare_p:n{\l_pbs_offset_tl<\l_pbs_fsize_tl} }{ \bool_if:NTF\g_pbs_pkgbigfiles_bool{ \iow_now:Nx\g_pbs_mstreams_stream{ m\l_pbs_usenum_tl (\pbs_filedump:nnn{\l_pbs_offset_tl}{32767}{ \pbs_second_of_two:nn#3 })P } }{ \special{ps: mark~ \l_pbs_usenum_tl~ (\pbs_filedump:nnn{\l_pbs_offset_tl}{32767}{ \pbs_second_of_two:nn#3 })~ /ASCIIHexDecode~filter~/PUT~ pdfmark } } \tl_set:Nx\l_pbs_offset_tl{\int_eval:n{\l_pbs_offset_tl+32767}} \message{.} } \bool_if:NTF\g_pbs_pkgbigfiles_bool{ \iow_now:Nx\g_pbs_mstreams_stream{ m\l_pbs_usenum_tl<<\pbs_first_of_two:nn#3>>PP~ m\l_pbs_usenum_tl~C~end } }{ \special{ps: mark~\l_pbs_usenum_tl~<<\pbs_first_of_two:nn#3>>~/PUT~pdfmark~ mark~\l_pbs_usenum_tl~/CLOSE~pdfmark } } \message{>} } } } \tl_gset_eq:NN\g_pbs_pdflastobj_tl\l_pbs_usenum_tl } \cs_new_protected_nopar:Nn\pbs_pdfannot:nnnn{ \group_begin: \dim_set:Nn\unitlength{1pt} \begin{picture}(0,0)% mark annotation rectangle \put(0,-\dim_to_decimal:n{#3}){ \special{ps:~currentpoint~/pbs@lly~exch~def~/pbs@llx~exch~def} } \put(\dim_to_decimal:n{#1},\dim_to_decimal:n{#2}){ \special{ps:~currentpoint~/pbs@ury~exch~def~/pbs@urx~exch~def} } \end{picture} \group_end: %dumb dummy Widget, workaround for AR bug; %see https://forums.adobe.com/message/5787612#5787612 \str_if_eq_x:nnF{\cs_if_exist_use:N\ocgbase_insert_oc:}{}{ \special{ps: mark~ /_objdef~{pbs@obj\int_use:N\g_pbs_obj_int} /Rect~[pbs@llx~pbs@lly~pbs@urx~pbs@ury] /Ff~65537/FT/Btn/Subtype/Widget /ANN~pdfmark } \int_gincr:N\g_pbs_obj_int } %the actual annotation \str_if_eq_x:nnF{#4}{}{ \special{ps: mark~ /_objdef~{pbs@obj\int_use:N\g_pbs_obj_int} /Rect~[pbs@llx~pbs@lly~pbs@urx~pbs@ury] \cs_if_exist_use:N\ocgbase_insert_oc:~#4 /ANN~pdfmark } \tl_gset:Nx\g_pbs_pdflastann_tl{{pbs@obj\int_use:N\g_pbs_obj_int}} \int_gincr:N\g_pbs_obj_int } } \cs_new_protected:Nn\pbs_pdflink:nn{ %dumb dummy Widget, workaround for AR bug; %see https://forums.adobe.com/message/5787612#5787612 \pbs_pdfannot:nnnn{3pt}{3pt}{0pt}{} \cs_if_exist:NTF\pdfmark{ \pdfmark[#2]{pdfmark=/ANN,Raw={ \cs_if_exist_use:N\ocgbase_insert_oc:~#1}} }{ \hbox_set:Nn\l_tmpb_box{#2} \pbs_pdfannot:nnnn{ \dim_use:N\box_wd:N\l_tmpb_box}{ \dim_use:N\box_ht:N\l_tmpb_box}{ \dim_use:N\box_dp:N\l_tmpb_box }{#1} \box_use_drop:N\l_tmpb_box } } \msg_set:nnn{pdfbase}{content~too~large}{ Line~\msg_line_number: :\\ Content~exceeds~paper~size~(width~and/or~height)\\ of~the~document~and~may~be~clipped~in~the~final\\ output. } \cs_new_protected_nopar:Nn\pbs_pdfxform:nnnnn{ % #1, #3 not used (resources are %this allows nesting \pbs_pdfxform:nnnnn{...} % managed by pdfmarks) \special{ps: gsave~ pbs@xform@level~0~eq~{/pbs@ctm@0~matrix~currentmatrix~def}~if~ pbs@ctm@0~setmatrix~ true~setglobal~ globaldict~/pbs@xform@level~pbs@xform@level~1~add~put~ false~setglobal } %rescale box to fit within the papersize while distilling \tl_gset:cx{scale_{pbs@obj\int_use:N\g_pbs_obj_int}}{\fp_eval:n{min(1.0, \dim_ratio:nn{\paperwidth}{\box_wd:N#5}, \dim_ratio:nn{\paperheight}{\box_ht:N#5+\box_dp:N#5} )}} \box_scale:Nnn#5{ \tl_use:c{scale_{pbs@obj\int_use:N\g_pbs_obj_int}} }{ \tl_use:c{scale_{pbs@obj\int_use:N\g_pbs_obj_int}} } \group_begin: %mark bbox of box#5 \dim_set:Nn\unitlength{1pt} \begin{picture}(0,0) \put(0,-\dim_to_decimal:n{\box_dp:N#5}){ \special{ps: currentpoint~/pbs@lly~exch~def~/pbs@llx~exch~def } } \put( \dim_to_decimal:n{\box_wd:N#5}, \dim_to_decimal:n{\box_ht:N#5} ){ \special{ps: currentpoint~/pbs@ury~exch~def~/pbs@urx~exch~def } } \end{picture} \group_end: %additional dict entries \tl_set:Nx\l_tmpa_tl{#4} \tl_trim_spaces:N\l_tmpa_tl \special{ps: gsave~ currentpoint~/pbs@cury~exch~def~/pbs@curx~exch~def~ %translate graphics to upper left page corner \bool_if:nF{\g_pbs_powerdot_bool||\g_pbs_lscape_bool}{ { pbs@llx~neg~pbs@ury~neg~translate~ Resolution~neg~VResolution~neg~translate %one inch left, one inch up }?pdfmark~ } %distill graphics into XObject gsave~pbs@curx~pbs@cury~translate~ %move origin (0,0) to the current mark~ %position /_objdef~{pbs@obj\int_use:N\g_pbs_obj_int} /BBox~[ pbs@llx~pbs@curx~sub~pbs@lly~pbs@cury~sub~ pbs@urx~pbs@curx~sub~pbs@ury~pbs@cury~sub ] %insert additional dict entries (the Distiller way) \str_if_eq_x:nnF{\l_tmpa_tl}{}{ product~(Distiller)~search~{pop~pop~pop~\l_tmpa_tl}{pop}ifelse } /BP~pdfmark~grestore~ \int_compare:nT{#2>\c_zero}{ %operations needed if used as annotation appearance { isls{%landscape mode (powerdot, geometry /w landscape option) /pbs@dxdy~{ pbs@urx~pbs@llx~sub~abs~ pbs@ury~pbs@lly~sub~abs~div }~bind~def /pbs@dydx~{1~pbs@dxdy~div}~bind~def /pbs@cx~{pbs@urx~pbs@llx~add~2~div}~bind~def /pbs@cy~{pbs@ury~pbs@lly~add~2~div}~bind~def %graphics needs to be rescaled for some reason ... [pbs@dxdy~0~0~pbs@dydx~1~pbs@dxdy~sub~pbs@cx~mul~ 1~pbs@dydx~sub~pbs@cy~mul]~concat %... rotated by 270 degrees ... [0~-1~1~0~pbs@cx~pbs@cy~sub~pbs@cx~pbs@cy~add]~concat %... and flipped around vertical axis [-1~0~0~1~pbs@llx~pbs@urx~add~0]~concat }{%flip around horizontal axis in portrait mode [1~0~0~-1~0~pbs@lly~pbs@ury~add]~concat }ifelse }?pdfmark } } \begin{picture}(0,0)\put(0,0){\box_use:N#5}\end{picture} \special{ps:~mark~/EP~pdfmark~grestore} %insert additional dict entries (the Ghostscript way) \str_if_eq_x:nnF{\l_tmpa_tl}{}{ \special{ps: product~(Ghostscript)~search~{ pop~pop~pop~ mark~{pbs@obj\int_use:N\g_pbs_obj_int}~<<\l_tmpa_tl>>~/PUT~pdfmark }{pop}ifelse } } \tl_gset:Nx\g_pbs_pdflastxform_tl{{pbs@obj\int_use:N\g_pbs_obj_int}} \int_gincr:N\g_pbs_obj_int \int_compare:nT{#2>\c_zero}{ %Form XObjects for use as annotation appearances require that %dvips generated PostScript to be further processed with ps2pdf %must not have the exaggerated dpi resolution resulting from dvips %option `-Ppdf'. \tl_if_exist:NF\g_pbs_dpiwarned_tl{ \tl_new:N\g_pbs_dpiwarned_tl \pbs_at_end_dvi:n{\special{ps::[nobreak]\pbs_dpiwarning:}} } } \special{ps: true~setglobal~ globaldict~/pbs@xform@level~pbs@xform@level~1~sub~put~ false~setglobal~ grestore } } \cs_new_protected_nopar:Nn\pbs_pdfrefxform:n{% #1: xform obj ID %The /SP pdfmark for placement of Form XObjects works reliably only %since gs-9.14. As gs-9.14 had some other TeX-related issues, we %require 9.15. \tl_if_exist:NF\g_pbs_gsoldwarned_tl{ \tl_new:N\g_pbs_gsoldwarned_tl \pbs_at_end_dvi:n{\special{ps::[nobreak]\pbs_gsoldwarning:}} } \special{ps: gsave~currentpoint~translate~1~\tl_use:c{scale_#1}~div~dup~scale~ mark~#1~/SP~pdfmark~grestore } } \cs_new_protected_nopar:Nn\pbs_pdfximage:n{ \filename@parse{#1} \tl_set:Nx\l_pbs_ext_tl{\tl_lower_case:n{\filename@ext}} \bool_if:nTF{ \str_if_eq_p:Vn\l_pbs_ext_tl{ps} ||\str_if_eq_p:Vn\l_pbs_ext_tl{eps} }{ \special{ps: mark~/_objdef~{pbs@obj\int_use:N\g_pbs_obj_int}~/NI~pdfmark } \special{psfile=#1~hsize=0~vsize=0} \special{ps: { 0~0~1~[1~0~0~1~0~0]~{}~image~%empty dummy, in case #1 is not }?pdfmark %a valid raster image file } \tl_gset:Nx\g_pbs_pdflastximage_tl{{pbs@obj\int_use:N\g_pbs_obj_int}} \int_gincr:N\g_pbs_obj_int }{ \msg_error:nnxxx{pdfbase}{wrong~image~resource}{#1}{dvips}{ Postscript~(ps/eps)~with~bitmapped~content } } } \cs_new_protected_nopar:Nn\pbs_pdfcatalog:n{ \special{ps:~mark~{Catalog}~<<#1>>~/PUT~pdfmark} } %marked content BDC/EMC operators %require Ghostscript v. >= 9.15 \cs_new_protected_nopar:Nn\pbs_pdfbdc:nn{ \special{ps:~mark~#1~#2~/BDC~pdfmark} \tl_if_exist:NF\g_pbs_gsoldwarned_tl{ \tl_new:N\g_pbs_gsoldwarned_tl \pbs_at_end_dvi:n{\special{ps::[nobreak]\pbs_gsoldwarning:}} } } \cs_new_nopar:Nn\pbs_pdfemc:{\special{ps:~mark~/EMC~pdfmark}} } } } \cs_new_nopar:Nn\pbs_pdflastobj:{\g_pbs_pdflastobj_tl} \cs_new_nopar:Nn\pbs_pdflastann:{\g_pbs_pdflastann_tl} \cs_new_nopar:Nn\pbs_pdflastxform:{\g_pbs_pdflastxform_tl} \cs_new_nopar:Nn\pbs_pdflastximage:{\g_pbs_pdflastximage_tl} %adding AcroForm dict to PDF Catalog \tl_new:N\g_pbs_fields_tl %takes object IDs of Fields (aka annots with \tl_new:N\g_pbs_form_fonts_tl %name tree of font resources used in text fields \pbs_at_end_dvi:n{ \tl_if_empty:NF\g_pbs_fields_tl{ \pbs_pdfobj:nnn{}{array}{\g_pbs_fields_tl} \pbs_pdfcatalog:n{ /AcroForm~<< /Fields~\pbs_pdflastobj:/NeedAppearances~false~ \tl_if_empty:NF\g_pbs_form_fonts_tl{ /DR~<> >> } >> } } } \cs_new_protected_nopar:Nn\pbs_appendtofields:n{ \tl_gput_left:Nx\g_pbs_fields_tl{#1\space} } %modify output routine for output box insertions \bool_new:N\l_pbs_is_vertical_bool \cs_set_eq:NN\pbs_outputpage_orig:\@outputpage \cs_set_nopar:Npn\@outputpage{ \int_gincr:N\g_pbs_page_int \iow_now:Nx\@mainaux{ \token_to_str:N\pbs@newkey{pbs@last@page}{\int_use:N\g_pbs_page_int} } \box_if_vertical:cTF{@outputbox}{ \bool_set_true:N\l_pbs_is_vertical_bool }{ \bool_set_false:N\l_pbs_is_vertical_bool } \hbox_set:Nn\@outputbox{ %begin of page \hbox_overlap_right:n{\seq_map_inline:Nn\g_pbs_bop_seq{##1}} \box_use_drop:N\@outputbox %end of page \hbox_overlap_right:n{\seq_map_inline:Nn\g_pbs_eop_seq{##1}} } \bool_if:NT\l_pbs_is_vertical_bool{ \vbox_set:Nn\@outputbox{\box_use_drop:N\@outputbox} } \pbs_outputpage_orig: } \RequirePackage{atbegshi} \AtBeginDocument{ \AtBeginShipout{ \AtBeginShipoutAddToBoxForeground{ %insert /Properties into current page's resources \pbs_insert_properties_entry: %end of dvi (last page) \int_compare:nT{\pbs@last@page=\g_pbs_page_int}{ \seq_map_variable:NNn\g_pbs_eod_seq\l_tmpa_tl{\l_tmpa_tl} } } } } \group_begin: \char_set_catcode_active:N\+\let+\space \cs_new_nopar:Nx\pbs_gsoldwarning:{ {product~(Ghostscript)~search~{pop~pop~pop~true}{pop~false}ifelse~ revision~915~lt~and~{ (\token_to_str:N\n @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\token_to_str:N\n @@++++++++++++Warning:+Ghostscript+too+old!++++++++++++@@\token_to_str:N\n @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\token_to_str:N\n @@+++++++++++++++++++++++++++++++++++++++++++++++++++++@@\token_to_str:N\n @@+Ghostscript+version+>=+9.15.+required!++++++++++++++@@\token_to_str:N\n @@+++++++++++++++++++++++++++++++++++++++++++++++++++++@@\token_to_str:N\n @@+Various+advanced+PDF+features+such+as+Layers+(OCGs)+@@\token_to_str:N\n @@+and+animations+may+not+work.++++++++++++++++++++++++@@\token_to_str:N\n @@+++++++++++++++++++++++++++++++++++++++++++++++++++++@@\token_to_str:N\n @@+Get+current+version+from++++++++++++++++++++++++++++@@\token_to_str:N\n @@+http://www.ghostscript.com/download+++++++++++++++++@@\token_to_str:N\n @@+++++++++++++++++++++++++++++++++++++++++++++++++++++@@\token_to_str:N\n @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\token_to_str:N\n) print}~if}~?pdfmark } \cs_new_nopar:Nx\pbs_dpiwarning:{ {Resolution~1200~gt~VResolution~1200~gt~or~product~(Ghostscript)~ search~{pop~pop~pop~true}{pop~false}ifelse~and~{ (\token_to_str:N\n @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\token_to_str:N\n @@+++++Warning:+DVI+resolution+greater+than+1200+dpi!+++++@@\token_to_str:N\n @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\token_to_str:N\n @@++++++++++++++++++++++++++++++++++++++++++++++++++++++++@@\token_to_str:N\n @@+PDF+Annotation+appearances+(buttons,+animation+frames)+@@\token_to_str:N\n @@+may+be+poorly+scaled,+clipped+or+invisible.++++++++++++@@\token_to_str:N\n @@++++++++++++++++++++++++++++++++++++++++++++++++++++++++@@\token_to_str:N\n @@+Dvips+should+be+called+either+without+option+`-Ppdf':++@@\token_to_str:N\n @@++++++++++++++++++++++++++++++++++++++++++++++++++++++++@@\token_to_str:N\n @@+++dvips+\jobname\token_to_str:N\n @@++++++++++++++++++++++++++++++++++++++++++++++++++++++++@@\token_to_str:N\n @@+or+with+a+different+resolution+setting,+e.g.:++++++++++@@\token_to_str:N\n @@++++++++++++++++++++++++++++++++++++++++++++++++++++++++@@\token_to_str:N\n @@+++dvips+-Ppdf+-D1200+\jobname\token_to_str:N\n @@++++++++++++++++++++++++++++++++++++++++++++++++++++++++@@\token_to_str:N\n @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\token_to_str:N\n) print}~if}~?pdfmark } \group_end: