diff options
Diffstat (limited to 'macros/latex/contrib/magicwatermark/magicwatermark.sty')
-rw-r--r-- | macros/latex/contrib/magicwatermark/magicwatermark.sty | 453 |
1 files changed, 453 insertions, 0 deletions
diff --git a/macros/latex/contrib/magicwatermark/magicwatermark.sty b/macros/latex/contrib/magicwatermark/magicwatermark.sty new file mode 100644 index 0000000000..e40af7ea0b --- /dev/null +++ b/macros/latex/contrib/magicwatermark/magicwatermark.sty @@ -0,0 +1,453 @@ +\ProvidesExplPackage{magicwatermark}{2024/06/11}{1.2B}{magic watermark, author} + + +\msg_new:nnn {magicwatermark}{ Unable to parse } +{ + Unable~to~parse~this~list~parameter.^^J + #1 +} + +\msg_new:nnn {magicwatermark}{ Enable TikZ } +{ + tikz~option~has~been~disabled,^^J + style~will~be~ignored. +} + +\msg_new:nnn {magicwatermark}{ Load TikZ } +{ + Please~load~tikz~package~before~magicwatermark. +} + +\seq_new:N \l__mw_tmpa_seq +\seq_new:N \l__mw_tmpb_seq +\seq_new:N \l__mw_tmpc_seq +\seq_new:N \l__mw_tmpd_seq + + +\int_new:N \l__mw_tmpa_int +\int_new:N \l__mw_tmpb_int +\int_new:N \l__mw_tmpc_int +\int_new:N \l__mw_tmpd_int +\int_new:N \l__mw_tmpe_int + +\clist_new:N \l__mw_list_arabic_number_clist +\clist_new:N \l__mw_list_roman_number_clist +\clist_new:N \l__mw_list_range_clist +\clist_new:N \l__mw_list_expression_clist + + + + +\clist_new:N \l__mw_tmpa_clist +\clist_new:N \l__mw_tmpb_clist +\clist_new:N \l__mw_tmpc_clist + + +\tl_new:N \l__mw_tmpa_tl +\tl_new:N \l__mw_tmpb_tl +\tl_new:N \l__mw_tmpc_tl +\tl_new:N \g__mw_list_tl + +\tl_new:N \g__mw_style_tl +\tl_new:N \g__mw_content_tl + +\bool_new:N \g__mw_is_append_bool +\bool_set_false:N \g__mw_is_append_bool +\bool_new:N \g__mw_tikz_bool +\bool_set_true:N \g__mw_tikz_bool + +\regex_const:Nn \c__mw_arabic_numbers_regex { ^\d+$ } +\regex_const:Nn \c__mw_roman_numbers_regex { ^[ivxlcdm]+$ } + + + +\int_new:N \g__mw_last_page_int + +\AtBeginDocument{ + \int_compare:nTF { \@abspage@last = \number\maxdimen } + { + \int_gset:Nn \g__mw_last_page_int { 10 } + } + { + \int_gset:Nn \g__mw_last_page_int { \@abspage@last } + } +} + +\cs_new_protected:Npn \__mw_clist_deduplicate:N #1 +{ + \group_begin: + \clist_clear:N \l_tmpa_clist + \clist_map_inline:Nn #1 + { + \clist_if_in:NnF \l_tmpa_clist { ##1 } + { \clist_put_right:Nn \l_tmpa_clist { ##1 } } + } + \clist_gset_eq:NN #1 \l_tmpa_clist + \group_end: +} + + +\cs_new:Npn \__mw_list_parser_aux:n #1 { + + \clist_clear:N \l__mw_list_arabic_number_clist + \clist_clear:N \l__mw_list_roman_number_clist + \clist_clear:N \l__mw_list_range_clist + \clist_clear:N \l__mw_list_expression_clist + + % split by commas + \group_begin: + \seq_set_split:Nnn \l__mw_tmpa_seq { , } { #1 } + \seq_map_inline:Nn \l__mw_tmpa_seq + { + \tl_if_eq:nnTF { ##1 } { odd } % odd, push 2X + 1 + { + \clist_gput_right:Nn \l__mw_list_expression_clist { 2X + 1 } + } + { + \tl_if_eq:nnTF { ##1 } { even } % even, push 2X + { + \clist_gput_right:Nn \l__mw_list_expression_clist { 2X } + } + { + \tl_if_in:nnTF { ##1 } { X } % expression, push ##1 + { + \clist_gput_right:Nn \l__mw_list_expression_clist { ##1 } + } + { + \tl_if_in:nnTF { ##1 } { - } % range, push ##1 + { + \clist_gput_right:Nn \l__mw_list_range_clist { ##1 } + } + { + \__mw_if_arabic_number:nTF { ##1 } + { + \clist_gput_right:Nn \l__mw_list_arabic_number_clist { ##1 } + } + { + \__mw_if_roman_number:nTF { ##1 } + { + \clist_gput_right:Nn \l__mw_list_roman_number_clist { ##1 } + } + { + % error + \msg_error:nnn {magicwatermark}{ Unable to parse } + { + Error~list~parameter~``##1''. + } + } + } + } + } + } + } + } + \group_end: +} + +\prg_new_conditional:Npnn \__mw_if_arabic_number:n #1 { p, T, F, TF } +{ + \regex_match:NnTF \c__mw_arabic_numbers_regex { #1 } + { + \prg_return_true: + } + { + \prg_return_false: + } +} + +\prg_new_conditional:Npnn \__mw_if_roman_number:n #1 { p, T, F, TF } +{ + \regex_match:NnTF \c__mw_roman_numbers_regex { #1 } + { + \prg_return_true: + } + { + \prg_return_false: + } +} + +\prg_generate_conditional_variant:Nnn \__mw_if_arabic_number:n { x } {p, T, F, TF} +\prg_generate_conditional_variant:Nnn \__mw_if_roman_number:n { x } {p, T, F, TF} + + +\cs_new:Npn \__mw_list_parser_for_arabic_number:n #1 { + % arabic number + \fp_compare:nTF { #1 <= \g__mw_last_page_int && #1 > 0 } + { + \clist_put_right:Nn \l__mw_tmpa_clist { #1 } + } + { + % error + \msg_error:nnn {magicwatermark}{ Unable to parse } + { + Error~list~parameter~``#1''.^^J + Error~number~``#1''. + } + } +} + + + +\cs_new:Npn \__mw_list_parser_for_roman_number:n #1 { + % roman number + \int_set:Nn \l__mw_tmpa_int { \g__mw_last_page_int - \int_from_roman:n { #1 } + 1 } + \fp_compare:nTF + { + \l__mw_tmpa_int <= \g__mw_last_page_int && \l__mw_tmpa_int > 0 + } + { + \clist_put_right:NV \l__mw_tmpa_clist \l__mw_tmpa_int + } + { + % error + \msg_error:nnn {magicwatermark}{ Unable to parse } + { + Error~list~parameter~``#1''.^^J + Error~roman~number~``#1''. + } + } +} + + +\cs_new:Npn \__mw_list_parser_for_range:n #1 { + % range, 1-5, 3-i + \seq_set_split:Nnn \l__mw_tmpb_seq { - } { #1 } + + \__mw_if_arabic_number:xTF { \seq_item:Nn \l__mw_tmpb_seq { 1 } } + { + \int_set:Nn \l__mw_tmpb_int { \seq_item:Nn \l__mw_tmpb_seq { 1 } } + } + { + \__mw_if_roman_number:xTF { \seq_item:Nn \l__mw_tmpb_seq { 1 } } + { + \exp_args:NNx \int_set:Nn \l__mw_tmpb_int + { + \g__mw_last_page_int - \exp_not:N \int_from_roman:n { \seq_item:Nn \l__mw_tmpb_seq { 1 } } + 1 + } + } + { + \int_set:Nn \l__mw_tmpb_int { -1 } + % error + \msg_error:nnn {magicwatermark}{ Unable to parse } + { + Error~list~parameter~``#1''.^^J + Error~range~left~``#1''. + } + } + } + + \__mw_if_arabic_number:xTF { \seq_item:Nn \l__mw_tmpb_seq { 2 } } + { + \int_set:Nn \l__mw_tmpc_int { \seq_item:Nn \l__mw_tmpb_seq { 2 } } + } + { + \__mw_if_roman_number:xTF { \seq_item:Nn \l__mw_tmpb_seq { 2 } } + { + \exp_args:NNx \int_set:Nn \l__mw_tmpc_int + { + \g__mw_last_page_int - \exp_not:N \int_from_roman:n { \seq_item:Nn \l__mw_tmpb_seq { 2 } } + 1 + } + } + { + \int_set:Nn \l__mw_tmpc_int { -1 } + % error + \msg_error:nnn {magicwatermark}{ Unable to parse } + { + Error~list~parameter~``#1''.^^J + Error~range~right~``#1''. + } + } + } + + \fp_compare:nT { \l__mw_tmpb_int > 0 && \l__mw_tmpc_int > 0} + { + \int_step_inline:nnn + { \int_min:nn { \l__mw_tmpb_int } { \l__mw_tmpc_int } } + { \int_max:nn { \l__mw_tmpb_int } { \l__mw_tmpc_int } } + { + \clist_put_right:Nn \l__mw_tmpa_clist { ##1 } + } + } +} + +\cs_new:Npn \__mw_list_parser_for_expression:n #1 { + \int_zero:N \l__mw_tmpd_int + \int_zero:N \l__mw_tmpe_int + \group_begin: + \tl_set:Nn \l__mw_tmpa_tl { #1 } + \regex_replace_all:nnN { (\d+)X } { \1*\c{l__mw_tmpe_int} } \l__mw_tmpa_tl + \tl_replace_all:Nnn \l__mw_tmpa_tl { X } { \l__mw_tmpe_int } + % \tl_show:N \l__mw_tmpa_tl + \int_while_do:nn { \l__mw_tmpd_int < \g__mw_last_page_int } + { + \int_set:Nn \l__mw_tmpd_int + { + \fp_eval:n { \l__mw_tmpa_tl } + } + \clist_gput_right:NV \l__mw_tmpa_clist \l__mw_tmpd_int + \int_incr:N \l__mw_tmpe_int + } + \group_end: +} + + +\cs_new_nopar:Npn \__mw_list_parser:nN #1#2 { + + % case 1 -> odd, even + % case 2 -> number, 1 + % case 3 -> roman, i + % case 4 -> range, 1-5, 3-ii + % case 5 -> expression, 3X + 1 + + \__mw_list_parser_aux:n { #1 } + + \clist_clear:N \l__mw_tmpa_clist + \clist_map_inline:Nn \l__mw_list_arabic_number_clist + { + \__mw_list_parser_for_arabic_number:n { ##1 } + } + + \clist_map_inline:Nn \l__mw_list_roman_number_clist + { + \__mw_list_parser_for_roman_number:n { ##1 } + } + + + \clist_map_inline:Nn \l__mw_list_range_clist + { + \__mw_list_parser_for_range:n { ##1 } + } + + + \clist_map_inline:Nn \l__mw_list_expression_clist + { + \__mw_list_parser_for_expression:n { ##1 } + } + + + \clist_sort:Nn \l__mw_tmpa_clist { + \int_compare:nNnTF { ##1 } > { ##2 } + { \sort_return_swapped: } + { \sort_return_same: } + } + \__mw_clist_deduplicate:N \l__mw_tmpa_clist + \clist_set_eq:NN #2 \l__mw_tmpa_clist +} + + +\cs_new:Npn \__mw_parser:nN #1#2 { + \clist_clear:N #2 + \tl_if_eq:nnTF { #1 } { * } + { + \int_step_inline:nnn { 1 } { \g__mw_last_page_int } + { + \clist_put_right:Nn #2 { ##1 } + } + } + { + \__mw_list_parser:nN { #1 } #2 + } +} + + + + +\keys_define:nn { mw / new } +{ + pages .tl_set:N = \g__mw_list_tl, + style .tl_set:N = \g__mw_style_tl, + % style .code:n = \__mw_parse_style:n { #1 }, + content .tl_set:N = \g__mw_content_tl, + is~append .bool_set:N = \g__mw_is_append_bool, + tikz .bool_set:N = \g__mw_tikz_bool +} + +\cs_new:Npn \__mw_parse_style: { + \tl_if_empty:NF \g__mw_style_tl + { + \bool_if:NTF \g__mw_tikz_bool + { + \IfPackageLoadedTF{tikz} + { + \tl_set_eq:NN \l__mw_tmpc_tl \g__mw_style_tl + } + { + \msg_error:nn {magicwatermark}{ Load TikZ } + } + } + { + \msg_warning:nn {magicwatermark}{ Enable TikZ } + } + } +} + +\keys_define:nn { mw } +{ + setup .code:n = \__mw_new_watermark:n {#1} +} + + +\cs_new:Npn \__mw_new_watermark:n #1 { + \group_begin: + \keys_set:nn { mw / new }{#1} + + % parse style + \__mw_parse_style: + + % parse pages + \exp_args:NV \__mw_parser:nN \g__mw_list_tl \l__mw_tmpc_clist + + \clist_map_inline:Nn \l__mw_tmpc_clist { + + \bool_if:NTF \g__mw_tikz_bool + { + \IfPackageLoadedTF{tikz} + { + \tl_set:Ne \l__mw_tmpb_tl + { + \exp_not:N \tikz[remember~picture, overlay] + { + \exp_not:N \node[inner~sep = 0pt, outer~sep = 0pt, opacity = .5, align = left, \exp_not:V \g__mw_style_tl] at (current~page.center) + { + \exp_not:V \g__mw_content_tl + }; + } + } + } + { + \msg_error:nn {magicwatermark}{ Load TikZ } + } + } + { + \tl_set:NV \l__mw_tmpb_tl \g__mw_content_tl + } + + \bool_if:nTF { \g__mw_is_append_bool && \tl_if_exist_p:c { g__mw_content_ \int_to_roman:n { ##1 } _tl } } + { + \tl_gput_right:cV { g__mw_content_ \int_to_roman:n { ##1 } _tl } \l__mw_tmpb_tl + } + { + \tl_gset:cV { g__mw_content_ \int_to_roman:n { ##1 } _tl } \l__mw_tmpb_tl + } + } + \group_end: +} + + +\NewDocumentCommand{\MagicWatermark}{m}{ + \group_begin: + \AtBeginDocument{ + \keys_set:nn { mw } { #1 } + \AddToHook{shipout/background}{ + \put(.5\paperwidth,-.5\paperheight){ + \tl_if_exist:cT { g__mw_content_ \int_to_roman:n { \value{page} }_tl } + { + \tl_use:c { g__mw_content_ \int_to_roman:n { \value{page} } _tl } + } + } + } + } + \group_end: +} + +\@onlypreamble\MagicWatermark
\ No newline at end of file |