xeCJK 通過文件名調用字體有問題?
費了好大勁才精簡出下面這一段可以重現問題的代碼:
documentclass{article}
usepackage{xeCJK}
setCJKmainfont{[simsun.ttc]}
egin{document}
extsl{測試}
end{document}
編譯出現的錯誤是:
LaTeX Font Info: Try loading font information for EU1+(0) on input line 9.
LaTeX Font Info: No file EU1(0).fd. on input line 9.
! No declaration for shape EU1/(0)/m/it.
sub@sfcnt ...e forspace shapespace mandatory@arg }
error@fontshape else #1{Fo...
l.9 extsl{測試}?
Missing character: There is no 測 in font [lmroman10-regular]:mapping=tex-text!
Missing character: There is no 試 in font [lmroman10-regular]:mapping=tex-text!
xeCJK 是通過 fontspec 宏包 [1] 來調用系統字體的,這個問題其實與 xeCJK 無關:
documentclass{article}
usepackage{fontspec}
setmainfont{[simsun.ttc]}
egin{document}
extsl{測試}
end{document}
將名稱用方括弧包起來表示文件名,這是 XeTeX 底層的語法。實際上 fontspec 的用戶手冊中並沒有提及這種語法,想通過文件名調用字體,並不需要方括弧。fontspec 會檢查名稱末尾是否有 .ttc 等常見字體擴展名來判斷,加了方括弧反而會導致它判斷錯誤。所以這個問題的解決辦法是把方括弧去掉。同時要注意 BoldFont、ItalicFont 等名稱也必須是文件名。
----------------------------------------
以下是原因分析,略高能,需要了解一點 LaTeX 的 NFSS [2]。
fontspec 簡單地說就是為 NFSS 提供一個簡單的設置介面,免去手寫 .fd 的麻煩。編譯上面的例子,打開日誌文件,會發現下面這麼一段,它記錄了 fontspec 的設置結果:.................................................
. fontspec info: "defining-font"
.
. Font family "[simsun.ttc](0)" created for font "[simsun.ttc]" with options
. [Ligatures=TeX].
.
. This font family consists of the following shapes:
.
. * "normal" with NFSS spec.:
. &<-&>"[simsun.ttc]/OT:script=latn;language=DFLT;mapping=tex-text;"
.
. * "small caps" with NFSS spec.:
.
. and font adjustment code:
.
.
. * "bold" with NFSS spec.:
. &<-&>"[simsun.ttc]/B/OT:script=latn;language=DFLT;mapping=tex-text;"
.
. * "bold small caps" with NFSS spec.:
.
. and font adjustment code:
.
.
. * "italic" with NFSS spec.:
. &<-&>"[simsun.ttc]/I/OT:script=latn;language=DFLT;mapping=tex-text;"
.
. * "small caps" with NFSS spec.:
.
. and font adjustment code:
.
.
. * "bold italic" with NFSS spec.:
. &<-&>"[simsun.ttc]/BI/OT:script=latn;language=DFLT;mapping=tex-text;"
.
. * "bold small caps" with NFSS spec.:
.
. and font adjustment code:
.
.................................................
fontspec 會做很多事情,與這個問題有關的是下面這麼三件事:
- 自動設置字體族的名稱,一般是字體名稱略去空格再加上編號的形式(加編號是為了可以通過不同特性來調用同一字體)。從日誌中發現,這裡設置的名稱是 [simsun.ttc](0)。
- 如果沒有指定義大利體或粗體等字形,fontspec 會給字體名稱加上 /I 或 /B 等後綴,並馬上調用它們,通過 fontname 來判斷是否設置字形。大概相當於
font1="SimSun" at 10pt
font2="SimSun/I" at 10pt
ifnumstrcmp{fontname1}{fontname2}=z@
%% 是同一個字體,不設置義大利體
else
%% 不是同一個字體,設置義大利體
fi
但這種機制只對字體內部名稱有效,對文件名是無效的 [3]。對文件名的判斷總是不相同的,因而 fontspec 在這裡也錯誤地自動設置了義大利字形。這也是 fontspec 不支持文件名方括弧語法的原因。如果 fontspec 通過擴展名判斷出是文件名,就不會進行這一步。
- fontspec 在設置義大利字形時,會自動把它設置成斜體(slshape)的替換字形。
documentclass{article}
DeclareFontFamily{OT1}{[cmr]}{}
DeclareFontShape{OT1}{[cmr]}{m}{n}{&<-&>cmr10}{}
DeclareFontShape{OT1}{[cmr]}{m}{sl}{&<-&>ssub*[cmr]/m/n}{}
egin{document}
fontfamily{[cmr]}selectfont
extsl{test}
end{document}
DeclareFontShape 的語法是 [2]:
可見 size-function 後面的方括弧會被認為是可選參數。在我們上面的例子中 size-function 是 ssub,cmr 就被當成了 ssub 的可選參數,fontarg 就只有 /m/n,這自然是錯誤的。
----------------------------------------
通過以上分析,我們知道,顯式指定 SlantedFont,會取代掉 fontspec 自動設置的替換字形,可以避免錯誤。最新版本(v2.4a)還可以設置 NFSSFamily 為不以方括弧開頭的名字(如 songti)取代掉 fontspec 自動設置的字體族名,也可以避免錯誤。但這兩種方法都會讓 fontspec 文件名判斷錯誤,做我們上面提到的事情 2,BoldFont 等需要是內部名稱,是文件名的話需要自己用花括弧包起來。
[1]: http://www.ctan.org/pkg/fontspec[2]: http://www.ctan.org/pkg/fntguide[3]: http://www.ctan.org/pkg/xetexrefdocumentclass{article}
usepackage{xeCJK}
setCJKmainfont[AutoFakeSlant]{SimSun.ttc}
egin{document}
extsl{測試}
end{document}
推薦閱讀:
※對齊命令 flushleft 相比
aggedright 有什麼區別與問題,而因此不應使用?
※TeX 編程有哪些資料與工具?
※如何評價 upTeX?
※商業出版公司真的有用 LaTeX 的嗎?
※你為什麼用LaTeX?