以下の内容はhttps://zrbabbler.hatenablog.com/entry/2024/12/18/000031より取得しました。


LaTeXで☃のマフラーの塗り潰しをもっともっと指定する方法

これは「TeX & LaTeX Advent Caleandar 2024」の18日めの記事です
17日めは Niccori 250k さん、19日めは doraTeX さんです。

Typstのアドカレの話の話

いきなり“TeX以外”の話で恐縮ですが、Typstのアドカレ8日目の記事において鹿野氏の話(←雑な要約)をしました。

鹿野氏の講演で述べられていた通り、「文字を複数の色に塗り分ける」には2つの方法があります。

  1. グリフのパスでクリップする。あとは“基底の領域”を好きな色で好きなように塗る。
    ※この方法だとグラデーションやパターンで塗り潰すことも可能。
  2. 文字を書いた後、別の色にしたい領域をクリップして、その別の色で同じ位置に再度文字を書く。
    ※この方法だと指定した1つの領域は単色でしか塗れない1

1の方法の方が自由度が高いわけですが、これを行うには「グリフのパスでクリップをする」機能が必要です。そして講演によると……

(鹿野氏の講演スライドより抜粋)

……PDFにはその機能がないということです。そして、TeXには(たとえLuaTeXでも)OpenTypeフォントのグリフのパスを取得する機能がない(はずな)ので、1の方法は実現不可能であり、結果的にTeXでは「複数の色に塗り分ける」ことは可能でも、指定した領域ごとに単色でしか塗れない、ということになります。

ざんねん🙃

本題の話

ざんねん🙃で終わってしまうのはざんねん🙃なので、やってみました😀2

※2の方法で実現不可能であることを担保するため、塗り潰しの中にも☃の文字を入れて「ゆきだるまinゆきだるま」にしてみました😃

%#!luaaltex
\documentclass{standalone}
% PDF描画命令の直書きと衝突する可能性を減らすため
% なるべく機構が単純なパッケージを利用する.
\usepackage{fontspec, color, ifthen}
\setmainfont{Harano Aji Mincho} % 原ノ味明朝
\setlength{\unitlength}{1bp}
\newcounter{cYPos}
% 色の定義
\definecolor{cback}    {rgb}{0.88,0.95,0.98}% ページ背景
\definecolor{cbbody}   {rgb}{0.00,0.40,0.00}% ゆきだるま背景
\definecolor{cfbody}   {rgb}{0.75,0.88,0.75}% ゆきだるま前景
\definecolor{cbmuffler}{rgb}{0.80,0.00,0.00}% マフラー背景
\definecolor{cfmuffler}{rgb}{1.00,0.75,0.75}% マフラー前景
\pagecolor{cback}
%!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TeX code BEGIN
% \cGlyphClipStart: クリップ用グリフパスの指定を開始する.
% これ以降 \cGlyphClipEnd までに書いた文字がクリップパスになる.
% 最後に \cGlyphClipClear を必ず実行する必要がある.
\NewDocumentCommand\cGlyphClipBegin{}{%
  \pdfextension save\relax
  \pdfextension literal page{7 Tr}%
}
% \cGlyphClipEnd: クリップ用グリフパスの指定を終了する.
\NewDocumentCommand\cGlyphClipEnd{}{%
  \pdfextension literal page{0 Tr}%
}
% \cGlyphClipEnd: グリフパスのクリップの適用を解除する.
\NewDocumentCommand\cGlyphClipClear{}{%
  \pdfextension restore\relax
}
%!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TeX code END
% \cSnowman: ゆきだるま☃.
\NewDocumentCommand\cSnowman{}{%
  \raisebox{0.12em}[1em][0em]{}%
}
% \cSize{<実数r>}: フォントサイズを r bp に指定する.
\NewDocumentCommand\cSize{m}{%
  \fontsize{#1bp}{0}\selectfont
}
% \cSnowmanBox{<サイズ>}{<前景色>}{<背景色>}
\NewDocumentCommand\cSnowmanBox{m m m}{%
  \setlength{\fboxsep}{0pt}%
  \colorbox{#3}{\cSize{#1}\textcolor{#2}{\cSnowman}}%
}
% \cPutM(<座標>){<個数>}: マフラー部分の出力.
\NewDocumentCommand\cPutM{r() m}{%
  \multiput(#1)(5,0){#2}{%
    \cSnowmanBox{5}{cfmuffler}{cbmuffler}%
  }%
}
\begin{document}
\begin{picture}(100,100)
  % 外の☃でクリップ指定
  \cGlyphClipBegin
  \put(0,0){\cSize{100}\cSnowman}
  \cGlyphClipEnd
  % 中の☃(全体)
  \setcounter{cYPos}{0}%
  \whiledo{\value{cYPos}<100}{%
    \multiput(0,\value{cYPos})(5,0){20}{%
      \cSnowmanBox{5}{cfbody}{cbbody}%
    }%
    \addtocounter{cYPos}{5}%
  }%
  % 中の☃(マフラー)
  \cPutM(60,30){4}\cPutM(40,35){8}\cPutM(25,40){10}%
  \cPutM(25,45){10}\cPutM(20,50){4}\cPutM(65,50){3}%
  \cPutM(20,55){3}\cPutM(70,55){2}%
  % おしまい
  \cGlyphClipClear
\end{picture}
\end{document}

出力結果(素敵😊)

素敵😊

まとめ

やっぱり「ゆきだるまinゆきだるま」はトッテモ素敵😊


  1. 結局「色を塗ることを文字を書くことで表している」わけであり、文字は単色でしか書けないからです。
  2. このソースは「PDF描画命令列を直書きする」ためにLuaTeXの拡張プリミティブ(\pdfextension)を用いているのでLuaLaTeX専用となりますが、命令列を直書きは他のワークフロー(pdfTeX・XeTeX・dvipdfmx)でもサポートされているため、これらのワークフローでも同じ出力を実装することは可能です。



以上の内容はhttps://zrbabbler.hatenablog.com/entry/2024/12/18/000031より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14