This answer is inspired by qingkuan@bbs.ctex.org.
When I saw your question yesterday, three possible solutions came into my mind. They are:
- Select a font whose chars has a rice-shaped grid (米字格).
- Use LaTeX tabular to draw these grids, and then fill Chinese chars into them.
- Get the position and size of each Chinese chars, and then, draw the grids with TikZ.
The first possible solution is direct but lack of portability, and the second one is not a good choice if one wish to make line-breaking automatically (also page-breaking). Hence, the last one seems to be the only choice.
The package soul
insert things after every possible hyphenation (see here), which could help us finding the line-break point. However, the package soul
is sometimes fragile, since it cannot work well with the package xeCJK
which is an important Chinese supporting package.
Qingkuan@bbs.ctex.org helped me replenishing the already-off trail.
Testing every chars in .tex
source file, xeCJK
is able to figure out if a specific char is a CJK (Chinese, Japanese and Korean) char. Hence, we are now able to get the position of every Chinese char's position.
Output
Let's see the output first.

Requirements
- Encoding: UTF-8
- Engine: XeTeX (start command line with
xelatex
)
- Packages:
xeCJK
(later than v3.2.8, 2013/12/05), ctex
- Font: Adobe Chinese-simp fonts (click here to start downloading automatically, these four fonts are free, don't worry about the copyright)
Code
%!TEX program = xelatex
\documentclass[UTF8, adobefonts]{ctexart}
\usepackage{tikz}
\usepackage{xcolor}
\usepackage{geometry}
\geometry{margin = 2.1cm, papersize = {16cm, 13cm}}
\pagestyle{empty}
\linespread{0.833333}
\makeatletter
\ExplSyntaxOn
\box_new:N \l_@@_grid_box % l means local
\coffin_new:N \l_@@_grid_coffin
\coffin_new:N \l_@@_charater_coffin
\int_const:Nn \c_@@_test_char { "4E00 }
\cs_new_protected_nopar:Npn \@@_update_grid_box:
{
\hbox_set:Nn \l_@@_grid_box
{ \XeTeXuseglyphmetrics = \c_zero \c_@@_test_char }
\use:x
{
\@@_update_grid_box:nnn
{ \dim_use:N \box_wd:N \l_@@_grid_box } % width
{ \dim_use:N \box_ht:N \l_@@_grid_box } % height
{ \dim_use:N \box_dp:N \l_@@_grid_box } % depth
}
\coffin_attach:NnnNnnnn
\l_@@_charater_coffin { hc } { vc }
\l_@@_grid_coffin { hc } { vc }
{ \c_zero_dim } { \c_zero_dim }
\hbox_set:Nn \l_@@_grid_box
{
\coffin_typeset:Nnnnn \l_@@_charater_coffin
{ H } { l } { \c_zero_dim } { \c_zero_dim }
}
\box_set_wd:Nn \l_@@_grid_box { \c_zero_dim }
\box_set_ht:Nn \l_@@_grid_box { \c_zero_dim }
\box_set_dp:Nn \l_@@_grid_box { \c_zero_dim }
}
\cs_new_protected_nopar:Npn \@@_update_grid_box:nnn #1#2#3
{
\hbox_set:Nn \l_@@_grid_box { }
\box_set_wd:Nn \l_@@_grid_box {#1}
\box_set_ht:Nn \l_@@_grid_box {#2}
\box_set_dp:Nn \l_@@_grid_box {#3}
\hcoffin_set:Nn \l_@@_charater_coffin { \box_use:N \l_@@_grid_box }
\@@_draw_grid:nn {#1} { (#2) + (#3) }
}
\cs_new_protected_nopar:Npn \@@_draw_grid:nn #1#2
{
\use:x
{
\@@_draw_grid:nnnn { \dim_eval:n {#1} } { \dim_eval:n {#2} }
{ \dim_eval:n { (#1) / 2 } } { \dim_eval:n { (#2) / 2 } }
}
}
\cs_new_protected_nopar:Npn \@@_draw_grid:nnnn #1#2#3#4
{
\hcoffin_set:Nn \l_@@_grid_coffin
{
\begin{tikzpicture}
\draw[help~lines] (0,#4) -- (#1,#4) (#3,0) -- (#3,#2);
\draw[help~lines,dashed] (0,0) -- (#1,#2) (0,#2) -- (#1,0);
\draw[help~lines, red, thick] (0,0) rectangle (#1,#2);
\end{tikzpicture}
}
}
\cs_new_protected_nopar:Npn \@@_grid_CJKsymbol:n
{ \box_use:N \l_@@_grid_box \@@_grid_CJKsymbol:n }
\cs_new_protected_nopar:Npn \@@_grid_CJKpunctsymbol:n
{ \box_use:N \l_@@_grid_box \@@_grid_CJKpunctsymbol:n }
\keys_define:nn { @@ }
{
format .tl_set:N = \l_@@_formal_tl ,
format .initial:n = { \normalfont }
}
\cs_new_protected:Npn \@@_active_grid:n #1
{
\xeCJKsetup{PunctStyle=plain,CJKglue=\allowbreak,AllowBreakBetweenPuncts}
\keys_set:nn { @@ } {#1}
\tl_use:N \l_@@_formal_tl
\@@_update_grid_box:
\xeCJK_swap_cs:NN \CJKsymbol \@@_grid_CJKsymbol:n
\xeCJK_swap_cs:NN \CJKpunctsymbol \@@_grid_CJKpunctsymbol:n
\__xeCJK_add_to_shipout:n
{
\xeCJK_swap_cs:NN \CJKsymbol \@@_grid_CJKsymbol:n
\xeCJK_swap_cs:NN \CJKpunctsymbol \@@_grid_CJKpunctsymbol:n
}
}
\NewDocumentCommand \CJKgrid { +O { } +m }
{ \group_begin: \@@_active_grid:n {#1} #2 \relax \group_end: }
\NewDocumentEnvironment { CJKGrid } { +O { } }
{ \@@_active_grid:n {#1} } { \par }
\ExplSyntaxOff
\begin{document}
\setlength{\parindent}{0pt}
\zihao{0}
\CJKgrid{\kaishu 我\color{gray!20}我我我我我我\color{white}我}
\CJKgrid{\kaishu 喜\color{gray!20}喜喜喜喜喜喜\color{white}喜}
\CJKgrid{\kaishu 歡\color{gray!20}歡歡歡歡歡歡\color{white}歡}
\CJKgrid{\kaishu 寫\color{gray!20}寫寫寫寫寫寫\color{white}寫}
\CJKgrid{\kaishu 漢\color{gray!20}漢漢漢漢漢漢\color{white}漢}
\CJKgrid{\kaishu 字\color{gray!20}字字字字字字\color{white}字}
\end{document}
EDIT
The Adobe fonts is not really necessary, since they are used here for displaying. One can replace the option adobefonts
by nofonts
, and then reset fonts by control sequences provided by xeCJK
(See its documentation for details).