![解决方案和问题](https://linux22.com/image/250470/%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%E5%92%8C%E9%97%AE%E9%A2%98.png)
我如何获取输入文本并将每个字符替换为代表该字符边界框的实心(和/或空心)矩形?如果两个字符因字距调整而更接近(例如microtype
),则框会重叠。添加框不应改变文本的间距 - 我正在寻找字母的“草稿模式”。
解决方案和问题
Yiannis Lazarides 和 egreg 提出的两种解决方案似乎对单个单词的处理都还不错,尽管如上所述,字距调整似乎没有完全得到尊重。以下是结果(没有 markup/egreg/Yiannis):
但是,当涉及多个单词时,这两种解决方案都会失败。其中一个答案完全占用了一个空格,而另一个则过度补偿。它们似乎也都因换行符而卡住了。
答案1
LuaTeX 解决方案。应该适用于我所知的所有情况:
\documentclass{article}
\usepackage{luacode,luatexbase}
\begin{document}
\begin{luacode*}
local GLYPH_ID = node.id("glyph")
local number_sp_in_a_pdf_point = 65782
function math.round(num)
return math.floor(num * 1000 + 0.5) / 1000
end
-- width/height/depth of a glyph and the whatsit node
local wd,ht,dp,w
-- head is a linked list (next/prev entries pointing to the next node)
function showcharbox(head)
while head do
if head.id == 0 or head.id == 1 then
-- a hbox/vbox
showcharbox(head.list)
elseif head.id == GLYPH_ID then
-- Create a pdf_literal node to draw a box with the dimensions
-- of the glyph
w = node.new("whatsit","pdf_literal")
wd = math.round(head.width / number_sp_in_a_pdf_point)
ht = math.round(head.height / number_sp_in_a_pdf_point)
dp = math.round(head.depth / number_sp_in_a_pdf_point)
-- draw a dashed line if depth not zero
if dp ~= 0 then
w.data = string.format("q 0.2 G 0.1 w 0 %g %g %g re S f [0.2] 0 d 0 0 m %g 0 l S Q",-dp,-wd,dp + ht,-wd)
else
w.data = string.format("q 0.2 G 0.1 w 0 %g %g %g re S f Q",-dp,-wd,dp + ht,-wd)
end
-- insert this new node after the current glyph and move pointer (head) to
-- the new whatsit node
w.next = head.next
w.prev = head
head.next = w
head = w
end
head = head.next
end
return true
end
luatexbase.add_to_callback("post_linebreak_filter",showcharbox,"showcharbox")
\end{luacode*}
A \emph{wonderful} serenity has taken {\large possession} of my entire soul, like these
\textsl{sweet}
\textbf{mornings} of spring which I enjoy with my whole heart. I am alone, and feel the
charm of existence in this spot, \textbf{which} was created for the bliss of souls like
mine. I am so happy, my dear friend, so absorbed in the exquisite sense of
mere tranquil existence, that I neglect my talents. I should be incapable of
drawing a single stroke at the present moment; and yet I feel that I never was
a greater artist than now.
\end{document}
得出的结果是:
(细节)
奖励:如果字形的深度不为 0,它会绘制基线。
这是一个用黑色矩形(规则)替换字形的解决方案:
\documentclass{article}
\usepackage{luacode,luatexbase,microtype}
\begin{document}
\begin{luacode*}
local GLYPH_ID = node.id("glyph")
-- head is a linked list (next/prev entries pointing to the next node)
-- parent it the surrounding h/vbox
function showcharbox(head,parent)
while head do
if head.id == 0 or head.id == 1 then
-- a hbox/vbox
showcharbox(head.list,head)
elseif head.id == GLYPH_ID then
r = node.new("rule")
r.width = head.width
r.height = head.height
r.depth = head.depth
-- replace the glyph by
-- the rule by changing the
-- pointers of the next/prev
-- entries of the rule node
if not head.prev then
-- first glyph in a list
parent.list = r
else
head.prev.next = r
end
if head.next then
head.next.prev = r
end
r.prev = head.prev
r.next = head.next
-- now the glyph points to
-- nowhere and we should remove
-- it from the memory
node.free(head)
head = r
end
head = head.next
end
return true
end
luatexbase.add_to_callback("post_linebreak_filter",showcharbox,"showcharbox")
\end{luacode*}
\hsize6cm
A wonderful serenity has taken possession of my entire soul, like these sweet
mornings of spring which I enjoy with my whole heart. I am alone, and feel the
charm of existence in this spot, which was created for the bliss of souls like
mine. I am so happy, my dear friend, so absorbed in the exquisite sense of
mere tranquil existence, that I neglect my talents. I should be incapable of
drawing a single stroke at the present moment; and yet I feel that I never was
a greater artist than now.
\end{document}
答案2
这是一个尊重字距调整(但不尊重连字符)的解决方案:
\documentclass{article}
\usepackage{xcolor}
\makeatletter
\def\showboxes#1{%
\begingroup\fboxrule=.1pt \fboxsep=-\fboxrule
\@showboxes#1\@showboxes\@empty
\endgroup}
\def\@showboxes#1#2{%
\ifx#2\@showboxes
\fbox{\color{gray}#1}\expandafter\@gobble
\else
\setbox0=\hbox{#1\kern0pt#2}\setbox2=\hbox{#1#2}%
\dimen0=\wd0 \advance\dimen0 -\wd2 % \dimen0 contains the kern between the two chars
\fbox{\color{gray}#1}\kern-\dimen0
\expandafter\@showboxes
\fi#2}
\begin{document}
\showboxes{AVov}
\end{document}
要输入更多单词,只需添加
\usepackage{xparse}
\def\showboxesaux#1{\showboxes{#1} }
\NewDocumentCommand\Showboxes{>{\SplitList{ }}m}
{\ProcessList{#1}\showboxesaux\unskip}
并使用
\Showboxes{The quick brown fox jumped over the lazy dog.}
但连字符不会被处理。
答案3
可能最好的是 TeXbook 中的代码,这个就留给你了。另一种选择是研究soul
软件包中的代码并使用提供的扫描仪。
以下是改编版本:
\documentclass{article}
\usepackage{soul,graphicx,xcolor}
\fboxrule=0.1pt
\fboxsep=-\fboxrule
\begin{document}
\makeatletter
\def\SOUL@soeverytoken{%
\fbox{\color{gray}\the\SOUL@token}}
\makeatother
\scalebox{7}{\color{purple}\so{ailbcdefgh}}
\end{document}
将灰色改为白色,使字母消失。
\fbox
如果您需要补偿 0.1pt 规则或使用我已采纳的评论中 egreg 的建议,则需要将其更改为基本的 TeX 原语。
答案4
来自context
当前的 TeXLive
\setuppagenumbering[location={}]
\definepapersize[DE][width=15cm,height=15cm]
\setuppapersize [DE][DE]
\setuplayout[width=13cm,height=13cm]
\definefontfeature[default][default][boundingbox={frame,blue,empty}]
\starttext
\bgroup
\showglyphs
\showfontkerns
\showmakeup[hbox]
\showmakeup[line]
% \showallmakeup
»Tee for Two« shows negative kerning.
\input sapolsky \par
\egroup
\stoptext