モバイル端末も iPhone7 など DCI-P3 サポートが増えてきて、CSS での広色域サポートもはじまりつつあるなかで、サーバサイドなどで画像をとりあつかうときに、正しく扱えていないというのはとても微妙です。HTTPS 対応が当然になっていくように、広色域対応も当然のこととなっていくことでしょう。

正しいやりかたといっても簡単で、

  • 付属するICCプロファイルをそのままにする (一番簡単)
  • なんらかの事情で sRGB にするならするでプロファイル変換する (CMSが必要)

ということです。全然当たり前で面白くないですね。でも考慮してないことが多いのではないでしょうか。

まず付属するICCプロファイルを保持するというのは一番簡単で確実です。

一方で小さい画像だとICCプロファイルのサイズが無視できなくなるので色再現よりファイルサイズを優先したいという場合もあります。この場合は sRGB に変換するのが適切です。プロファイルなしを sRGB として扱うブラウザが多く、今 sRGB として取り扱ってないブラウザもそのうち sRGB 扱いするであろう期待があるためです。(画像だけがモニタプロファイルに直接影響されブラウザ内で閉じていない状況というのは canvas や CSS color との整合性がとれないので)

しかしいくらファイルサイズを減らしたいといっても、単にICCプロファイルを不必要なメタデータとして削除するだけの実装がしばしばあって、これはかなりよくない実装です。

いくつかの実装で正しいやりかたをするにはどうすれば良いか調べてみました。

外部から実装をみたときの考慮ポイント

  • ICCプロファイルを保持するか
  • 保持しないなら適切に変換されるか

プロファイルを単純に捨てるとどうなるか?

プロファイルなしの画像をどう扱うかで変わってきますが、sRGB としてみなす環境を想定する場合だと

  • 元画像が sRGB なら問題ありません。
  • 元画像が広色域 (AdobeRGB / DCI-P3 など) だと大きく色が変わります。画像全体の色が変化するので、ホワイトバランスが崩れて元の画像の印象と大きく変わってきます。彩度も、正しく sRGB 変換に変換するのと違って大きく下がります。

テスト画像

http://www.color.org/version4html.xalter にあるうち Upper_Right.jpg は変換に失敗すると色がおかしいのが一目でわかるので便利です。

exiftool -profiledescription *.jpg          
======== Lower_Left.jpg
Profile Description             : GBR
======== Lower_Right.jpg
Profile Description             : Adobe RGB (1998)
======== Upper_Left.jpg
Profile Description             : e-sRGB
======== Upper_Right.jpg
Profile Description             : sYCC 8-bit
    4 image files read

exiftool だとカラープロファイルがない場合は Profile Description もでません。

ImageMagick で strip を使っているなら要注意

まずはコマンドラインから。

特に何もせずに resize などをしてもプロファイルは失われません。verbose の出力に元のプロファイルと関係なく sRGB とかでるけど、これは謎で、出力プロファイルとは関係ありません。作業用スペースなのかな?

$ convert Upper_Right.jpg -resize 128x -verbose x.jpg
Upper_Right.jpg=>x.jpg JPEG 261x196=>128x96 128x96+0+0 8-bit sRGB 26878B 0.010u 0:00.009


$ exiftool -profiledescription x.jpg             
Profile Description             : sYCC 8-bit


画像の表示に直接関係のないメタデータを一括で削除するコマンドとして strip がありますが、これをするとカラープロファイルも失われます。入力に sRGB 以外の画像が入る可能性があるなら strip は単体でつかってはいけません。

sRGB に変換 (-profile) しつつカラープロファイルなどメタデータを削除 (-strip) するなら以下の通りにします。プロファイル変換のため little-cms 対応のビルドが必要です。

convert Upper_Right.jpg -profile /System/Library/ColorSync/Profiles/sRGB\ Profile.icc -strip x.jpg

LCMS 対応ビルドを homebrew で入れる場合

デフォルトでは有効にならないので、オプションが必要です

$ brew install imagemagick --with-little-cms --with-little-cms2

$ convert --version
Version: ImageMagick 7.0.5-9 Q16 x86_64 2017-06-01 http://www.imagemagick.org
Copyright: © 1999-2017 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Features: Cipher DPC HDRI Modules 
Delegates (built-in): bzlib freetype jng jpeg lcms ltdl lzma png tiff xml zlib

Delegates に lcms が入っていればオッケー

ImageMagick (Perl)

Perl に限らず ImageMagick の API はどれもほぼ一緒なはずです。

ちなみに little-cms 付きでビルドしていないと色域変換ができないにも関わらずエラーにならないので罠いです。これは Perl だけかもしれないですが……

コマンドラインと同じように Strip したい場合 (sRGB に変換すべきケース) では以下のようにします

#!/usr/bin/env perl
use utf8;
use strict;
use warnings;
use v5.10.0;
use lib lib => '/usr/local/lib/perl5/site_perl';

use Image::Magick;
use Path::Class;

warn Image::Magick->new->Get('version');
#=> ImageMagick 7.0.5-9 Q16 x86_64 2017-06-02 http://www.imagemagick.org

my $p = Image::Magick->new;
$p->Read("./Upper_Right.jpg");

# little-cms (lcms) 付きでビルドしていないとエラーもなく失敗するので注意
my $err = $p->Profile(
	name               => '/System/Library/ColorSync/Profiles/sRGB Profile.icc',
	'rendering-intent' => 'Perceptual',
);
warn "$err" if "$err";

# メタデータ削除
$p->Strip;

$p->Write("x.jpg");

Profile() メソッドを呼ぶと変換もしてくれるようです。ドキュメントを見るといまいち変換してくれるのかわかりにくいけど変換してくれます。引数もわかりにくいけど name にファイル名を渡すのがお手軽っぽいです。上にも書いた通り little-cms 対応ビルドじゃないとダメで、エラーにもならないのでとても注意が必要です。

jpegtran

Independent JPEG Group's JPEGTRAN, version 8d  15-Jan-2012
Copyright (C) 2012, Thomas G. Lane, Guido Vollbeding
$  jpegtran -outfile x.jpg  Upper_Right.jpg 

デフォルトでカラー変換なしでプロファイルが消滅します。保持するためには以下のようにしてメタデータを全て保持するしかない。

$ jpegtran -copy all -outfile x.jpg Upper_Right.jpg 

ICC プロファイルだけ残す設定はないようです。

プロファイルを変換するオプションもないので、sRGB にしつつプロファイルを削除したい場合は別のツール (たとえば ImageMagick) が必要となります。

mozjpeg

/usr/local/opt/mozjpeg/bin/jpegtran -v
mozjpeg version 3.2 (build 20170501)
Copyright (C) 2009-2016 D. R. Commander
Copyright (C) 2011-2016 Siarhei Siamashka
Copyright (C) 2015-2016 Matthieu Darbois
Copyright (C) 2015 Google, Inc.
Copyright (C) 2014 Mozilla Corporation
Copyright (C) 2013-2014 MIPS Technologies, Inc.
Copyright (C) 2013 Linaro Limited
Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies)
Copyright (C) 2009 Pierre Ossman for Cendio AB
Copyright (C) 1999-2006 MIYASAKA Masaru
Copyright (C) 1991-2016 Thomas G. Lane, Guido Vollbeding

Emulating The Independent JPEG Group's software, version 8d  15-Jan-2012
 /usr/local/opt/mozjpeg/bin/jpegtran  -outfile x.jpg  Upper_Right.jpg 

オリジナルの jpegtran と同様デフォルトでカラー変換なしでプロファイルが消滅します。保持する方法も一緒です。

Progressive encoding with "jpegrescan" optimization. It can be applied to any JPEG file (with jpegtran) to losslessly reduce file size.

https://github.com/mozilla/mozjpeg

(強調は引用者) losslessly って書いてあってモヤモヤしますね。デフォルトでロスしてる。

プロファイルを変換するオプションもないので、sRGB にしつつプロファイルを削除したい場合は別のツール (たとえば ImageMagick) が必要となります。

jpegoptim

$ jpegoptim --version
jpegoptim v1.4.4  x86_64-apple-darwin16.0.0
Copyright (c) 1996-2016, Timo Kokkonen

libjpeg version: 8d  15-Jan-2012
Copyright (C) 2012, Thomas G. Lane, Guido Vollbeding
$ jpegoptim --stdout Upper_Right.jpg  > x.jpg 
Upper_Right.jpg 261x196 24bit N Exif IPTC XMP ICC Adobe JFIF  [OK] 27862 --> 27193 bytes (2.40%), optimized.

デフォルトでは消さないようです。

オプションで -s / --strip-all をつけると ICC プロファイルも消えてしまうため、ICCプロファイルだけ残す場合は以下のようにめんどうな感じになります。

$  jpegoptim --strip-com --strip-exif --strip-iptc --strip-xmp --stdout Upper_Right.jpg  > x.jpg 

プロファイルを変換するオプションもないので、sRGB にしつつプロファイルを削除したい場合は別のツール (たとえば ImageMagick) が必要となります。

cwebp

$ cwebp -version
0.6.0
$ cwebp Upper_Right.jpg -o x.jpg
Saving file 'x.jpg'
File:      Upper_Right.jpg
Dimension: 261 x 196
Output:    1722 bytes Y-U-V-All-PSNR 44.43 45.04 44.25   44.49 dB
block count:  intra4: 59
              intra16: 162  (-> 73.30%)
              skipped block: 54 (24.43%)
bytes used:  header:             47  (2.7%)
             mode-partition:    290  (16.8%)
 Residuals bytes  |segment 1|segment 2|segment 3|segment 4|  total
    macroblocks:  |       5%|       5%|       8%|      80%|     221
      quantizer:  |      36 |      36 |      32 |      23 |
   filter level:  |      11 |       8 |       6 |       5 |

デフォルトでICCプロファイルが消滅します。

cwebp  -metadata icc Upper_Right.jpg -o x.jpg

で ICC プロファイルだけ残せます。

プロファイルを変換するオプションもないので、sRGB にしつつプロファイルを削除したい場合は別のツール (たとえば ImageMagick) が必要となります。

ref

  1. トップ
  2. tech
  3. 広色域時代の画像の正しい扱いかた