2013年12月24日 星期二

利用Pango來區分不同書寫系統的文字

各位超級久不見。忙著學語言...(鞠躬)。不過也正是因為忙著學語言,才有今天這個主題。

基本上來說,我的語言筆記會呈現一定的樣式。例如說單字筆記就一定會是單字、翻譯、解釋以及例句。課文筆記一定有課文,還有(可能)每個字的解釋,相關文法等。如果說可以用一個統一的格式來表示,然後利用文件產生器來生產pdf檔的話應該很棒對吧~就說我超懶的!

要產生這樣的pdf文件,就必須要進行排版;要排版則需要有文字的語言資訊,才可以恰當的做斷行。同時,也必須確保繪製系統可以選擇系統內相對應的字型,也要有恰當的文字排列引擎等等。要收集這些資訊很曠日費時,很麻煩,要懂unicode,要懂fontconfig...所幸我們現在有pango來替我們把這些資訊整理好列出以供我們使用。

程式碼請見:https://github.com/inorindesu/pango-itemizer/blob/master/main.c

程式流程大略是

  1. 把一些原料搬進廠房
  2. 把原料切成恰當的等分
    (utf8界線切割)
  3. 把切割好的原料傳給 pango_itemize 做處理
  4. 把pango_itemize 處理好的 PangoItem 放到出貨區
  5. 收拾
將上面的步驟持續下去直到沒有原料(?),或是原料裡面有蟲(??)才停止

2013年9月7日 星期六

使用 Chart 和 Chart-cairo 繪製統計圖

很多時候我們會想要用圖來呈現我們的資料,畢竟我們對數字的敏銳度不是很高。提到統計繪圖,大部分人會想到 gnuplot 或是 R。對於程式設計人員來說,這代表他們必須寫程式來產生讓 R 或是 gnuplot 繪圖的程式碼,然後再利用作業系統的程式呼叫方法(fork + exec* , CreateProcess)來執行這段程式碼。這樣做不只麻煩(呼叫並管理子程式在某些書甚至會佔去一整章),而且還會犧牲掉不少效能。

Haskell 跟許多程式語言一樣,有人替它寫了圖表繪製程式庫(chart library) Chart。在它的 wiki 裡面可以看到幾個簡單的例子,而且畫出來的圖也挺好看的,更支援 svg, png 等格式的輸出(藉著 cairo 或 diagrams),簡直意圖誘惑人使用。

那些例子裡面沒有說明的部份,包括了中文字使用,字型調整這兩項。所以,我以這兩個項目為主軸,隨便弄了簡單的資料,畫出了相當精簡的圖。主要的程式碼請參考這裡

圖會出來會變成

(我應該放點心思在配色上的..應該是,請看在我肝臟的份上原諒我吧Orz)

使用中文字的關鍵在於設定正確的字型。如果設定的字型沒有中文字,則在應該是中文字的地方會出現方塊圖樣,暗示在該字型中找不到中文字。

Chart 程式庫最特別的地方在於它利用了 lens (不妨 google "Control.Lens" 來找相關的資料) 來讓設定圖表變得(相對的)比較容易。只是對於 lens 我還是第一次使用,所以程式碼裡面難免會有些不漂亮的寫法。如果有幸某大師瞧見了拙作,歡迎不吝指教!

2013年9月6日 星期五

使用 cabal (1.18) 安裝 cairo (改0.12.4.1 beta) 的 haskell binding

Cabal 1.18, 帶有萬眾矚目沙盒功能的 cabal 終於降臨這個世界了!從聽說這版本會導入沙盒功能開始就一直期待到現在,終於出了!或許我們可以準備 cabal-dev 的退休金,讓他回鄉下養老了。關於沙盒功能,有篇文章做了不錯的介紹,歡迎參考。

上面那個其實算是題外話。這裡要紀錄如何修改,讓 cairo-0.12.4.1 (目前,20130906,在 gtk2hs 程式碼倉庫上最新的版本)可以被 cabal 1.18 建置。

首先,要從 gtk2hs 的原始碼倉庫取得最新版的 cairo 原始檔,接著照下面修改:

diff -rN -u old-gtk2hs/cairo/cairo.cabal new-gtk2hs/cairo/cairo.cabal
--- old-gtk2hs/cairo/cairo.cabal        2013-09-06 21:17:11.559949736 +0800
+++ new-gtk2hs/cairo/cairo.cabal        2013-09-06 21:17:11.798946617 +0800
@@ -1,5 +1,5 @@
 Name:           cairo
-Version:        0.12.4.1
+Version:        0.12.4.1.1
 License:        BSD3
 License-file:   COPYRIGHT
 Copyright:      (c) 2001-2010 The Gtk2Hs Team, (c) Paolo Martini 2005, (c) Abraham Egnor 2003, 2004, (c) Aetion Technologies LLC 2004
diff -rN -u old-gtk2hs/cairo/Gtk2HsSetup.hs new-gtk2hs/cairo/Gtk2HsSetup.hs
--- old-gtk2hs/cairo/Gtk2HsSetup.hs     2013-09-06 21:17:11.557949762 +0800
+++ new-gtk2hs/cairo/Gtk2HsSetup.hs     2013-09-06 21:17:11.797946630 +0800
@@ -17,6 +17,7 @@
 
 import Distribution.Simple
 import Distribution.Simple.PreProcess
+import Distribution.Simple.Program.Find (defaultProgramSearchPath)
 import Distribution.InstalledPackageInfo ( importDirs,
                                            showInstalledPackageInfo,
                                            libraryDirs,
@@ -441,7 +442,7 @@
 checkGtk2hsBuildtools :: [Program] -> IO ()
 checkGtk2hsBuildtools programs = do
   programInfos <- mapM (\ prog -> do
-                         location <- programFindLocation prog normal
+                         location <- programFindLocation prog normal defaultProgramSearchPath
                          return (programName prog, location)
                       ) programs
   let printError name = do
diff -rN -u old-gtk2hs/cairo/SetupWrapper.hs new-gtk2hs/cairo/SetupWrapper.hs
--- old-gtk2hs/cairo/SetupWrapper.hs    2013-09-06 21:17:11.558949749 +0800
+++ new-gtk2hs/cairo/SetupWrapper.hs    2013-09-06 21:17:11.797946630 +0800
@@ -6,7 +6,7 @@
 
 import Distribution.Package
 import Distribution.Compiler
-import Distribution.Simple.Utils
+import Distribution.Simple.Utils hiding (moreRecentFile)
 import Distribution.Simple.Program
 import Distribution.Simple.Compiler
 import Distribution.Simple.BuildPaths (exeExtension)

接著

cd /path/to/your/designated/sandbox
cabal sandbox init
cabal install path/to/patched/cairo

注意事項

如果使用

cabal --with-ghc=your-ghc install
的話有機會導致失敗:在建立安裝程式碼的時候,cabal 似乎會使用系統預設的 ghc ,也就是在系統路徑下可以找到的那個 ghc。如果 your-ghc 的版本和 ghc 差太多,而且各自的預設 haskell 套件庫裡面的 Cabal 版本不一致,就會導致很嚴重且難以追蹤的錯誤。

這樣子弄完後應該就可以使用了。為了弄 Chart 以及 Chart-cairo (Chart-diagrams 好像很悲劇的不能畫出中文)結果被 cairo 卡了好幾個小時...

2013年8月19日 星期一

[Fedora] 讓 yum 保留更多的 kernel

最近 Fedora 18/19 的 kernel 升級到 3.10 系列。這樣平常的事情(喔喔!又有新核心升級了!),讓我了解所謂悲劇(好吧其實沒那麼嚴重XD)就是從這些看似日常生活的小事來的。

有天我要使用隨身碟,發現系統無論如何都無法讓隨身碟就緒(是指放到 /dev/sdX1 使可以掛載)。檢視 dmesg 輸出後發現該裝置以某個頻率被重設。搜尋後的結果發現不是電源供應器的問題,而是新發行的 3.10 核心的蟲。這個蟲應該只會影響到某些廠牌,某些型號的隨身碟。

當時已經有個可以解決這個問題 patch 存在,(看了 patch 的感想:僅僅三行的改變,就修復了這個臭蟲。反過來說,僅僅差三行,就讓電腦的隨身碟功能無法運作...)然而,處理作業系統核心對我來說太陌生,所以決定要等 rpm 包裝小組所謂的「上游修復 (upstream)」。這時候我可以用系統內的 3.9 系列核心來擋一下。

2013年8月4日 星期日

使用前請先看說明書喔~

使用任何東西之前,即使自以為熟悉,也要掃描過說明書。如果不恰當的使用這個東西會造成不幸,那就要詳讀說明書。

看了上面的話會不會覺得接著要說的事情很嚴肅?其實這句話是這樣來的,請聽我娓娓道來..

因為有可能會在沒有網路的情況下寫 haskell 程式,很擔心寫到一半發現漏掉了某個程式庫,就只能輕扯頭髮,責罵自己的糊塗...。但我沒有預測未來的能力,很難判斷自己會不會突然需要哪個程式庫..那,如果可以擁有整個 hackage 的話呢(也就是做一個 hackage 的私人 mirror)?

在這樣的構想下,對 hackage 進行探索,發現藉由取得 00-index.tar.gz 即可得到所有 hackage package 存放的位置等珍貴資訊。我可以依據這樣的資料下載整個 hackage 到自己的電腦裡。

對這個程式有興趣的見這裡。這個程式的流程大概是:使用 http-conduit 的 simpleHttp 下載索引檔,剖析它的目錄結構,接著規劃下載(當然也利用 http-conduit 的 simpleHttp),然後全部下載完後做解壓縮測試看有沒有下載錯誤。這樣就結束了是也~為什麼用 http-conduit 的 simpleHttp?它就寫在 http-conduit 說明文件最上端的範例裡,就用下去了。

2013年8月2日 星期五

Parsec 練習:寫個 ass 字幕剖析程式

有些事情很講求緣份,像是遇到不錯且值得去認識的人,或是看到了不錯的程式語言,或是注意到某家餐廳的文宣...。這裡也一樣。

某天在讀 Real World Haskell 的 parsec 那章,有點累想看影片的時候,發現某個 ass 字幕和影片不同步...(差了一秒鐘左右)。隨手找了個叫做 AegisSub 的軟體,正打算安裝起來時發現它需要 wxWidget 2.9 (的樣子),而 Fedora 19 附帶的只有 wx 2.8。正在思考要不要安裝 wx 2.9 的時候突然有種靈光一閃的感覺:「這不是練習使用 hasell parser combinator 的好時機嗎?」,就動工了 :p

2013年7月22日 星期一

用Haskell來食用標籤湯!

網路逛久了總會冒出一些像是「能不能收集某頁面中的所有連結」等想要把某些網頁集合起來做整理的想法。數量少的話,可以手工的做;但數量要是多起來...會很可怕的喔!

這時候就讓自己的程式設計能力上場吧!如果網站沒有提供特別的程式設計界面的話,直接抓取網頁下來分析可能是唯一的方法了。在瀏覽器裡面被排得美美的網頁實際上由 html 這種標記語言所描述,由瀏覽器所呈現。也就是,想要瀏覽器裡面看到的資料,多半可以藉著分析所得網頁的 html 來取得。(利用 javascript 即時生成內容的 Twitter 則是例外。幸好,Twitter 似乎有提供程式設計界面。)

在 Haskell 界最常被提到的 html 剖析器有 HXT 以及 tagsoup。這裡我試用tagsoup寫了一個用來處理簡單的網頁的小程式:見此

寫作這類程式最常不放心的點在於,「網頁改版了,那我的程式就只能去喝西北風了」。有些人會考慮到這點,然後在自己的程式裡面加上一些比較彈性的寫法。然而,我也聽過某些人認為這種擔心是不必要的:到時再重寫就好啦!

反正到時候一定可以解決,不用擔心,先寫再說吧!