リリース: Python製作図ライブラリ Drawlib

## 概要

Drawlib というPythonでイラストを描画するための機能豊富なライブラリを作ってリリースしました。
Pythonを知っていれば新しいことを覚えなくてもすぐに使えますし、IDE(VSCodeなど)がコード補完やヘルプ表示で書くことを支援してくれます。
GitHub などでドキュメントなどのイラストをコードとして管理するのに便利なはずです。
Illustration as Code !!

Drawlib では以下の画像のようにコードからイラストを作成します。

![image_about2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/bb88b179-c770-55b1-feee-5afc7706ecd2.png)![image_about1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/d8c641b9-90f2-f53b-67d9-cfc964c193ee.png)


ここでは誰が見ても分かるように円を描画する circle 関数において、どこにどれぐらいの大きさかを書き、その見た目のスタイルを ShapeStyle クラスで定義しています。
読めばなんとなく何をするか想像できますね。
上の例のように `circle` に `ShapeStyle` を定義するのは HTML に CSS をベタ書きしているようなものです。

多くのかたがご存知のように HTMLであれば、CSSのベタ書きは推奨されません。HTMLファイルがCSSファイルを参照し、タグに事前定義スタイルを適用させるのが普通です。

Drawlib もこれと全く同じです。Pythonのコードとしてスタイル定義を書いたファイルを作り、それをイラストを書くコードが参照して、名前でスタイルを適用するのが本来のdrawlibの利用方法です。
そのようにすると、先のサンプルコードのスタイル定義は名前指定だけになります。コードも短くなりますし、スタイル定義をいじるだけでそれを参照しているすべての図が更新されます。
すばやく書いて、変更を楽にして、見ために一貫性をもたせるのに便利です。たくさんのイラストを作成する場合は特におすすめです。

### 公式ドキュメントと GitHub リポジトリ

英語ですが Drawlib の公式ドキュメントは以下となります。ベータリリースを卒業した段階で日本語のドキュメントも書くかもしれませんが、今の段階ではブラウザなどの機械翻訳で日本語にして読んでください。

https://www.drawlib.com/docs/v0_2/index.html

GitHub リポジトリは以下となります。黙って開発して、プライベートアルファ版からパブリックベータ版に進んで公開した直後です。記事を書いた時点では全然見られていないですね(笑)。気に入ってもらえればスターなどで応援してくれるとうれしいです。使って仲間を増やしてくれるともっとうれしいです。

https://github.com/yuichi110/drawlib

ちなみに、開発のトリガーは某出版社からの「Pythonの上級者向け書籍を書いてくれませんか」という依頼です。OKしたものの「うーん、またイラストにパワポ使うの嫌だな。俺 Google で働いているから宗教的にも微妙なのよね。買うの高いし。。。よっしゃライブラリ作るか」という現実逃避がスタート地点ですね。出版社さま、執筆前に余計な時間をかけてすみません。。。

これも余談ですが、ライブラリ開発にAIをがっつり活用してみました。3~4ヶ月ぐらいかけて、働きながら業務時間外におよそコード5万行(4万行ぐらいはマクロとAIで生成しましたが。。。)、ユニットテスト350個、英語ドキュメントを本一冊ぶんぐらい書いた気がします。コンセプトのブラッシュアップやソフトウェアのアーキテクチャ設計などの重要な難しい箇所は私がやりましたが、それほど難しくない局所的(関数レベルやテスト)な実装や docstring 含めたドキュメント系にはだいぶAIを使っています。特に私の幼稚な英語をそれっぽい英語に添削してくれたのは非常に助かりました。いろいろチャレンジしましたが「今の段階では開発支援系のAIは素人のためではなくベテランのためのものだな」という感想になりました。

以上で要約と感想は終わりです。以下から記事のメインコンテンツが始まります!!


## Python 作図ライブラリ Drawlib の紹介

### Illustration as Code の実現。シンプルなコードをそのままイラストへ。

マークダウンでドキュメントを書いていますか。
便利ですよね、テキスト形式でドキュメントの構造を書けるのでバージョン管理もしやすいです。
そこに書かれているままにドキュメントを作れるのは便利なので、IT領域では開発でもインフラでも広く利用されているはずです。
IT以外でもnoteやブログなどのページ作成に利用しているかたも多いかもしれません。

ただ、そこで使う作画されたイラストはどうでしょうか。
以下のようなものです。

![image_about1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/1681e256-0e55-81fc-d688-eb05dd547948.png)


これは少し前に書いた私の本からの引用ですが、当時はパワーポイントやGoogleスライドなどを使って作図していました。それのスクリーンショットを撮って使うかたちです。(上記はそれをベースにプロのかたに再作成してもらったものです。)

本やドキュメントを書くのにマークダウンを使い、バージョン管理しながらどんどんとアップデートしていきます。一人でやる場合もあれば複数人での共同作業の場合もあるでしょう。チームでやるなら、誰がなにを変更したかをすぐに把握したいところです。私が本を書く場合はGitHubのプライベートリポジトリで共同で分担作業をしています。私が本を書き、編集者が直し、ドキュメントをビルドして体裁を整える。チームとして動けています。仕事でドキュメントを書くことも多いですが、マークダウン系の場合にやることはたいして変わりません。

ただし、イラストとなると話は別です。パワーポイントに書いた図は人間の手作業での作図そのものであり、GitHubなどでの管理と相性が非常に悪いです。作図も属人化しますし、本のような規模が大きいものだとスタイルがちぐはぐになったりして手直しに苦労することも多いです。

Drawlibはそういった状況を改善するために開発したツールです。非常に短いPythonのコードで作図をし、それがそのままイメージデータ(PNGなど)になります。

![image_about2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/1caf72ae-9792-94ac-551c-a26db29bba5a.png)

上記のイラスト(これもハイライトされたコード含めてDrawlibで書いてます。英語ドキュメントからの引用なので日本語じゃないのは勘弁してください)はDrawlibの利用イメージです。円をどこにどれぐらいの大きさで、どういう見た目(本来はCSSみたいに事前定義したものを適用するが、ここではベタ書き)で書くかを定義し、それがそのままイラストになっています。まさに「Illustration as Code」ですね。これがやりたくて、自分で手を動かして「あれも必要、これも必要」と欲張りにそこそこ大きなライブラリを開発してしまいました。ちなみに、本業はGoogleでアプリ開発とインフラ設計のコンサルタントをやっています。開発のAI支援なども試したく4月ぐらいから3ヶ月かけて5~6万行(ほとんどマクロ生成で自分で書いたのは1万行ぐらいですが)のコードと150Pぐらいの本一冊になりそうな量の英語ドキュメント(ネイティブじゃないので英語は苦手です)を、本業の前後で実現できました。2-3年前だと想像できないですね、おそろしい世界です。

以下からは本家ドキュメントの概要とインストール、クイックスタートを日本語訳したものを紹介します。

[Drawlib Documentation](https://www.drawlib.com/docs/)


### 豊富な描画アイテム

Drawlibは、様々なスタイルの描画アイテムを提供します。
以下は、主要な描画アイテムを様々なスタイルで描いたサンプル画像です。

![image_about3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/12471abb-8378-c915-0a01-6dde3c15f326.png)

- アイコン (Icon): 5つのスタイル (thin, light, regular, bold, fill) で 1500 種類以上のパターンを用意.
- 画像 (Image): かんたんに効果を適用可能.
- 線 (Line): さまざまなスタイルに対応.
- 形状 (Shape): 約 20 種類のパターン.
- テキスト (Text): さまざまなサイズ、フォント、ウェイト (light, regular, bold) をサポートし、主要な地域言語に対応.

Drawlibは、Microsoft PowerPointの機能を参考に開発されました。
可能な限り多くの一般的な機能を実装することを目指しています。
Drawlibは、基本的な描画機能に加え、コードハイライト機能など、スマートアートとして実装 (jissō) された高度 な機能も備えています。

### コンセプト: スタイルをコンテンツに適用

円のパラメータには、座標、サイズ、色などが含まれます。多くの描画ツールでは、これらのパラメータを一律に扱います。
しかし、Drawlibでは、パラメータを以下の 2 つに分割します。

- コンテンツ: 座標、サイズ、角度など、描画アイテムの種類を定義する情報です。
- スタイル: 色、線の太さ、フォントなどの要素です。

HTML/CSS に慣れ親しんでいる方にとって、コンテンツは HTML に、スタイルは CSS に相当します。CSS でスタイルを定義し、HTML で参照することを推奨するように、Drawlib ではスタイルを別途定義し、イラストレーションコードで参照することを奨励します。

![image_about4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/e3b79fe4-30f7-5697-e151-0d3b2af6271a.png)

確かに、芸術的な観点からは、コンテンツとスタイルの融合が不可欠です。
しかし、芸術的な外観を必要としないイラストの場合、コンテンツはスタイルよりも重要です。線の太さや色は、線が引かれている場所よりも重要ではありません。

コンテンツとスタイルを分離することで、最初に重要なコンテンツに焦点を当てることができます。
コンテンツが作成されると、コンテンツ外のスタイルを変更することで外観を変更できます。
さらに、コンテンツが分離されている場合は、1 つのスタイルを複数のコンテンツ アイテムに適用できます。
イラストの一貫性を維持するために、多くのアイテムに同じスタイルを使用することが重要です。

### 整理された API 

Drawlib は、イラストレーション作成を 簡素化することを目指しています。アイコン、画像、線、形状、テキストなどの描画のための 幅広い API を提供し、様々なスタイルにも対応しています。

描画を開始するために細部をすべて覚える必要はありません。ライブラリのデザインを理解することで、効率的なコードを書くことができます。IDE は、クラス、関数、およびそのオプションにすばやくアクセスできるようにすることで支援してくれます。

Drawlib は以下の API を中心として構成されております。

- 基本クラスと関数: save() や config() など、キャンバス操作の基本的なメソッドが含まれます.
- 描画関数: circle() や line() などが挙げられます.
- スタイルクラス: ShapeStyle や LineStyle などのクラスは、要素の視覚的な外観を定義します.
- テーマとスタイルアクセサモジュール (dtheme): このモジュールは、テーマの管理と、ドローイング間でのスタイルへのアクセスを容易にします.
- 高度なクラスと関数: これらのコンポーネントは、前述の API を内部的に利用して、拡張機能を提供します.

![image_about5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/ca70ab99-9bea-ba31-279e-75666f82d93f.png)

上記のイメージは、Drawlib のコアコンポーネントを 5 つのセクションに分類し、各 API を表しています。Drawlib は一見複雑に見えますが、関数引数とスタイルクラスの一貫性が保たれています。

ライブラリの基本概念を理解すれば、関数と引数の結果を直感的に予測できるようになります。


### Drawlib: ドキュメントや書籍に適したライブラリ

現代のソフトウェア開発において、バージョン管理はコードだけでなくドキュメントにも広がりつつあります。すべては Git を通してシームレスに管理されます。

私も技術文書やリファレンスマニュアルを作成する際は、VSCode と Markdown を使用していますが、以前はイラストには PowerPoint に頼っていました。しかしながら、このアプローチでは、バージョン管理されているドキュメントのイメージとの互換性がありません。

そこで登場するのが Drawlib です。 Drawlib を使えば、テキストのドキュメントだけでなく、イラストレーションコードも Git を通して管理することができるようになります。これにより、スクリプトや CI/CD パイプラインを使用したビルドタスクの自動化が容易になります。

![image_about6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/c9bce317-926c-f28e-c519-f5a64986b813.png)


Drawlib をワークフローに導入することは 直感的で、マークダウンドキュメントの管理と大きな違いはありません。マークダウンや類似のフォーマットを使用してドキュメントを作成しているなら、Drawlib を簡単に採用できます 


## インストール

Drawlib は、以下のコマンドでインストールできます。システム上で Python 3 と pip 3 を利用している場合は置き換えてください。

```bash
$ pip install drawlib
```

Drawlib のインストールが成功したかどうかは、以下のコマンドで確認できます。

```bash
$ python -m drawlib --version
software=0.1.24
api=0.1.24

$ drawlib --version
software=0.1.24
api=0.1.24
```

Drawlib パッケージのインストールには、drawlib コマンドも含まれます。このコマンドは、大量の画像を生成する際に便利です。詳細についてはドキュメントを参照ください。

Windows限定ですが、もし以下のようなエラーが出たら matplotlib のインストールに失敗していますので、追加で msvc-runtime をいれてください。

```bash
ImportError: DLL load failed while importing _cext: The specified module could not be found

pip install msvc-runtime
```

# Quick Start

### Standard Procedure for Drawing with Drawlib

Drawlib を使用した描画は、以下の手順で行います。

1. Drawlib ライブラリのインポート: まず、Python 環境に Drawlib ライブラリをインポートします。
2. (オプション) スタイルコードとユーティリティのインポート:  必要に応じて、カスタムスタイル定義やユーティリティ関数がある場合はインポートします
3. (オプション) キャンバスの設定:  キャンバスのサイズと解像度を指定して設定します
4. 要素の描画: Drawlib の API を使って、アイコン、画像、線、形状、テキストなどをキャンバスに描画します
5. キャンバスの保存: 描画が完了したら、キャンバスを画像ファイルとして保存します

詳細な説明は、以降のドキュメントで解説しますが、各ステップを簡単な例と共に概観してみましょう。

```python
from drawlib.apis import *

config(width=100, height=100)

line((10, 10), (90, 90))
circle((25, 75), radius=20)
image((75, 25), width=30, image="python.png")
text((75, 5), "Hello drawlib!")

save()
```

このコードを実行すると以下のような画像が生成されます。

![image_abstract1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/ac46d0ad-2ea8-1226-35be-08b5c38a02c7.png)


Drawlib の基本的な使い方を理解しましたね。
では、これから Drawlib の機能を 1 つずつ詳しく見ていきましょう。

### Importing Drawlib

Drawlib は純粋な Python ライブラリであり、インストール後、他のライブラリと同様にインポートして使用できます。
多くのライブラリは API を複数のパッケージに分散させていますが、 Drawlib は公開 API をすべて `drawlib.apis` パッケージ内にまとめ、以下のようにワイルドカード `*` を使ってすべての API をインポートすることを推奨します

```python
from drawlib.apis import *
```

一般的に、Python のコーディング規約である PEP 8 では、コードのわかりやすさと保守性を保つためにワイルドカードインポートを推奨していません。
ただし、Drawlibは簡潔なスクリプトであることがほとんどですので、ワイルドカードインポートは簡潔でコードの見通しが良くなります。

このインポート方法では、インストールされている Drawlib で利用可能な最新の API にすべてアクセスできます。

Drawlib の古いバージョンで使用されていた API を使いたい場合は、以下のようにバージョンを指定してインポートすることが可能です。

```python
from drawlib.v0_2.apis import *
```

ここでは `v0_2` はバージョン `0.2.*` を意味します。

### キャンバスのサイズと DPI の設定

Drawlib ライブラリをインポートしたら、描画を開始できます。
しかし、キャンバスサイズなどのパラメーターを定義するために、`config()` 関数を使用してキャンバスを設定することをお勧めします。

たとえば、次のようなコードは、キャンバスの幅を 100 ユニット、高さを 100 ユニットに設定します。

```python
config(width=100, height=100)
```

このコードスニペットは、キャンバスの幅を 100 ユニット、高さを 100 ユニットに設定します。
これらの単位は、ピクセル値ではなく、キャンバス内での座標を表します。
幅と高さの両方を 100 に設定すると、X 軸と Y 軸の両方の座標範囲は 0 から 100 になります。
幅と高さを両方とも 10 に設定した場合、x = 20 を指定すると範囲外になります。
Drawlib はこの場合エラーを発生させませんが、アイテムが期待通りにレンダリングされない可能性があります。
デフォルトでは、幅と高さの両方が 100 ユニットに設定されています。

`config(width=200, height=100)` を使用してキャンバスを設定すると、各アイテムの座標系を維持したまま、より幅広のキャンバスが生成されます。
以下に出力画像をご覧ください

![image_config1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/cbd2abd7-64a5-1969-b7f6-03808db98ad7.png)


高解像度の画像を作成するには、DPI (Dots Per Inch) を調整する必要があります。

```python
config(dpi=200)
```

Drawlib はキャンバスの幅を常に 10 インチに維持します。
そのため、前述の例からの座標ベースの幅の変更は出力に影響しません

提示された例では、「10 インチ x 200 DPI」のキャンバスサイズで、画像の幅は 2000 ピクセルになります。
DPI を 400 に増やすと、画像の幅は 2 倍の 4000 ピクセルになります。

ただし、高解像度の画像を生成すると、より多くの時間とディスク容量が消費されます。
上限値は設定されていませんが、DPI 1000 は過剰な場合があります。

### キャンバスグリッドの設定

Drawlib の `config()` 関数は、グリッド機能など、いくつかの高度なオプションを提供します。
グリッド機能は、キャンバス上のアイテムをすばやく配置するのに特に便利です。

```python
config(width=100, height=100, grid=True)
```

`grid=True` を有効にすると、通常の画像生成に影響を与えずに、画像にグリッドが追加されます。
したがって、グリッドのない画像を取得するために `grid=True` オプションを削除する必要はありません。
グリッド画像のみが必要な場合は、代わりに `grid_only=True` を使用できます。
デフォルトでは、グリッドとグリッド_オンリーはどちらも `False` に設定されています。

これらの調整の効果は、次のファイルで示されています。

![image_config2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/1dca67c8-5758-ba45-e1c2-80297b022d9f.png)


And

![image_config2_grid.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/9413b78c-1307-4a2a-9c30-0acf0b8021a0.png)


コードファイル `image_config2.py` は、2 つのファイル `image_config2.png` と `image_config2_grid.png` を生成します。

- グリッドなしの画像ファイルは通常のファイル名です。
- グリッド付きの画像ファイルは、末尾に「_grid」が付きます。

### 座標系と配置

Drawlib は、描画機能をアイコン、イメージ、ライン、シェイプ、テキストの 5 つの主要カテゴリに分類しています。
これらのカテゴリを詳しく調べる前に、すべての描画オブジェクトが依存している Drawlib の座標系を理解することが不可欠です

Drawlib の描画オブジェクトはそれぞれ、xy 座標を使用して配置されます。
これらの xy 座標の配置は、水平方向 (halign) と垂直方向 (valign) の配置設定に依存します。
一般的な配置オプションとしては以下が挙げられます。

#### 水平方向の配置 ``halign``

- left
- center
- right

#### 垂直方向の配置 ``valign`` 

- bottom
- center
- top

例を通して配置オプションを確認する。

```python
from drawlib.apis import *

config(width=100, height=50, grid_only=True)

circle(
    xy=(25, 25),
    radius=10,
    style=ShapeStyle(halign="center", valign="center"),
)
circle(
    xy=(25, 25),
    radius=1,
    style=ShapeStyle(fcolor=Colors.Red, lcolor=Colors.Red),
)
text((25, 10), "Align center,center", style=TextStyle(color=Colors.Red))

circle(
    xy=(75, 25),
    radius=10,
    style=ShapeStyle(halign="left", valign="bottom"),
)
circle(
    xy=(75, 25),
    radius=1,
    style=ShapeStyle(fcolor=Colors.Red, lcolor=Colors.Red),
)
text((75, 10), "Align left,bottom", style=TextStyle(color=Colors.Red))

save()
```

![image_coordinate1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/6c82d9cd-eb77-2aa0-ffd6-40dbe37367a2.png)


イメージ内の左側にある円は、指定どおり xy 座標が "center, center" に配置されています。
一方、右側にある円は xy 座標が "left, bottom" に配置されています。

Drawlib は、矩形などのシェイプの配置をデフォルトで "center, center" に設定します。
これは、他の多くの "left, bottom" をデフォルトとする描画システムとは異なります。
Drawlib が "center, center" を選択しているのは、さまざまなサイズのアイテムを縦横両方向に揃えるプロセスを簡素化するためです

デフォルト設定ではありますが、"center, center" よりも "left, bottom" の配置が望ましい場合もあります。
そのような場合は、目的の配置設定を持つカスタムスタイルオブジェクトを定義し、特定のアイテムに選択的に適用することをお勧めします。
Drawlib では、プライマリスタイルをセカンダリスタイルで簡単に上書きできます。
詳細はドキュメントをご参照ください。


### アイコンを描く

ドローイングアイコンは、画像イメージを描くことと似ています.
しかし、イメージは通常 png/jpeg 画像を指すのに対し、Drawlib のアイコンはフォントアイコンです。
フォントアイコンに慣れていない場合は、最初に Font Awesome をチェックすることをお勧めします。

Drawlib は、アイコンを描くための 2 つの方法を提供します。

- `icon()` 関数を使用する
- `icon_phosphor` モジュールとその機能を使用する

独自のフォントアイコンファイルを使用してアイコンを描画したい場合は、icon() 関数を使用できます。
たとえば、Font Awesome (デフォルトではサポートされていません) を使用する場合は、この関数にファイルと描画パラメーターを指定する必要があります。

`icon_phosphor` モジュールは、埋め込みフォントアイコンと、それらをドローイングするための関数を提供します 
誰でもアクセスできるということから、イラストレーションをコードとして容易にする利便性が高い Phosphor (https://phosphoricons.com) を活用しています。

icon_phosphor を使用した例を次に示します。

```python
from drawlib.apis import *

config(width=100, height=60, grid=True)

icon_phosphor.airplane((25, 30), width=20)
icon_phosphor.coffee(
    xy=(75, 30),
    width=20,
    angle=45,
    style=IconStyle(color=Colors.Red, style="fill"),
)

save()
```

このコードを実行すると、次の出力画像が生成されます。

![](/images/articles![image_icon1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/3d212235-7c21-4ed2-c572-888f70eb72b4.png)

示すように、関数の名前が描画するアイコンを決定し、`IconStyle` を調整して色、スタイル、およびその他の属性を変更できます。

`icon()` 関数の詳細な使用方法については、アイコンのドキュメントを参照してください。
このトピックは、このクイックスタートガイドの範囲外です。


### 画像イメージを描く

`image()` 関数は、指定された xy 座標と幅で、提供された画像をキャンバス上に描画します。
高さは、元の画像のアスペクト比を維持するために、幅に基づいて自動的に計算されます。
アスペクト比を調整する必要がある場合は、後で説明する `Dimage` クラスを使用できます。

次に、image() 関数を使用した例を示します。

```python
from drawlib.apis import *

config(width=100, height=50, grid=True)

image(xy=(25, 25), width=20, image="python.png")
image(
    xy=(75, 25),
    width=20,
    angle=45,
    image="python.png",
    style=ImageStyle(lwidth=1),
)

save()
```

Python コマンドを使用してこのコードを実行すると、画像が生成されます。

![image_image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/5ac5d33f-a7a8-b15e-2bc2-750d9a36a713.png)


ご覧のように、角度を指定したり、`ImageStyle` を使用して配置と境界線を管理したりすることができます。

画像自体を修正したい場合は、`Dimage` クラスを使用することを検討してください。このクラスは、画像操作のためのさまざまなメソッドを提供します。

```python
from drawlib.apis import *

config(width=100, height=50, grid=True)

image(xy=(25, 25), width=20, image="python.png")
dimg = Dimage("python.png").mirror().sepia()
image(xy=(75, 25), width=20, image=dimg)

save()
```

`Dimage` クラスは、文字列のようなオブジェクトです。
効果を適用するためのメソッドは、画像自体を変更するのではなく、新しい画像オブジェクトを作成します。
したがって、メソッドチェーンを使用して、ミラーリング (水平反転) やセピア (色の変更) などの操作を適用します。

![image_image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/cc37adff-9117-151f-5791-de0a1d63b99a.png)


`image()` 関数と `Dimage` クラスはどちらも、人気の Pillow ライブラリからの画像を受け取ることができます。高度な画像処理を実行したい場合は、Pillow を使用してから、image() 関数と Dimage クラスを使用して処理済み画像を扱うことをお勧めします

オリジナル画像の解像度が高い場合は出力 DPI を増やすことをおすすめします。

### 線を描く


Drawlib は、線を描くための line() 関数を備えていますが、他にもさまざまな線描画オプションを提供しています。

* line
* line_curved
* line_bezier1
* line_bezier2
* lines
* lines_curved
* lines_bezier

「line」で始まる関数は、点 xy1 から点 xy2 まで線を引くように設計されており、「lines」で始まる関数は、複数の点を通過する線のために設計されています。

いくつかの線の種類を見てみましょう。

```python
from drawlib.apis import *

config(width=100, height=50, grid=True)

line((20, 7), (80, 7))
line_curved((20, 20), (80, 20), bend=0.2)
line_curved((20, 30), (80, 30), bend=-0.2)
lines([(20, 40), (30, 45), (70, 45), (80, 40)])

save()
```

`line_curved()` 関数は、xy1 から xy2 まで線を引きますが、bend パラメータを使用すると、曲線を作成できます。
bend の値が 0.2 の場合は、直線より 1.2 倍長い曲線を意味し、-0.2 の場合は反対方向にカーブを作成します。

![image_line1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/47395957-9337-ceff-8837-cdc6dc5634d8.png)


ベジェ曲線関数はもう少し複雑です。
詳細については、線のドキュメントを参照してください。
ただし、複雑な曲線を制御するのに非常に役立ちます

線のスタイルという観点からは、以下の 2 つのカテゴリがあります。

- 矢印 
- 見栄えのスタイル: 色、太さ、線のスタイル (実線、破線など) など

矢印は論理的な意味を持つため、HTML の等価物として、関数引数 `arrowhead` で指定します。
しかし、見栄えのスタイルはあまり意味を持たないため、 スタイルクラス `LineStyle` として指定します

スタイル設定の例を次に示します。

```python
from drawlib.apis import *

config(width=100, height=50, grid=True)

line((20, 7), (80, 7))
line(
    (20, 16),
    (80, 16),
    style=LineStyle(style="dashed", width=5, color=Colors.Red),
)
line((20, 25), (80, 25), arrowhead="->")
line((20, 34), (80, 34), arrowhead="<->")
line((20, 43), (80, 43), arrowhead="<-", style=LineStyle(ahscale=50, style="dashdot", ahfill=True))

save()
```

このコードを実行すると、次のような画像が生成されます。

![image_line2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/1e714cff-5632-bcff-717d-ca61a1552188.png)


ご覧のように、LineStyle クラスを使用して線の幅、色、スタイルなどを設定できます。
矢印のスタイルは、関数の引数で直接指定します。

### 図形を描く

Drawlib のキーワードである「Shape」には、円、矩形などさまざまな図形が含まれます。
既に `circle()` 関数に慣れ親しんでいますが、Drawlib では、他にもさまざまな図形を描くための関数が導入されています。

* arrow()
* arc()
* bubblespeech()
* chevron()
* circle()
* donuts()
* ellipse()
* fan()
* parallelogram()
* polygon()
* rectangle()
* regularpolygon()
* rhombus()
* shape()
* star()
* trapezoid()
* triangle()
* wedge()

これらの関数のほとんどは、円型と矩形型の 2 つのカテゴリのいずれかに分類されます。
円タイプの図形は、xy 座標と半径などのパラメーターで定義され、矩形タイプの図形は、xy 座標、幅、高さなどのパラメーターで定義されます。
例外は、arrow(), polygon(), shape() です。

このクイックスタートガイドでは詳細については説明しませんが、`shape()` 関数は、特にカスタムシェイプオブジェクトを作成するのに便利な機能です。
これを使用すると、アイテムを指定された xy 座標に配置したり、角度を調整したりするなどのタスクが自動的に処理されます

それでは、円形の「star()」関数と矩形の「rectangle()」関数の 2 つの例を見てみましょう。

```python
from drawlib.apis import *

config(width=100, height=50, grid=True)

star((25, 25), num_vertex=5, radius_ext=20, radius_int=7.5)
rectangle((75, 25), width=30, height=20, r=3, angle=45)

save()
```

このコードを実行すると、次の画像が生成されます。

![image_shape1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/2528e657-4d85-65fe-bf29-0d93f24278f0.png)


円タイプの図形は半径で定義され、矩形タイプの図形は幅と高さで定義されます。
デフォルトでは、xy 座標は図形の中心を示します。arrow() と polygon() を除くすべての関数は、角度パラメーターを受け取ることができます

図形は、2 種類のスタイルを使用してスタイル設定することもできます。

- ``ShapeStyle``: 線の幅、色、塗りつぶし色などの基本的な図形のスタイル設定に使用します
- ``ShapeTextStyle``: 図形の中のテキストのスタイル設定に使用します

それでは、スタイル設定の例を見てみましょう。

```python
from drawlib.apis import *

config(width=100, height=50, grid=True)

rectangle(
    (25, 25),
    width=30,
    height=20,
    angle=45,
    text="Hello!",
    style=ShapeStyle(lstyle="dashed", lwidth=5, lcolor=Colors.Red, fcolor=Colors.Transparent),
)
rectangle(
    (75, 25),
    width=30,
    height=20,
    angle=45,
    text="Hello!",
    textstyle=ShapeTextStyle(color=Colors.White, size=20, xy_shift=(-10, 0), angle=0),
)

save()
```

このコードを実行すると、次の出力が生成されます。

![image_shape2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/245b0aa9-8c74-fe71-3f9f-3f05411de68e.png)


左の例では、ShapeStyle を設定して矩形にスタイルを追加します。
`l` で始まるパラメーターは、`line` の省略形で、線のスタイル設定を表します。
たとえば、lwidth は線の幅, lcolor は線の色の設定です。
fcolor は塗りつぶし色を設定します。
図形の線のオプションは、LineStyle のオプションとほぼ同じです。
シェイプラインが必要ない場合は、lwidth=0 を設定し、塗りつぶし色が必要ない場合は、fcolor=Colors.Transparent を設定します。

テキストの角度は、デフォルトで図形の角度に追従することに注意してください。
右の例では、矩形の中央のテキストに対して ShapeTextStyle を設定しています。
color、size、fontなどのパラメーターは、TextStyle と同様です。
ただし、ShapeTextStyle には xy_shift や angle などの追加オプションが含まれています。

xy_shift を指定すると、テキストの中心ポイントを移動できます。
xy 座標はグローバル座標ではなく、図形に対する相対座標であり、図形の角度を考慮に入れています。
したがって、(-10, 0) を指定すると、中心点は左だけでなく、図形が 45 度傾いているため下にも移動します。

### テキストの描画

`text()` 関数はキャンバス上にテキストを描画するために使用されます
この関数には、xy 座標、テキストメッセージ、およびオプションの角度を指定する必要があります。
他のすべてのテキストパラメーターは「TextStyle」内で定義されますが、例外としてフォントサイズだけは TextStyle に加えて text() 関数からも直接設定できるようにしています。

以前説明した ShapeTextStyle とは異なり、TextStyle には xy_shift や angle などの機能はありません。
これらは text() の引数として直接設定できるためです。
ただし、TextStyle には ShapeTextStyle にはないオプション、テキストの背景オプションが含まれています

いくつかのコード例を見てみましょう。

```python
from drawlib.apis import *

config(width=100, height=50)

text((50, 7), "Hello drawlib. こんにちは。")
text(
    (50, 16),
    "Hello drawlib. こんにちは。",
    angle=10,
    style=TextStyle(font=FontRoboto.ROBOTO_REGULAR),
)
text(
    (50, 25),
    "Hello drawlib.",
    style=TextStyle(font=FontFile("avenger/regular.ttf")),
)
text(
    (50, 34),
    "Hello drawlib. こんにちは。",
    style=TextStyle(color=Colors.Red, size=24),
)
text(
    (50, 43),
    "Hello drawlib. こんにちは。",
    style=TextStyle(color=Colors.White, bgfcolor=Colors.Black),
)
save()
```

このコードを実行すると、次の画像が生成されます。

![image_text1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/6876e580-e487-b3da-ad5b-de996ed6de29.png)

この例では、いくつかの TextStyle パラメーターを設定しました。
テスト用に日本語テキストを使用しました。
ご覧のように、Roboto フォントは正しくレンダリングできません。
非アルファベット文字を使用する場合は注意してください。
Drawlib は、Font-Something クラスで分類されたさまざまな組み込みフォントをサポートしています。
たとえば、日本語フォントは `FontJapanese` 内で定義されています。

フォントは、最初に使用されたときにインターネットからダウンロードされ、その後はマシンの drawlib ライブラリ内にローカルにキャッシュされます。
以前に使用されたフォントはダウンロードされません。
インターネットが使えない環境で新しいフォントを使用して text() を呼び出すと、ダウンロードエラーが発生する可能性があります。

3 番目の例では、ローカルに準備したフォントファイルを使用しました。
使用したいフォントが Drawlib にない場合は、`FontFile` クラスを使用してスタイルのフォントパラメーターに渡すことができます

4 番目と 5 番目の例では、色、サイズ、背景などのテキストパラメーターを設定しました。
これらの設定は特に複雑なものではありませんが、キャンバスの幅と高さが変更されてもフォントサイズは一定のままになることに注意してください。
キャンバスのサイズを 2 倍にしても、フォントのテキスト サイズが半分になるわけではなく、元のサイズと同じままです

### 公式テーマを使用する

Drawlib では、ShapeStyle や TextStyleなどのスタイルクラスオブジェクトを使用して、描画アイテムのスタイルを定義できます。
ただし、アイテムごとにスタイルを指定するのは煩雑になりやすく、一貫性が失われるおそれがあります。
これを解決するために、Drawlib はテーマとスタイル機能を提供しており、テーマを選択してそのスタイルを名前で簡単に適用することができます

テーマを使用したスタイリングの例。style 引数はテキスト値を取ることに注意してください。

```python
from drawlib.apis import *

config(width=100, height=50)
x1 = 12
x2 = 34
x3 = 62
x4 = 88
line_y = 40
line_length = 7
circle_y = 25
text_y = 10

# blue style
line((x1 - line_length, line_y), (x1 + line_length, line_y), style="blue")
circle((x1, circle_y), radius=8, style="blue")
text((x1, text_y), text="blue", style="blue")

# blue solid style
line((x2 - line_length, line_y), (x2 + line_length, line_y), style="blue_solid")
circle((x2, circle_y), radius=8, style="blue_solid")
text((x2, text_y), text='style="blue_solid"', style="blue")

# green dashed style
line((x3 - line_length, line_y), (x3 + line_length, line_y), style="green_dashed_bold")
circle((x3, circle_y), radius=8, style="green_dashed_bold")
text((x3, text_y), text='style="green_dashed_bold"', style="green_bold")

# red flat style
line((x4 - line_length, line_y), (x4 + line_length, line_y), style="red")
circle((x4, circle_y), radius=8, style="red_flat")
text((x4, text_y), text='style="red_flat"', style="red")

save()
```

スタイルには、次の構文があります: ``<color>_<type>_<weight>``. 

`<color>` 部分は色の名前で、`<type>` は線の種類で、`<weight>` は線の太さを表します。
`<color>` および `<type>` と `<weight>` がデフォルトの場合は、スタイル名に表示されません。

このコードを実行すると、次の画像が生成されます

![image_theme1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65787/9a858a68-0b66-a6a9-0410-d8e99bc06e23.png)

Drawlib はいくつかの公式テーマを提供しています。

- ``default``
- ``essentials``
- ``monochrome``

The style naming rules are consistent across all themes. 

使用可能なスタイルクラスごとに使用可能なスタイル名を確認するには、`dtheme.print_style_table()` を使用します。
多くのスタイル名は少数のスタイルクラスのみをサポートすることに注意してください。
なぜなら、「`flat` (境界線なし塗りつぶし)」スタイルは線とテキストに適さないからです。

以下は、テーマで使用可能なスタイルを印刷する方法です。

```python
from drawlib.apis import *

dtheme.apply_official_theme("default")
dtheme.print_style_table()


# +----------------+---+-------+------+------+-------+-------------+------------+--------+--------------+-------------+
# | class \ name   |   | light | bold | flat | solid | solid_light | solid_bold | dashed | dashed_light | dashed_bold |
# +----------------+---+-------+------+------+-------+-------------+------------+--------+--------------+-------------+
# | IconStyle      | x | x     | x    | x    |       |             |            |        |              |             |
# | ImageStyle     | x | x     | x    | x    | x     | x           | x          | x      | x            | x           |
# | LineStyle      | x | x     | x    |      | x     | x           | x          | x      | x            | x           |
# | ShapeStyle     | x | x     | x    | x    | x     | x           | x          | x      | x            | x           |
# | ShapeTextStyle | x | x     | x    |      |       |             |            |        |              |             |
# | TextStyle      | x | x     | x    |      |       |             |            |        |              |             |
# +----------------+---+-------+------+------+-------+-------------+------------+--------+--------------+-------------+

# +----------------+-----+-----------+----------+----------+-----------+-----------------+----------------+------------+------------------+-----------------+
# | class \ name   | red | red_light | red_bold | red_flat | red_solid | red_solid_light | red_solid_bold | red_dashed | red_dashed_light | red_dashed_bold |
# +----------------+-----+-----------+----------+----------+-----------+-----------------+----------------+------------+------------------+-----------------+
# | IconStyle      | x   | x         | x        | x        |           |                 |                |            |                  |                 |
# | ImageStyle     | x   | x         | x        | x        | x         | x               | x              | x          | x                | x               |
# | LineStyle      | x   | x         | x        |          | x         | x               | x              | x          | x                | x               |
# | ShapeStyle     | x   | x         | x        | x        | x         | x               | x              | x          | x                | x               |
# | ShapeTextStyle | x   | x         | x        |          |           |                 |                |            |                  |                 |
# | TextStyle      | x   | x         | x        |          |           |                 |                |            |                  |                 |
# +----------------+-----+-----------+----------+----------+-----------+-----------------+----------------+------------+------------------+-----------------+

# +----------------+-------+-------------+------------+------------+-------------+-------------------+------------------+--------------+--------------------+-------------------+
# | class \ name   | green | green_light | green_bold | green_flat | green_solid | green_solid_light | green_solid_bold | green_dashed | green_dashed_light | green_dashed_bold |
# +----------------+-------+-------------+------------+------------+-------------+-------------------+------------------+--------------+--------------------+-------------------+
# | IconStyle      | x     | x           | x          | x          |             |                   |                  |              |                    |                   |
# | ImageStyle     | x     | x           | x          | x          | x           | x                 | x                | x            | x                  | x                 |
# | LineStyle      | x     | x           | x          |            | x           | x                 | x                | x            | x                  | x                 |
# | ShapeStyle     | x     | x           | x          | x          | x           | x                 | x                | x            | x                  | x                 |
# | ShapeTextStyle | x     | x           | x          |            |             |                   |                  |              |                    |                   |
# | TextStyle      | x     | x           | x          |            |             |                   |                  |              |                    |                   |
# +----------------+-------+-------------+------------+------------+-------------+-------------------+------------------+--------------+--------------------+-------------------+

# +----------------+------+------------+-----------+-----------+------------+------------------+-----------------+-------------+-------------------+------------------+
# | class \ name   | blue | blue_light | blue_bold | blue_flat | blue_solid | blue_solid_light | blue_solid_bold | blue_dashed | blue_dashed_light | blue_dashed_bold |
# +----------------+------+------------+-----------+-----------+------------+------------------+-----------------+-------------+-------------------+------------------+
# | IconStyle      | x    | x          | x         | x         |            |                  |                 |             |                   |                  |
# | ImageStyle     | x    | x          | x         | x         | x          | x                | x               | x           | x                 | x                |
# | LineStyle      | x    | x          | x         |           | x          | x                | x               | x           | x                 | x                |
# | ShapeStyle     | x    | x          | x         | x         | x          | x                | x               | x           | x                 | x                |
# | ShapeTextStyle | x    | x          | x         |           |            |                  |                 |             |                   |                  |
# | TextStyle      | x    | x          | x         |           |            |                  |                 |             |                   |                  |
# +----------------+------+------------+-----------+-----------+------------+------------------+-----------------+-------------+-------------------+------------------+

# +----------------+-------+-------------+------------+------------+-------------+-------------------+------------------+--------------+--------------------+-------------------+
# | class \ name   | black | black_light | black_bold | black_flat | black_solid | black_solid_light | black_solid_bold | black_dashed | black_dashed_light | black_dashed_bold |
# +----------------+-------+-------------+------------+------------+-------------+-------------------+------------------+--------------+--------------------+-------------------+
# | IconStyle      | x     | x           | x          | x          |             |                   |                  |              |                    |                   |
# | ImageStyle     | x     | x           | x          | x          | x           | x                 | x                | x            | x                  | x                 |
# | LineStyle      | x     | x           | x          |            | x           | x                 | x                | x            | x                  | x                 |
# | ShapeStyle     | x     | x           | x          | x          | x           | x                 | x                | x            | x                  | x                 |
# | ShapeTextStyle | x     | x           | x          |            |             |                   |                  |              |                    |                   |
# | TextStyle      | x     | x           | x          |            |             |                   |                  |              |                    |                   |
# +----------------+-------+-------------+------------+------------+-------------+-------------------+------------------+--------------+--------------------+-------------------+

# +----------------+-------+-------------+------------+------------+-------------+-------------------+------------------+--------------+--------------------+-------------------+
# | class \ name   | white | white_light | white_bold | white_flat | white_solid | white_solid_light | white_solid_bold | white_dashed | white_dashed_light | white_dashed_bold |
# +----------------+-------+-------------+------------+------------+-------------+-------------------+------------------+--------------+--------------------+-------------------+
# | IconStyle      | x     | x           | x          | x          |             |                   |                  |              |                    |                   |
# | ImageStyle     | x     | x           | x          | x          | x           | x                 | x                | x            | x                  | x                 |
# | LineStyle      | x     | x           | x          |            | x           | x                 | x                | x            | x                  | x                 |
# | ShapeStyle     | x     | x           | x          | x          | x           | x                 | x                | x            | x                  | x                 |
# | ShapeTextStyle | x     | x           | x          |            |             |                   |                  |              |                    |                   |
# | TextStyle      | x     | x           | x          |            |             |                   |                  |              |                    |                   |
# +----------------+-------+-------------+------------+------------+-------------+-------------------+------------------+--------------+--------------------+-------------------+

```