中間的な四捨五入処理

ここまでの四捨五入の処理は、以下の仕様でした。

 

❶ 単独の数値、または2個繋いだ数値の前方の数値は四捨五入し、整数化

❷ 単独の数値、2個繋いだ数値の全てを、小数第1位に丸める

 

▪小数点で繋いだ後方の数値は1より小さい値なので、その大小をなるべく残すために、常に小数第1位に丸める

 

この方式を反芻していて、❷の2個繋いだ数値の前方は、例えば「302.12」の場合もあれば「0.12」の場合もあり、前者は小数第1位に丸めず「302」で良いのではと考えました。

 

そこから、❷の場合を分けて、以下の処理方式を作りました。

❸ 単独の数値、または2個繋いだ数値の前方の数値は、10以上なら四捨五入で整数化し、10未満なら小数第1位に丸める

 

この処理は、❶❷の中間的な処理になるわけです。 この仕様で処理した結果の文字数は、❶ < ❸ < ❷ の順になります。

 

 

 

操作インターフェイスを変更 

❶❷❸の3段階の処理が纏まったのですが、これまでの操作仕様では、結果の比較がし難くなりました。 そこで「Fnキー」の機能を根本から改めました。 この再編成のために、「カンマ区切り」の自動判別を導入しています。

 

「F1」:  Sサイズ 通常の四捨五入 (処理❶)

「F2」:  Mサイズ 10以下を 小数第1位出力 (処理❸)

「F3」:  Lサイズ 全数を 小数第1位出力 (処理❷)

「F4」:  オリジナルのSVG画像 (元のSVG画像を処理せずに下側に表示)

 

「F6」:  不要属性の削除を処理に追加

「F7」:  元画像と処理後の画像から不要タグを削除

 

 

「F1」「F2」「F3」「F4」 

「F1」➔「F2」➔「F3」の順にpathの文字数が増えます。これらのキーと「F4」とを交互に押して、処理した画像の劣化程度を比較できます。

 

 

「F6」 

「F6」キーを押すごとに「属性処理」の有無が切替わります。 その状態は入力枠の最初に表示され、「F1」~「F3」を押した処理時に反映します。

 

 

「属性処理」の内容は、以下の処理です。

 

function beautify(Svg){
    Svg.removeAttribute("xmlns"); // xmlns属性を削除
    Svg.removeAttribute("xml:space"); // xml:space属性を削除
    Svg.removeAttribute("xmlns:xlink"); // xmlns:xlink属性を削除
    Svg.removeAttribute("version"); // version属性を削除
}

 

◎ これらの属性は、SVGを出力したアプリや提供サイトが追加する場合が多く、SVGを利用する際には殆ど不要になります。 但し、場合によって必要になる事が有り得るので、「属性処理」のチェックを外すと削除しない様にできます。

 

◎「属性処理」にチェック入れて処理をすると結果が思わしくない場合は、「F6」を押してチェックを外し処理を試します。 デフォルトは「属性処理」がONです。 

 

◎「処理元のSVGコード」は、「属性処理」で書換えられる事はありません。

 

 

「F7」 

このキーだけは、「処理元のSVG」も「処理済のSVG」も、コードを書換えます。

 

◎「F7」キーを押すと、SVGのソースコードに「titleタグ」「HTMLコメントタグ」が記入されている場合は、それらを削除します。

 

 

 

SVG画像の文字数カウンターを組込みました 

「Simple SVG」の簡略化は「通常表示」で行うので、操作時にHTMLが見えません。 そこで、文字数をカウントして処理操作毎に表示して、簡略化が数値でも判断できる様にしました。

 

やはり、この結果も記事タイトル入力枠に表示します。

 

 

このカウンターは、「svgタグ」の「<svg …」に始まり「… </svg>」までの文字数をカウントし、コピーして利用する場合に必要な実際の文字数がほぼ判ります。

 

◎ カウンターは「F1」~「F4」キーを押した時に機能します。

 

◎ 細かな問題として、サイズの「height」「width」「fill」等を外部のCSSで指定するかタグ内で直接指定するか、実装時は「viewBox属性」が必要な場合が多い、などの要件で、少し違って来ます。

 

◎ HTMLを確認すると、不要なstyle属性やクラス名があったりするので、最終チェックは手作業になります。

 

 

 

「Simple SVG」の扱い方 

SVGアイコンを自作する手順は、下のページに纏めています。

 

 

以下は、現在のバージョンの基本的な操作方法です。

 

◎「Tampermonkey」で「Simple SVG」を「ON」にします。このツールは、SVG画像のコードを処理する場合にのみ「ON」にしてください。(非常駐型ツール)

 

◎ このツールは編集画面を利用してSVG画像を処理し、ブログ記事の通常の編集とは別の状態になります。 処理操作時の記事を投稿・保存が出来ますが、記事内容は保証されません。 ブログ記事の編集は、必ずこのツールを「OFF」にしてから、新たに別の編集画面を開いて行ってください。

 

◎ 新しい編集画面を開き、「HTML表示」で「SVG画像」のソースコードをペーストします。 この場合のソースコードとは、画像の「svgタグ」の内容全ての事です。

この際、不要な付帯タグなどが削除できるものは、手作業で削除します。 編集枠には、元画像のソースコードを記入するだけで、他の記入はしないのがベストです。

 

◎「通常表示」に戻りSVGコードの整形処理と簡略化処理を行います。

現在利用できる機能はこのページの前項を参照ください。

 

◎「HTML表示」で処理元のSVG画像のコードを手作業で修正したり、処理元のSVG画像を差替えて、新しいSVG画像を処理することができます。

 

◎「F1」「F2」「F3」を押した瞬間に処理が行われます。 

上部に処理元のSVG画像が表示され「F7」以外のキーでは、元のSVGコードは書換えられる事はありません。

処理後のSVG画像は、下側に表示されます。「F4」は元のSVG画像と同等なので、画像の劣化や崩れの有無が細かく判ります。

 

◎ 記事タイトル右端に「dot2個」「dot3個(以上)」の「数値塊」の数をカウントして表示します。

 

◎ 処理結果は「HTML表示」で、「======」線で区切られた下側のSVGコードをコピーして取得します。

 

 

 

「Simple SVG」を利用するには 

このツールは Chrome / Edge / Firefox の拡張機能「Tampermonkey」上で動作します。 このツールは処理操作をする場合のみ「ON」にする非常駐型ツールです。 処理の必要がなくなった時に、必ず「OFF」にしてください。

 

以下に、このツールの導入手順を簡単に説明します。

 

❶「Tampermonkey」を導入します

使用しているブラウザに拡張機能「Tampermonkey」を導入する事が必要です。 以下のページに簡単な導入の説明があるので参照ください。

 

 

❷「Tampermonkey」にスクリプトを登録します

●「Tampermonkey」の「」マークの「新規スクリプト」タブを開きます。

 

 

●「新規スクリプト」には、最初からテンプレートが記入されています。 これは全て削除して、完全に空白の編集枠に 下のコードをコピー&ペーストします。

 

〔コピー方法〕 右サイドバーの   マークのボタンを1度押してください。

 コード枠内の右クリック ➔ コード全体の選択 ➔ コピー操作 が可能になります。

 

● 最後に「ファイル」メニューの「保存」を押すと、ツールが使用可能になります。

 

 

〔 Simple SVG 〕 ver. 0.5

 

// ==UserScript==
// @name          Simple SVG ⭐
// @namespace  http://tampermonkey.net/
// @version        0.5
// @description  ブログ編集画面でpathコードを簡略化
// @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 f_mode; // 四捨五入の処理形式
    let attr_mode=1; // 属性整理の有無
    let dot2; // 💢
    let dot3; // 💢


    let target=document.querySelector('#cke_1_contents');
    let monitor=new MutationObserver( catch_key );
    monitor.observe(target, {childList: true});

    catch_key();

    function catch_key(){

        disp_attr_mode();

        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();
                        f_mode=1;
                        clear_space();
                        svg_arrange();
                        disp_result(); } // 💢

                    if(event.keyCode==113){ // ショートカット「F2」
                        event.preventDefault();
                        event.stopImmediatePropagation();
                        f_mode=2;
                        clear_space();
                        svg_arrange();
                        disp_result(); } // 💢

                    if(event.keyCode==114){ // ショートカット「F3」
                        event.preventDefault();
                        event.stopImmediatePropagation();
                        f_mode=3;
                        clear_space();
                        svg_arrange();
                        disp_result(); } // 💢

                    if(event.keyCode==115){ // ショートカット「F4」
                        event.preventDefault();
                        event.stopImmediatePropagation();
                        f_mode=4;
                        clear_space();
                        svg_arrange();
                        disp_result();
                        count_c(); } // 💢

                    if(event.keyCode==117){ // ショートカット「F6」
                        event.preventDefault();
                        event.stopImmediatePropagation();
                        if(attr_mode==0){
                            attr_mode=1;
                            disp_attr_mode(); }
                        else{
                            attr_mode=0;
                            disp_attr_mode(); }
                        clear_space(); }

                    if(event.keyCode==118){ // ショートカット「F7」
                        event.preventDefault();
                        event.stopImmediatePropagation();
                        f_mode=7;
                        clear_space();
                        clear_title();
                        clear_comment();
                        clear_comment();
                        disp_result(); }

                }}}

    } // catch_key()



    function svg_arrange(){
        dot2=0; // 💢
        dot3=0; // 💢

        if(document.querySelector('.cke_wysiwyg_frame') !=null){ //「通常表示」で実行
            editor_iframe=document.querySelector('.cke_wysiwyg_frame');
            iframe_doc=editor_iframe.contentWindow.document;
            if(iframe_doc){
                iframe_body=iframe_doc.querySelector('.cke_editable');
                if(iframe_body){

                    let svg_or;
                    let path_or;
                    let svg_n

                    svg_or=iframe_doc.querySelector('.cke_editable svg');// 処理元のSVG
                    if(svg_or){ // 元のSVG画像が無いと動作しない

                        let line=iframe_doc.createElement('p');
                        line.id='line';
                        line.textContent=
                            '=========================================';
                        if(!iframe_body.querySelector('#line')){
                            iframe_body.appendChild(line); }

                        svg_n=svg_or.cloneNode(true);

                        let svg_all=iframe_body.querySelectorAll('svg');
                        for(let k=0; k<svg_all.length-1; k++){
                            svg_all[k+1].remove(); } // 最初のSVG以降は削除
                        iframe_body.appendChild(svg_n);

                        if(attr_mode==1){
                            beautify(svg_n); } // 属性処理

                        path_or=svg_n.querySelectorAll('path'); // 処理元のSVGの全てのpath
                        for(let k=0; k<path_or.length; k++){
                            let d_or=path_or[k].getAttribute("d");
                            path_or[k].setAttribute("d", path_trim(d_or)); }



                        function path_trim(D_or){
                            let d_all=[];
                            if(select_type(D_or)){ // カンマ区切りの処理
                                d_all=D_or.split(','); }
                            else{
                                d_all=D_or.split(' '); }

                            if(f_mode<5){
                                let temp_d;
                                temp_d=d_all.join(' ');
                                if(f_mode==4){
                                    return temp_d; } // 数値処理なしで出力
                                else{
                                    return arrange_i_code(temp_d); }}



                            function arrange_i_code(Temp_d){ // path全体の処理
                                let c_count=0; // 数として処理した文字数
                                let i_code=[]; // 全pathを1文字ずつにした配列
                                let i_code_new=[]; // 処理後の数と文字を格納する配列

                                i_code=Temp_d.split(''); // pathの全体を文字1個ずつに分解
                                for(let k=0; k<i_code.length; k++){
                                    if(i_code[k].match(/[A-Za-z]| |-/g)){
                                        if(c_count==0){
                                            i_code_new.push(i_code[k]); }
                                        else{
                                            i_code_new.push(arr_i_code(c_count, k));
                                            c_count=0; }}
                                    else{ // 数字または「.」の場合
                                        c_count+=1; }}

                                return i_code_new.join(''); // 処理後のpath



                                function arr_i_code(Count, K){
                                    let tmp=[];
                                    let tmp_num; // 再構成した数値(小数を含む)
                                    let tmp_round; // 四捨五入した数値
                                    for(let i=0; i<Count; i++){
                                        tmp.push(i_code[K-Count+i]); }


                                    if(count_dot(tmp)<2){ //「.」が1個以内
                                        if(count_dot(tmp)==1){
                                            tmp_num=parseFloat(tmp.join(''));
                                            if(f_mode==2 || f_mode==3){
                                                if(tmp_num>=10 && f_mode==2){ // 🌐
                                                    tmp_round=Math.round(tmp_num); }
                                                else{
                                                    tmp_round=(Math.round(tmp_num*10))/10; }}
                                            else{
                                                tmp_round=Math.round(tmp_num); }}
                                        else if(count_dot(tmp)==0){
                                            tmp_round=parseInt(tmp.join('')); }

                                        return tmp_round.toString()+i_code[K]; }


                                    else if(count_dot(tmp)==2){ //「.」が2個
                                        dot2+=1; // 💢
                                        let sub_count=0;
                                        let sub_tmp1=[];
                                        let sub_tmp2=[];
                                        let tmp_num1;
                                        let tmp_num2;
                                        let r_tmp_num2;

                                        for(let i=0; i<tmp.length; i++){
                                            if(sub_count==0){
                                                sub_tmp1.push(tmp[i]);
                                                if(tmp[i]=="."){
                                                    sub_count=1; }}
                                            else if(sub_count==1){
                                                if(tmp[i]!="."){
                                                    sub_tmp1.push(tmp[i]); }
                                                if(tmp[i]=="."){
                                                    sub_count=2;
                                                    sub_tmp2.push(tmp[i]); }}
                                            else{
                                                sub_tmp2.push(tmp[i]); }}

                                        tmp_num1=parseFloat(sub_tmp1.join(''));
                                        tmp_num2=parseFloat(sub_tmp2.join(''));
                                        r_tmp_num2=(Math.round(tmp_num2*10))/10;

                                        if(f_mode==2 || f_mode==3){
                                            if(r_tmp_num2<1 && r_tmp_num2!=0){
                                                if(tmp_num1>=10 && f_mode==2){ // 🌐
                                                    return (Math.round(tmp_num1)).toString()+
                                                        ' '+r_tmp_num2.toString().slice(1)+
                                                        i_code[K]; }
                                                else{
                                                    return ((Math.round(tmp_num1*10))/10).toString()+
                                                        ' '+r_tmp_num2.toString().slice(1)+
                                                        i_code[K]; }}
                                            else if(r_tmp_num2==0){
                                                if(tmp_num1>=10 && f_mode==2){ // 🌐
                                                    return (Math.round(tmp_num1)).toString()+
                                                        ' 0'+i_code[K]; }
                                                else{
                                                    return ((Math.round(tmp_num1*10))/10).toString()+
                                                        ' 0'+i_code[K]; }}
                                            else{
                                                if(tmp_num1>10 && f_mode==2){ // 🌐
                                                    return (Math.round(tmp_num1)).toString()+
                                                        ' 1'+i_code[K]; }
                                                else{
                                                    return ((Math.round(tmp_num1*10))/10).toString()+
                                                        ' 1'+i_code[K]; }}}

                                        else{
                                            if(r_tmp_num2<1 && r_tmp_num2!=0){
                                                return (Math.round(tmp_num1)).toString()+
                                                    ' '+r_tmp_num2.toString().slice(1)+
                                                    i_code[K]; }
                                            else if(r_tmp_num2==0){
                                                return (Math.round(tmp_num1)).toString()+
                                                    ' 0'+i_code[K]; }
                                            else{
                                                return (Math.round(tmp_num1)).toString()+
                                                    ' 1'+i_code[K]; }}} // 桁上がりして1.0になる

                                    else{ //「.」が3個以上
                                        dot3+=1; // 💢
                                        return tmp.join('')+i_code[K]; }


                                    function count_dot(arr){
                                        let count=0;
                                        arr.forEach(function(item){
                                            if(item=='.'){
                                                count+=1; }});
                                        return count; }

                                } // arr_i_code

                            } // arrange_i_code()
                        } // path_trim

                    }}}}} // svg_arrange()



    function select_type(DD_or){
        let regex=/,/;
        return regex.test(DD_or); } // カンマ有り true / 無し false



    function beautify(Svg){
        Svg.removeAttribute("xmlns"); // xmlns属性を削除
        Svg.removeAttribute("xml:space"); // xml:space属性を削除
        Svg.removeAttribute("xmlns:xlink"); // xmlns:xlink属性を削除
        Svg.removeAttribute("version"); // version属性を削除
    } // beautify()



    function clear_title(){ // titleタグを削除
        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 title_tag=iframe_body.querySelectorAll('title');
                    for(let k=0; k<title_tag.length; k++){
                        title_tag[k].remove(); }
                }}}} // clear_title()



    function clear_comment(){ // コメントタグを削除
        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 iframe_node=iframe_body.childNodes;
                    for(let k=0; k<iframe_node.length; k++){
                        if(iframe_node[k].nodeType==8){
                            iframe_node[k].remove(); }}
                }}}} // clear_comment()



    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()



    function count_c(){
        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 svg1_c=0;
                    let svg2_c=0;
                    let svg_all=iframe_body.querySelectorAll('svg');
                    if(svg_all[0]){
                        svg1_c=svg_all[0].outerHTML.length; }
                    if(svg_all[1]){
                        svg2_c=svg_all[1].outerHTML.length; }
                    return '文字数 '+svg1_c+' == '+svg2_c; }}}}



    function disp_attr_mode(){
        let p_title=document.querySelector('.p-title__text');
        if(p_title){
            p_title.style.outline='auto red';
            if(attr_mode==1){
                p_title.value='☑ 属性処理  [F6] 処理結果が不適当ならチェックを外します'; }
            else{
                p_title.value='☐ 属性処理  [F6] 不要属性の削除を試すにはチェックを入れます'; }}}



    function disp_result(){
        let p_title=document.querySelector('.p-title__text');
        if(p_title){
            let mode_text='';
            if(f_mode==1){
                mode_text='[F1] Sサイズ 通常の四捨五入 '+ count_c() +
                    '  Dot2: '+dot2 +' Dot3: '+dot3; }
            if(f_mode==2){
                mode_text='[F2] Mサイズ 10以下を 小数第1位出力 '+ count_c() +
                    '  Dot2: '+dot2 +' Dot3: '+dot3; }
            if(f_mode==3){
                mode_text='[F3] Lサイズ 全数を 小数第1位出力 '+ count_c() +
                    '  Dot2: '+dot2 +' Dot3: '+dot3; }
            if(f_mode==4){
                mode_text='[F4] オリジナルのSVG画像 '+ count_c(); }
            if(f_mode==7){
                mode_text='[F7] 元画像と処理後の画像から不要タグ削除しました'; }

            if(attr_mode==1){
                p_title.value='☑ 属性処理  '+ mode_text; }
            else{
                p_title.value='☐ 属性処理  '+ mode_text; }

        }} // disp_result()


} // main()


 

〔追記〕 2021.01.22

このツールをOFFにする事を忘れて、ブログ記事の再編集を始めると、本来の記事タイトルが書き換えられてしまいます。 その場合は、記事の保存を絶対に避け、編集画面を閉じれば事なきを得ます。 ただ、この誤りは直ぐに気付くにこしたことはないので、ツールの起動時は「記事タイトル部に赤のアウトライン」を表示する様に改めました。 上記コードは、この修正済です。

 

 

サンプルデータ 

以下は、SVG画像のサンプルのソースコードです。「HTML表示」にペーストして表示させ、「Simple SVG」のテストをする事ができます。

 

<?xml version="1.0" standalone="yes"?>
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="0 0 32 32">
<path style="fill:#000;" d="M13 9C16.2922 8.75399 21.9439 4.6432 24.7431 6.03627C28.4251 7.86871 24.6286 12.2736 22.9514 13.9514C19.2286 17.6755 16.6743 17.5715 12 16C15.4105 27.7562 30.0743 17.3082 30.6628 9.00077C31.1812 1.68439 22.9716 -0.222603 18.0185 3.42901C15.921 4.97541 14.4844 6.91175 13 9M19 23C15.7078 23.246 10.0561 27.3568 7.25694 25.9637C3.57493 24.1313 7.37139 19.7264 9.04861 18.0486C12.7714 14.3245 15.3257 14.4285 20 16C16.5895 4.24378 1.92574 14.6918 1.33719 22.9992C0.818849 30.3156 9.02838 32.2226 13.9815 28.571C16.0791 27.0246 17.5156 25.0883 19 23z"/></svg>

 

これは「32×32」2値画像から生成されたSVGアイコン画像のソースです。 新しいインターフェイスで、簡略処理の段階ごとの画質の変化が良く判ると思います。

 

 

 

 

「Simple SVG」最新版について 

旧いバージョンの JavaScriptツールは、アメーバのページ構成の変更で動作しない場合があり、導入する場合は最新バージョンをお勧めします。

 

●「Simple SVG」の最新バージョンへのリンクは、以下のページのリンクリストから探せます。