pgf-tikz / pgf

A Portable Graphic Format for TeX
https://pgf-tikz.github.io/
1.12k stars 106 forks source link

Font is not embedded when using tikzfadingfrompicture for color gradient on font glyphs #1315

Open branleb opened 5 months ago

branleb commented 5 months ago

Brief outline of the bug

When using a tikzfadingfrompicture to render one or more font glyphs with a color gradient e.g. for a background watermark, the font used for rendering the text is not embedded in the produced PDF. This behaviour is independent of the engine (xelatex, or lualatex). When using a plain tikzpicture without tikzfadingfrompicture for the gradient, the font is embedded as expected, but when using tikzfadingfrompicture, the font is not embedded.

The lualatex shell output reveals that the necessity of the font is known at the pdf generation stage:

[1] (./test-fontembedding.aux))
(see the transcript file for additional information)
 933 words of node memory still in use:
   19 hlist, 1 vlist, 9 rule, 2 glue, 3 kern, 1 glyph, 53 attribute, 48 glue_spec, 53 attribute_list, 2 write, 16 pdf_literal, 16 pdf_colorstack nodes
   avail lists: 1:1,2:135,3:79,4:10,5:74,6:2,7:1806,9:70,10:3,11:144
</usr/share/fonts/truetype/DejaVuSans.ttf></usr/share/fonts/truetype/DejaVuSerif.ttf>

Nevertheless, the background font does not get embedded in the PDF:

> pdffonts test-fontembedding.pdf
name                                 type              encoding         emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
RMPGEQ+DejaVuSans                    CID TrueType      Identity-H       yes yes yes     39  0

A simple $ gs -P- -dSAFER -q -P- -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sstdout=%stderr -sOutputFile=test-fontembedding.full.pdf -dPDFSETTINGS=/prepress -dEmbedAllFonts=true test-fontembedding.pdf will fix that, but should not be necessary. The output file should already have the font embedded.

Otherwise it's dependent on the target system displaying the file if the watermark is shown (e.g. if the font is not present there and when using unicode glyphs that are not present in the default font).

Minimal working example (MWE)

\documentclass[a4paper,12pt]{report}
\usepackage{mwe}
\usepackage{fontspec}

\setmainfont{DejaVu Sans}
\newfontfamily\bgfont[Scale=1.0]{DejaVu Serif}
% Alternative Font for Testing with an Emoji
% \newfontfamily\bgfont[Scale=1.0]{Noto Emoji}

\usepackage{tikz}

\usetikzlibrary{fadings,patterns}

\AddToHook{shipout/background}{
    \put (1.5in,-4.5in){
        \begin{tikzfadingfrompicture}[name=backgroundemojibus]
        \node [text=transparent!40] (textnodebus)
        {
            \bgfont\fontsize{360}{360}\selectfont T
% Alternative to the simple T: an emoji 
%             \char"1F68C
        };
        \end{tikzfadingfrompicture}

        \begin{tikzpicture}
        \shade[path fading=backgroundemojibus,fit fading=false, opacity=0.4, left color=green,right color=blue](textnodebus.south west) rectangle (textnodebus.north east);
        \end{tikzpicture}

% Alternative test without tikzfadingfrompicture
%       \begin{tikzpicture}
%         \node [text=transparent!40]
%         {
%             \emojifont\color{red}\fontsize{360}{360}\selectfont T
% Alternative to the simple T: an emoji 
%       \char"1F68C
%         };
%         \end{tikzpicture}

    }
}

\begin{document}

\blindtext

\end{document}
muzimuzhi commented 5 months ago

It reproduces even with the (second) tikzfadingfrompicture example in pgfmanual. https://tikz.dev/tikz-transparency#pgf.tikzfadingfrompicture

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fadings,patterns}
\pagestyle{empty}

\begin{document}
\begin{tikzfadingfrompicture}[name=tikz]
  \node [text=transparent!20]
    {\fontencoding{T1}\fontfamily{ptm}\fontsize{45}{45}\bfseries\selectfont Ti\emph{k}Z};
\end{tikzfadingfrompicture}

\begin{tikzpicture}
  \fill [black!20] (-2,-1) rectangle (2,1);
  \pattern [pattern=checkerboard,pattern color=black!30]
    (-2,-1) rectangle (2,1);
  \shade[path fading=tikz,fit fading=false,left color=blue,right color=black]
    (-2,-1) rectangle (2,1);
\end{tikzpicture}
\end{document}

image

muzimuzhi commented 5 months ago

The alternative way using knockout transparency group gives PDF with font(s) correctly embedded.

But knockout group is not supported by some PDF readers, for example the popper-based built-in reader in editor TeXstudio. And when used inside shipout/background hook, Adobe Acrobat Reader thinks the PDF produced by XeLaTeX was broken. Maybe related to #960.

% !TeX program = lualatex
\documentclass[a4paper,12pt]{report}
\usepackage{mwe}
\usepackage{fontspec}

\setmainfont{DejaVu Sans}
\newfontfamily\bgfont[Scale=1.0]{DejaVu Serif}

\usepackage{tikz}
\usetikzlibrary{backgrounds,fadings,patterns}

\AddToHook{shipout/background}{
  \put (1.5in,-4.5in){%
    \begin{tikzpicture}
      \begin{scope}[transparency group=knockout]
        \node [name=tikz, fill=white, text opacity=0, inner sep=2pt,
               font=\fontsize{360}{360}\bgfont]
          {T};
      \end{scope}
      \begin{scope}[on background layer={}]
        \shade [left color=green, right color=blue, opacity=.4]
          % make shading slightly smaller than node, to avoid thin lines
          % rendered by some PDF readers
          ([shift={( 1pt, 1pt)}]tikz.south west) rectangle
          ([shift={(-1pt,-1pt)}]tikz.north east);
      \end{scope}
    \end{tikzpicture}%        
    }
}

\begin{document}

\blindtext

\end{document}
> pdffonts tikz-gh1315-test-fontembedding.pdf
name                                 type              encoding         emb sub uni object ID
------------------------------------ ----------------- ---------------- --- --- --- ---------
RMPGEQ+DejaVuSans                    CID TrueType      Identity-H       yes yes yes     35  0
XQLTJA+DejaVuSerif                   CID TrueType      Identity-H       yes yes yes     38  0
muzimuzhi commented 5 months ago

Checking directly the decompressed output PDF, I find the font used in tikzfadingfrompicture is indeed embedded.

Testing with other readers/tools,

Maybe the internal structure of output PDF is not strictly valid, or detection for embedded fonts in tools like pdffonts and mutool share some flaw.

This Example is based on https://github.com/pgf-tikz/pgf/issues/1315#issuecomment-2041847269:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{fadings}
\pagestyle{empty}

\begin{document}
ABC

\begin{tikzfadingfrompicture}[name=tikz]
  \node [text=transparent!20]
    {\fontencoding{T1}\fontfamily{ptm}\fontsize{45}{45}\bfseries\selectfont Ti\emph{k}Z};
\end{tikzfadingfrompicture}

\begin{tikzpicture}
  \shade[path fading=tikz,fit fading=false,left color=blue,right color=black]
    (-2,-1) rectangle (2,1);
\end{tikzpicture}
\end{document}
Full contents of corresponding 3 PDF objects

```pdf 47 0 obj << /Type /FontDescriptor /FontName /QBBONQ+CMR10 /Flags 4 /FontBBox [ -40 -250 1009 750 ] /Ascent 694 /CapHeight 683 /Descent -194 /ItalicAngle 0 /StemV 69 /XHeight 431 /CharSet (/A/B/C) /FontFile 46 0 R >> endobj 49 0 obj << /Type /FontDescriptor /FontName /PLLTNZ+NimbusRomNo9L-Medi /Flags 4 /FontBBox [ -168 -341 1000 960 ] /Ascent 690 /CapHeight 690 /Descent -209 /ItalicAngle 0 /StemV 140 /XHeight 461 /CharSet (/T/Z/i) /FontFile 48 0 R >> endobj 51 0 obj << /Type /FontDescriptor /FontName /GRAVKX+NimbusRomNo9L-MediItal /Flags 4 /FontBBox [ -200 -324 996 964 ] /Ascent 688 /CapHeight 688 /Descent -209 /ItalicAngle -15 /StemV 120 /XHeight 462 /CharSet (/k) /FontFile 50 0 R >> endobj ```

muzimuzhi commented 5 months ago

If I convert the original PDF produced by pdflatex with

mutool convert -o <output.pdf> <input.pdf>

then both mutool info -F <file.pdf> and pdffonts list 3, instead of only 1 embedded fonts, but pdffonts also raises 3 identical warnings

Syntax Warning: Mismatch between font type and embedded font file