標籤:

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 會做很多事情,與這個問題有關的是下面這麼三件事:

  1. 自動設置字體族的名稱,一般是字體名稱略去空格再加上編號的形式(加編號是為了可以通過不同特性來調用同一字體)。從日誌中發現,這裡設置的名稱是 [simsun.ttc](0)。

  2. 如果沒有指定義大利體或粗體等字形,fontspec 會給字體名稱加上 /I 或 /B 等後綴,並馬上調用它們,通過 fontname 來判斷是否設置字形。大概相當於

    font1="SimSun" at 10pt
    font2="SimSun/I" at 10pt
    ifnumstrcmp{fontname1}{fontname2}=z@
    %% 是同一個字體,不設置義大利體
    else
    %% 不是同一個字體,設置義大利體
    fi

    但這種機制只對字體內部名稱有效,對文件名是無效的 [3]。對文件名的判斷總是不相同的,因而 fontspec 在這裡也錯誤地自動設置了義大利字形。這也是 fontspec 不支持文件名方括弧語法的原因。如果 fontspec 通過擴展名判斷出是文件名,就不會進行這一步。

  3. fontspec 在設置義大利字形時,會自動把它設置成斜體(slshape)的替換字形。

以上三件事合起來,造成了 NFSS 語法衝突,例子可以精簡為:

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]:

其中 loading-info 由一段或者數段 fontshape-decl 組成。fontshape-decl 的語法是:

可見 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/xetexref


documentclass{article}

usepackage{xeCJK}

setCJKmainfont[AutoFakeSlant]{SimSun.ttc}

egin{document}

extsl{測試}

end{document}


推薦閱讀:

對齊命令 flushleft 相比
aggedright 有什麼區別與問題,而因此不應使用?

TeX 編程有哪些資料與工具?
如何評價 upTeX?
商業出版公司真的有用 LaTeX 的嗎?
你為什麼用LaTeX?

TAG:LaTeX | XeTeX |