C++でCairoやろうぜ！Cairomm入門 (1) 基礎的な関数


前 : [C++でCairoやろうぜ！Cairomm入門 (0) 環境構築/ビルド](https://qiita.com/Perukii/items/26ee5b990a82f2df4cdb)


今回は、前回の続きということで、
**Cairommの基礎的な機能となる関数** を紹介します。
( 実装例としていくつかの描画関数も紹介しますが、ダイジェストです。次回まとめて紹介します )

# 続き

では、前回のコードをもう一度確認してみましょう。

```cpp:test.cpp

#include <cairomm/context.h>
#include <iostream>

int main(){
    // ImageSurfaceの作成
    Cairo::RefPtr<Cairo::ImageSurface> surface = 
        Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, 300, 300);

    // 描画内容を取り込むContextを作成
    Cairo::RefPtr<Cairo::Context> cr = 
        Cairo::Context::create(surface);

    // ImageSurfaceをPNGに出力
    surface->write_to_png("cairo.png");

    // コンソールへの出力(解説省略)
    std::cout<<
        "Hello, World!"
            <<std::endl;
}
```

このプログラムの全体的な流れを展開してみていきます。

___

### ImageSurfaceの作成

```cpp 
Cairo::RefPtr<Cairo::ImageSurface> surface = 
        Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, 300, 300);
```

`Cairo::RefPtr<Cairo::ImageSurface> ` : クラス
`Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, 300, 300) ` : 新しいImageSurfaceを作成し、そのポインタを返す。(フォーマットformat, 幅width, 高さheight)

___

cairommにおけるImageSurfaceは、画像そのものを表します。
ここでは基本的に「描画対象」といった扱いになります。
(他のImageSurface上に上乗せ描画することもできます。が、詳細はまた今度)

**ここからは読まなくていいよ！**

クラス本体を説明する前に言及しておくと、`Cairo::RefPtr<class> `はスマートポインタを表します。
ImageSurfaceやContextを利用するの必要であるため、この先よく登場しますが、単にポインタに近いものだと考えていただいて構いません(従って、クラス内の関数等に参照するときは`->`を用います。)

ここで`Cairo::FORMAT_ARGB32 `の部分では、surfaceのフォーマット:各ピクセルの色情報のメモリ上における値の振り方を指定することができますが、入門記事ですからいちいち気にする必要はないでしょう。随時それっぽい部分があれば`Cairo::FORMAT_ARGB32 `と書いておきましょう。
細かいことを知りたい場合は、例えばhttps://rcairo.github.io/doc/ja/ 等を参照してください(こちらはRubyラッパーのcairoですが…
___

### 描画内容を取り込むContextを作成

```cpp
Cairo::RefPtr<Cairo::Context> cr = 
        Cairo::Context::create(surface);
```

`Cairo::RefPtr<Cairo::Context> ` : クラス
`cairo::Context::create(surface) ` : 新しいContextを作成し、そのポインタを返す。(描画対象surface)

___

Contextは、ユーザの描画内容を保持するクラスです。
このクラスに「色を指定する」「矩形を描く」等の任意の描画関数を適用することで、描画対象のsurface上に描画を行います。

___

### ImageSurfaceをPNGに出力

```
surface->write_to_png("cairo.png");
```

`surface->write_to_png("cairo.png")` : ImageSurfaceをPNG画像として出力し、カレントディレクトリに保存する。

___

**1.ImageSurfaceの作成**
**2.描画内容を取り込むContextを作成**
**3.ImageSurfaceをPNGに出力**


この一連の流れによって、さっきの真っ透明な画像が生成されたわけです。
(実は、このようなただ画像を生成するだけのプログラムなら2の作業は必要ないのですが、入門記事の次のステップに進みやすくするための一応の補足として...)

# 実際に描画してみる

このプログラムに描画関数を加えて、実際にさっきの画像に色を塗ったり形を作ったりしてみましょう。


```cpp

#include <cairomm/context.h>
#include <iostream>

int main(){
    // ImageSurfaceの作成
    Cairo::RefPtr<Cairo::ImageSurface> surface = 
        Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, 300, 300);

    // 描画内容を取り込むContextを作成
    Cairo::RefPtr<Cairo::Context> cr = 
        Cairo::Context::create(surface);

    // 使う色を指定
    cr->set_source_rgba(1.0, 0.8, 0.8, 1.0);
    // 塗る
    cr->paint();

    // ImageSurfaceをPNGに出力
    surface->write_to_png("cairo.png");
}
```

これを実行すると...

![cairo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558987/b5d57c88-70f1-c68a-b119-4e8e71df7d45.png)


このような全部薄オレンジの画像が出来上がります。

```cpp
    // 使う色を指定
    cr->set_source_rgba(1.0, 0.8, 0.8, 1.0);
    // 塗る
    cr->paint();
```

描画内容を示しているのがこの部分です。
色を指定して、ImageSurface全体に貼り付けています。

このように、描画内容は基本的にContextから関数を引っ張り出して表現します。
`cr->[描画関数](引数)`
例外もありますが、これが基本形なのを意識しておいてください。そしたら...なんか簡単に見えてくるでしょう？？？？

さらに多くの情報を追加してみましょう。


```cpp

#include <cairomm/context.h>
#include <iostream>

int main(){
    // ImageSurfaceの作成
    Cairo::RefPtr<Cairo::ImageSurface> surface = 
        Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, 300, 300);

    // 描画内容を取り込むContextを作成
    Cairo::RefPtr<Cairo::Context> cr = 
        Cairo::Context::create(surface);

    cr->set_source_rgba(1.0,0.8,0.8,1.0);
    cr->paint();

    cr->set_source_rgba(1.0,0.7,0.7,1.0);

    // 描画する多角形をパスとして表現して指定 (move_toで始点を指定)
    cr->move_to(70,70);
    cr->line_to(250,50);
    cr->line_to(230,230);
    cr->line_to(50,250);

    // パスを閉じる
    cr->close_path();

    // 範囲内の塗りつぶしを描画(このとき、描画範囲は保存。cr->fill()でも塗りつぶせるが描画範囲は保存されないので、枠線などの追加はできない)
    cr->fill_preserve();

    cr->set_source_rgba(1.0,0.0,0.0,1.0);
    // 枠線の太さを指定
    cr->set_line_width(1.0);
    // 枠線を描画
    cr->stroke();


    // ImageSurfaceをPNGに出力
    surface->write_to_png("cairo.png");

}
```

![cairo.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558987/586a50ac-568a-edfe-ea9d-173dcf709900.png)

こんな感じです。
流れは掴めてきたでしょうか？

# 終わりに

こんな感じで今回は終了します。
次回はもっとたくさんの描画関数をご紹介します。好ご期待！

一部参考: https://rcairo.github.io/doc/ja/