SVGの「path」コード
SVGのアイコンや画像を扱う様になりましたが、扱う上で一番問題になるのは、コードの文字数が増える事です。 それだけを注意すれば、大変有難い機能です。
SVGのコードは、ベクトル画像の設計図となる数値が「path」の「d属性」としてズラズラ並びます。 これを精密にすれば線や辺縁が綺麗になりますが、有る程度簡素化しても、アイコン等の余り拡大しない用途なら充分です。 従って、どこまで間引くかが、SVG画像を自製する場合のポイントになります。
ネットを調べると、定番に近いSVGコードの最適化ツール「SVGO」がありました。 これは相当に高度ですが、どうも私の目的通りに使いこなせません。 試したい方は以下を参考に。
で、こういったツールの扱いに慣れるより、作った方が早いと思いたちました。
小数点以下を四捨五入
アイコン用に、自分でSVG画像を作る方法は、かなり慣れて来ました。
◎「256×256 dpt」の2値(モノクロ)か、3値(補助色部あり)の元絵を作る。
◎ 以下のサイトで「png→svg」変換を行い、処理後のsvg画像(ファイル)をダウンロードして入手する。
◎ SVG画像をメモ帳で開き、ソースコード(テキスト)として扱う。
これまでは、ここから「path」の数を手作業で処理していましたが、慣れても1件について10分程度はかかります。 これは非効率なので、この処理をJavaScriptを使って自動化しました。
処理をどこで行うか
JavaScriptで扱うための「場所」は幾つか考えられます。
最初は仮のブログ記事を作り、その記事にSVG画像をHTML編集で載せ、表示された記事をJavaScriptで処理する方法を採りました。 処理結果は DevToolsにコンソールログとして出力し、それをコピペしていました。
しかし、もっと簡単にするため、処理場所を編集画面にしました。 結果として、ブログ編集画面だけで「path」コードの簡略化処理ができ、ずいぶん便利になりました。
コードは粗削りな処理分岐で、もう少し自動化できる場合がありそうですが、必要で効果的な分岐が見つかれば、コードに追加して行こうと思っています。
処理の手順
◎「Simple SVG」をONにした上で「ブログ編集画面」を開きます。
◎ 処理するSVG画像のソースコードを「HTML表示」画面に書き込みます。 これは、SVG画像だけを載せた記事を作ることになります。
◎「通常表示」に戻ると、編集枠内に処理前のSVG画像が表示されます。
◎「F1」キーを押すと、記事上の最初のSVG画像を対象として処理を実行します。
簡略化の処理後のSVG画像が、「======」の区切り線を挟んで追加されます。
◎ 簡略化した「path」コードは、「HTML表示」を再度開いてコピーします。 区切り線の上側は元のSVG画像のコードで、下側が処理した結果のSVG画像のコードです。
上の例では、半分位の文字数に簡略化できています。 もっと文字数を減らしたければ、変換元の画像サイズを小さくすれば良いのですが、次第に怪しい絵になります。 そういう試行も、「Simple SVG」があれば楽に試せます。
◎「HTML表示」で、処理元のSVG画像のコードをHTML修正し、再び「通常表示」に戻って、改めて「F1」を押して再処理できます。
前回の処理後のSVG画像は削除され、再処理の結果のSVG画像が追加されます。 つまり、編集枠内に処理前・処理後のSVG画像の数は、常に1個ずつです。 ただし、区切りの「======」線は処理ごとに増えるので、邪魔になれば削除します。
◎ 処理元のSVG画像を差替えて、続けて新しいSVG画像を処理することもできます。
処理の内容
◎ JavaScriptで「path」コードを抽出して、「半角空白」区切りの「数値の塊」を一旦配列に取得します。
◎「数値の塊」ごとに「-」記号や「M,L,C,z」等の文字を含むかどうかで処理を分けて、可能な塊を小数以下の四捨五入して簡略化します。
◎「M,L,C」を含む塊は、この文字を挟む両側を個別の数値と判断し、四捨五入。 但し、先頭の「数値の塊」は「Mnnn」の形になるので、処理せず手作業に任せる。
◎ 処理した「数値の塊」の配列を、元の「半角空白」や「M,L,C」で繋ぎます。
◎ 元のSVG画像のサイズ属性などを取得し、処理をした「path」と属性値を組み合わせて「処理済のSVG画像」を作り、編集枠内の記事に記入しています。
◎ 処理は「F1」を押した瞬間に行われます。 処理前と処理後の「SVG画像」が表示されるので、処理が満足できるか、想定外の崩れが無いかなどが判ります。
処理上の注意点
● 複数の「path」を持つSVG画像に対応していません。 複数「path」がある場合は、SVGの最初の「path」部のみ処理します。
多くの場合、元画像のベースの範囲を示す簡単な「path」が最初にあるので、これは削除して、1個の「path」だけのSVG画像を処理します。 下の例の太字の部分の事で、これは無くてもSVG画像として成立します。
<path style="fill:#ffffff; stroke:none;" d="M0 0L0 400L520 400L520 0L0 0z"/>
<path style="fill:#000000; stroke:none;" d="M365 103L365 258L337 230C327.989 220.989 319.692 212.024 306 217.854C301.206 219.895 297.587 224.366 294.004 228C289.202 232.869 285.65
~~以降略~~
● 画像が複雑で「path」が複数になる場合、見かけ上は画像が崩れても良いので、1個ずつの「path」のSVGとして、複数回処理し、後で「path」を組み合わせます。
●「path」コードで、「nnn.nnn.nnn」の様な「数値の塊」にドットが2個以上ある形式の塊については、処理をせずにそのままの塊を戻します。
●「-」が入った「数値の塊」は、処理をせずにそのままの塊を戻します。
● 処理対象外になる「数値の塊」が非常に多い「path」コードは、本来、処理対象に向いていません。 上記の「autotracer.org」サイトで変換すると、処理対象外の塊はとても少なく適しています。「Font Awesome」が提供するSVGは、適していない様で、元デザインとして利用する場合が多いです。
●「Simple SVG」の処理後に、未処理で戻された「数値の塊」をチェックし、手作業で処理を仕上げます。
「Simple SVG」を利用するには
このツールは Chrome / Edge / Firefox の拡張機能「Tampermonkey」上で動作します。 以下に、このツールの導入手順を簡単に説明します。
❶「Tampermonkey」を導入します
使用しているブラウザに拡張機能「Tampermonkey」を導入する事が必要です。 以下のページに簡単な導入の説明があるので参照ください。
❷「Tampermonkey」にスクリプトを登録します
●「Tampermonkey」の「+」マークの「新規スクリプト」タブを開きます。
●「新規スクリプト」には、最初からテンプレートが記入されています。 これは全て削除して、完全に空白の編集枠に 下のコードをコピー&ペーストします。
〔コピー方法〕 軽量シンプルなツール「PreBox Button 」を使うと
コード枠内を「Ctrl+左Click」➔「Copy code 」を「左Click」
の操作で、掲載コードのコピーが可能になります。
● 最後に「ファイル」メニューの「保存」を押すと、ツールが使用可能になります。
〔 Simple SVG 〕 ver. 0.1
// ==UserScript== // @name Simple SVG ⭐ // @namespace http://tampermonkey.net/ // @version 0.1 // @description ブログ編集画面でpathコードを簡略化 実行キー「F1」 // @author Ameba Blog User // @match https://blog.ameba.jp/ucs/entry/srventry* // @exclude https://blog.ameba.jp/ucs/entry/srventrylist.do* // @grant none // ==/UserScript== let retry=0; let interval=setInterval(wait_target, 100); function wait_target(){ retry++; if(retry>10){ // リトライ制限 10回 1sec clearInterval(interval); } let target=document.getElementById('cke_1_contents'); // 監視 target if(target){ clearInterval(interval); main(); }} function main(){ let editor_iframe; let iframe_doc; let iframe_body; let target=document.querySelector('#cke_1_contents'); let monitor=new MutationObserver( catch_key ); monitor.observe(target, {childList: true}); catch_key(); function catch_key(){ editor_iframe=document.querySelector('.cke_wysiwyg_frame'); if(editor_iframe){ iframe_doc=editor_iframe.contentWindow.document; if(iframe_doc){ iframe_doc.addEventListener('keydown', check_key); document.addEventListener('keydown', check_key); function check_key(event){ if(event.keyCode==112){ // ショートカット「F1」 event.preventDefault(); event.stopImmediatePropagation(); clear_space(); svg_arrange(); }}}} } // catch_key() function svg_arrange(){ if(document.querySelector('.cke_wysiwyg_frame') !=null){ //「通常表示」から実行開始 editor_iframe=document.querySelector('.cke_wysiwyg_frame'); iframe_doc=editor_iframe.contentWindow.document; if(iframe_doc){ let svg_or; let width_or; let height_or; let path_or; let d_or; svg_or=iframe_doc.querySelector('.cke_editable svg'); if(svg_or){ width_or=svg_or.getAttribute("width"); height_or=svg_or.getAttribute("height"); } path_or=iframe_doc.querySelector('.cke_editable path'); if(path_or){ d_or=path_or.getAttribute("d"); let d_all=d_or.split(' '); for(let k=0; k<d_all.length; k++){ if(!d_all[k].match(/[-]/g)){ if(d_all[k].match('C')){ let d_c=d_all[k].split('C'); if(d_c.length==2){ if(count_dot(d_c[0]) && count_dot(d_c[1])){ d_all[k]=Math.round(d_c[0]) +'C'+Math.round(d_c[1]); }}} if(d_all[k].match('M')){ let d_m=d_all[k].split('M'); if(d_m.length==2 && d_m[0]!=0){ if(count_dot(d_m[0]) && count_dot(d_m[1])){ d_all[k]=Math.round(d_m[0]) +'M'+Math.round(d_m[1]); }}} if(d_all[k].match('L')){ let d_l=d_all[k].split('L'); if(d_l.length==2){ if(count_dot(d_l[0]) && count_dot(d_l[1])){ d_all[k]=Math.round(d_l[0]) +'L'+Math.round(d_l[1]); }}} if(!d_all[k].match(/[A-Za-z]/g)){ if(count_dot(d_all[k])){ d_all[k]=Math.round(d_all[k]); }}}} function count_dot(str){ let count=0; for (let i=0; i<str.length; i++){ if(str[i]=="."){ count++; }} if(count<2){ return true; } else{ return false; }} let new_path=d_all.join(' '); add_svg(new_path, width_or, height_or); function add_svg(ex_path, width_, height_){ let SVG= '<p>==================================</p>'+ '<svg width="'+ width_ +'" height="'+ height_ +'" '+ 'class="output_svg"><path d="'+ ex_path + '"></path></svg>'; let SVG_P=iframe_doc.createElement('p'); SVG_P.id="svgp"; let iframe_body=iframe_doc.querySelector('.cke_editable'); if(iframe_body){ if(iframe_body.querySelector('.output_svg')){ iframe_body.querySelector('.output_svg').remove(); } iframe_body.appendChild(SVG_P); let SVGP=iframe_body.querySelector('#svgp'); if(SVGP){ SVGP.outerHTML=SVG; }}} }}}} // svg_arrange() function clear_space(){ // svgタグの後に増殖する空白行を削除 editor_iframe=document.querySelector('.cke_wysiwyg_frame'); if(editor_iframe){ iframe_doc=editor_iframe.contentWindow.document; if(iframe_doc){ let iframe_body=iframe_doc.querySelector('.cke_editable'); if(iframe_body){ let elements=iframe_body.querySelectorAll('p'); for(let k=0; k<elements.length; k++){ if(elements[k].childNodes.length=="1"){ if(elements[k].firstElementChild){ if(elements[k].firstElementChild.tagName=="BR"){ elements[k].remove(); }}}} }}}} // clear_space() } // main() // ブログ記事にSVGをHTMLで書き込む // 通常表示に戻り「F1」を押すと、処理したSVGが追加される
「Simple SVG」最新版について
旧いバージョンの JavaScriptツールは、アメーバのページ構成の変更で動作しない場合があり、導入する場合は最新バージョンをお勧めします。
●「Simple SVG」の最新バージョンへのリンクは、以下のページのリンクリストから探せます。