モバイル端末も 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 と同様デフォルトでカラー変換なしでプロファイルが消滅します。保持する方法も一緒です。
(強調は引用者) 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
- Chrome の画像色空間関係バグ (未解決) https://bugs.chromium.org/p/chromium/issues/detail?id=667431