更新-1:此问题会影响所有假定字形重叠的字体。受影响的三大类字体为:1) 所有非拉丁文脚本的字体,这些字体本身需要字形重叠;2) 拉丁文脚本的手写(草书)字体;3) 装饰字体,旨在通过重复部分重叠的字形图案来构建复杂的装饰(如装饰边框/框架)。
更新-2:该问题尚未得到解答。后大卫·普顿发布下面的这个“相关答案”,正确的理解是 tikz“透明度组”也会将分组透明度应用于节点文本。我的 tikz 代码中的错误是我调用了透明度分组,但在不同的范围级别指定了不透明度。我已经更新了有问题的原始代码,tikz 输出看起来不错。这意味着文本模式(tikz 之外)中透明度分组所需的代码可以从 tikz 代码库改编,也可以由了解的人编写
PDF XObjects
。即使透明度仅应用于 latex 的牢不可破的框(如包textpos
的环境texblock
或minipage
,或纯 tex 的框(vbox
和hbox
),这也是没问题的;这本身就是一个巨大的飞跃。了解宏的人\pdfxform
),这也是没问题的;这本身就是一个巨大的飞跃。了解宏的pdftex 用户手册第 8.8 节也许能有所帮助。
在某些脚本中,几乎不可能有不重叠的字形组件。这要么是因为一些复杂的字形本身由多个(可能重叠的)组件字形组成,要么是设计上相邻的字形需要重叠才能形成一个单词。这两种情况对于天城文都是正确的,后者是因为单词中字形的“上划线”必须重叠才能形成一个单词(这是除单词间距之外的脚本功能)。当文本设置为纯色时,这些重叠(理所当然地)不可见,而当文本设置为透明时,这些重叠可见。
为此类脚本设置fontspec
不透明度会产生丑陋的结果(使其无法使用),例如,请参见下图,这是使用不透明度设置的印地语父级(पिताजी)的单词。如您所见,不透明度设置会导致重叠区域出现较暗的斑点。这是因为在应用透明度之前未对文本进行分组(不透明度设置在单个字形级别应用透明度)。如果使用其隐式或显式透明度分组,Tikz 不会出现此问题(此处未显示 tikz 输出,可以通过编译此问题中的代码来查看)。以下字体规格Opacity
输出是 Adobe InDesign 2020 的输出(幸运的是我仍然可以访问 InDesign 的试用版),看起来很棒(重叠处没有黑点,结果看起来很统一)。我测试了 Tikz 和 Adobe InDesign 的文本透明度分组的输出,文本在分组后不会转换为路径(文本是可复制/可搜索的,这很棒)。从大卫·普顿的分析Tikz 和 Adobe InDesign 生成类似的 PDF 代码。
LuaLaTeX 和fontspec
输出Opacity<1
:
Adobe InDesign 2020 输出:
理想的解决方案是执行分组透明度文本模式(如果它只适用于 HarfBuzz,那就没问题了),就像“透明组”对 tikz 文本和图形的工作方式一样。文本仍然应该像 pdf 中的文本一样,它应该是可搜索和可复制的,并且不应该在文本模式下添加任何限制(例如透明文本可以跨越段落等)。如果它使实现更容易,解决方案可以限制自己将分组透明度应用于包的textpos
环境textblock
,或者minipage
使该环境中的所有对象都成为透明度组的一部分(可能带有混合模式的参数,并且可能可以像 tikz 透明度组和颜色命令一样嵌套组\color/\textcolor
[尽管嵌套是一个额外的好处,但不是最重要的])。 附注:我并不是在寻找一个 tikz 解决方案(其作用类似于具有分组透明度的 textpos 或 minipage),但欢迎您在此处为更广泛的社区发布一个解决方案(第一行明确以粗体说明“这不是这个问题的解决方案,在这里发布只是为了展示用 tikz 可以实现什么。”)。[1]
[1] 这可能听起来太严格了,但在我看来,一个似乎部分解决问题的错误答案可能不会引发进一步的探究/推动找到正确的解决方案。
作为参考,以下截图来自asppdf 手册第 17.3.1 节可以引导我们找到解决方案。看来,这个问题的解决方案需要实现一个透明度分组,就像屏幕截图左下角的图一样。四个透明度分组图像上方的段落很好地解释了事情。当前的透明度实现功能类似于右上图像(没有分组的透明度,导致字形相互合成)。
这是重现重叠处暗区问题的测试代码。您可能需要放大才能在屏幕上看到问题,但在打印的文档中它会清晰可见且令人分心。最后,这是不是字体问题,并可以用任何现有的天城体字体重新创建。
% >> lualatex opacityoverlap.tex
\documentclass{article}
\usepackage{fontspec}
\usepackage{tikz}
\newfontfamily{\devanagarifamtext}{Noto Sans Devanagari}[Script=Devanagari, Scale=1, Renderer=HarfBuzz, Color=FF0000, Opacity=0.25]
\newfontfamily{\devanagarifamtikz}{Noto Sans Devanagari}[Script=Devanagari, Scale=1, Renderer=HarfBuzz, Color=FF0000]
\begin{document}
Text mode: {\devanagarifamtext एक गांव में पिताजी}
Tikz mode: \tikz[baseline,blend group=hue,opacity=0.25]{\node[inner sep=0pt,minimum width=0pt,outer sep=0pt,anchor=base] () {\devanagarifamtikz एक गांव में पिताजी};}
\end{document}
答案1
这不是这个问题的解决方案,发布在这里只是为了展示使用 tikz/pgf 可以实现什么(按照问题指示)。
更新:仅限 PGF 答案
这是一个仅使用 的优化解决方案pgf
。它比使用接口的开销要小tikz
。经过长时间的研究,我认为这是迄今为止最好的解决方案。它实现起来简单得多,可以与其他软件包配合使用,并且对速度的影响最小。
除非您非常小心地布置文本,否则混合模式在各个查看器中似乎都不可靠,pgfpicture
所以我认为使用它们没有任何好处。
%! TeX Program = lualatex
\documentclass{article}
\usepackage{xparse}
\usepackage{pgf}
\ExplSyntaxOn
\NewDocumentEnvironment { transparencygroup }
{ m +b }
{
\par
\dim_set_eq:NN \l_tmpa_dim \prevdepth
\noindent
\pgfrememberpicturepositiononpagefalse
\begin { pgfpicture }
\pgfsetfillopacity { #1 }
\begin { pgftransparencygroup } [ isolated=false ]
\pgfpathmoveto { \pgfpointorigin }
\pgftext [ base ]
{
\vbox:n
{
\dim_set_eq:NN \prevdepth \l_tmpa_dim
#2
}
}
\end { pgftransparencygroup }
\end { pgfpicture }
}
{ }
\NewDocumentCommand \texttransparencygroup { m m }
{
\mode_leave_vertical:
\hbox:n
{
\pgfrememberpicturepositiononpagefalse
\begin { pgfpicture }
\pgfsetfillopacity { #1 }
\begin { pgftransparencygroup } [ isolated=true ]
\pgfpathmoveto { \pgfpointorigin }
\pgftext [ base ] { #2 }
\end { pgftransparencygroup }
\end { pgfpicture }
}
}
\ExplSyntaxOff
\usepackage{fontspec}
\newfontfamily{\devanagari}{Noto Sans Devanagari}[Script=Devanagari, Renderer=HarfBuzz]
\begin{document}
\Huge
English {\devanagari \texttransparencygroup{0.4}{एक गांव में पिताजी}} English
\devanagari\color{red}
\begin{transparencygroup}{0.5}
एक गांव में पिताजी
\end{transparencygroup}
\vskip-8mm
\color{green}
\begin{transparencygroup}{0.25}
एक गांव में पिताजी
\end{transparencygroup}
\end{document}
TIKZ 答案
InDesign 中的 PDF 本质上使用与 tikz 相同的方法。它创建一个带有透明度组的 Form XObject 并将文本放入其中。然后它将此 Form XObject 插入到页面流中。即使您不使用 tikz,您仍然必须将内容装入 XObject 中。透明度组不仅仅是您可以在流中打开和关闭的图形标志。
诀窍tikz
似乎是将文本放入透明度组中:
\documentclass{article}
\usepackage{l3pdf}
\ExplSyntaxOn
\pdf_uncompress:
\ExplSyntaxOff
\usepackage{fontspec}
\usepackage{tikz}
\newfontfamily{\devanagari}{Noto Sans Devanagari}[Script=Devanagari, Scale=1, Renderer=HarfBuzz]
\begin{document}
\begin{tikzpicture}[opacity=0.5]
\fill[cyan] (0,0) circle [radius=10pt];
\begin{scope}[transparency group]
\node[text=red, font=\devanagari] {एक गांव में पिताजी};
\end{scope}
\end{tikzpicture}
\end{document}
这是一个更完整的示例,展示了如何将几个不同颜色的段落放在透明组中。它还允许您指定混合模式。但是,任何背景图形都必须位于混合组中。如果您只想要透明度,则这不是限制。
\documentclass{article}
\usepackage{l3pdf}
\ExplSyntaxOn
\pdf_uncompress:
\ExplSyntaxOff
\usepackage{fontspec}
\usepackage{tikz}
\usepackage{lipsum}
\newfontfamily{\devanagari}{Noto Sans Devanagari}[Script=Devanagari, Scale=1, Renderer=HarfBuzz]
\newcommand*{\tgopacity}{0.5}
\newcommand*{\tgblendmode}{normal}
\newcommand*{\tggraphics}{}
% \begin{transparentgroup}{opacity}{blend mode}{graphics within blend group}
\newenvironment{transparentgroup}[3]{%
\renewcommand*{\tgopacity}{#1}%
\renewcommand*{\tgblendmode}{#2}%
\renewcommand{\tggraphics}{#3}%
\setbox0=\vbox\bgroup
}{%
\egroup
\noindent\begin{tikzpicture}[
inner sep=0pt, outer sep=0pt, blend group=\tgblendmode
]
\tggraphics
\pgfresetboundingbox
\begin{scope}[transparency group, opacity=\tgopacity]
\node [anchor=north west] {\box0};
\end{scope}
\end{tikzpicture}}
\begin{document}
\noindent\tikz[remember picture, overlay] \fill[green, opacity=0.5]
([yshift=7cm]current page.center) circle [radius=20pt];%
\begin{transparentgroup}{0.5}{lighten}{
\fill[green, opacity=0.5] (10mm,-5mm) circle [radius=20pt];
}
\textcolor{red}{\devanagari एक गांव में पिताजी}
\lipsum[1]
\end{transparentgroup}
\textcolor{red}{\devanagari एक गांव में पिताजी}
\lipsum[1]
\end{document}
答案2
您可以做您想做的事情,但这很麻烦。下面的示例有一个简单的界面来设置材质,\vbox
并允许您设置不透明度和混合模式。
用法是:
\begin{transparencygroup}[
opacity = < Value between 0 and 1 >,
blend mode = < One of the standard PDF blend modes >
]
\end{transparencygroup}
由于页面资源的接口较差,其他向页面资源添加内容的包可能会出现问题。
此示例代码并未尝试与其他软件包一起使用,因此可能无法正常工作如果您加载了其他会产生干扰的软件包/ExtGState
(例如tikz
,、、、的不透明度功能等)。提供了一个可在您需要使用时使用的钩子。colorspace
transparent
fontspec
tikz
tikz
%! TeX Program = lualatex
\documentclass{article}
\pagestyle{empty}
% grouped transparency implementation
% Limitations:
%
% 1. Because of the poor interface for page resources, there can be problems
% with other packages that add things to the /ExtGState dictionary (e.g.,
% tikz, colorspace, transparent, etc.).
%
% 2. You can't use the Opacity feature of fontspec as this puts the
% transparency code inside the transparency group, and you'll still get the
% overlapping glyphs.
%
% 3. Only LuaLaTeX is supported.
\usepackage{l3pdf}
\usepackage{xparse}
\usepackage{everyshi}
\ExplSyntaxOn
\pdf_uncompress:
% l3pdf extensions (lualatex only)
\cs_generate_variant:Nn \pdf_object_new:nn { xn }
\cs_generate_variant:Nn \pdf_object_write:nn { xx }
\cs_generate_variant:Nn \pdf_object_ref:n { e }
\cs_new_protected:Nn \__reportaman_pdf_xform_now:Nnn
{
\tex_immediate:D \tex_pdfxform:D
attr { #2 }
resources { #3 }
#1
}
\cs_generate_variant:Nn \__reportaman_pdf_xform_now:Nnn { Nxx }
\cs_new_protected:Nx \__reportaman_pdf_xform_last:
{
\exp_not:N \int_value:w
\exp_not:N \tex_pdflastxform:D
\c_space_tl 0 ~ R
}
\cs_new_protected:Nn \__reportaman_pdf_refxform_last:
{
\tex_pdfrefxform:D \tex_pdflastxform:D
}
\cs_new_protected:Nn \__reportaman_pdf_pageresources_gput_right:nn
{
\tex_global:D
\tex_pdfvariable:D pageresources
\exp_after:wN
{
\tex_the:D \tex_pdfvariable:D pageresources / #1 ~ #2
}
}
\cs_generate_variant:Nn \__reportaman_pdf_pageresources_gput_right:nn { nx }
\cs_new_protected:Nn \__reportaman_pdf_literal_direct:n
{
\tex_pdfextension:D literal direct
{
#1
}
}
\cs_generate_variant:Nn \__reportaman_pdf_literal_direct:n { x }
\cs_new_protected:Nn \__reportaman_pdf_save_gs:
{
\__reportaman_pdf_literal_direct:n { q }
}
\cs_new_protected:Nn \__reportaman_pdf_restore_gs:
{
\__reportaman_pdf_literal_direct:n { Q }
}
% grouped transparency back end
\clist_new:N \g__reportaman_ca_clist
\clist_new:N \g__reportaman_bm_clist
\int_new:N \g__reportaman_extgstate_int
\cs_new_protected:Nn \__reportaman_set_pdf_page_resources:
{
\clist_remove_duplicates:N \g__reportaman_ca_clist
\clist_remove_duplicates:N \g__reportaman_bm_clist
\tl_clear:N \l_tmpa_tl
\clist_map_inline:Nn \g__reportaman_ca_clist
{
\tl_put_right:Nn \l_tmpa_tl
{
/reportaman_CA_##1 ~ << ~ /CA ~ ##1 ~ >> ~
/reportaman_ca_##1 ~ << ~ /ca ~ ##1 ~ >> ~
}
}
\clist_map_inline:Nn \g__reportaman_bm_clist
{
\tl_put_right:Nn \l_tmpa_tl
{
/reportaman_bm_##1 ~ << ~ /BM ~ [ ~ /##1 ~ ] ~ >> ~
}
}
\clist_gclear:N \g__reportaman_ca_clist
\clist_gclear:N \g__reportaman_bm_clist
\exp_args:Nx \pdf_object_if_exist:nT
{
reportaman_extgstate_ \int_use:N \g__reportaman_extgstate_int
}
{
\pdf_object_write:xx
{ reportaman_extgstate_ \int_use:N \g__reportaman_extgstate_int }
{ \l_tmpa_tl }
\__reportaman_pdf_pageresources_gput_right:nx
{ ExtGState }
{
\pdf_object_ref:e
{
reportaman_extgstate_ \int_use:N \g__reportaman_extgstate_int
}
}
\int_gincr:N \g__reportaman_extgstate_int
}
}
\EveryShipout { \__reportaman_set_pdf_page_resources: }
\keys_define:nn { reportaman }
{
opacity .tl_set:N = \l__reportaman_opacity_tl,
opacity .value_required:n = true,
blend ~ mode .choice:,
blend ~ mode .choices:nn =
{ Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge,
ColorBurn, HardLight, SoftLight, Difference, Exclusion, Hue, Saturation,
Color, Luminosity }
{ \tl_set_eq:NN \l__reportaman_blend_mode_tl \l_keys_choice_tl },
blend ~ mode .value_required:n = true,
}
% grouped transparency front end
% \begin{transparencygroup}[
% opacity = < Value between 0 and 1 >,
% blend mode = < One of the standard PDF blend modes >
% ]
% \end{transparencygroup}
\NewDocumentEnvironment { transparentgroup }
{ o +b }
{
\keys_set:nn { reportaman }
{
opacity = { 1 },
blend ~ mode = { Normal }
}
\IfValueT { #1 }
{
\keys_set:nn { reportaman } { #1 }
}
\clist_gput_right:Nx \g__reportaman_ca_clist { \l__reportaman_opacity_tl }
\clist_gput_right:Nx \g__reportaman_bm_clist { \l__reportaman_blend_mode_tl }
\vbox_set:Nn \l_tmpa_box
{
\__reportaman_pdf_literal_direct:x
{
/reportaman_bm_\l__reportaman_blend_mode_tl \c_space_tl gs
}
#2
}
\exp_args:Nx \pdf_object_if_exist:nF
{
reportaman_extgstate_ \int_use:N \g__reportaman_extgstate_int
}
{
\pdf_object_new:xn
{ reportaman_extgstate_ \int_use:N \g__reportaman_extgstate_int }
{ dict }
}
\__reportaman_pdf_xform_now:Nxx
\l_tmpa_box
{ /Group ~ << ~ /S ~ /Transparency ~ /I ~ true ~ /K ~ false ~ >> }
{ /ExtGState ~
\pdf_object_ref:e
{
reportaman_extgstate_ \int_use:N \g__reportaman_extgstate_int
}
}
\__reportaman_pdf_save_gs:
\__reportaman_pdf_literal_direct:x
{
/reportaman_CA_\l__reportaman_opacity_tl \c_space_tl gs \iow_newline:
/reportaman_ca_\l__reportaman_opacity_tl \c_space_tl gs
}
\__reportaman_pdf_refxform_last:
\__reportaman_pdf_restore_gs:
}
{
}
\ExplSyntaxOff
% Usage example
\usepackage{xcolor}
\usepackage{fontspec}
\newfontfamily{\devanagari}{Noto Sans Devanagari}[Script=Devanagari, Scale=1, Renderer=HarfBuzz]
\begin{document}
\begin{transparentgroup}[opacity=0.25, blend mode=Hue]
\devanagari\Huge
\color{red}एक गांव में पिताजी
\vspace{-7mm}\quad
\color{green}एक गांव में पिताजी
\end{transparentgroup}
\begin{transparentgroup}[opacity=0.5]
\devanagari\Huge
\color{red}एक गांव में पिताजी
\vspace{-7mm}\quad
\color{blue}एक गांव में पिताजी
\end{transparentgroup}
\begin{transparentgroup}
\devanagari\Huge
\color{red}एक गांव में पिताजी
\vspace{-7mm}\quad
\color{yellow}एक गांव में पिताजी
\end{transparentgroup}
\end{document}