%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % pdfbase.sty % % driver independent access to low-level pdf features % % Copyright 2015--\today, Alexander Grahn % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Support package for media9 and ocgx2. % % 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, % 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: content (dict [key-value], string, file); if #3 && #1 are both empty, % an object reference will be reserved for later use as #1 % % \pbs_pdflastobj: % inserts ID of PDF object created/processed during most recent call of % \pbs_pdfobj:nnn % % -------- % % \pbs_pdfannot:nnnn % #1: width, #2: height, #3: depth, #4: dict (key-value) % % \pbs_pdflastann: % inserts ID of PDF object created during most recent call of % \pbs_pdfannot:nnnn % % -------- % % \pbs_pdflink:nn % #1: dict (key-value), #2: text % % -------- % % \pbs_pdfxform:nn % #1: used as PDF annotation appearance ? (1|0) % #2: savebox number % % creates PDF Form XObject from savebox content % % \pbs_pdflastxform: % inserts ID of PDF Form XObject created during most recent call of % \pbs_pdfxform:nn % % \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 file name % % \pbs_pdflastximage: % inserts ID of PDF Image XObject created during most recent call of % \pbs_pdfximage:n % % -------- % % \pbs_pdfcatalog:n % #1: dict (key-value) % % -------- % % marked content BDC/EMC operators % \pbs_pdfbdc:nn ... \pbs_pdfemc: % #1: tag, #2: properties dict obj ID % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 % of this license or (at your option) any later version. % The latest version of this license is in % http://mirrors.ctan.org/help/Catalogue/licenses.lppl.html % and version 1.3 or later is part of all distributions of LaTeX % version 2005/12/01 or later. % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is A. Grahn. \RequirePackage{expl3} \RequirePackage{l3regex} \RequirePackage{l3keys2e} \RequirePackage{atbegshi} \RequirePackage{atenddvi} \def\g@pbs@date@tl{2016/02/25} \def\g@pbs@version@tl{0.5} \ProvidesExplPackage{pdfbase}{\g@pbs@date@tl}{\g@pbs@version@tl} {driver independent access to low-level PDF features} %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.}{} } } %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 \keys_define:nn{pdfbase}{ xetex .bool_gset:N = \g_pbs_dvipdfmx_bool, dvipdfmx .bool_gset:N = \g_pbs_dvipdfmx_bool, bigfiles .choice:, bigfiles / true .code:n = {\bool_gset_true:N\g_pbs_pkgbigfiles_bool}, bigfiles / false .code:n = {\bool_gset_false:N\g_pbs_pkgbigfiles_bool}, bigfiles .default:n = {true}, unknown .code:n = { \msg_error:nnx{pdfbase}{unknown~package~option}{\l_keys_key_tl} } } \ProcessKeysOptions{pdfbase} \sys_if_engine_xetex:T{\bool_gset_true:N\g_pbs_dvipdfmx_bool} %commands for creating PDF objects, annots etc. \sys_if_output_pdf:TF{ %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} % \cs_new_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~{#3}} {fstream}{\immediate\pdfobj~\l_pbs_usenum_tl~stream~file~{#3}} } } \tl_gset:Nx\g_pbs_pdflastobj_tl{\the\pdflastobj\space 0~R} } \cs_new_nopar:Nn\pbs_pdfannot:nnnn{ \immediate\pdfannot~width~#1~height~#2~depth~#3 {#4} \tl_gset:Nx\g_pbs_pdflastann_tl{\int_use:c{pdflastannot}~0~R} } \cs_new:Nn\pbs_pdflink:nn{ \immediate\pdfstartlink~user~{#1}#2\pdfendlink } \cs_new_nopar:Nn\pbs_pdfxform:nn{ \int_compare:nT{#1>\c_zero}{\immediate} \pdfxform~resources~{\the\pdfpageresources}~#2 \tl_gset:Nx\g_pbs_pdflastxform_tl{\int_use:c{pdflastxform}~0~R} } \cs_new:Nn\pbs_pdfrefxform:n{% #1: xform obj ID \begin{picture}(0,0)\put(0,0){\pdfrefxform\pbs_reftonum:n{#1}}\end{picture} } \cs_new_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{\int_use:c{pdflastximage}~0~R} }{ \msg_error:nnnnn{pdfbase}{wrong~image~resource}{#1}{pdftex}{ png,~jpeg~and~jbig2 } } } \cs_new_nopar:Nn\pbs_pdfrefximage:n{% #1: xform obj ID \hbox_overlap_right:n{ \vbox_to_zero:n{\vss\pdfrefximage\pbs_reftonum:n{#1}} } } \cs_new_nopar:Nn\pbs_pdfcatalog:n{\pdfcatalog{#1}} \int_new:N\g_pbs_oc_int % object ID for marked content Properties \cs_new_nopar:Nn\pbs_pdfbdc:nn{ \pdfliteral~page~{#1/rm@oc\int_use:N\g_pbs_oc_int\space BDC} \tl_if_empty:NTF\g_pbs_ocmap_tl{ \tl_gset:Nx\g_pbs_ocmap_tl{/rm@oc\int_use:N\g_pbs_oc_int\space#2} }{ \tl_gput_right:Nx\g_pbs_ocmap_tl{~/rm@oc\int_use:N\g_pbs_oc_int\space#2} } \tl_set:Nx\l_pbs_pdfpageresources_tl{\the\pdfpageresources} \regex_replace_all:NnN\l_pbs_regex{}\l_pbs_pdfpageresources_tl \group_begin: \tl_set:Nx\l_pbs_temp_tl{\group_end: \global\pdfpageresources{ \l_pbs_pdfpageresources_tl /Properties<<\g_pbs_ocmap_tl>> } }\l_pbs_temp_tl \int_gincr:N\g_pbs_oc_int } \tl_new:N\g_pbs_ocmap_tl \regex_const:Nn\l_pbs_regex{\/Properties<<(?:\s*\/rm@oc[^R]+R\s*)+>>} \cs_new_nopar:Nn\pbs_pdfemc:{\pdfliteral~page~{EMC}} %modify output routine to purge \pdfpageresources from OCG properties \AtBeginShipout{\tl_gclear:N\g_pbs_ocmap_tl} \tl_gset:Nx\g_pbs_output_tl{\the\output} \global\output{ \g_pbs_output_tl \tl_if_blank:VT\g_pbs_ocmap_tl{ \tl_set:Nx\l_pbs_pdfpageresources_tl{\the\pdfpageresources} \regex_replace_all:NnN\l_pbs_regex{}\l_pbs_pdfpageresources_tl \group_begin: \tl_set:Nx\l_pbs_temp_tl{\group_end: \global\pdfpageresources{\l_pbs_pdfpageresources_tl} }\l_pbs_temp_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 \cs_new_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(#3)}} {fstream}{ \message{<#3>} \special{pdf:fstream~\l_pbs_usenum_tl\space(#3)} } } } \tl_gset_eq:NN\g_pbs_pdflastobj_tl\l_pbs_usenum_tl } \cs_new_nopar:Nn\pbs_pdfannot:nnnn{ \special{pdf:ann~@pbs@obj\int_use:N\g_pbs_obj_int\space width~#1\space height~#2\space depth~#3~<<#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:Nn\pbs_pdflink:nn{ \special{pdf:bann~<<#1>>}#2\special{pdf:eann} } \cs_new_nopar:Nn\pbs_pdfxform:nn{ \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#2\space height\space\dim_use:N\box_ht:N#2\space depth\space \dim_use:N\box_dp:N#2 } \box_use:N#2 \bool_if:NT\g_pbs_pgfloaded_bool{ % transparency et al. for PGF \tl_set:Nn\l_pbs_temp_tl{} \ifpgf@sys@pdf@extgs@exists \tl_set:Nn\l_pbs_temp_tl{/ExtGState~@pgfextgs} \fi \ifpgf@sys@pdf@patterns@exists \tl_put_right:Nn\l_pbs_temp_tl{/Pattern~@pgfpatterns} \fi \ifpgf@sys@pdf@colorspaces@exists \tl_put_right:Nn\l_pbs_temp_tl{/ColorSpace~@pgfcolorspaces} \fi \tl_if_blank:VF\l_pbs_temp_tl{ \special{pdf:put~@resources~<<\l_pbs_temp_tl>>} } } \special{pdf:exobj} } \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_nopar:Nn\pbs_pdfrefxform:n{\special{pdf:uxobj~#1}}% #1: xform obj ID \cs_new_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_gset_eq:NN\pbs_pdfrefximage:n\pbs_pdfrefxform:n \cs_new_nopar:Nn\pbs_pdfcatalog:n{\special{pdf:put~@catalog~<<#1>>}} \int_new:N\g_pbs_oc_int % object ID \cs_new_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}} }{ % 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}} } } \@ifpackageloaded{hyperref}{}{ %define `?pdfmark' operator as in file hdvips.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~ } } \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 /C{/CLOSE~pdfmark}bind~def~end } } \cs_new_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~(#3)/PUT~pdfmark~}} {fstream}{ \tl_set:Nn\l_pbs_offset_tl{0} \tl_set:Nx\l_pbs_fsize_tl{\pbs_filesize:n{#3}} \message{<#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}{#3})P } }{ \special{ps:~ mark~ \l_pbs_usenum_tl~ (\pbs_filedump:nnn{\l_pbs_offset_tl}{32767}{#3})~ /ASCIIHexDecode~filter~/PUT~ pdfmark~ } } \tl_set:Nx\l_pbs_offset_tl{\int_eval:n{\l_pbs_offset_tl+32767}} \message{.} } \message{>} \bool_if:NTF\g_pbs_pkgbigfiles_bool{ \iow_now:Nx\g_pbs_mstreams_stream{ m\l_pbs_usenum_tl~C~end } }{ \special{ps:~ mark~\l_pbs_usenum_tl~/CLOSE~pdfmark~ } } } } } \tl_gset_eq:NN\g_pbs_pdflastobj_tl\l_pbs_usenum_tl } \cs_new_nopar:Nn\pbs_pdfannot:nnnn{ \hbox_set:Nn\l_tmpa_box{ \box_move_down:nn{#3}{ \hbox_to_zero:n{ \special{ps:~currentpoint~/pbs@lly~exch~def~/pbs@llx~exch~def} } } \skip_horizontal:n{#1} \box_move_up:nn{#2}{ \hbox_to_zero:n{ \special{ps:~currentpoint~/pbs@ury~exch~def~/pbs@urx~exch~def} } } } \box_set_wd:Nn\l_tmpa_box{\c_zero_dim} \box_set_ht:Nn\l_tmpa_box{\c_zero_dim} \box_set_dp:Nn\l_tmpa_box{\c_zero_dim} \box_use_clear:N\l_tmpa_box \special{ps:~ mark~ /_objdef~{pbs@obj\int_use:N\g_pbs_obj_int} /Rect~[pbs@llx~pbs@lly~pbs@urx~pbs@ury] #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:Nn\pbs_pdflink:nn{ \cs_if_exist:NTF\pdfmark{ \pdfmark[#2]{pdfmark=/ANN,Raw={#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_clear:N\l_tmpb_box } } \cs_new_nopar:Nn\pbs_pdfxform:nn{ %mark bbox of box#2 \group_begin: \dim_set:Nn\unitlength{1pt} \begin{picture}(0,0) %mark BBox of the graphics \put(0,-\dim_to_decimal:n{\box_dp:N#2}){ \special{ps: currentpoint~/pbs@lly~exch~def~/pbs@llx~exch~def~ } } \put( \dim_to_decimal:n{\box_wd:N#2}, \dim_to_decimal:n{\box_ht:N#2} ){ \special{ps: currentpoint~/pbs@ury~exch~def~/pbs@urx~exch~def~ } } %define some length values in current PS coordinate units \put(0,0){ \special{ps: currentpoint~/origin@y~exch~def~/origin@x~exch~def~ } } \dim_set:Nn\unitlength{1in} \put(1,1){ \special{ps: currentpoint~origin@y~exch~sub~/one@inch@y~exch~def~ origin@x~sub~/one@inch@x~exch~def~ } } \end{picture} \group_end: \tl_gset:cx{origin:{pbs@obj\int_use:N\g_pbs_obj_int}}{ origin@pbs@\int_use:N\g_pbs_obj_int } \special{ps:~ gsave~ %keep a record of lower left corner coordinates true~setglobal~globaldict~ /origin@pbs@\int_use:N\g_pbs_obj_int~[currentpoint]~cvx~put~ false~setglobal~ %translate graphics to upper left page corner \bool_if:NF\g_pbs_powerdot_bool{ { pbs@llx~neg~pbs@ury~neg~translate~ one@inch@x~DVImag~div~neg~one@inch@y~DVImag~div~neg~translate }?pdfmark~ } %distill graphics into XObject mark~ /_objdef~{pbs@obj\int_use:N\g_pbs_obj_int} /BBox~[pbs@llx~pbs@lly~pbs@urx~pbs@ury] /BP~pdfmark~ % operations needed if used as annotation appearance \int_compare:nT{#1>\c_zero}{ { 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#2}\end{picture} \special{ps:~mark~/EP~pdfmark~grestore} \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_nopar:Nn\pbs_pdfrefxform:n{% #1: xform obj ID \special{ps:~ gsave~ currentpoint~pop~\tl_use:c{origin:#1}~pop~sub~ currentpoint~exch~pop~\tl_use:c{origin:#1}~exch~pop~sub~translate~ mark~#1~/SP~pdfmark~ grestore~ } } \cs_new_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_nopar:Nn\pbs_pdfrefximage:n{% #1: ximage obj ID %not implemented; how to insert an image XObject with pdfmarks? %\special{ps:~ % gsave~ % mark~#1~/SP~pdfmark~ % grestore~ %} } \cs_new_nopar:Nn\pbs_pdfcatalog:n{ \special{ps:~mark~{Catalog}~<<#1>>~/PUT~pdfmark} } %marked content BDC/EMC operators %require Ghostscript v. >= 9.15 \cs_new_nopar:Nn\pbs_pdfbdc:nn{ \tl_if_exist:NF\g_pbs_gsoldwarned_tl{ \tl_new:N\g_pbs_gsoldwarned_tl \AtEndDvi{\special{ps::[nobreak]\pbs_gsoldwarning:}} } \special{ps:~mark~#1~#2~/BDC~pdfmark} } \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} \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 @@+PDF+features+such+as+Layers+(OCGs)+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 } \group_end: