ちょっぴり壊れたICCプロファイルをもつ JPEG 画像のブラウザ表示

# はじめに

先頭 4 bytes が正しくない ICC プロファイルをもつ JPEG 画像はブラウザによって表示が変わるお話です。先にまとめを言うと、LittleCMS を使う実装と OS のカラーマネジメントを使う側とで分かれるようです。

JPEG と ICC プロファイルの関係についてはこちらを参考にしてください。

- JPEG と ICC プロファイル
   - http://awmlabs.github.io/2016/09/10/jpegicc/

# Profile size フィールド

ICC プロファイルの先頭 4 bytes (big endian) には、その全体データサイズの値を収納します。仕様書でいう "Profile size" field です。

|![profile_header_fields.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1798/c8b3cd3d-3ce9-6418-72e8-a2b1f26fbf2d.png)|
|---|
|![スクリーンショット 2020-09-06 22.20.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1798/0659d708-72f4-5b01-f9cc-1466fa06a179.png) |
| (c) http://www.color.org/specification/ICC1v43_2010-12.pdf |

ImageMagick に埋め込まれる sRGB プロファイルを例にとると、ICC プロファイルの全体長が 3212 bytes なので 16進数だと 0xc8c 。以下のように先頭から 4 bytes が 0x00000c8c になります。big endian なので左の値から素直に読めます。

```shell
% hexdump -C ImageMagick_sRGB.icc
00000000  00 00 0c 8c 61 72 67 6c  02 20 00 00 6d 6e 74 72  |....argl. ..mntr|
          ~~~~~~~~~~~
```

0x00000c8c => 3212 で、プロファイルのファイルサイズと一致します。

```
% ls -l ImageMagick_sRGB.icc
-rw-r--r--@ 1 yoya  devel  3212  2 19  2017 ImageMagick_sRGB.icc
```

問題になるのは、実際に ICC プロファイルを利用する際にファイルサイズや格納コンテナ等でプロファイルの全体サイズが分かる事が多いので、

- Profile size を無視して、プロファイルを画像に適用する
- Profile size 分の ICC プロファイルだけ画像に適用する
- Profile は無かった事にして画像表示する。
- そもそも画像表示を諦める

といったように、その異常時の対応によって画像の表示結果が異なる事です。

あと、表示でなくファイル画像の変換の場合は、プロファイルに応じたRGB変換をせず、元の ICC プロファイルを変換後の画像に載せ直す手もあります。ImageMagick がそうしてます。

# 実験ファイル

プロファイルが有効か無効か。以下のサイトを真似して GBR プロファイルで検証します。

- http://tete009.seesaa.net/article/365211300.html#A365211300

| オリジナル画像 | GBR プロファイル適用画像| GBR 適用失敗画像 |
|---|---|---|
| ![IMG_2925.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1798/d874167e-a8dc-bdc6-1fe2-5bd116186474.jpeg)| ![IMG_2925-profileGBR.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1798/3136bae7-84ab-9775-bdfb-1daece1bbb4b.jpeg)| ![IMG_2925-profileGBR-noprofile.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1798/6292f656-d02c-9312-ca35-ae13d7172708.jpeg) |

この真ん中の GBR プロファイル適用画像は、いまどきのブラウザであれば普通に表示できます。仮にプロファイル適用に失敗した場合は、一番右のように色が壊れて表示されます。

では、GBR プロファイルの先頭4byte を壊した画像は以下のものです。

|ちょっぴり壊れたICCプロファイルをもつ JPEG 画像 |
|---|
|![IMG_2925-profileGBR-shortsize.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1798/f95c93d7-1c8d-8fdd-6121-dd9b6ecc9098.jpeg)|

この画像はブラウザによって表示が変わります。

# ブラウザ毎の実験。

手元で試した結果をまとめました。(念のため誰か追試して頂けると嬉しいです)

プロファイルが適用される場合を ○、プロファイルが無視される場合を × とします。未調査またはブラウザが無い分を .　とします。
見易くする為、便宜的に ○、× の記号を用いましたが、どっちかの挙動の方が正しいといった事はありません。

| OS ＼ブラウザ| Chrome | Safari | IE11 | Firefox | Edge |
|---|---|---|---|---|---|
| Windows    | ×    |   .    | ○  |   ×    |  ×    | 
| macOS      | ×     | ○      | . |   ×    |   ×   | 
| iPhone     |  ○     | ○      | .  |  ○    |   ○   |
| Android    | ×     | .      | .  |    ×   |   ×   |

この表を見て分かる通り、Chrome や Firefox など × をつけたブラウザは軒並み ICC プロファイル変換に LittleCMS、またはその派生の qcms を使っています。LittleCMS は変換時にこの Profile size フィールドをチェックするようです。
なお、iPhone(iOS) はブラウザコアの独自実装が許されないので、Chrome,Firefox,Edge も Safari と同じ動きになります。

# 考察

- OS デフォルトの IE11 や Safari は先頭4bytesが壊れていても無視して、その ICC プロファイルを適用します
- 仕様的に壊れている ICC プロファイルを無視する Chrome は間違えているとは言えません。むしろ仕様に忠実
- ですが、IE11 や Safari が表示できてしまう為か、壊れた ICC プロファイルがそこそこ流通しているようです
- OS デフォルトのブラウザに合わせるのが自然と言えますが、現状で Apple,MS 陣営 vs Google 陣営。もし IE11 から Edge へ移行が進めば Apple 陣営 vs MS,Google陣営と、分かれているのが困り物です

# 蛇足

- 本エントリでは先頭4bytesが壊れたICCプロファイルを例にしましたが、中身の情報要素がおかしい ICC プロファイルも世の中に結構流通していて、例えば libpng は駄目な ICCプロファイルの md5 値をもっていて PNG 変換時に チェック出来るようになっています。