パスワードを忘れた? アカウント作成
12061572 story
プログラミング

JavaScriptをPNGに圧縮するテクニック 33

ストーリー by hylom
素人にはおすすめしない 部門より

JavaScriptをPNG画像に変換することで圧縮するテクニックとそのためのツール「JS Packer」が公開されている(JavaScript を PNG に圧縮する)。

デモシーンと呼ばれる、プログラム技術とグラフィックや音楽製作技術を組み合わせてデモを作成する分野での利用を想定しているようだ。JavaScriptコード中の文字を色に置き換えた画像を8ビットPNG形式で圧縮する、というもので、オリジナルのJavaScriptファイルよりもサイズを小さくでき、簡単にエンコード/デコードできるというのが特徴。ただし多くの場合GZIPのほうが圧縮率が高くなるとのことで、一般的にはGZIPの利用がすすめられるとのこと。

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • by ogino (1668) on 2015年05月14日 7時46分 (#2814001) 日記
    超難読なスクリプトとして使えそうな気がする。Gumblar [wikipedia.org]系などの Web サイト改ざんタイプのマルウェアに使われたらイヤだな…
  • PNGの可逆圧縮は、
    画像専用アルゴリズムとしての特殊なことは基本的にほとんど何もせず、
    ビットマップデータを、gzipと同じdeflateで圧縮するだけのものです。
    (PNG独自な画像ベースの圧縮処理として、deflateをかける前に、上や左の画素との差分を取っておくフィルタ処理もありますがが、差分を取るかどうかは自由(圧縮プログラムが、より圧縮しやすい方を選べばいい)で、プログラムコードを画像にマップした場合、このフィルタ処理は有効とは思えないので、単なるdeflate圧縮になっていると思います)

    そういうものですので「余計なPNGとしてのヘッダ情報」を付加する必要がない分、
    「GZIPのほうが圧縮率が高くなる」のは当たりまえですね。
    むしろ「gzipとほぼ同等の圧縮率が実現できる」とアピールしてもいいんじゃないかなぁ。

    • by Anonymous Coward

      そこでWebP losslessですよ。試したところ、gzよりも小さくなってます。

    • by Anonymous Coward

      おっしゃるとおりです

      しかし,差分を取るフィルタ処理がたまたまうまく寄与する場合も,可能性としてはありえます.
      例えば,画像情報を配列で内部に持っているjavascriptであれば,データとしてはほぼ画像データになりますので
      画像専用のアルゴリズムのほうが有利になりえます

      ですから「GZIPのほうが圧縮率が高くなる」のは多くの場合正しいですが,「当たりまえ」ではありません

      ここまで考えると,タレコミ文にある「ただし多くの場合GZIPのほうが圧縮率が高くなる」という表現のほうが適切になると思います.

  • 何故今更? (スコア:2, 参考になる)

    by Anonymous Coward on 2015年05月14日 13時08分 (#2814176)

    幾ら速報サイトではないとはいえ、7年前の再発明を記事にしなくても…。
    と思ったんですが、コメント見る限り知らない人が多そうですね。
    Web系のsraderなら8割位知っているはずの有名な話だと思ったのですが。

    最初は2008年のこのブログ(404) [nihilogic.dk]で公開されたテクニックです。
    日本だと2010年のJavaScriptとCSSをPNGファイルに含めて圧縮する方法 [mynavi.jp]で最初に紹介されました。

    当時はかなり話題になって、、、
    スゲー、JS超圧縮できるじゃん!
    いや、普通にApacheでgzipしろよ…
    PNGヘッダーの分、サイズ増えてるだろ!
    バカ言うなやる事に意味があるんだ!!
    いや、ちょっとまて、flickrやフォト蔵をjs置き場に出来るって事じゃないか!?
    天才現る!
    いや、普通にサービス規約的にダメだろ
    いや、ちょっとまて、pngって事はdataURIでもOKって事じゃね?
    HTMLにJSが埋め込めるぞ!あれ?
    頭大丈夫?
    いや、ちょっとまて、転送URLにdataURIぶち込めばいんじゃね?
    本物の天才現る!
    いや、普通にサービス規約的にダメだろ
    と言うか、これcanvas使ってるからIEだめじゃね?
    あ…

    って、感じの事がありました。で、IEがcanvasに対応した時にに再燃して、
    もしかして、JSをpngに圧縮する技術の時代が来たんじゃね?
    それだ!
    PNG最高!
    スゲー、JS超圧縮できるじゃん!IEでもちゃんと動くよ!
    いや、普通にnginxでgzipしろよ…
    今更言うなよ!もうrailsのプラグイン書いちゃっただろ!!
    いや、ちょっとまて、flickrやフォト蔵をjs置き場に出来るって事じゃないか!?
    そういうのもう終わってるから。
    いや、ちょっとまて、これ究極の難読化じゃね?
    よし!お前はまずevalの前にブレークを入れる作業に入るんだ
    まあ、evalの前、覗かれたらPacker [edwards.name]でも同じだしな。
    普通にClosure Compilerの最適化MAXで良いだろ。
    いや、あんな気持ち悪いルールでコード書きたくないし。
    で、結論は?
    使えねぇ

    って、感じの2周目もありました。因みにやってみると分かりますが、
    圧縮側もjsの解凍側も凄く簡単に実装できるのでネット中に実装あふれてます。
    休日の暇つぶしにちょうど良い位のボリュームなので、実装してみると楽しいですよ。

    今更たまたま実装した個人がまた出たってだけでストーリーになるのが意外でした。
    メガデモに使うって言うのも海外のサイトではありましたし。
    そもそも、sradで一度も取り上げられてなかったのが意外ですね。
    コメント欄とか日記とかまで探せば取り上げられてそうな気はしますが。

    • by Anonymous Coward

      おっさんの昔話が始まったぞ。
      すっごく長くなるからみんな覚悟しろ!

  • by nemui4 (20313) on 2015年05月14日 8時09分 (#2814006) 日記

    >demoecene は基本的に
    >
    >・ローカルにファイルとして存在しているものを使う
    >・そのファイル容量は 1 バイトでも少ないほうがいい (容量制限がある分野がある)
    それはわかったけど

    >ただし多くの場合GZIPのほうが圧縮率が高くなるとのことで、一般的にはGZIPの利用がすすめられるとのこと。

    ほなこれいらんやん。
    #思いついたら作ってしまう、作ったら公開してしまう。アレゲなる人情に称賛。

    • by Anonymous Coward on 2015年05月14日 8時13分 (#2814008)

      GZIPの展開処理を付け加えるとプログラムが肥大化するので
      ありあわせのPNGデコーダでなんとかしたかったのでは?

      親コメント
    • by minet (45149) on 2015年05月14日 8時40分 (#2814018) 日記

      メガデモ用途ですよ。
      スクリプトを圧縮した結果であるPNG画像自体もテクスチャとかカオティックなノイズ源とかとして使い回すんでしょう。

      親コメント
    • by Anonymous Coward on 2015年05月14日 9時52分 (#2814061)

      ・ローカルにファイルとして存在しているものを使う
      →Accept-Encoding使えないのでgzip使えない

      加えて、この手法は自己解凍機能を持ってます。
      文字通り自己解凍です。このpngファイル1つで完結できます。いやマジで。

      親コメント
      • by nemui4 (20313) on 2015年05月14日 10時29分 (#2814078) 日記

        >文字通り自己解凍です。このpngファイル1つで完結できます。いやマジで。
        なるほど、そういう世界だったのか。
        #電脳世界は広大だ。でもこの話はlocal限定っぽいけど。

        親コメント
      • by Anonymous Coward

        PNGに偽装しといて自己展開とかエンコード方法の部分より遥かにアレゲな要素ですね。
        コード部をテクスチャとして使う以外にもテクスチャを普通に後ろに添付できそうだ。

        自己展開の言語もJSなら頭のマジックはどう処分するんだろう……?

    • by Anonymous Coward

      雑誌でソースコード配布するさいにQRコード見たいに読み取ればタイプミスでエラーとかなくせるんじゃね?
      #ネットで配布した方が早いとかいわない!

    • by Anonymous Coward

      プログラムを圧縮した結果が絵になるように工夫して、プログラム中で自身を画像として読み込んで加工するんでしょ。
      メガデモってデータ込み500KBでOpenGL使うようなやつだよ

  • by Anonymous Coward on 2015年05月14日 7時56分 (#2814002)

    「メガデモ」が懐かしすぎる。昔から謎技術で圧縮重視、計算によるシーンの構築だったな。

  • by Anonymous Coward on 2015年05月14日 8時33分 (#2814014)

    これってキャッシュはしてくれるのかな?
    できればローカルで展開してくれた形でキャッシュされてほしい(無理だろうけど)

    • by Anonymous Coward

      ブラウザからみたら単なるファイルなんでキャッシュするでしょう。
      #一般的ヘッダなら
      展開した形でキャッシュしたいならWeb Storage使えばいいんじゃね?
      #でもメガデモじゃ不必要だけど。つかgzip使えっつーことに。

  • by Anonymous Coward on 2015年05月14日 10時03分 (#2814066)

    PNG偽装のスクリプト上げられるって
    中々に穴が開きそうな気がするんですが

    JavascriptでPNGからスクリプト抽出&実行できる環境に
    アップローダーの組み合わせみたいな

    アップロードディレクトリを
    public_htmlの外においている安全策も
    PHPには有効でしょうけど
    クライアントで実行されるスクリプトには無力なような

    デモサイトを自前で公開する方は
    よく考えて実装したほうがよさげ

    • > PNG偽装のスクリプト上げられるって
      > 中々に穴が開きそうな気がするんですが

      いや、もう穴自体はあいてますよ。
      ていうか、JavaScriptコードがエンコードされたファイルはあくまで画像ファイルですので、そこからJavaScriptコードの抽出処理を行わなければまったくの無害です。

      問題は、どうやってコード抽出処理を行うか。
      ストーリーのリンク先で説明されていますが、このJS圧縮PNGは、自己展開実行機能を持たせることも可能としています。その原理は、

      ・IEはContent-Typeを無視し、データの中身を見てファイル種別を判断する
      ・そのためPNGのヘッダ情報に(コメントデータとして)HTMLのタグっぽいものを埋め込んでおくと、HTMLデータと誤認する
      ・そこで、PNGのヘッダに、HTMLとして「画像変換されたコードを抽出実行するJavaScriptコード」を埋めこんでおくと、
      ・画像のURLを直接ブラウザで開くと、HTMLと解釈されて抽出コードが稼働し、画像化されたコードも実行される

      という流れ。この前半部分、最初に展開コードの実行をキックする流れ自体は、「JSをPNGに変換する部分」とは無関係な技です。

      つまり、今回のネタとは関係なく、「画像ファイルをアップロードできるアップローダ」で、「アップロードしたそのまま生の画像」を「(imgタグ経由ではなく)URL指定でブラウザから直接開くことができる」場合、
      余所のサイトから、 a href="画像URL"> といった画像直リンクを踏ませることで、
      スクリプトインジェクションが可能になる、ということです。

      インジェクションさせないためには、アップローダとして、
      ・画像アップローダでは、(拡張子偽装がされていないかどうか)実データの形式チェック
      は必須ですが、それに加えて、
      ・ファイルのブラウザ直接表示はさせない(Content-Dispositionなどのヘッダを付けて、ダウンロードさせる)
      ・画像は、アップロードしたファイルそのままではなく、不要なヘッダは捨てるフィルタ処理を行う
      ・REFERチェックなどで、画像直リンクは許さない
      などといった対策は必要でしょう。

      #一番のガンは、Content-Typeを無視するIEですが…

      親コメント
      • by Anonymous Coward

        Macで開発してるっぽいのに、なんでIEの話が出てくるん?

        • すみません、自己展開処理については説明を誤読してました。
          JavaScriptコードを埋め込んだPNGファイルを、拡張子 html にして(Content-Type: text/html にして)、ブラウザに送り込んでますね。
          これなら、IEに限らずブラウザ汎用で動作します。

          でも、元コメの「穴があくんじゃないのか」という疑問に対しては、
          画像として特殊なことはしてませんので、だからどうしたということは特になく、
          そもそも「HTMLデータを送りこめてる」時点で大穴、ということになります。

          親コメント
          • by Anonymous Coward

            気になるのは、これが PNG だからという理由でセキュリティソフトのチェックをすり抜けるかどうかです。

      • by Anonymous Coward

        >ストーリーのリンク先で説明されていますが
        IEの話なんてどこに書いてあるんです?

        • 確かに、リンク先の説明はブラウザ汎用っぽい文章になっており、IEの話なんて書かれてないんですが、実際のところそれが動作するのはIEだけです。
          それ以外のブラウザ(少なくともFirefoxとChromeとOperaとSafari)は、ちゃんとContent-Typeを見て動作しますので、Content-Typeを画像と偽装したHTMLデータがHTMLとしてレンダリングされることはありません。

          親コメント
          • by Anonymous Coward

            いや、リンク先のデモ画像もMacのブラウザ(絶対IEではない)だろ...
            IE憎しで頭おかしくなってないか?

    • by Anonymous Coward

      どうもPNGバイナリ中に任意文字列として埋めたHTMLとその中のスクリプトで起動するようなので、アップロードされたファイルをHTMLとして解釈されなければ大丈夫だと思います。

      ……そういえば、コンテントタイプ無視してHTMLっぽければHTMLとして解釈するWebブラウザも居ましたね。

  • by Anonymous Coward on 2015年05月14日 12時42分 (#2814153)

    モバイル環境等で,強制的に画像の再圧縮をかけるようなプロキシが
    設置されていた場合には,どういったことが起こるんだろうか?

    • by Anonymous Coward

      メガデモ用ソリューションで、htmlファイルとしてローカルに置く想定。
      サーバに置いても動くかわからない。
      もし動くとしてもhtmlとしておくので再圧縮はかけない。
      もし再圧縮かけるクソ仕様なら動かない。バグる。

  • by Anonymous Coward on 2015年05月15日 8時38分 (#2814672)

    さらに1/10くらいになる?

    • by Anonymous Coward

      JPEGは不可逆圧縮だから、元のスクリプトに戻せないんじゃないの?
      ロスレスな圧縮もできるだろうけれど、その場合は大した圧縮率ではないですし。

typodupeerror

最初のバージョンは常に打ち捨てられる。

読み込み中...