QOI
この項目「QOI」は翻訳されたばかりのものです。不自然あるいは曖昧な表現などが含まれる可能性があり、このままでは読みづらいかもしれません。(原文:英語版 "QOI (image format)" 2023年6月20日 (火) 10:49 (UTC)) 修正、加筆に協力し、現在の表現をより自然な表現にして下さる方を求めています。ノートページや履歴も参照してください。(2023年6月) |
拡張子 | .qoi |
---|---|
マジック ナンバー | qoif (4バイト、ASCII) |
開発者 | ドミニク・シャブレフスキ |
初版 | 2021年11月24日 |
最新版 | 1.0 (2022年1月5日 ) |
種別 | 可逆ビットマップ画像ファイルフォーマット |
国際標準 | 仕様 |
オープン フォーマット | Yes |
ウェブサイト | qoiformat |
QOI(Quite OK Image Format)は、ドミニク・シャブレフスキ(ポーランド語: Dominic Szablewski)によって開発され2021年11月24日に初めて発表された24ビット[注釈 1]または32ビット[注釈 2]カラービットマップ(ラスター)画像の可逆画像圧縮の仕様である[1]。
概要
[編集]計画された目標は、PNGよりも実装が簡単で高速に処理ができるオープンソースの可逆圧縮方式を作成することであった。第三者によるYouTubeの動画では、PNGとQOIの圧縮がどのように行われるかについて説明している[2]。作者による最初の発表とこの動画では、同様のファイルサイズのPNGと比較した場合、エンコードは20倍から50倍速く、デコードは3倍から4倍速いと主張している[1]。作者はQOIの仕様をパブリックドメイン(CC0)であると宣言した。
ソフトウェアとプログラミング言語の対応
[編集]QOIはImageMagick[3]、IrfanView(バージョン4.60以降)[4]、FFmpeg(バージョン5.1以降)[5]及びGraphicconverter(バージョン11.8以降)[6]がネイティブに対応している。
コミュニティが作成したプラグインをGIMP、Paint.NET及びXnViewで利用することができる[7]。
Rust、Python、Java、C++、C#などのプログラミング言語向けの実装も存在する[注釈 3][8]。
ファイルフォーマット
[編集]ヘッダ
[編集]QOIファイルは14バイトのヘッダと、それに続く任意の数のデータチャンクと8バイトの終端マーカーで構成される。
qoi_header { char magic[4]; // マジックナンバー(qoif) uint32_t width; // 画像の幅(ビッグエンディアン) uint32_t height; // 画像の高さ(ビッグエンディアン) uint8_t channels; // 3 = RGB、4 = RGBA uint8_t colorspace; // 0 = 線形アルファチャンネル付きsRGB // 1 = 全てのチャンネルが線形 };
色空間とチャンネルのフィールドは純粋に情報を提供するだけである。これらによってデータチャンクの符号化方法が変更されることはない。
符号化
[編集]画像は行ごとに左から右、上から下に符号化が行われる。デコーダとエンコーダは最初のピクセルの前のピクセル値が{r: 0, g: 0, b: 0, a: 255}
であるとして処理を開始する。width * height
で指定された全てのピクセルが処理されると画像が完成する。ピクセルは次のように符号化される:
- 直前のピクセル値に基づく連長圧縮(
QOI_OP_RUN
) - 以前のピクセル値に基づく辞書式圧縮法(
QOI_OP_INDEX
) - 直前のピクセルのRGB値に基づく差分符号化(
QOI_OP_DIFF
またはQOI_OP_LUMA
) - 完全なRGB値またはRGBA値(
QOI_OP_RGB
またはQOI_OP_RGBA
)
カラーチャンネルはアルファチャンネルと乗算済みでないと想定される。エンコーダとデコーダは過去に出現したピクセル値をゼロ値で初期化されたarray[64]
にバッファとして保持する。このバッファの添え字は、ピクセルのRGBA値にハッシュ関数を適用して得られた値を使用する。
エンコーダでは、インデックスのピクセル値が現在のピクセルと一致する場合、このインデックスの位置はQOI_OP_INDEX
としてストリームに書き込まれる。添え字を計算するハッシュ関数は次の通り:
index_position = (r * 3 + g * 5 + b * 7 + a * 11) % 64
各チャンクは2ビットまたは8ビットのタグで始まり、それにデータビットが続く。全てのチャンクはバイトアライメントされている。これらのデータビットに符号化された全ての値は左端に最上位ビットがある。8ビットのタグは2ビットのタグよりも優先される。デコーダは最初に8ビットのタグの存在を確認する必要がある。バイトストリームの終端は7個の0x00
とそれに続く1個の0x01
でマークされる。
チャンクの種類は次の通り:
QOI_OP_RGB
[編集]Byte[0] | Byte[1] | Byte[2] | Byte[3] | |||||||
---|---|---|---|---|---|---|---|---|---|---|
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 .. 0 | 7 .. 0 | 7 .. 0 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 赤 | 緑 | 青 |
- 8ビットタグ
b11111110
(254) - 8ビット赤チャンネル値
- 8ビット緑チャンネル値
- 8ビット青チャンネル値
アルファ値は前のピクセルから変更されない。
QOI_OP_RGBA
[編集]Byte[0] | Byte[1] | Byte[2] | Byte[3] | Byte[4] | |||||||
---|---|---|---|---|---|---|---|---|---|---|---|
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 .. 0 | 7 .. 0 | 7 .. 0 | 7 .. 0 |
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 赤 | 緑 | 青 | アルファ |
- 8ビットタグ(
b11111111
、255) - 8ビット赤チャンネル値
- 8ビット緑チャンネル値
- 8ビット青チャンネル値
- 8ビットアルファチャンネル値
QOI_OP_INDEX
[編集]Byte[0](範囲: 0 .. 63) | |||||||
---|---|---|---|---|---|---|---|
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
0 | 0 | インデックス |
- 2ビットタグ(
b00
) - 6ビット添え字(
0..63
)
有効なエンコーダは同じインデックスに対して2個以上の連続したQOI_OP_INDEX
チャンクを出してはならない。代わりにQOI_OP_RUN
を使用する必要がある。
QOI_OP_DIFF
[編集]Byte[0](範囲: 64 .. 127) | |||||||
---|---|---|---|---|---|---|---|
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
0 | 1 | 赤チャンネル値の差分 | 緑チャンネル値の差分 | 青チャンネル値の差分 |
- 2ビットタグ(
b01
) - 直前のピクセルの赤チャンネルとの差分値(2ビット、
-2..1
) - 直前のピクセルの緑チャンネルとの差分値(2ビット、
-2..1
) - 直前のピクセルの青チャンネルとの差分値(2ビット、
-2..1
)
現在のチャンネルとの差分の計算にはラップアラウンド演算が使用されているので、1 - 2
の結果は255となり、255 + 1
の結果は0となる。
値はエクセス2で表現される符号無し整数として保存される。例えば、−2は0(b00
)として保存され、1は3(b11
)として保存される。アルファ値は前のピクセルから変更されない。
QOI_OP_LUMA
[編集]Byte[0](範囲: 128 .. 191) | Byte[1] | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
1 | 0 | 緑チャンネル値の差分 | 赤チャンネル値 - 緑チャンネル値 | 青チャンネル値 - 緑チャンネル値 |
- 2ビットタグ(
b10
) - 直前のピクセルの緑チャンネルとの差分値(6ビット、
-32..31
) - 赤チャンネルと緑チャンネルとの差分値(4ビット、
-8..7
) - 青チャンネルと緑チャンネルとの差分値(4ビット、
-8..7
)
緑チャンネルは一般的な変化の方向を示すために使用され、6ビットで符号化される。赤チャンネルと青チャンネルはこれらと緑チャンネルとの差分に基づいて符号化される。つまり:
dr_dg = (cur_px.r - prev_px.r) - (cur_px.g - prev_px.g) db_dg = (cur_px.b - prev_px.b) - (cur_px.g - prev_px.g)
現在のチャンネルとの差分の計算にはラップアラウンド演算が使用されているので、10 - 13
の結果は253となり、250 + 7
の結果は1となる。
値は緑チャンネルはエクセス32、赤チャンネルと青チャンネルがエクセス8で表現される符号無し整数として保存される。アルファ値は前のピクセルから変更されない。
QOI_OP_RUN
[編集]Byte[0](範囲: 192 .. 253) | |||||||
---|---|---|---|---|---|---|---|
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
1 | 1 | ランレングス |
- 2ビットタグ(
b11
) - 直前のピクセルを繰り返すランレングス(6ビット)
ランレングスはエクセス−1で保存される。ランレングス63と64(b111110
とb111111
)はQOI_OP_RGB
タグとQOI_OP_RGBA
タグによって占有されているので、不正であることに注意[9]。
脚注
[編集]注釈
[編集]出典
[編集]- ^ a b “Lossless Image Compression in O(n) Time”. Phoboslab.org (2021年11月24日). May 1, 2022閲覧。
- ^ Reducible (March 3, 2022). “How PNG Works: Compromising Speed for Quality”. YouTube.com. May 1, 2022閲覧。
- ^ “ImageMagick - Image Formats”. May 4, 2022閲覧。
- ^ “History of IrfanView Changes/Versions”. www.irfanview.com. 2022年5月10日閲覧。
- ^ “FFmpeg Changelog - Gitweb”. ffmpeg.org. 2022年7月13日閲覧。
- ^ “GraphicConverter Release Notes version 11.8 (build 5762)”. Lemke Software. 21 February 2023閲覧。
- ^ James Hein. “Moving images to the next level”. Bangkok Post April 1, 2022閲覧。
- ^ Simon Sharwood. “Developer creates ‘Quite OK Image Format’ – but it performs better than just OK”. The Register
- ^ Szablewski, Dominic (2022年1月5日). “The Quite OK Image Format Specification”. 2022年6月5日閲覧。 この記事には現在パブリックドメインとなった次の出版物からの記述が含まれています。