当 MATLAB 字符编码为 UTF-8 时出现问题,Linux 用户通常是这种情况(因此 Amro 使用 CP1252 的配置没有问题)。当 MATLAB 字符集编码(使用slCharacterEncoding()
UTF-8 获取)时,MATLAB eps 导出函数存在错误(至少在 R2011b 之前),因为它以八进制转义 UTF-8 格式(2 个字节)导出非 ASCII 字符,而 Postscript解释器设置为解码 1 字节格式。
让我们用字符 ö U+00F6 来说明这个错误,它的一些表示是:
- UTF-16:0x00F6
- UTF-8:0xC3 0xB6
- 八进制转义 UTF-8:\303\266
- XML 十进制实体:ö
MATLAB 创建的 eps 文件包含:
/Helvetica /ISOLatin1Encoding 120 FMSR
(\303\266) s
MATLAB 在 eps 文件中定义了一个FMSR
将 Helvetica 字体重新编码为另一种编码的函数,这里ISOLatin1Encoding是两个内置编码向量之一,并且与 ISO-8859-1 (Latin1) 标准非常匹配(参见第 329 页) 330 的 Postscript 语言参考手册了解更多详细信息)。简而言之,编码向量是将字符名称与字符代码相关联的 256 元素数组。所以它只读取 1 字节的字符代码。在 ISO-8859-1 中,\303=195=à 和 \266=182=¶。结果,它打印出ö。
使用 UTF-8 语言环境导出非 ASCII ISO-8859-1 字符的选项
将八进制 UTF-8 代码转换为八进制 ISO-8859-1 代码,这很容易,因为非 ASCII ISO-8859-1 字符在 UTF-8 中遵循相同的布局。例如,使用可以从命令窗口或导出脚本运行的程序 sed:
!sed -i -e 's/\\302\(\\2[4-7][0-7]\)/\1/g' -e 's/\\303\\2\([0-7][0-7]\)/\\3\1/g' file.eps
因此,\303\266
变为\366
=246=ö。您可以在 MATLAB 中直接键入非 ASCII 字符。
在将文本添加到图窗之前更改 MATLAB 字符集编码slCharacterEncoding('ISO-8859-1')
,如果您从命令窗口添加文本,请对非 ASCII 字符使用 char(number)。如果使用绘图工具直接在图中添加文本,则可以输入非 ASCII 字符。此解决方案并不理想,因为非 ASCII 字符不会以默认字体(Linux 上的 MATLAB 默认使用 Helvetica)出现在图形上,并且如果您编写图形创建脚本,则需要使用 char(number)。
稍后通过使用用户提交的 MATLAB 函数(例如 LaPrint 或其分支之一)使用 LaTex 渲染文本,该函数会创建一个包含图形文本的 tex 文件和一个包含图形非文本部分的 eps 文件。一个类似的解决方案是 matlab2tikz,它创建一个 tikz/pgfplot 文件和一个 tex 文件。
使用 MATLAB 的 Latex 解释器:\"{o}
. MATLAB 通过将 ASCII 字符与其变音符号组合来创建字符,但由于相对定位不好(变音符号与字符相比在右侧有点过多),结果质量低下。MATLAB 使用 Computer Modern 字体中的字形并将字体嵌入到 eps 文件中(增加了 ~ 80 Ko)。此外,从 eps 创建的 pdf 中的原始文本不包含ö
but o ̈
。
导出非 ISO-8859-1 字符
对于导出不在 ISO-8859-1 中的字符,如果需要的字符数少于 256(8 位格式)并且理想情况下在标准编码集中,则可能有一个合理的解决方案。它涉及以下步骤:
- 将八进制代码转换为 Unicode 字符;
- 将文件保存为目标编码标准(8位格式);
- 添加目标编码集的编码向量。
例如,如果要导出波兰语文本,则需要将文件转换为 ISO-8859-2。这是在 Linux 上使用 Bash 的实现:
#!/bin/bash
name=$(basename "$1" .eps)
ascii2uni -a K "$1" > /tmp/eps_uni.eps
iconv -t ISO-8859-2 /tmp/eps_uni.eps -o "$name"_latin2.eps
sed -i -e '/%EndPageSetup/ r ISOLatin2Encoding.ps' -e 's/ISOLatin1Encoding/MyEncoding/' "$name"_latin2.eps
保存为 eps_lat2;然后运行该命令sh eps_lat2 file.eps
会使用 Latin-2 编码创建 file_latin2.eps。文件 ISOLatin2Encoding.ps 包含以下内容:
/MyEncoding
% The first 144 entries are the same as the ISO Latin-1 encoding.
ISOLatin1Encoding 0 144 getinterval aload pop
% \22x
/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
% \24x
/nbspace /Aogonek /breve /Lslash /currency /Lcaron /Sacute /section
/dieresis /Scaron /Scedilla /Tcaron /Zacute /hyphen /Zcaron /Zdotaccent
/degree /aogonek /ogonek /lslash /acute /lcaron /sacute /caron
/cedilla /scaron /scedilla /tcaron /zacute /hungarumlaut /zcaron /zdotaccent
% \30x
/Racute /Aacute /Acircumflex /Abreve /Adieresis /Lacute /Cacute /Ccedilla
/Ccaron /Eacute /Eogonek /Edieresis /Ecaron /Iacute /Icircumflex /Dcaron
/Dcroat /Nacute /Ncaron /Oacute /Ocircumflex /Ohungarumlaut /Odieresis /multiply
/Rcaron /Uring /Uacute /Uhungarumlaut /Udieresis /Yacute /Tcedilla /germandbls
% \34x
/racute /aacute /acircumflex /abreve /adieresis /lacute /cacute /ccedilla
/ccaron /eacute /eogonek /edieresis /ecaron /iacute /icircumflex /dcaron
/dcroat /nacute /ncaron /oacute /ocircumflex /ohungarumlaut /odieresis /divide
/rcaron /uring /uacute /uhungarumlaut /udieresis /yacute /tcedilla /dotaccent
256 packedarray def
这是 Python 的另一个实现(因此它也可以在 Windows 和 Mac 上工作):
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys,codecs
input = sys.argv[1]
fo = codecs.open(input[:-4]+'_latin2.eps','w','latin2')
with codecs.open(input,'r','string_escape') as fi:
data = fi.readlines()
with open('ISOLatin2Encoding.ps') as fenc:
for line in data:
fo.write(line.decode('utf-8').replace('ISOLatin1Encoding','MyEncoding'))
if line.startswith('%%EndPageSetup'):
fo.write(fenc.read())
fo.close()
保存为 eps_lat2.py;然后运行该命令python eps_lat2.py file.eps
会使用 Latin-2 编码创建 file_latin2.eps。
通过更改脚本中的编码向量和 iconv(或 codecs.open)参数,它可以很容易地适应其他 8 位编码标准。