Winformsで自分用のペイントソフトつくるよ！

## おことわり

記事タイトルのようなことをしていますっていう，初心者による　車輪の最発明　な日記です．

## 話

[DRPGのようなものをつくったとき](https://qiita.com/NyancoRitter/items/912d9364e2b6f50ef452)，そこそこ絵を描く必要があったのだが，えらく苦労した．

「絵を描く能力の不足という面で」苦労したという話もあるけども今回はそっちじゃなくて， **「絵を描く手段の面で」** 苦労したという話だ．
何故かと言うと……

## MS Paint がどんどんゴミになっていく！

私は **Win98～XP あたりのペイント** を愛用していた．
PCで「ガチな(?)絵」を描く機会なんてのは私には無いわけで，そしたら私がペイントソフトを使う場面というのは

* アイコンとかちょっとしたドット絵みたいなのを描くとき
* 画像データの特定の範囲を特定の色で塗っておくとき（マスクデータ(?)というかそういうのが必要なとき）

くらいなのであり，そういう用途にはペイントが丁度良いのだ．
そして長年ペイントを使ってきたがために，その他のペイントソフトを使うのだと「勝手が違いすぎてつらい」っていう体になってしまっている．

それなのに，肝心のペイントときたらもうね，時代と共にどんどん改悪されており，もはや見る影もない．
現代の(Win11の)ペイントに至っては，等倍でのサムネイル表示すらできないという最悪なゴミに成り下がっている．どうかしてる．

Win7あたりの時代では「Paint XP」というのをダウンロードして使っていたのだが，最近ダウンロードしてみたら，どう見ても動作が激しくバグっていてまったく使い物にならなかった．
また，たとえバグっていなかったとしても，もはや最大表示倍率等の面で正直使うのが厳しいという感もある．困った．

そんなわけで，いろいろと代替品を探し回ったのだが……結論を言えば，ダメである．
どれもこれもダメ．
ここでいう「ダメ」ってのは，「以下の全てを兼ね備えていない」という意味だ．

* ペイントが持っていた「馬鹿でも説明無しでフィーリングで使える単純さ」
* 私がもやは完全に依存しきってしまっている，古き良きペイントが持っていた機能群（とその振る舞い）
* 高DPIがどうの～　とかいう話の影響でぼやけないこと
* Win11上で動く
* フリー

## Last resort

そのような経緯で，代替品探しに疲れきった精神が **最終手段：「これもう，欲しい物は自分で作る方が早い」** に行き着いてしまったというわけだ．

### 方針

1. **自分が必要とする機能だけ実装する**
	* 無い機能に関しては素直に別の高機能なAPPに任せれば良いと割り切る（クリップボードやファイルを介して行き来すればよい）
	* 「ペイントには（というか，ペイントを使おうという場面では）」レイヤーとか要らねぇんだわマジで
	* ペイントの機能でも自分が使わないものは実装しない（エアブラシ，四角とか円，テキスト，etc）
2. **自分が必須だと考える以下の 特徴/機能 を再現する**
	* 基本操作：
		* **左右ボタンに個別に色を割り振れて，右ボタンでも描画できる（これは絶対に譲れない）**
		* 描画中に逆側のボタンで描画キャンセル
	* 鉛筆ツール：
		* Shift押下で直線を引くモードになる（これについては挙動再現ではなくて，自分が使う形で実装）
	* 直線ツール：
		* Shift押下で45度単位方向
		* 後から頂点を移動するような機能は無い（←そういうのはむしろ邪魔）
	* 消しゴムツール：
		* こいつの機能は「右ボタンの色」での塗りつぶし（「透明」にするとか「白」にするとかじゃなく）
		* 右ドラッグ時には「左ボタンの色」な部分だけに作用する
	* 範囲選択：
		* 矩形と自由形状の２モード
		* 選択範囲をドラッグした際，元の場所は「右ボタンの色」で塗られる
		* Ctrl+ドラッグ時にはその領域のコピーが生成される
		* 「右ボタンの色」な部分を透過するモード
		* 範囲選択してDELでその範囲を「右ボタンの色」で塗りつぶす
	* ピクセル等倍のサムネイル表示
	* **起動時にパレットに並ぶ色が原色丸出し（個人的な用途の都合上，重要）**
3. **ペイントのいくつかの不満点に対処する**
	* Undo/Redo 回数を増やす（３回ってのはさすがにつらい）
	* 拡大表示倍率を増やす（現代のモニタ解像度では 800%[^1] ってのはさすがに不足すぎる）
	* スポイト機能はいちいち機能として選ぶんじゃなくてもっと手軽にやりたい
	* 左右ボタンの色をさっと交換できる機能があると便利かも

……と，まぁ，隅から隅まで完全に自分仕様なのだが，広い世の中にはこういうのを求めている人があと6人くらい（= 世界６大陸に1人ずつくらい）はいるのではなかろうか？　とか思ったりもするので，フリーソフト的に公開すれば彼らの役に立つ可能性があるのかもしれない．

[^1]: 拡大率を選ぶ場所の下端ギリギリをクリックするともうちょい拡大できる（おそらく 1000% ）っていう裏技(?)はあったが，クリック難易度高すぎ！
なお，Win11のペイントでも未だに最大倍率は800%である．何なの？

### 現状

こんな見た目になったよ！ 「Winforms 丸出し！」って感じだ．
世界に6人ほどいるであろう精神的ドッペルケンガーのことを考慮して GUI 表記は片言イングリッシュにしてある．

APPの名前は "Paint.CAT" とした．
何が「ドット」で何が「キャット」なのかさっぱり意味はわからんが，なんだか「かわいい」気がしてくる．

![PaintDotCat_SC.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3574818/2e9fb1b6-7436-490b-8c67-ffa5eab4360f.png)

基本機能はとりあえずほぼできている…んじゃないかな．普通にお絵かきはできる状態かと．
とりえあずこれを Ver.1.00 なのだとしよう．

### 既知の問題点

* 現在，自由形状で選択した範囲をコピーした場合，それを別のAPPに画像としてペーストできない．
  クリップボードが透明度に対応していないとかいう話への対処中なのだが，なんかうまくいかない．要再検討．
* 選択範囲の表示とかが灰色なので，絵も灰色だと見えないっていう．
  まぁこれはレアケースすぎるから別にいいかな？

### 今後追加したいかも？　という機能

* あまり使用機会は無さそうだが，鉛筆ツールでも太さを選べると良いかも？
* 選択範囲を画像ファイルとして保存する機能
* 描画領域の縁をドラッグして画像サイズを変更する機能
* モノクロBMPとしての保存

## 実装の話

`Bitmap` クラス様がいろいろと必要な機能をお持ちであるので，基本的にはそれに頼れば結構簡単にいける模様．

ただ， `Bitmap.MakeTransparent()` というメソッドがあるのだが，これの逆を行う（：元に戻す）方法がわからん．見当たらん．
仕方ないので，透明具合を変える際には毎回大元の `Bitmap` から `Clone` して `Maketransprent()` している．

### DrawRectangle の話

こいつはどうやってもまともな範囲を描画しない様子(?)．
`PixelOffsetMode` とかいうのが関係していて，コレ次第で「どこがどっちにずれるか」が変わる様子だが， **正直，正解パターンを探索するのが面倒すぎてやってられん** ので，適当に +1 とかして辻褄を合わせている．

### TabControl の話

ツールの選択手段を `TabControl` にしたのだが，上図のようにタブを横につけた状態で `Appearance` を変更するとタブとタブページ領域との間に広大な謎のスペースが出来上がるという謎の超常現象が解決できなくて諦めた．（Winforms のバグ？）
デフォルトの見た目だと現在どのタブが選択されているのかという視認性が妙に悪いので，ほんとはボタン的な見た目にしたかったのだが……
仕方ないので，「選択中のタブにだけ Text を付ける」という形にしてみている（タブの部分に色を付けるとかも実現が大変みたいなので，簡便な方法として）．

### FlowLayoutPanel の話

パレットのところに使っているのだが，こいつのレイアウトがたまに（起動時とかに）変な状態になる（ `FlowLayoutPanel` のサイズに合わせて内容物を並べるべきところが，そうならずにスクロールバーを出してきたりする）のもバグなのか何なのか．
よくわからん．

### Undoの実装

方法論として以下の２通り（あるいはその複合）が考えられたが，実装難易度が低いであろう後者側とした．

1. 「直前の作業とは逆の作業になる手段」というのを実装する：
  最も単純には「作業直前の画像全体のコピーをとっておき，Undoって言われたら画像をそれに差し替える」という処理になるだろうが，「さすがにそれはどうかなー」とか考えだすと，まぁいろいろと難易度があがる．
  Undoの処理は軽いが，要は実装すべき処理が増える．
2. これまで実施してきた処理を最初からやりなおす：
  「一個前の作業までを最初から再実行すれば，それがUndoだよね」っていう方向の話．
   とりあえず「逆方向の処理」を実装せずに済むが，Undo処理が重いものになる．
   なので，「数回に一回は画像全体のコピーを作業履歴に突っ込んでおき，Undo時の再実行の出発点にする」みたいな工夫が必要．

現在，Undo回数に制限はかけていないのだが，「これってメモリ馬鹿食いするのでは？」とか心配になるので，何なら「俺は今さらUndoとかしねぇから，履歴を捨てろ！」みたいなボタンが必要なのでは？　みたいな気もしてくる．

## 公開

ちょっと前に [こういうゴミを置いておく場所](https://nyancoritter.uunyan.com/) を用意したので，こいつもそこで公開することにする．
（どう考えても精神的ドッペル達がたどり着ける場所とは思えないが）

なお，本件のソースコードは [Github とやら](https://github.com/NyancoRitter/MyKittenPaint.git) に置いてみている．（コードは もちろん ぐっちゃぐちゃですぞ）