JPEGファイルの理解を深める

## JPEGの仕組み

JPEGは、画像をデータにする時に一片が`8pixelの倍数`の小さい画像に分割し
個々の画像をデータに変換します。この小さい画像をMCU(Minimum Coded Unit)と呼びます。

さらにJPEGには

1. `ベースライン方式`
2. `拡張ベースライン方式`
3. `プログレッシブ方式`
4. `ロス無し方式`

の4種類あり、そのうちメジャーな2つだけ説明します。

**ベースライン方式**: データを先頭からロードして表示する方式。
**プログレッシブ方式**:まず画像全体を低解像度でロードし、その後に徐々に高解像度で表示する方式。容量はこちらの方がやや軽くなる。

## 画像データのJPEG変換について

画像をJPEGに変換するには以下のステップを踏みます。

1. RGB-YCbCr変換(サンプリングファクタ ＆ サンプリング)
2. DCT変換(離散コサイン変換)
3. 量子化
4. ランレングス・ハフマン圧縮

この変換の際に必要な用語について解説します。
尚、以降の説明はベースライン方式を前提として説明していきます。

### サンプリングファクタ

人間の目は色合いの違いより明るさの違いに敏感であるという特性を利用して、
RGBデータをJPEGファイルに変換する際は、ピクセルデータを主に`色差`と`輝度`の2成分に分割します。
このとき、人間の目は色合いの違いより明るさの違いに敏感であるという特性を利用して
色差の情報はある値まで間引きされます。(一般的には1/4に間引かれる。)
この、`間引く割合`をサンプリングファクタといい、成分ごとに
縦(V)と横(H)の値を持っています。

V = vertical
H = horizntal

### サンプリング

RGBデータをJPEGファイルに変換する時、先述した画像成分の分解と共に、四角い小さな画像データに分割します。
この小さい画像データに分割する処理のことを`サンプリング`と言います。
この時に先述した`サンプリングファクタ`を使います。
この時画像成分の中で最大のサンプリングファクタを8倍した値が、この小さな画像1片の長さになります。

例えば

輝度成分(Y)のサンプリングファクタ = 横1 : 縦:2
青色色差成分(Cb)のサンプリングファクタ = 横1 : 縦1

の場合画像を横8pixel * 16pixelのサイズで分割します

### サンプリング比

先述のサンプリングリストを比率にしたものをサンプリング比と呼びます。

### パディング

先述したとおり、JPEGファイルは8pixelの倍数のサイズのMCUという単位でさらに小さく分割されますが、
この時8の倍数で割り切れない場合、画像の右端・下端のデータが余ります。
この時JPEGでは余ったデータにダミーのデータを加えて追加でMCUを作成します。
このダミーのデータのことを`パディング`と呼びます。
尚、SOFにはパディングサイズを差し引いた画像が記録されます。

### 量子化

MCUは8pixel * 8pixelの倍数で構成されると表記しましたが、実際には8pixel * 8pixel
そのままのサイズで構成されることが多いです。この8*8のデータ(ブロック)の中身についてのお話です。

JPEGファイルは8ビット精度で、1pixelで1Byte、1ブロックで64Bytesのデータサイズです。
このデータをDCT変換(離散コサイン変換)と呼ばれる方法で64段階の周波数成分に分解し、
低周波のものから並べますす。
この時サイズはそのまま64Bytesです。

(DTC変換は離散フーリエ変換の一種で8pixel四方(64個)のデータを周波数分解します)

この時一番左上のデータをDC成分と呼び、その他の成分をAC成分と呼びます。
この値を、Y(輝度)・Cb(青色色差)・Cr(赤色色差)の各成分ごとに用意されている量子化テーブル
の値(整数)で割ります。逆に画像を再生するときは、量子化テーブルを掛けます。

このとき割った余りを捨てるんですが、余りが大きいほど画像が劣化します。
このようにブロックのデータを段階的なデータにして値を丸める処理を`量子化`と呼びます。
そして量子化されたデータを`係数`と呼びます。

### ジグザグスキャン

量子化された8Bytes * 8Bytesの2次元データをジグザグに辿って
線形に並べた64Bytesのデータにしていく処理をジグザグスキャンと呼びます。
(画像は「ジグザグスキャン」で調べてください🙇♂️)
このとき低周波から高周波になるように左上から右下にジグザグ状に辿っていくことで
圧縮効率が上がる&データの劣化を抑えることができます。理由を次に解説します。

先述のDCT変換の際に、ブロック内のデータは左上ほど低周波で右下にいくほど高周波に並んでいます。
すると右下に近いほど0の頻出度が高くなります。
ハフマン圧縮では0が連続するほど圧縮効率が高くなり安いので
先述した通り左上から右下にジグザグに辿ることで圧縮効率が上がります。

### ハフマン圧縮

これまでバイト単位でデータを加工していましたが、このハフマン圧縮ではビット単位でデータを加工します。
このビット単位で処理する過程でデータが圧縮されます。詳しく見てみましょう。

まず、用語の説明になりますが
特定コードの連続を`ラン`と呼びます。
そして`0が連続した回数`をランレングスと呼び
ハフマン圧縮では`コードの連続を繰り返さず連続回数を記録`することでデータ長を短くし圧縮します。
この際、ハフマンテーブルというテーブルが用いられます。

### スタッフィングビット

JPEGのフレーム内の画像データはビット単位で記録されますが、対してその後に出現する
マーカはバイト単位で記録されます。
画像データがバイト境界で終了しない(8bitで割り切れない)場合、次のバイト境界まで
`1`を詰めてデータちょうを揃えます。
この時詰められるビットを`スタッフィングビット`と呼び、JPEGでは`1`を詰める規定になっています。

## JPEGフォーマットの全体構造

JPEGファイルは先頭に`SOI(Start of Image)マーカ` 、末尾に`EOI(End of Image)マーカ`があり
その間に複数のセグメント領域とイメージデータ(画像データ)があります。

このSOIマーカとEOIマーカに挟まれている領域を`フレーム`と呼びます。

つまり大きく分けるとJPEGはSOIマーカ、フレーム、EOIマーカの3つから成り立っています。

### マーカについて

マーカは、種別を合わす2Byteのコードで、1Byte目は必ず`0xFF`になっています。

SOIは`0xFFD8`、EOIは`0xFFD9`です。(暗記する必要はなさそう)
またそれぞれスタートマーカ、エンドマーカと呼ばれたりします。

### セグメントについて

色々ありますが、JPEGファイル表示に必須のセグメントを4つ載せます。

**DQT(量子化テーブル定義)**

量子化する際に参照される量子化テーブルがこのマーカ内で定義されます。

**DHT(ハフマンテーブル定義)**

ハフマン圧縮する際に参照されるハフマンテーブルがこのマーカ内で定義されます。

**SOF(Start of Frame)**

フレームヘッダです。JPEGファイルの種類やサイズなどの情報が記録されています。
全部で13種類あり、`SOF0(ベースライン方式)`と`SOF2(プログレッシブ方式)`の2つがメジャーです。

**SOS(Start of Sacn)**

イメージデータの先頭に記録され、直後にイメージデータが続くことを表しています。
イメージデータの成分などもここに記録されます。