24

概要

圧縮を気にせずに、できるだけ早く .png ファイルを書きたいと思っています。つまり、ファイル サイズはあまり気にしませんが、できるだけ早く書き込みが行われるように気を付けています。

動機

クライアント側で OpenLayers を使用し、バックエンドで python/C++ を使用して Web ベースのマップ アプリケーションを作成しています。アプリケーションは、ユーザーがマップ上を移動するときに動的コンテンツをすばやく描画できる必要があります。タイルベース (256x256 タイル) と単一画像ベース (「単一タイル」) の両方のバージョンが動作していますが、どちらの場合も、バックエンド レンダリングの最も遅い部分は、実際には画像を png ファイルとして保存することです ( -ディスクまたはメモリ内)。たとえば、特定のビューの「raw」、「tga」、または「tiff」バージョンを約 200 ミリ秒で生成できる場合がありますが、.png バージョンを生成するのに 1.2 秒ほどかかります。保存にはほぼ 1 秒かかりますが、他の形式を実際に保存する時間は 100 ミリ秒以下です (「生の」ファイルは .png ファイルの 5 倍のサイズですが)。また、このファイル保存時間は、結果のイメージをサーバーからクライアントに転送する時間よりも大幅に長くなります。(私のアプリの重要な特性の 1 つは、一般に「バックエンド」がブラウザーと同じマシンで実行されるため、大きなファイルであっても転送時間は無視できることです。)

.png の書き込みを高速化できると思いました (C++ から libpng を使用する場合)。

    png_set_compression_level( png_ptr, 0 );

png_write_...関数を呼び出す前に。ただし、その呼び出しは確かに libpng によるファイルの圧縮を停止しているように見えますが (結果のファイルは .raw ファイルとほぼ同じサイズになります)、.png の保存が著しく高速になるわけではありません。

助けてください

これらの画像には .png を使用する必要があります。これは、これらの画像をベース マップの上に透明なオーバーレイにする必要があり、GIF で提供される 256 色以上が必要だからです。OpenLayers は単純に html img タグを使用しているため、有効な img 形式しか使用できないと理解しています。

実際の圧縮を行わずに.pngファイルをすばやく書き込む方法があると思います(.pngは「常に圧縮」されていることは理解していますが、これには「ヌル圧縮」が含まれる可能性があると思いました)。単純な固定ヘッダーの後に圧縮されていないデータが続き、その後に固定フッターが続くように書くことができるはずです。または、同じアイデアかもしれませんが、行ごとの方法です。ポイントは、メモリ内のこの 2.5 MB の生データを C++ で非常に迅速にループ処理し、さまざまなファイル形式に非常に迅速にダンプできることです。 、非圧縮の .png 形式にもすばやく変換できます。

そうですか?それを行うコードの例がどこにあるか知っていますか?

4

2 に答える 2

32

あなたが望むのは、あなたの目的に特化した実装です。独自のエンコーダーを作成する必要があります。実際にはそれほど難しくなく、仕様は無料です。

フォーマットは複雑すぎず、エンコーダーを実装するのは簡単なはずです

注:すべての値は符号なしです。複数バイトの整数は「ネットワーク バイト順」(最上位バイトが最初) です。


フォーマットはチャンクで構成されています。チャンク構造:

  • チャンクの内容の長さ、4 バイト
  • チャンク識別子 (ASCII)、4 バイト
  • チャンクの内容、「チャンクの内容の長さ」バイト
  • 識別子と内容の CRC (つまり、長さを除く)、4 バイト

実装には、マジック ナンバーと 3 つのチャンクのみが必要です。


詳細なレイアウト:

  • { 137, 80, 78, 71, 13, 10, 26, 10 } (マジックナンバー)、8バイト
  • IHDR チャンクのバイト長、4 バイト (値: 13)
  • { 73, 72, 68, 82 } (「IHDR」)、4 バイト
  • 幅、4 バイト
  • 高さ、4 バイト
  • ビット深度 (色ごと)、1 バイト (8 = 24/32 ビット色)
  • 色の種類、1 バイト (2 = RGB)
  • 圧縮方法、1 バイト (0 =圧縮を許可しないDEFLATEアルゴリズム)
  • フィルター方法、1 バイト (0 = フィルターなし)
  • インターレース方式、1 バイト (0 = インターレースなし)
  • IHDR チャンクの CRC、4 バイト
  • IDAT チャンクの内容のバイト長、4 バイト
  • { 73, 68, 65, 84 } ("IDAT")、4 バイト
  • DEFLATE アルゴ ラッピングを使用した生の画像データ、「IDAT チャンク コンテンツのバイト長」バイト
  • IDAT チャンクの CRC、4 バイト
  • IEND チャンクのバイト長、4 バイト (値: 0)
  • { 73, 69, 78, 68 } ("IEND")、4 バイト
  • IEND チャンクの CRC、4 バイト (事前計算可能)

圧縮なしのDEFLATEデータエンコーディング

データは 65535 バイトのチャンクに分割され、形式は単純です。

  • 最初の X チャンク
    • ヘッダー、1 バイト (値: 0)
    • データ、65535 バイト
  • 最終チャンク
    • ヘッダー、1 バイト (値: 1)
    • データ、65535 バイト以下

それでおしまい


それが高速なpngファイルを作成する方法です

于 2011-11-13T18:46:25.333 に答える
15

PNG の圧縮速度は、主に次の 2 つのパラメータの影響を受けます。

  1. ZLIB 圧縮の圧縮レベル。0 に設定すると、png_set_compression_level本質的にこの圧縮が無効になります。

  2. ピクセル フィルタリング。これは行ごとに異なる可能性があり、選択はヒューリスティックによって行われることが多く、サイズに関しては効率的ですが、時間がかかる可能性があります。png_set_filter速度が主な関心事で png_set_filter_heuristicsある場合 (さらに、ZLIB 圧縮が無効になっている場合) を参照してください。単一のフィルターを選択する必要があります。PNG_FILTER_NONE

速度を最適化するためにやるべきことはあと少しだと思います。BMP や TGA などの「生の」形式と比較すると、圧縮されていない PNG には、各チャンクの CRC32 と ZLIB の内部 Adler CRC を計算するという (小さな) 負荷がまだあります。そして、それはほとんどすべてです。

(記録のために、メモリと CPU の効率を追求する完全な純粋な Java コーダー/エンコーダーをコーディングしました: PNGJ )

于 2013-07-05T13:38:22.890 に答える