1 ポイント 投稿者 GN⁺ 21 시간 전 | 1件のコメント | WhatsAppで共有
  • プログレッシブ JPEG のマルチスキャン構造を変形すると、ダウンロードが進むほど画質が向上する代わりに、すでに表示された画像を別の画像へ継続的に変化させられる
  • 各スキャンは色チャンネル、DCT 周波数範囲、精度を指定し、同じ解像度の JPEG から一部のマーカーを取り除いて連結すると、既存のレンダリングデータを上書きできる
  • デコーダーは圧縮爆弾に似た問題を防ぐため処理するスキャン数を制限しており、Chrome は約 90 フレームまでレンダリングし、Firefox などはさらに多く処理する
  • フレームごとに DC 専用スキャンを 1 つだけ使えば、フレーム数を増やしつつ残像を避けられるが、DCT ブロックの特性上、結果の解像度は元画像の1/16に低下する
  • 単一の JPEG に動画のように複数フレームを格納できるが、タイミング情報がないため再生速度はネットワーク遅延に左右され、実用的な動画よりも部分レンダリングを活用した HTML・シングルページアプリの実験に適している

プログレッシブ JPEG が画像を表示する仕組み

  • JPEG は低周波成分を先に保存することで、ファイルを一部だけダウンロードした状態でも、切り欠けた画像ではなく低解像度のプレビューを表示できる
  • 圧縮データは複数の**スキャン(scan)**に分けられ、各スキャンの前にはヘッダーが付く
    • FF DA はスキャン開始マーカーである
    • 続いて長さフィールド、含まれるチャンネル数と ID、Huffman テーブルのインデックスが入る
    • 開始・終了 DCT ビンと精度を指定したあと、Huffman 符号化された DCT 係数を保存する
  • 最初のスキャンには、3 つの色チャンネルにおける最も低いDC 周波数ビンが含まれる

YCbCr と段階的な品質改善

  • JPEG の 3 つの色チャンネルは、一般的な RGB ではなく YCbCr を使用する
    • Y は輝度なので高い品質が必要
    • CbCr は色差成分のため、品質を下げても視覚的な影響は大きくない
    • 非常に大まかに表すと、Y = GCb = B - GCr = R - G である
  • 例の JPEG はスキャン 0 から 9 までデータを段階的に埋めていく
    • スキャン 0: Y Cb Cr、DCT ビン 0–0 を半分の精度で保存し、非常に低解像度のプレビューを提供する
    • スキャン 1: Y、ビン 1–5 を 1/4 の精度で追加し、輝度の詳細情報を補強する
    • スキャン 2・3: CbCr のビン 1–63 を半分の精度で追加する
    • スキャン 4: Y のビン 6–63 を 1/4 の精度で埋め、スキャン 1 が残した範囲を補完する
    • スキャン 5: Y のビン 1–63 を半分の精度へ改善する
    • スキャン 6–9: 各チャンネルに最後のビットを追加し、完全な品質にする
  • 色差データは輝度より先に完成するが、色差は半分の解像度、つまりピクセル数で 1/4 として保存されるため、Cr + Cb 全体の容量も輝度の半分にすぎない

ダウンロード中に画像を変える

  • 各スキャンは適用する周波数範囲を明示するため、後続のスキャンで既にレンダリングされた画像データを上書きする JPEGを作れる
  • 同じ解像度の画像を複数連結し、次のマーカーを除去する方式で実装する
    • 画像開始(start-of-image)
    • フレーム開始(start-of-frame)
    • 画像終了(end-of-image)
  • 16 進エディタでも作成できるが、実際の生成には簡単な C プログラムを使用する
  • ファイルを遅いネットワークで転送すると、ダウンロードが進む間に複数の画像が順番に切り替わる

デコーダーのスキャン制限

  • ほとんどの JPEG デコーダーは、一定数のスキャンを処理すると停止する
  • 圧縮爆弾に似た問題を避けるための制限と推測され、単純な結合方式では9 フレーム以上を実現するのは難しい
  • より長いアニメーションを作るには、フレームごとに必要なスキャン数を最小化する必要がある

Baseline JPEG を使えない理由

  • スキャンを 1 つだけ使う Baseline JPEG から始める方式は動作しない
  • プログレッシブモードでは、1 つのスキャンに DC データであるビン 0 と、AC データであるビン 1 以上を一緒に入れることができない
  • Baseline モードにはこの制限がないが、Baseline デコーダーは最初のスキャンの後で処理を停止する
  • AC データは DC データの後に来る必要があるため、最小のプログレッシブ JPEG フレームは DC 専用スキャン 1 つで構成される

DC 専用フレームの構成と解像度

  • DCT は16×16 ブロック単位で処理されるため、DC データだけを含めても単色ではなく、元画像の 1/16 解像度の画像を作れる
  • 最小フレームは、Y Cb Cr 3 チャンネルの DCT ビン 0–0 を完全な精度で保存するスキャンを 1 つだけ使う
  • この構成では、Chrome が処理を停止するまでに約90 フレームをレンダリングする
    • Firefox のような他のブラウザは、より多くのスキャンを処理する
    • 90 個のスキャンで構成された画像は、ほぼすべてのブラウザで動作する

残像のないフレーム切り替え

  • 単純な結合方式で残像が出るのは、AC スキャンが既存データを精密化するよう設計されているためである
  • 一般的なプログレッシブ JPEG では、ファイルサイズを大きく増やさずに複数の精度段階を含められるが、画像を置き換える方式には合わない
  • 実際のプログレッシブ改善なしに DC 専用スキャンだけを使えば、以前の AC データの精密化が起こらないため、残像を避けられる
  • DC 専用フレームは標準に準拠した JPEG 画像なので、特殊なエンコーダーは不要
    • スキャン仕様では、0,1,2:0-0,0,0; のように 3 チャンネルの DC ビンだけを指定する

単一 JPEG 動画の限界

  • DC 専用フレームを連結すれば、1 つの JPEG ファイルに動画全体を格納できる
  • JPEG スキャンにはフレームタイミングを追加する方法がないため、再生速度は完全にネットワーク遅延に左右される
  • 非伝統的な Rickroll やいたずら以外には、実用的な応用分野はない

部分レンダリングを拡張した実験

1件のコメント

 
Hacker News のコメント
  • Adam7 インターレース PNG でかなり似たことをやったことがある: https://www.da.vidbuchanan.co.uk/adamation/image.png
    再生は結局ネットワーク遅延に左右されるが、サーバーが各フレームを一定間隔で別々に送るようにしていた。フレームが小さいので、ネットワークが極端に遅くなければ、サーバーが再生タイミングを決める

    • HTTP サーバーを制御できるなら、レスポンスヘッダーに Refresh を設定して、クライアントが新しいアニメーションフレームを定期的に取りに来るようにもできる[1]。2013年の IOCCC 作品もこの手法で PNG で描画した時計を継続的に更新している[2]
      [1] https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/...
      [2] https://www.ioccc.org/2013/mills/index.html
      次の行には Refresh ヘッダーが逆向きにエンコードされている: https://github.com/ioccc-src/winner/blob/619f554bbdb19e5003a...
    • 無限 GIF でライブ映像をストリーミングする似たようなこともやった: https://github.com/jbochi/gifstreaming#live-video-streaming-...
    • PNG をアニメーション化するために裏技を使っている横で、APNG が「自分もいるぞ!」と叫んでいる感じ
    • 20年前の職場の地図アプリケーションにリアルタイムの大気質レイヤーを追加するために、アニメーション GIF で同じことをやった。画像は Java2D でレンダリングし、点群の代わりにグラデーションの塊を作るため JOGL 版も開発したが、サーバー管理者が OpenGL ドライバーのインストールを許可せず、完成しなかった
  • 呪われた手法だが、たしかにここにはふさわしい

    • 大手テック企業はこれを ブラウザーフィンガープリンティング にどう使うか考えそう
  • この手法でデータを目の前に隠す ステガノグラフィー が可能なのか気になる。自動画像解析プログラムの大半は最後の画像だけを見る可能性が高く、学生が学校のコンテンツフィルターを回避するのに使えそう

    • 人間向けのメッセージは最初のフレームに、AI 向けのメッセージは最後のフレームに入れる AI かく乱手法 にできる。猫の写真を送り合って Skynet を倒すようなもの
    • 普通のステガノグラフィーより良い方法には見えない
  • 同じネットワークで並列に読み込む処理の 進捗バー として使って、ユーザーが残りの遅延時間を見積もれるようにできないだろうか

    • 4chan のような場所では不快または違法な画像を隠すのに悪用され、この動作を完全にブロックしたと記憶している
  • Web サーバーがその場で「JPEG」を生成し、時間を空けた断片 としてクライアントに送れば、再生タイミングをある程度制御できる。Web カメラをソースにすれば、終わりなく続く「JPEG」も可能

    • すでに一部の Web カメラが multipart/x-mixed-replace という MIME の仕組みでこれを実現している。サーバーが、今送ったデータを新しいデータで置き換えるようクライアントに指示する方式で、JavaScript なしで通常の HTTP と JPEG だけで動く
    • 多くの IP カメラがすでに https://en.wikipedia.org/wiki/Motion_JPEG でこれを実現している
    • GIF でも可能。以前、GIF をフレーム単位で送り、イメージマップでクリックを処理して、JavaScript なしで リモートデスクトップ のように使えるおもちゃの CGI を作ったことがある。JPEG のほうが良かったかもしれないので、また試してみる価値はある
  • Service Worker で遅い接続を擬似的に再現すれば、再生速度を制御できる

  • 環境によって動作が違うのが奇妙。デスクトップ版 Firefox では正常に再生されるが、iOS モバイルでは「JPEG の中の動画全体」がほぼ単色の茶色→オレンジ→赤の 3 フレームと、ぼやけた猫の輪郭しか見えない
    色がフレームごとに変わるので動いていることはわかるが、動画と呼ぶには厳しい。デスクトップでは本物の動画のように再生されて驚いたし、iOS の画像デコーダーの妙な境界条件 に触れているようだ

  • 最近 OpenGL と jpeg-turbo で画像を高速表示する作業をしたが、JPEG の プログレッシブモード を有効にするとデコードが大幅に遅くなった。プログレッシブ JPEG があると良いという昔の助言は、もう有効ではない可能性が高い
    何十年もかけて画像が段階的に鮮明になる様子をほとんど見ていないので、実用的な価値もなさそう

    • ページの読み込み直後に画像が少しぼやけていて、次の段階で鮮明になる様子を見逃していたのかもしれない。昔のように最初の段階が判別不能なほどではないが、全ファイルサイズの約 30% だけで低解像度プレビュー をほぼ無料で提供できる価値はまだある
    • エンコーダーとして cjpegli を使っているが、デフォルトのプログレッシブとフル 4:4:4 の組み合わせで圧縮率が最も良いので、単なるおまけ機能ではない
    • プログレッシブで保存した JPEG 写真は普通 約 5% 小さく、JPEG をプログレッシブ形式へ無劣化変換することもできる。JPEG XL に無劣化変換すれば、さらに容量を節約できる
    • プログレッシブデコードはデコード自体を速くするためではなく、特に遅いモバイル接続で 大きな画像をより早く表示する ための機能
      例: https://youtube.com/watch?v=UphN1_7nP8U
  • 最初の画像の「間違った」係数から高周波係数を苦労して計算する方法をまず思いついたが、単に 2 枚の画像を結合するやり方が賢い。片方の画像の 低周波成分 の後ろに、もう片方の画像の 高周波成分 をつなぐだけで、驚くほどうまく動く

  • カメラでも 低周波成分 を直接取得できるのか気になる。k-space で低周波を先に取得する MRI の方式も思い出す