我想对一些文本应用转换,使其按照梯形倾斜,例如《星球大战》系列著名的开场白:
这似乎很难做到,因为它不是仿射变换。我试过在谷歌上搜索,但没有成功。
空的 MWE:
\documentclass{article}
\newcommand{\starwarsbox}[1]{\fbox{#1}}
\begin{document}
\begin{center}
\starwarsbox{
\parbox{0.8\linewidth}
{
Star wars effect demo.
\begin{itemize}
\item Lots of text here
\item And environments such as \texttt{itemize}, too!
\end{itemize}
}
}
\end{center}
\end{document}
有什么想法吗?谢谢!
答案1
这一切都始于布鲁诺的\slantbox
(剪切变换一个“盒子”) 并逐个字母地应用它。作为参考,提供给 Bruno 程序的倾斜值是倾斜角的正切。
我正在编辑以更好地解释我在这里所做的事情。关键是定义一个消失点和一个坐标系,并了解您相对于它的当前位置。
昨晚写完代码后,我累了,愚蠢地定义了一个左手系统,其中X是相对于消失点的当前水平位置,并且是是向下页面上与消失点之间的距离。因此,三角计算中需要一些额外的负数来消除左手系的影响。
\xvpref
透视图的左边距由连接消失点和坐标 ( , )的线定义\ypvref
,坐标相对于消失点指定。因此,更改 的值会\xvpref
改变文本的宽度,而更改\yvpref
会改变地平线的垂直位置。在我原来的方法(前景中的第一行文本)中,这也是第一行文本的开始位置。在更正的方法(前景中的最后一行文本)中,起点位于 ( \xvp
, \ypv
)
输入通过和\nextline
进行处理 ,以便一次处理一个字母,考虑到空格。一旦每个字母被隔离,就会在 内计算从其位置回到消失点的切线,并使用。该切线将确定倾斜度。\nextword
\nextletter
\nextletter
\FPdiv
除了倾斜度之外,还需要确定字母的放大倍数。放大倍数在 中确定\setmagf
,仅作为(且与)的函数是-与消失点的距离(这样给定的线就都具有相同的放大倍数)。一旦知道了字母的倾斜度和放大倍数,这些参数就会\shslbox
通过传递给\nextletter
。宏\shslbox
只是缩放字母并将其传递给 Bruno 的
\slantbox
。
随着每个字母的呈现,X值已更新(在\xvp
),这将影响消失点的切线斜率,从而影响后续字母的倾斜度。
\nextline
除了处理每行中的字母之外,宏还必须执行额外的簿记。调用\parallax
宏以通过正确的 来注册消失左边距上的当前位置\hspace
。\setmagf
调用宏来确定此行文本的 mag 因子。调用 A\vspace
来将行向上移动(原始方法)或向下移动(校正方法),在此过程中考虑 mag 因子。修订后的 值是当然,也会影响消失点的切线。
右侧没有进行边距调整,因此仍然参差不齐,必须手动调整以适应。这可以通过将整个单词移至相邻行来实现,或者通过填充单词来\,
增加单词之间的间隙。
修正方法(前景中的最后一行文本)
\documentclass{article}
\usepackage{fp,amssymb,graphicx,xcolor}
\makeatletter
\def\strippt{\strip@pt}
\makeatother
\newsavebox\foobox
\newcommand\slbox[2]{%
\slantbox[\result]{#2}%
}%
\newcommand{\slantbox}[2][30]{%
\mbox{%
\global\sbox{\foobox}{\textcolor{yellow}{#2}}%
\hskip\wd\foobox
\pdfsave
\pdfsetmatrix{1 0 #1 1}%
\llap{\usebox{\foobox}}%
\pdfrestore
}}
\newcommand\shslbox[3]{\slbox{#1}{\scalebox{#3}{#2}}}
\newlength\yvp
\newlength\xvp
\newlength\yvpref
\newlength\xvpref
\yvpref 50pt\relax
\xvpref -75pt\relax
\xvp=\xvpref\relax
\yvp=.3\yvpref\relax
\newcommand\nextletter[1]{%
\FPdiv{\result}{\strippt\xvp}{-\strippt\yvp}%
\shslbox{\result}{#1}{\themagf}%
\addtolength{\xvp}{\wd\foobox}%
}
\newcommand\nextword[1]{\nextwordhelp #1\relax}
\def\nextwordhelp#1#2\relax{%
\nextletter{#1}%
\ifx\relax#2\relax\sbox{\foobox}{\scalebox{\themagf}{~}}\addtolength{\xvp}{\wd\foobox}\usebox{\foobox}%
\else\nextwordhelp#2\relax\fi%
}
\newcommand\nextline[1]{%
\parallax\setmagf\nextlinehelp #1 \relax \relax%
\vspace{-\dimexpr\baselineskip-\themagf\baselineskip}\par%
\addtolength\yvp{\themagf\baselineskip}\xvp\xvpref\relax%
\ignorespaces%
}
\def\nextlinehelp#1 #2\relax{%
\nextword{#1}%
\ifx\relax#2\relax\else\nextlinehelp #2\relax\fi%
}
\newcommand\parallax{%
\FPdiv{\result}{\strippt\yvp}{\strippt\yvpref}%
\FPsub{\result}{1}{\result}%
\hspace{-\result\xvpref}\addtolength{\xvp}{-\result\xvpref}%
}
\def\setmagf{\global\FPdiv{\themagf}{\strippt\yvp}{\strippt\yvpref}}
\parindent 0pt
\begin{document}
\pagecolor{black}\sffamily\bfseries%
\nextline{In a galaxy, far, far away, the Empire}
\nextline{struck back. Our hero, Luke Skywalker}
\nextline{nearly died, but didn't. Meanwhile,}
\nextline{R2D2 and C3PO were stuck on the}
\nextline{planet Tatoine.}
\nextline{~}
\nextline{The evil Darth Vader was plotting}
\nextline{terrible deeds.}
\end{document}
原始方法(前景中的第一行文本)
\documentclass{article}
\usepackage{fp,amssymb,graphicx,xcolor}
\makeatletter
\def\strippt{\strip@pt}
\makeatother
\newsavebox\foobox
\newcommand\slbox[2]{%
\slantbox[\result]{#2}%
}%
\newcommand{\slantbox}[2][30]{%
\mbox{%
\global\sbox{\foobox}{\textcolor{yellow!50}{#2}}%
\hskip\wd\foobox
\pdfsave
\pdfsetmatrix{1 0 #1 1}%
\llap{\usebox{\foobox}}%
\pdfrestore
}}
\newcommand\shslbox[3]{\slbox{#1}{\scalebox{#3}{#2}}}
\newlength\yvp
\newlength\xvp
\newlength\yvpref
\newlength\xvpref
\yvpref 50pt\relax
\xvpref -50pt\relax
\xvp=\xvpref\relax
\yvp=\yvpref\relax
\newcommand\nextletter[1]{%
\FPdiv{\result}{\strippt\xvp}{-\strippt\yvp}%
\shslbox{\result}{#1}{\themagf}%
\addtolength{\xvp}{\wd\foobox}%
}
\newcommand\nextword[1]{\nextwordhelp #1\relax}
\def\nextwordhelp#1#2\relax{%
\nextletter{#1}%
\ifx\relax#2\relax\sbox{\foobox}{\scalebox{\themagf}{~}}\addtolength{\xvp}{\wd\foobox}\usebox{\foobox}%
\else\nextwordhelp#2\relax\fi%
}
\newcommand\nextline[1]{\setmagf\nextlinehelp #1 \relax \relax%
\vspace{-\dimexpr\baselineskip+\themagf\baselineskip}\par%
\addtolength\yvp{-\themagf\baselineskip}\xvp\xvpref\relax%
\parallax\ignorespaces%
}
\def\nextlinehelp#1 #2\relax{%
\nextword{#1}%
\ifx\relax#2\relax\else\nextlinehelp #2\relax\fi%
}
\newcommand\parallax{%
\FPdiv{\result}{\strippt\yvp}{\strippt\yvpref}%
\FPsub{\result}{1}{\result}%
\hspace{-\result\xvpref}\addtolength{\xvp}{-\result\xvpref}%
}
\def\setmagf{\global\FPdiv{\themagf}{\strippt\yvp}{\strippt\yvpref}}
\parindent 0pt
\begin{document}
\pagecolor{black}
\nextline{In a galaxy, far, far away}
\nextline{the Empire struck back.}
\nextline{Our hero Luke Skywalker}
\nextline{nearly died, but didn't}
\nextline{Meanwhile, R2D2 and}
\nextline{C3PO were stuck on}
\nextline{the planet Tatoine.}
\end{document}
只需将值\yvpref
从 50pt 更改为 30pt 即可改变淡入淡出角度:
将负值\xvpref
从 -50pt 增加到 -80pt 允许一行中包含更多文本。当然,需要调整文本规范,因为它是逐行输入的。此外,\yvpref
设置为 50pt。