C++11でCSS color用のライブラリを作った話

# ColorM
簡潔に言うと、[CSS color module 4](https://www.w3.org/TR/css-color-4/)に対応した[Chroma.js](https://github.com/gka/chroma.js)風のライブラリです。欲しい人は[github](https://github.com/soreja/colorm)から持って行ってください。

## 経緯
３年くらい前ですが数十あるSVGアイコンの色を調整しなければいけない状況がありました。

そのときはまず一度画像化してから色を修正して、SVGアイコンをテキストエディタで開いて修正後の色を一つずつ確認ながら色文字列を書き換えていくという力技で済ませてしまいましたが、もっと簡単にやりたいところでした。

HSLで色を調整するのは知識のある人からすると論外なので、最低でもCIE L\*a\*b\*が使えてかつCSS Colorの読み書きができるライブラリないと自動化できないですから、自分の目で判断して色を決めた方が早くなってしまいました。

その後、CSSファイルの編集も必要になってしまったので、何かいいライブラリがないかgithubあたりで探してみたものの、C++には使おうと思えば使えないことはないくらいの微妙なものしか見当たらないので最終的に自分で作りました。

それをCSS color module 4の去年の４月の草案に従って修正して翌月にアップロードしました。

## 使いかた

[README](https://github.com/soreja/colorm/blob/master/README.md)に書いてあるとおりですが、`"colorm.h"`をパスが通っているところにコピーしてインクルードするだけです。6848 slocある大きいファイルなのでプリコンパイル済みヘッダーがあるならばそちらに入れてください。

```c++
#include "colorm.h"
#include <iostream>

int main()
{
	using namespace colorm;
	const Oklch c1("hsl(350, 70%, 40%)");         // CSS colorを読む。失敗すると例外を投げる
	const Oklch c2 = c1.brighten(0.2).rotate(30); // c1を明るくして色相を30度ずらしてc2とする
	const ColorScale<Oklch> s({c1, c2});          // c1からc2への線形補完領域を定義する
	for (const auto& c : s.colors(4)) {           // 四色のグラデーションを作成する
		std::cout << Rgb(c).css() << std::endl;   // rgb(?, ?, ?)形式で表示する
	}
}
```

## サンプルの内容
### pastel
READMEにあるサンプルコードと同じものです。A.htmlのすべての色をパステルカラーに置き換えてB.htmlに出力します。この程度の処理でもライブラリ無しでやろうとすると相当に大変ですので、ライブラリの有用性を示すには十分でしょう。

### discolored
pastelの方でHTML/CSSの編集のサンプルを書いたのでこちらではSVGを編集するコマンドを書いてみました。使うのに少々コツが要りますが、アイコンをちょっと赤っぽくしたい全体的に彩度を下げたいなどであればそのまま使えないこともありません。

### colorstr
入力した色を複数まとめて別の色空間の色に変換して出力します。色の代わりに`-`を使用することで簡単なグラデーションの作成もできます。HSL値がHEXで何になるのか調べるためにグラフィックソフトを立ち上げてカラーピッカーを使うのが面倒くさいという人は、これを代わりに使えないこともありません。

## 作成にあたって考えたこと

### GPLは迷惑でしかない
この[ColorMライブラリ](https://github.com/soreja/colorm)ですが、全てネット上で入手可能な知識からできています。参照したウェブサイトのURLは全てソースコードの中に書いてあります。作成に時間はかかるし難しいところもありますが、誰でも作れるといえば作れます。

こういう自分で考えたわけでもないアイディアで構成されているものをGPLにして権利を主張する人もいますが、そういうのはいかがなものかと思います。酷いものになると100行くらいの小さいプログラムでもGPLだったりしますので、それは私のプログラムとほとんど同じだけれども、あなたの真似をしたわけではなく偶々同じになっただけですが、あなたに一体何の権利があるというんですか？と思うこともあります。

同じ資料を参考にして作れば自然と似てしまうものですから、それに対して権利を主張するのは無神経です。

そこで、ライセンスは限界まで緩くして[Unlicense ライセンス](https://unlicense.org/)、実質パブリックドメインとしました。

### 何に使うのか誰が使うのか
githubでライブラリを公開している人は多いのですが、使う人のことを考えていない、ただ作ることそれ自体が目的になってしまっている人もまた多いです。

色空間を扱うライブラリの場合、文字列の入出力関連の機能が貧弱でCSS colorを扱うには向かないし、かといってSIMDで最適化されているわけでもないので画像処理にも向かないし、動画でしか使わないようなYUV系の色空間を実装しているのに動画を読み込めるわけでもないし、いったい何に使うんだよ！というライブラリがあります。

自分にとっていらない機能を実装している部分は自分にとってはデッドコードですから少ないほうがいいですし、誰も使わないような機能を大量に付け加えて多機能風にされても困ります。

それで、このライブラリではSVGやHTML/CSSの編集に使いやすければ他の用途で使いにくくてもよいという方針で機能を選択してみました。SVG画像の中で使用される色などせいぜい数十個ですから、計算速度より精度優先でよいと考えて、内部的にはdouble型の値を必ず使用するようになっています。その分、余計な複雑さがないので扱いやすいです。

### READMEやサンプルで手抜きするのはやめよう
github内のプロジェクトを見るとREADMEが手抜きされていることがよくあります。作った本人は全ての仕様を熟知していますからREADMEを必要としないのはわかりますが、本人以外には詳しい説明が必要です。

日本の開発者の場合は、英語が下手過ぎてもはや手抜きを超えて何を説明しているのかわからないことすらあります。そういうのは好ましくないので、恥ずかしくない程度には丁寧に書いてみました。

サンプルがなかったり、サンプルがあってもテストコードと区別がつかないことがあります。そういうのは好ましくないので、少し修正すれば何かに使えそうなサンプルを書いてみました。

### テストはそれなりに書いておく
オープンソースのライブラリを使っていてバグに悩まされることがあります。自分で作る手間が減っても、その分デバッグにかかる手間が増えたのではライブラリを使う価値がありません。

無料で公開するものにそれぼど時間をかけられないので発見の難しいバグが残るのは許容するとしても、最低限のテストは済ませてから公開するのがマナーだと考えて、MSVCとGCCでそれなりにテストしてあります。

### 人より優れた所がないものを作る奴はダサい、根拠もなく自画自賛してる奴はもっとダサい
自作のプログラムを紹介する記事を時々見かけますが、他の人が既に同じようなプログラムを作っていることも多いです。そういう時はせめて他の人の仕事と比べてどこが優れているのか説明しないとただの二番煎じになってしまいます。

反対に誇大広告的に「すごく使いやすい」などと書いてあるものの、何と比べてどう使いやすいのかはどこにも書いていない、といった記事も見かけます。そういうのは恰好が悪いです。

このライブラリの場合、他の人の仕事と比べて優れたところは主に３つあります。

* ライセンスが緩い
* 読みやすい
* 使いやすい

#### ライセンスが緩い
これは前述のとおりUnlicense ライセンスです。ライセンス表示の義務がないので気軽に使えます。

#### 読みやすい
何を根拠に読みやすいといってるのかが問題になってきますが、私的にC++のプログラムが読みにくくなる三大原因は、

* テンプレートを使いすぎる
* クラスの継承が多すぎる
* 関数が大きすぎる

ですのでその逆の、テンプレートの数を減らす、クラスの継承の数を減らす、関数を小さくするの方針で書きました。他にも読みやすくなるなら何でもやっていく方針で書きました。

たとえば[この辺のライブラリ](https://github.com/dmilos/color)などと比較してもらえれば、速く読めるのはわかっていただけるはずなので、同じカテゴリーの他のライブラリより読みやすいと断言しておきます。

#### 使いやすい
何を根拠に使いやすいといってるのかが問題になってきますが、このライブラリでは

* 評判のいいライブラリの仕様に似せる
* 標準や普通に従う
* ヘッダオンリーライブラリにする

という方針にしています。

具体的にはgithubでスターが9.2k個ついている[Chroma.js](https://github.com/gka/chroma.js)というJavaScriptのライブラリに似た仕様ならば使いやすいだろうと考えました。

CSS colorには色の取り扱い方に詳しい専門家が長時間検討して決めた[最新の勧告候補](https://www.w3.org/TR/css-color-4/)があるので、素人は黙って標準に従っておくことにしました。

たとえば色の編集に[Oklab/Oklch](https://bottosson.github.io/posts/oklab/)を使ってみると、明らかに色のクオリティーが上がりますから専門家の勧めることには説得力があります。

C++の色用のライブラリとしては算術演算子が定義されている方が普通のようなのでそれも実装してあります。

変な色気をだして自分の好みを押し付けても使いにくいと言われるだけだということを理解できる大人なので、そうさせてもらいました。

また、ヘッダオンリーライブラリにしたのは、ライブラリのリンクに関連したトラブルを避けるためです。これは好みがわかれるかもしれませんが、一般的には使いやすいとされているかと思います。

逆にダメなところはSVGやHTML/CSSの編集以外の用途にはあまり向かないところでしょうか。画像や動画の色を編集したい人は[OpenCV](https://opencv.org/)でも使っていただいた方が幸せになれます。

## まとめ
使ってください。全く告知せずにアップロードして放置しておいたら本当に誰も使ってくれないので記事にしてみました。ソフトウエア開発に携わっていれば、SVGやCSSを扱う機会はあるはずです。

HSLは卒業して、Oklch(と[ColorMライブラリ](https://github.com/soreja/colorm))を今から使い始めましょう。