2015年2月23日 星期一

字型雜記

sans-serif vs. serif

單字的字義就說明了一切: serif (襯線字) 是在字的邊端加裝飾 (如垂直線條), 用意是利於辨識相似的字, 而 sans-serif (無襯線字)則是沒有加裝飾。serif 最早是用在西方文字印刷體的內文, 如今在中文字或是電腦、行動裝置螢幕上, 情境大不同, 無此必要。

中文相對於的例子是明體的橫線右上角有個三角形, 類似 serif; 而黑體則沒有, 類似 sans-serif。字型的運用大家有不同的說法, 原本我以為內文該用明體, 標題用黑體, 就如同 serif 和 sans-serif 的用法。但是《字型散步:日常生活的中文字型學》用內文用黑體, UDN 改版後內文也用黑體。我現在也覺得黑體較順眼 [*1]。

另外, 明體也有可能用在大字, 《字型散步》舉例福音戰士用明體作為大字, 就用得很漂亮, 所以還是要看選用的字型。換句話說, 了解這些知識是清楚它們的特色。如同其它CS技術一樣, 要依配套措施決定如何使用。

明體特色

除水平線的右上角有個三角形外, 還有水平細, 直筆粗, 避免文字擁擠。

黑體特色

筆劃筆直, 大多無襯線。

康熙字典體

直接取用康熙字典內的字, 沒有修正, 相較之下較破碎和零亂。原本應該是缺點, 但因為與眾不同, 反到成了優點, 每個字看起來比較「有感覺」, 比較文青。

定寬字和比例字

中文字無此差異, 主要是西方文字、數字和符號有差。

細明體是定寬字, 裡面附的英數字每個字都占「半格」; 新細明體是比例字, 英數字是依字的實際大小決定寬度。用 terminal 或開發程式的 IDE, 習慣用定寬字。閱讀內文則是用比例字。

字體和字型

字體是概念, 字型是實踐的產品格式。設計一套字體, 然後作成字型供電腦使用。類似音樂和 MP3。不過大多數情境兩者混用也通。

瀏覽器用字的順序和方塊字

瀏覽器會依 CSS font-family 定的順序找字, 有找到就用, 沒找到就用下一個。依此規則, 一般會先放英文字型再放中文字型, 因為英文字型不會附中文字, 但中文字型會附英文字。藉此用比較好看的英文字型, 沒有的時候再套用中文字型附的英文字。看到方塊字的話, 我猜應該是字型裡沒作這個字的樣子, 卻填了個方塊, 瀏覽器就拿去用了。如果字型檔不附上方塊圖, 應該可以選用下一個字型。實際情況如何, 要研究字型檔和字型函式庫才知道了。

日文字型和中文字型

有些日文字型比較漂亮, 但是用日文字型有個風險, 少部份字的樣子可能寫法和中文不同, 或是缺字造成方塊字。待有看到強烈的例子再來思考是否因此避免使用日文字型。

像 UDN 目前用的字體順序是「Helvetica,Heiti TC,Segoe UI,Meiryo,微軟正黑體」, 其中 Meiryo 是日文的 sans-serif, 我用的 Windows 7 有內建 Meriyo微軟正黑體, 因此瀏覽器會選用 Meriyo。但是... Meriyo 真的比微軟正黑體好看, 沒遇到什麼狀況的話, 我應該也會用 Meriyo 吧。

Web Font

Web Font 是在載入網頁時再立即下載用到的字的字型, 因為用到的字不多, 理論上載入速度很快。Web Font 讓使用字型更為靈活, 可避免用圖替代文字。利於日後修改還有內文搜尋、複製貼上。

我覺得有兩個情況不適合使用 Web Font:

  • 內文: 用在內文時, 有時會看到內文一片白, 然後才顯示出來。慢了一點還以為網頁壞了, 就關掉網頁了。
  • 行動裝置, 特別是手機: 用 2.5G/3G 上網時 latency 遠大於一般的情況, 即使下載的字型檔只有 1 byte, 也可能等個一會兒。雖然 4G 大幅縮小 latency, 但普及率不高, 目前還不是使用時機。

另外使用在粗體字時 (如標題), 要小心 Web Font 的設定。如果設定只取普通的字型, 瀏覽器會自己模擬出粗體, 結果就不好看了。配套解法見 Fake Bolding of Web Fonts

其它

還有許多有趣的知識, 照樣抄寫下來有些瑣碎, 這裡只有留日後自己可能會用到的東西。另外留下參考資料供日後備查。

參考資料

備註

1. 懶得改既有 blog 設定了, 因為不能只是改字型, 字高段落間隙和標題等都要改。要作新網站的時候, 再多放些心思在字型上吧。

2015年2月6日 星期五

跳掉檔案開頭數 bytes 的作法

假設有個大檔案 (e.g. 500MB) 在開頭存有 meta data, 後面存有內容, 要怎麼跳掉開頭的 meta data, 只留下內容呢?

命令列的作法

這裡看到兩個有效率的作法:

使用 subshell: 先用一個 dd 跳掉開頭 1131 bytes (block size=1131, read 1 block), 再用第二個 dd 用正常的 block size 讀寫檔, 這樣效率就和直接用 dd 複製檔案差不多了。

$ ( dd bs=1131 count=1 of=dev_null && dd bs=4K of=out.mp3 ) < 100827_MR029_LobbyControl.mp3

使用 pipe 配合 a group of commands: 概念差不多, 只是改用 pipe。

$ dd if=filtered.dump bs=512k | { dd bs=1131 count=1 of=/dev/null; dd bs=512k of=trimmed.dump; }

Python 不建立新檔的作法

產生新檔案的時間成本有點高, 可能會花到數秒。如果是 Python 程式內要用的話, 可以直接用 file object 然後想辦法跳掉開頭資料。

偷懶的作法是直接用 file object, 然後先呼叫 file.read(N) 跳掉開頭 N bytes。缺點是若 file object 會傳入 third-party lib 使用, 其它程式碼可能會用 seek() 回頭讀開頭的內容。

保險的作法是自訂一個 file object wrapper。這個 wrapper 行為和內建 file object 一模一樣, 只是讀不到開頭數個 bytes。這樣效率和一般的 file object 幾乎沒差。 程式碼見這裡, 另外這裡是測試碼。關鍵是覆寫和移動檔案位置有關的 seektell。然後用 Python 提供的 __getattr__(self, attr) 實作剩下沒改到的 method。

那麼, 要怎麼知道該覆寫那些 method 呢? 用 ipython 建一個 file object, 然後利用補字功能, 再一個個看 method 說明, 很快就知道該覆寫那些了。

以下是示意的操作過程:

$ ipython

In [1]: f = open('/etc/fstab')

In [2]: f.<TAB>
f.close       f.encoding    f.fileno      f.isatty      f.name        f.next        f.readinto    f.readlines   f.softspace   f.truncate    f.writelines
f.closed      f.errors      f.flush       f.mode        f.newlines    f.read        f.readline    f.seek        f.tell        f.write       f.xreadlines

In [2]: f.close?
Type:       builtin_function_or_method
Base Class: <type 'builtin_function_or_method'>
String Form:<built-in method close of file object at 0x1a9a660>
Namespace:  Interactive
Docstring:
close() -> None or (perhaps) an integer.  Close the file.

Sets data attribute .closed to True.  A closed file cannot be used for
further I/O operations.  close() may be called more than once without
error.  Some kinds of file objects (for example, opened by popen())
may return an exit status upon closing.

In [3]: f.encoding?

...

In [21]: f.seek?

Type:       builtin_function_or_method
Base Class: <type 'builtin_function_or_method'>
String Form:<built-in method seek of file object at 0x1a9a660>
Namespace:  Interactive
Docstring:
seek(offset[, whence]) -> None.  Move to new file position.

Argument offset is a byte count.  Optional argument whence defaults to
0 (offset from start of file, offset should be >= 0); other values are 1
(move relative to current position, positive or negative), and 2 (move
relative to end of file, usually negative, although many platforms allow
seeking beyond the end of a file).  If the file is opened in text mode,
only offsets returned by tell() are legal.  Use of other offsets causes
undefined behavior.
Note that not all file objects are seekable.

...

在 Fedora 下裝 id-utils

Fedora 似乎因為執行檔撞名,而沒有提供 id-utils 的套件 ,但這是使用 gj 的必要套件,只好自己編。從官網抓好 tarball ,解開來編譯 (./configure && make)就是了。 但編譯後會遇到錯誤: ./stdio.h:10...