メルマガ業務駆逐ツールを制作中です
自動画像スライサー出来ました✨https://t.co/35kxWAcAKh
— じゃがいも - JS勉強中 (@haruka_develop) August 2, 2020
※Chrome以外動きません!(必要十分なので他ブラウザ対応の予定なし)
また、Macでしか検証してません。
いくつかのバグは追々なおすとして、決まった使い方をすれば直ぐにでも自分のメルマガ制作の助けになりそう\(^^)/ pic.twitter.com/J0ZRCX7aLo
作ったツールはこちら:https://automatic-images-slicer.n-haruka.dev/
Githubはこちら:https://github.com/mimosusc/automatic-images-slicer
今のところ可能なのは画像のオートスライスです。
※PCのChrome以外は動作しません(Mac以外未検証)
※いくつかバグがあります
前書き
作っているツール自体開発途中なので記事もまだ未完ですが、技術を学び始めた人が自力で有益なツールを作ったり開発を楽しめるようになるキッカケになればいいなという思いと、文章も書けるようになった方がいいよなあという思いで、書ける範囲で書き切って投下しました。
プログラミングを勉強したものの何を作ればいいのか分からないという人に、何かしらの参考になると嬉しいです。
※この記事は自作ツール開発の軌跡を綴った日記のようなもので、技術的な問題を解決に導くような内容はほぼ含みません。
こういうルーティン作業をしていました
ツールの開発を始めた当時は、主にサイト運用とメルマガ制作を担当していました。
メルマガ制作とは、Photoshopでpng画像を開き、地道にスライスし、スライスした画像間の余白を計り、コードに落とし込む… いわゆるザ☆ルーティンワークです。
※スライスとは、Photoshopで切り出したいところを範囲選択して指定する画像の書き出す方法です(ズレないようにズームしてキワを見極めてやるので、けっこう凝視するし手間がかかります)
面白みが無いうえ目も疲れるし、正直なところ、もっとメルマガ以外のことをやりたいなと思うくらいには苦痛を感じていました。
画像オートスライサーの発案
ある時、いつものようにPhotoshopの画面を見ていて、ふと頭に浮かんだのがHTML5のcanvas要素。
canvasをしっかりと使ったことはなかったが、JSでブラウザ上に図を描画できることだけは知っていた。
“描画ができるんなら、ピクセルの色を取得することもできるんじゃないか?”
調べてみると、canvas要素を用いて座標の色を取得する方法がわんさと出てきた。ビンゴビンゴ♪
座標の色を取得できるということは、違う座標の色との比較ができるということ。つまり、理論的には色が切り替わった座標を検知できる。
この瞬間、スライス作業自動化に希望の光が差した。
しかし、スライス作業を行えるようにするには矩形範囲選択ができる必要がある。JSでできるだろうか。Chromeで「矩形画像選択 js」と打ち込み、ググった。するとコード付きの詳しい解説記事がヒットした!part3まで連載されていて心強い。これはいける気がする。
ヒットしたプチモンテさんの記事:画像をマウスで範囲選択する[Canvasの矩形選択1]
https://www.petitmonte.com/javascript/canvas_select_range.html
※矩形選択範囲に関しては基本的にプチモンテさんで掲載しているコードで実装させていただきました
コードジェネレーターへの進化
軌道に乗り始めてきたところでアイディアが更に発展する。
メルマガを作る上で案件ごとに異なるのは、主に下記に列挙するものたち。(以降、これらを案件変数と呼びます)
- 挨拶文テキスト(大抵、デバイスフォントで作る)
- 画像ファイル、画像のwidth & height
- 余白のwidth & height
- 遷移先のリンク
メルマガはほとんどが画像と余白で構築されていて、それらの値を決定づけているのが実はスライス作業。つまり、この作業をブラウザ上で行う事ができれば、必要な案件変数の多くをJS内に保持することができるから、スライス作業のみならず、メルマガコーディング自体を自動化できるかもしれないのだ!(これはデカい!テンションが上がった!)
※この辺りで自動化する事の偉大さに気づきました。これまでは面倒な作業を省きたい一心でしたが、例えば仕事の9割を自動化できたら、極論10%の労働だけで生きていける訳ですよね…(会社員はそうもいきませんが)自分がそれを実現できるかもしれないと思うとすごく自信になりますし、ルーティンでつまらない作業もプログラムにやってもらおうと思うと世界観が別物で、とってもクリエイティブになります(ずっとイージーモードでやらされていたゲームでハードモードを解禁されたような感覚かもしれませんw 技術ももっと身に付くはずです)
仕様を決める
“実現できそう”という判断に至ったので、仕様を決めていく。
当初は画像をアップロードしただけでHTMLを吐くようにしたいと考えていたものの、これはなかなか難しい課題があって非現実的だった。
まず、テキストはデバイスフォントでなければならない箇所が存在するし、案件によって個別に判断が必要なこと。
また、リンクを設定しなければならない要素が存在するが、画像からその要素を認識するのはJSでは難しい。
このように、JSでの解決が容易でない問題が見えてきたので、これらは人間側に判断させる方針にしてアプリのグレードを引き下げた。
※難題とはいえ、何か方法がないかと調べてみました。
着目したのは画像からテキストを読み取ってくれるJSのOCRライブラリ、Tesseract.jsです。
https://co.bsnws.net/article/198
日本語にも対応しています。英語の精度はかなりのものですが、日本語はもう一押しというところ。安全策をとって導入しませんでした。
また、機械学習の処理を可能にするJSライブラリがあるようです。
https://avinton.com/blog/2019/07/tensorflow-js/
画像分類もできるようなので、ボタンを認識させることも可能なのかもしれません。ライブラリの理解に時間がかかるかなと思い、今回は導入しませんでした(まずは完成を最優先)
どちらも、いずれご縁があったら使ってみたいと思います^^
よし、最終的に下記の仕様で確定した(ざっくり)
- 選択範囲機能でスライスしたい要素を囲むと、対象の要素にスナップする(吸着する)
- スナップ済み要素を確認できる
- スナップ済み要素上で右クリックすると独自のコンテキストメニューを表示。そこからデバイスフォント指定や、リンク指定など、人間側で判断する事項を指定できる
- スナップ済み要素を画像にして一括ダウンロードできる
- メルマガ用コードをビルドして出力する
あとは、コードをもりもり書いて形にするだけ。
“画像の劣化”という壁
矩形選択範囲はプチモンテさんのブログ記事を参考にしながらなんとか実装が終わった。
※私が序盤に実装したい機能が詰まっていたから、本当に有り難かったです。
次のステップは、“対象の要素にスナップする”。
ここからは自分で考えて書いていく必要がある。とはいえ、“こうすればイケるだろう”という案があったので、着手自体は辛くない。アテが外れてからが戦い。はい。案の定アテが外れました 笑
※ツールの詳しい実装方法は別記事で掲載予定です
書き出された後の画像は、わずかながら劣化している。単色の中にスライスしたい要素がある場合、まずは要素を囲った選択範囲の上辺から下に向かって色の切り替わりを探知していく感じになるが、人間の目では同じ単色に見えていても実際はそうではない。それを見越して、色そのものの比較ではなくどの位の割合で一致していたかというパーセンテージによる検知で実装したのだが、それでも感知がシビアすぎた。ひと工夫して、もっと人間の視覚に寄せていく必要がある。
そこで、作戦を練り直した。
ピクセルの横一行の色を先に全て取得し、最も割合が多かった色を”メインカラー”とする。
そして、“許容値”という値を変数で新たに設け、適度な数値を入れておく(15にした)。次に、メインカラーとピクセルの横一行の色を順繰りに比較していく。色の差が許容値の範囲内なら、そのピクセルの色をメインカラーと同じ色とみなす作戦だ。“許容値”という概念を盛り込むことで認識精度のコントロールが出来るようになり、人間の認識に近い精度を実現することができた。
※ちなみに、最初はメインカラーを決めず、隣接するピクセルの色を許容値で比較する実装を考えていました。しかし、この実装方法だと基準となる色が次々と変動してしまいます。それだとバグの原因になりそうなので、基準となる色をあらかじめ決める方針に軌道修正しました。
この色識別処理をスナップしたい要素の前後左右にかけることで、オートスライスが可能となった。
次のステップは“コンテキストメニューを設置して人間が入力した指定データを保持する”の実装だ…
※1 色の差はどういう基準で判別している?:RGBの合計値の差の絶対値です。この絶対値が許容値以下であれば、同じ色と認識する仕組みになっています。
※2 許容値が15である理由:Photoshop上で要素の色が着き始めたピクセルと要素でないピクセルの色の差※1を比較すると、小さなもので30ほどの違い。対して、劣化による色の差は大きくて10程度。間を取って15としました。
Comming Soon!
実装中です:コンテキストメニューを設置して人間が入力した指定データを保持する