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画像として成立します。

 

<svg  width="520" height="400">
<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」の最新バージョンへのリンクは、以下のページのリンクリストから探せます。