cairoをいじってみた。

備忘録ついでのソースコード
なかなか気軽に使えて便利。

#!/usr/bin/env ruby

#gemで入れたのでgem経由require
require "rubygems"
gem "cairo"
require "cairo"

#設定。
width = 640
height = 480
str = "str"

output = "hoge.pdf"

#画像で吐くときはこっちをつかう
#surface = Cairo::ImageSurface.new( width, height )

#PDFで吐くときはこっちを使う
surface = Cairo::PDFSurface.new( output, width, height )

#共通操作は全部context経由で。
context = Cairo::Context.new( surface )

#背景を白で埋める
context.set_source_rgb( 1, 1, 1 ).rectangle( 0, 0, width, height ).fill

#円を書いてみる
context.set_source_rgb( 0, 1, 1 ).circle( 0, 0, 120 ).fill
context.set_source_rgb( 1, 0, 1 ).circle( width / 2, height / 2, 120 ).stroke
context.set_source_rgb( 1, 1, 0 ).circle( width, height, 120 ).fill

#フォントをセットしてみる
context.set_font_size( 100 ).select_font_face( "ヒラギノ明朝 Pro W6", 0, 0 )

#文字を書く領域を得る(事前計算
ext = context.text_extents( str )

#これからズレます。
#以後中心が0,0になる。
#そういや授業でいまやってるglにもあるなぁこういう概念。
#マトリックスか
context.translate( width / 2, height / 2 )

#文字をパスとして書く(黒
#最初からfillされたのを書くときはshow_textでもおっけー
context.set_source_rgb( 0, 0, 0 ).move_to( 0, 0 ).text_path( str ).stroke

#領域。bearingが青、advanceが緑
context.set_source_rgb( 0, 0, 1 ).move_to( ext.x_bearing, -height/2 ).line_to( ext.x_bearing, height/2 ).stroke
context.set_source_rgb( 0, 0, 1 ).move_to( -width/2, ext.y_bearing ).line_to( width/2, ext.y_bearing ).stroke
context.set_source_rgb( 0, 1, 0 ).move_to( ext.x_advance, -height/2 ).line_to( ext.x_advance, height/2 ).stroke
context.set_source_rgb( 0, 1, 0 ).move_to( -width/2, ext.y_advance ).line_to( width/2, ext.y_advance ).stroke
#実行結果を見れば分かるが上・左がbearing、右・下がadvance

#ちなみにゼロはここ。(赤矢印
#x_bearingが微妙にずれてるので注意。
context.set_source_rgb( 1, 0, 0 ).move_to( 0, -height/2 + 20).line_to( -10, -height/2).line_to( 10, -height/2).fill
context.set_source_rgb( 1, 0, 0 ).move_to( 0, +height/2 - 20).line_to( -10, +height/2).line_to( 10, +height/2).fill
context.set_source_rgb( 1, 0, 0 ).move_to( -width/2 + 20, 0).line_to( -width/2, -10).line_to( -width/2, 10).fill
context.set_source_rgb( 1, 0, 0 ).move_to( +width/2 - 20, 0).line_to( +width/2, -10).line_to( +width/2, 10).fill

#画像で吐くときはこっちを使う
#context.targetはsurfaceのこと。
#surface.write_to_png( "hoge.png" )でもいい
#context.target.write_to_png( "hoge.png" )

#PDFで吐くときはこっちを使う
#画像で吐くときはshow_pageはいらないが、PDFでは必要。
#あとfinishも。出力ファイルを渡すタイミング違うので注意。
context.show_page
context.target.finish

あと使えそうな概念はsaveとstore
translateみたいなの使いまくると混乱するのでsaveしておいてstoreすると楽。
saveはブロックを使えて、storeし忘れを防げる。

以上備忘録!!