diff options
Diffstat (limited to 'Master/texmf-dist/source/latex-dev/l3backend/l3backend-opacity.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex-dev/l3backend/l3backend-opacity.dtx | 353 |
1 files changed, 353 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex-dev/l3backend/l3backend-opacity.dtx b/Master/texmf-dist/source/latex-dev/l3backend/l3backend-opacity.dtx new file mode 100644 index 00000000000..0c29574c377 --- /dev/null +++ b/Master/texmf-dist/source/latex-dev/l3backend/l3backend-opacity.dtx @@ -0,0 +1,353 @@ +% \iffalse meta-comment +% +%% File: l3backend-opacity.dtx +% +% Copyright (C) 2021-2024 The LaTeX Project +% +% It may be distributed and/or modified under the conditions of the +% LaTeX Project Public License (LPPL), either version 1.3c of this +% license or (at your option) any later version. The latest version +% of this license is in the file +% +% https://www.latex-project.org/lppl.txt +% +% This file is part of the "l3backend bundle" (The Work in LPPL) +% and all files in that bundle must be distributed together. +% +% ----------------------------------------------------------------------- +% +% The development version of the bundle can be found at +% +% https://github.com/latex3/latex3 +% +% for those people who are interested. +% +%<*driver> +\documentclass[full,kernel]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3backend-opacity} module\\ Backend opacity support^^A +% } +% +% \author{^^A +% The \LaTeX{} Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released 2024-04-11} +% +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3backend-opacity} implementation} +% +% \begin{macrocode} +%<*package> +%<@@=opacity> +% \end{macrocode} +% +% Although opacity is not color, it needs to be managed in a somewhat +% similar way: using a dedicated stack if possible. Depending on the backend, +% that may not be possible. There is also the need to cover fill/stroke setting +% as well as more general running opacity. It is easiest to describe the value +% used in terms of opacity, although commonly this is referred to as +% transparency. +% +% \begin{macrocode} +%<*dvips> +% \end{macrocode} +% +% \begin{macro}{\@@_backend_select:n} +% \begin{macro}{\@@_backend_fill:n, \@@_backend_stroke:n} +% \begin{macro}{\@@_backend:nnn} +% No stack so set values directly. The need to deal with Distiller and +% Ghostscript separately means we use a common auxiliary: the two +% systems require different PostScript for transparency. This is +% of course not quite as efficient as doing one test for setting all +% transparency, but it keeps things clearer here. Thanks to Alex Grahn +% for the detail on testing for GhostScript. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_select:n #1 + { + \@@_backend:nnn {#1} { fill } { ca } + \@@_backend:nnn {#1} { stroke } { CA } + } +\cs_new_protected:Npn \@@_backend_fill:n #1 + { + \@@_backend:nnn + { #1 } + { fill } + { ca } + } +\cs_new_protected:Npn \@@_backend_stroke:n #1 + { + \@@_backend:nnn + { #1 } + { stroke } + { CA } + } +\cs_new_protected:Npn \@@_backend:nnn #1#2#3 + { + \__kernel_backend_postscript:n + { + product ~ (Ghostscript) ~ search + { + pop ~ pop ~ pop ~ + #1 ~ .set #2 constantalpha + } + { + pop ~ + mark ~ + /#3 ~ #1 + /SetTransparency ~ + pdfmark + } + ifelse + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</dvips> +% \end{macrocode} +% +% \begin{macrocode} +%<*dvipdfmx|luatex|pdftex|xetex> +% \end{macrocode} +% +% \begin{variable}{\c_@@_backend_stack_int} +% Set up a stack, where that is applicable. +% \begin{macrocode} +\bool_lazy_and:nnT + { \cs_if_exist_p:N \pdfmanagement_if_active_p: } + { \pdfmanagement_if_active_p: } + { +%<*luatex|pdftex> + \__kernel_color_backend_stack_init:Nnn \c_@@_backend_stack_int + { page ~ direct } { /opacity 1 ~ gs } +%</luatex|pdftex> + \pdfmanagement_add:nnn { Page / Resources / ExtGState } + { opacity 1 } { << /ca ~ 1 /CA ~ 1 >> } + } +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_backend_fill_tl, \l_@@_backend_stroke_tl} +% We use |tl| here for speed: at the backend, this should be reasonable. +% Both need to start off fully opaque. +% \begin{macrocode} +\tl_new:N \l_@@_backend_fill_tl +\tl_new:N \l_@@_backend_stroke_tl +\tl_set:Nn \l_@@_backend_fill_tl { 1 } +\tl_set:Nn \l_@@_backend_stroke_tl { 1 } +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@_backend_select:n} +% \begin{macro}{\@@_backend_reset:} +% Much the same as color. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_select:n #1 + { + \tl_set:Nn \l_@@_backend_fill_tl {#1} + \tl_set:Nn \l_@@_backend_stroke_tl {#1} + \pdfmanagement_add:nnn { Page / Resources / ExtGState } + { opacity #1 } + { << /ca ~ #1 /CA ~ #1 >> } +%<*dvipdfmx|xetex> + \__kernel_backend_literal_pdf:n +%</dvipdfmx|xetex> +%<*luatex|pdftex> + \__kernel_color_backend_stack_push:nn \c_@@_backend_stack_int +%</luatex|pdftex> + { /opacity #1 ~ gs } + \group_insert_after:N \@@_backend_reset: + } +\cs_new_protected:Npn \@@_backend_reset: + { +%<*dvipdfmx|xetex> + \__kernel_backend_literal_pdf:n + { /opacity1 ~ gs } +%</dvipdfmx|xetex> +%<*luatex|pdftex> + \__kernel_color_backend_stack_pop:n \c_@@_backend_stack_int +%</luatex|pdftex> + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_backend_fill:n, \@@_backend_stroke:n} +% \begin{macro}{\@@_backend_fill_stroke:nn} +% For separate fill and stroke, we need to work out if we need to do +% more work or if we can stick to a single setting. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_fill:n #1 + { + \exp_args:Nno \@@_backend_fill_stroke:nn + { #1 } + { \l_@@_backend_stroke_tl } + } +\cs_new_protected:Npn \@@_backend_stroke:n #1 + { + \exp_args:No \@@_backend_fill_stroke:nn + { \l_@@_backend_fill_tl } + { #1 } + } +\cs_new_protected:Npn \@@_backend_fill_stroke:nn #1#2 + { + \str_if_eq:nnTF {#1} {#2} + { \@@_backend_select:n {#1} } + { + \tl_set:Nn \l_@@_backend_fill_tl {#1} + \tl_set:Nn \l_@@_backend_stroke_tl {#2} + \pdfmanagement_add:nnn { Page / Resources / ExtGState } + { opacity.fill #1 } + { << /ca ~ #1 >> } + \pdfmanagement_add:nnn { Page / Resources / ExtGState } + { opacity.stroke #2 } + { << /CA ~ #2 >> } +%<*dvipdfmx|xetex> + \__kernel_backend_literal_pdf:n +%</dvipdfmx|xetex> +%<*luatex|pdftex> + \__kernel_color_backend_stack_push:nn \c_@@_backend_stack_int +%</luatex|pdftex> + { /opacity.fill #1 ~ gs /opacity.stroke #2 ~ gs } + \group_insert_after:N \@@_backend_reset: + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_backend_select:n, \@@_backend_fill_stroke:nn} +% Redefine them to stubs if pdfmanagement is either not loaded or +% deactivated. +% \begin{macrocode} +\bool_lazy_and:nnF + { \cs_if_exist_p:N \pdfmanagement_if_active_p: } + { \pdfmanagement_if_active_p: } + { + \cs_gset_protected:Npn \@@_backend_select:n #1 { } + \cs_gset_protected:Npn \@@_backend_fill_stroke:nn #1#2 { } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</dvipdfmx|luatex|pdftex|xetex> +% \end{macrocode} +% +% \begin{macrocode} +%<*dvisvgm> +% \end{macrocode} +% +% \begin{macro}{\@@_backend_select:n, \@@_backend_fill:n, \@@_backend_stroke:n} +% \begin{macro}{\@@_backend:nn} +% Once again, we use a scope here. There is a general opacity function for +% SVG, but that is of course not set up using the stack. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_select:n #1 + { \@@_backend:nn {#1} { } } +\cs_new_protected:Npn \@@_backend_fill:n #1 + { \@@_backend:nn {#1} { fill- } } +\cs_new_protected:Npn \@@_backend_stroke:n #1 + { \@@_backend:nn {#1} { stroke- } } +\cs_new_protected:Npn \@@_backend:nn #1#2 + { \__kernel_backend_scope:e { #2 opacity = " #1 " } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</dvisvgm> +% \end{macrocode} +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \subsection{Font handling integration} +% +% In \LuaTeX{} we want to use these functions also for transparent fonts +% to avoid interference between both uses of transparency. +% +% \begin{macrocode} +%<*lua> +% \end{macrocode} +% +% First we need to check if pdfmanagement is active from Lua. +% \begin{macrocode} +local pdfmanagement_active do + local pdfmanagement_if_active_p = token.create'pdfmanagement_if_active_p:' + local cmd = pdfmanagement_if_active_p.cmdname + if cmd == 'undefined_cs' then + pdfmanagement_active = false + else + token.put_next(pdfmanagement_if_active_p) + pdfmanagement_active = token.scan_int() ~= 0 + end +end + +if pdfmanagement_active and luaotfload and luaotfload.set_transparent_colorstack then + luaotfload.set_transparent_colorstack(function() return token.create'c_@@_backend_stack_int'.index end) + + local transparent_register = { + token.create'pdfmanagement_add:nnn', + token.new(0, 1), + 'Page/Resources/ExtGState', + token.new(0, 2), + token.new(0, 1), + '', + token.new(0, 2), + token.new(0, 1), + '<</ca ', + '', + '/CA ', + '', + '>>', + token.new(0, 2), + } + luatexbase.add_to_callback('luaotfload.parse_transparent', function(value) + value = (octet * -1):match(value) + if not value then + tex.error'Invalid transparency value' + return + end + value = value:sub(1, -2) + local result = 'opacity' .. value + tex.runtoks(function() + transparent_register[6], transparent_register[10], transparent_register[12] = result, value, value + tex.sprint(-2, transparent_register) + end) + return '/' .. result .. ' gs' + end, 'l3opacity') +end +% \end{macrocode} +% +% \begin{macrocode} +%</lua> +% \end{macrocode} +% +% +% \end{implementation} +% +% \PrintIndex |