【追記あり】SVGコードゴルフと,GIZMODO「Google新ロゴ」記事へ反論

<ここから追記:2015-09-10>

当初投稿した内容が、前提から誤った思い込みで書かれておりました、詳しくは後半の追記を参照してください。
</追記ここまで>





はじめに

先日こうしたツイートが話題になりました。

https://twitter.com/thespite/status/639107572679712772



これは先頃リニューアルが発表されたGoogle社のロゴ

Evolving the Google Identity - Library - Google Design
がシンプルな構成に見えることから、それを荒く手軽に作るなら(quick and dirty version)290バイトで作れるよ!という内容です。


リンク先の中身を見てみるとこのような490バイトのSVGファイルになっており

<svg xmlns="http://www.w3.org/2000/svg" width="600" height="250"><g stroke-width="16" fill="none"><path d="M173 102a51 51 0 1 1-13-30m20 37h-53" stroke="#4a87ee"/><circle cx="227" cy="128" r="32" stroke="#d83038"/><circle cx="313" cy="128" r="32" stroke="#f4c022"/><path d="M401 160a31 31 0 1 1 0-61m-4 0a24 29 0 1 1 0 61m26-67v79m-1-12a20 20 0 1 1-52 17" stroke="#4a87ee"/><path stroke="#4ab95a" d="M449 51v115"/><path d="M529 118a30 30 0 1 0-2 24m5-32l-62 28" stroke="#d83038"/></g></svg>

gzip圧縮すると手元の環境では292バイトになりました*1
なかなか面白い試みではありますが、その一方でこのSVGファイルにはまだまだ無駄が多くファイルサイズは削れるな……とも感じました。というのも、私は2013年にも似たようなことをやっているんですよね。

SVG画像を1バイトでも削るためのコードゴルフ
無駄を省いてなるべく短く記述する、というのはコードゴルフと呼ばれる遊びです。
ただSVGではどのようにすると短く書けるのか?といったノウハウはまだまだ知られていないと思うのでそうしたSVGゴルフのテクニック紹介と、後半ではこのことを取り上げたGIZMODOの記事が本当に酷かったのでそれへの検証と反論を行っていきます。


簡易目次





コードゴルフとは

まずコードゴルフとはなにか?の説明から。
ゴルフをしているイラスト
コードゴルフとは任意のソースコードを出来るだけ短く書くことを目的にしたものです。そのコードの動作を損なわなず、かつ可能な限り短く記述できる手法を試行錯誤していく様子が、ゴルフのように少ない打法で競うところに似ていることからこのように呼ばれています。


既に行われているコードゴルフ

とは言え実はTwitter上では既にコードゴルフが行われています。色々なバリエーションがありますが、比較的穏当なもの*2はこちら

https://twitter.com/fgnass/status/639215596958261249

<svg viewbox="0 0 600 200" fill=none stroke-width=16><path d="M102 20a51 51 0 1 0 20 40h-53M375 80a30 30 0 1 0 0 1m0-40v80a30 30 0 0 1-51 20"stroke=#4285f4 /><path d="M400 0v115"stroke=#34a853 /><path d="M290 80a30 30 0 1 0 0 .01"stroke=#fbbc05 /><path d="M205 80a30 30 0 1 0 0 .01M480 95a30 30 0 1 1 0-30l-50 25"stroke=#ea4335>

このツイートのものは328バイトgzip圧縮すると手元の環境では196バイトになりした。*3

デモページ
どうやっているのか?というと、これはSVGファイルではなくHTMLファイルなんですよね
SVGXMLを基盤としている規格のため、例えばviewboxではなくviewBoxと記述する必要があるなど、厳格なルールがあります。しかし、HTML5ではインラインSVGでの配置が可能になりましたから、XMLと異なり比較的解釈も緩く少しくらい雑な書き方をしても表示されます。
なによりSVG名前空間宣言も省略できますし。
これはこれでコードゴルフの一つではありますが、SVGファイルの形態を変えると応用が効かないのと、そもそも色もサイズも変えるのはどうなのよ……と私は思うので今回はこれとは別の方向性でコードゴルフを行ってみます。

今回のコードゴルフの自己ルール

コードゴルフの対象

このツイートで公開された490バイトのSVGファイルを元に行います。

ここでの自己ルール

今回のルールとしては

  • SVG1.1SEの仕様に準拠する
  • 内容については変更を加えない
  • 最終成果物はsvgzのファイルサイズで行う

としました。
それぞれのルールを補足すると、

SVG1.1SEの仕様に準拠する

HTMLファイルとして有効であっても、SVGファイルとしては利用できないのであれば使い勝手が悪いですし、最低限SVGファイルの体裁は維持します。そのためここではSVG 1.1 Second Editionの仕様に準拠する範囲でコードゴルフを行います。

内容については変更を加えない

色を変更するとか、図形を変えるとか、内容に対して手を入れればファイルサイズは確実に軽くできますが、それでは際限が無いので。

最終成果物はsvgzのファイルサイズで行う

SVGファイルはテキストデータなので、HTML/JavaScript/CSSファイルのようにgzip圧縮の効果が効きます。
そのためHTMLファイルなどと同様にmod_deflateなどでgzip圧縮して使われるのですが、最初からgzip圧縮したsvgzファイル形式というのが仕様にもありますから、ここではそれで行います。




というわけで前置きがかなり長くなりましたが、ここからコードゴルフを実際に行っていきます。

コードゴルフ実践編:ソースコードを短くする

不要なg要素を削除する

490バイト(改行を除く)の元ファイルです。gzip圧縮後は292バイト。

<svg xmlns="http://www.w3.org/2000/svg" width="600" height="250">
<g stroke-width="16" fill="none">
<path d="M173 102a51 51 0 1 1-13-30m20 37h-53" stroke="#4a87ee"/>
<circle cx="227" cy="128" r="32" stroke="#d83038"/>
<circle cx="313" cy="128" r="32" stroke="#f4c022"/>
<path d="M401 160a31 31 0 1 1 0-61m-4 0a24 29 0 1 1 0 61m26-67v79m-1-12a20 20 0 1 1-52 17" stroke="#4a87ee"/>
<path stroke="#4ab95a" d="M449 51v115"/>
<path d="M529 118a30 30 0 1 0-2 24m5-32l-62 28" stroke="#d83038"/>
</g>
</svg>

ここからは見やすいよう、改行を適宜加えてあります。


このコードを見ると、g要素にプレゼンテーション属性を指定していますがそれはルート要素に移動できるので、g要素は削除できます。

<svg xmlns="http://www.w3.org/2000/svg" width="600" height="250" stroke-width="16" fill="none">
<path d="M173 102a51 51 0 1 1-13-30m20 37h-53" stroke="#4a87ee"/>
<circle cx="227" cy="128" r="32" stroke="#d83038"/>
<circle cx="313" cy="128" r="32" stroke="#f4c022"/>
<path d="M401 160a31 31 0 1 1 0-61m-4 0a24 29 0 1 1 0 61m26-67v79m-1-12a20 20 0 1 1-52 17" stroke="#4a87ee"/>
<path stroke="#4ab95a" d="M449 51v115"/>
<path d="M529 118a30 30 0 1 0-2 24m5-32l-62 28" stroke="#d83038"/>
</svg>


これで7バイト削減して483バイトにできました。

色の指定をまとめる

画像を見ると「G」「g」の色が同じでstroke="#4a87ee"が重複していますね。これは無駄なので、ルート要素にまとめましょう。

<svg xmlns="http://www.w3.org/2000/svg" width="600" height="250" stroke-width="16" fill="none" stroke="#4a87ee">
<path d="M173 102a51 51 0 1 1-13-30m20 37h-53"/>
<circle cx="227" cy="128" r="32" stroke="#d83038"/>
<circle cx="313" cy="128" r="32" stroke="#f4c022"/>
<path d="M401 160a31 31 0 1 1 0-61m-4 0a24 29 0 1 1 0 61m26-67v79m-1-12a20 20 0 1 1-52 17"/>
<path stroke="#4ab95a" d="M449 51v115"/>
<path d="M529 118a30 30 0 1 0-2 24m5-32l-62 28" stroke="#d83038"/>
</svg>


これにより17バイト削減できて、466バイトになりました。

linetoコマンドの省略

最後に配置されているpath要素、画像では「e」の直線部分の指定にlinetoコマンドが使われています。

<path d="M529 118a30 30 0 1 0-2 24m5-32l-62 28" stroke="#d83038"/>

これはmovetoコマンドの直後に記述されているため、仕様により省略できます。

moveto に続けて複数の座標成分ペアが与えられた場合、2番目以降のペアは暗黙の lineto 命令として扱われる。 この暗黙の lineto 命令は moveto が相対の場合は相対に、絶対の場合は絶対と見なされる。

http://www.hcn.zaq.ne.jp/___/SVG11-2nd/paths.html#PathDataMovetoCommands

つまりこうなるわけですね。

<svg xmlns="http://www.w3.org/2000/svg" width="600" height="250" stroke-width="16" fill="none" stroke="#4a87ee">
<path d="M173 102a51 51 0 1 1-13-30m20 37h-53"/>
<circle cx="227" cy="128" r="32" stroke="#d83038"/>
<circle cx="313" cy="128" r="32" stroke="#f4c022"/>
<path d="M401 160a31 31 0 1 1 0-61m-4 0a24 29 0 1 1 0 61m26-67v79m-1-12a20 20 0 1 1-52 17"/>
<path stroke="#4ab95a" d="M449 51v115"/>
<path d="M529 118a30 30 0 1 0-2 24m5-32-62 28" stroke="#d83038"/>
</svg>

これにより、1バイト削減でき、465バイトになりました。
この時点でgzip圧縮すると284バイトのsvgzファイルが生成されます。内容に手を加えないコードの削減はここまでが限度ですから、ここからはgzip圧縮アルゴリズムに最適化したコードゴルフになっていきます。

圧縮アルゴリズムの気持ちになるですよ

記述の削減はこれ以上行えませんが、仮にファイルサイズは同じあっても圧縮アルゴリズムに最適化することで、圧縮効率を高めることはできます。


例えばこの文字列は、aからzまでのアルファベット26文字が20回出てくるランダムな内容です。

onqwmbeyxtqgssfsrqddubditstqjxwsktiagxdeloeygwcslihecctmdbgoanxbfcknlltvjbbfjmfsdpzzhkduolejrswirqzhgkfgnsumtpffprjryqyscodjzuonfqbnmjnxyvbcilyyafazbeywruzokseyhozangmwdpagxaftolxgnummjhhmgkfpyvabfvtaqspwujfeireodylcltcrxvakbwhbyinsmlzlhelaxvkphuvqardqsvvoojukqhukkiscpqkwyynipgwmtwwhvpqfvlkegypnbtukxtubxbrugilfcvihqezvcxoizozemrcjokxgmxhwidrbtvrntylckaezwmsbkqubunpiaksprwwaehtzwpzivmjvzlrhiyjsllpmxadvwfgemjuheviqrazmvuygdjyglqoqzghmapzkjawpsrubojtcjgxoitxgzcrceocbtjzadpfmqnyfexhdncpeccdhvnkhrxfxwslidrfunniqudnpjdto

26文字×20なので、520バイトのテキストファイルです。
これをgzip圧縮すると357バイトになります。


しかし、こう並び替えるとどうでしょうか?

abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz

これも同じ、aからzまでのアルファベット26文字が20回出てくる520バイトの文字列です。
ファイルに含まれる文字の種類、数は同じですがこのように並べ替えるとgzip圧縮効果が高まり、53バイトになりました。


なぜこうした違いが現れるかというと、同じフレーズの繰り返しは圧縮アルゴリズムにより、効率的に情報が整理できるためです。


もちろん内容の変更はできませんから、行える範囲の限度はあるものの、このことを意識して先ほどのSVGファイルを見てみるとまだ改善の余地があると分かりますね。

属性の並び替え

<svg xmlns="http://www.w3.org/2000/svg" width="600" height="250" stroke-width="16" fill="none" stroke="#4a87ee">
<path d="M173 102a51 51 0 1 1-13-30m20 37h-53"/>
<circle cx="227" cy="128" r="32" stroke="#d83038"/>
<circle cx="313" cy="128" r="32" stroke="#f4c022"/>
<path d="M401 160a31 31 0 1 1 0-61m-4 0a24 29 0 1 1 0 61m26-67v79m-1-12a20 20 0 1 1-52 17"/>
<path stroke="#4ab95a" d="M449 51v115"/>
<path d="M529 118a30 30 0 1 0-2 24m5-32-62 28" stroke="#d83038"/>
</svg>

これの各属性を並び替えると、

<svg xmlns="http://www.w3.org/2000/svg" width="600" height="250" stroke-width="16" fill="none" stroke="#4a87ee">
<path d="M173 102a51 51 0 1 1-13-30m20 37h-53"/>
<circle cy="128" r="32" cx="227" stroke="#d83038"/>
<circle cy="128" r="32" cx="313" stroke="#f4c022"/>
<path d="M401 160a31 31 0 1 1 0-61m-4 0a24 29 0 1 1 0 61m26-67v79m-1-12a20 20 0 1 1-52 17"/>
<path d="M449 51v115" stroke="#4ab95a"/>
<path d="M529 118a30 30 0 1 0-2 24m5-32-62 28" stroke="#d83038"/>
</svg>

<path d="M<circle cy="128" r="32" cx="
などの繰り返し部分が増えSVGのファイルサイズは465バイトのまま変わりませんが、gzip圧縮後の比較では先の284バイトから280バイトと4バイト削減できました。



movetoコマンドの変更

<path d="M173 102a51 51 0 1 1-13-30m20 37h-53"/>

path要素の最初にmovetoコマンドのMが使われていますが、ファイル全体を通して大文字のMはここでしか使われておらず、圧縮アルゴリズム的には効率が悪いですからこれを小文字のmに変えます。
つまりこうなるわけですね。

<svg xmlns="http://www.w3.org/2000/svg" width="600" height="250" stroke-width="16" fill="none" stroke="#4a87ee">
<path d="m173 102a51 51 0 1 1-13-30m20 37h-53"/>
<circle cy="128" r="32" cx="227" stroke="#d83038"/>
<circle cy="128" r="32" cx="313" stroke="#f4c022"/>
<path d="m401 160a31 31 0 1 1 0-61m-4 0a24 29 0 1 1 0 61m26-67v79m-1-12a20 20 0 1 1-52 17"/>
<path d="m449 51v115" stroke="#4ab95a"/>
<path d="m529 118a30 30 0 1 0-2 24m5-32-62 28" stroke="#d83038"/>
</svg>


これは仕様により、

パスデータは "moveto" 命令で始められなければならない。

http://www.hcn.zaq.ne.jp/___/SVG11-2nd/paths.html#PathDataMovetoCommands

相対の "moveto"(m)がパスの最初に現れた場合のパラメタは絶対座標成分ペアと見なされる。

http://www.hcn.zaq.ne.jp/___/SVG11-2nd/paths.html#PathDataMovetoCommands

となるため、最初のM絶対座標movetoコマンドを小文字mの相対座標movetoコマンドに書き替えても問題ありません。
これによりハフマン符号の効果が高まるので、先の例からは2バイト削減され、278バイトになりました。




SVGコードゴルフのまとめと最適化ツール

今回はここまで終了ですね。
SVGコードゴルフではこのように無駄な記述の削減から始め、最終段階ではgzip圧縮アルゴリズムを鑑みた効率的な記述を試行錯誤するのが定石になっています。
とは言え、これを全てのSVGファイルに対して行うのは骨が折れる作業ですから、普段の制作には簡易的な最適化ツールを利用するのが良いでしょう。大抵はそれで十分です。

SVGO https://github.com/svg/svgo
SVGの最適化ツールにはSVGOが便利です。GUI版やAdobe Illustratorプラグイン版など様々なバージョンがあり使いやすいです。ただその反面、少し過剰に最適化し過ぎて表示が壊れてしまうケースもあるため、いくつかのプラグインは無効にしておいた方が良いでしょう。

参考記事

SVGOを使ったSVGの軽量化方法(アニメーションさせるときの注意とか)|2.IDEA
注意した方が良いプラグインの解説などが詳しい記事。
Useful SVGO(ptimization) Tools
SVGO関連ツールのまとめ





突然の宣伝

宣伝になりますが、こんな風にSVGに関する解説や、最新ニュースを毎週お届けする「週刊SVG」というブログを私はやっています。

週刊SVG http://ssvvgg.net/
古いブラウザも減り、使える環境が整ってきたとは言えまだまだ誤解の多いSVGの使い方の説明や、便利なツールやアプリの紹介などを行っています。
興味のある方は是非!




そんな「週刊SVG」を運営している立場からするとSVGに関心が集まるのは歓迎する面もあるのですが、今回のGIZMODOの記事が酷いのでここからは検証と反論を行っていきます。



GIZMODOの記事について

キャッチーなタイトルで多くの注目を集めたこの記事、よくよく読むと細部があやふやです。










<ここから追記:2015-09-10>

myakuraさんからコメントで指摘をいただいたのですが Google Designの記事に14,000バイト、305バイトのSVGファイルについて記載があり、低帯域での利用の際には305バイトのSVGファイルが表示される仕様になっているようです。
SVGファイルそのものは確認できませんでしたが、動画を見る限りおそらく均一幅のロゴであるようです。つまり以降の文章の前提が大きく異なっております。
該当の記事にリンクを張っていたにもかかわらず、きちんと内容を読み込まずに却って誤った記事を書いてしまい大変申し訳ありませんでした。

</追記ここまで>









14,000バイトのグーグルの旧ロゴはどこにあるのか?

タイトルにもなっている14,000バイトの旧ロゴですが、そのファイルそのものは原文の記事内にもQuoraにも全く示されていません。

またタイトルでは14,000バイトとしつつ、記事本文では

The old logo uses a complicated serif font which can only be created using bezier curves. All together, it has 100 anchor points, resulting in a 6 KB (6,380 bytes) file. When compressed, the size comes down to 2 KB (2,145 bytes).

とバラバラ。

そもそもそのSVGファイルがGoogle公式なのかすらはっきりしません。

SVGではアンカーポイントが100個だろうが、ファイルサイズをわざと重くしようと思えばいくらでもできる(参考記事)ので、比較するならばきちんと中身を提示しなければフェアではありません。

Google公式では旧ロゴをSVGで使ったケースは知る限りでは無いんですよね。私は2015年5月にこうした記事を書いたのですが

SVGを使用してる企業・団体のサイトを22ヶ国、160件以上調べてみた

このときに、Google社の関連サービスも含めSVG使用状況を調査しましたが、ロゴをSVGファイルにしていた事例はありませんでした。*4


一応探してみると Wikimedia Commons に条件に該当しそうなGoogleのロゴがあったのですが、

File:Logo Google 2013 Official.svg - Wikimedia Commons

これはソースを読むと、CorelDrawやInkscapeで作図されたメタデータがそのまま残っていますから、Google公式ではなくユーザーが勝手にトレースして作ったSVGファイルですよね……。

仮にこれだとするとGoogle公式でもない、無関係の第三者が勝手に作ったSVGファイルが根拠になっているわけです。


305バイトの新しいロゴはどこにあるのか?

これも記事にはどこにもありません。(※ありました追記を参照)

To verify this, I recreated the first letter (G) in the SVG format, resulting in a file that's 302 bytes uncompressed, and 195 bytes compressed.

と軽さをアピールしていますが、これはあくまで「G」一文字のデータ量であって単純には比較できないでしょう。

そして冒頭でも取り上げた @thespiteさんのツイート を記事では紹介しているわけですが、

@thespiteさん自身も書かれている通り、あくまで「quick and dirty version」であってこれは元のロゴからデザインを変更しています。このロゴではファイルサイズ削減のため太さが一定になっていますが、実際のロゴを確認すると微妙に太さを変更していることが分かります。

小文字の「g」が分かりやすいですね、実際のロゴは太さが一定ではありません。

太さを一定にした線でトレースして比較。

こちらの記事が詳しいのですが

新しいGoogleのロゴは線(ストローク)だけでは表現できません - jdash2000 site

書体は一見 同じ幅で描かれているよう見えても繊細に線幅の調整を行って少しでも良いもの、読みやすいものになるようデザインされています。ロゴならなおさら手間をかけて試行錯誤を繰り返します。


こうしたこだわりを全く切り捨てて、線幅を一定にしたからファイルサイズを削減できた!というのは遊びなら良いかもしれませんが、比較として使うのは適切では無いです。


そして重要なこと:Googleでは通常はロゴにSVGは使われていません

Googleの検索ページではPNG画像ファイルなんですよね。

そもそもSVGファイルはロゴに使われていません、少なくとも現時点では。*5


Googleのロゴは円と長方形だけでは無い

そして

シンプルになった新しいロゴの場合、小文字のg以外の大部分が丸と長方形だけを使って作られています。

この前提から違います。

大文字の「G」も単純な円と長方形ではありません。

僅かに太くなっているのは、デザイナーの工夫の現れでしょう。



つまり


旧ロゴがこれだけファイルサイズが大きかった!とタイトルで大きく掲げるも、根拠となる元のファイルを示さず。



Google公式でもなんでもない第三者が作った「ロゴもどき」を持ち出してこんなに軽くなった!と誇大に煽り



さらには細部まで調整したデザイナーのこだわりを全く切り捨てて円と長方形だけと乱暴に断言しているわけで、いい加減にもほどがある雑な分析です。




ロゴのデザインをした人からしてもこんな妙な分析が流布するのは迷惑だろうな、きっと……と思ったので書いてみました。



まー、こうして反論記事を書いてみたものの、大げさなに面白おかしく煽った方がきっと広まってしまうんだろうなー、と思うと残念な気持ちになりますね……。


ちなみにGoogle公式のSVGファイルは

GoogleによるロゴのSVGはこのページの一番下にあるので、

Evolving the Google Identity - Articles - Google Design

論評するのであればまずそれを取り上げるのが筋だと思うんですよね。

これはあくまで黒一色バージョンですが*6、単純な円と長方形ではないことがよく分かるかと。


ただ、ゴルファー的な観点からするとviewBox

 width="180" height="62" viewBox="-0.1 0 180 62"

-0.1ってどう考えても無駄なので、削除すればいいのに、と思うのですが。



><

*1:Windows7Lhaplus 1.73で圧縮しました、環境によって異なるのかもしれません。

*2:Twitterでさらにmentionをたどると色や形状にまで手を加えてファイルサイズの削減を行っている事例もあります

*3:圧縮結果が違うのは環境の違いか分かりませんが

*4:もちろん全てのページを網羅しているわけではありませんから利用していた場合は、情報提供していただけるとありがたいです

*5:将来的には分かりませんが

*6:カラー版と白黒印刷用では細部でデザインを変更することがあります