何かを変えるためには習慣を変えるほかないということで、とりあえず毎日1時間ぐらい歩くことをはじめてみてる。

大まかに以下の通り4通りのパターンが考えられる。

  1. 朝、自宅最寄り駅に近い数駅歩く
  2. 朝、会社最寄り駅に近い数駅歩く
  3. 夜、自宅最寄り駅に近い数駅歩く
  4. 夜、会社最寄り駅に近い数駅歩く

しかし通勤時間帯を避けようと思うと、2 は無理。夜歩くと帰宅時間が結構遅くなるので嫌。ということで1になる。

しかし最寄り駅付近は歩いても面白くないという致命的な問題がある。立地の事情により特定ルートを通らざるを得なく続けていると単調になってしまう。

変化

正直いってあんまりない。便通が改善したかもしれない。晴れている日が多くて気持ちいいけど精神的に良くなったりはしてない。

Chrome, Firefox, Safari で調べたところ、

  • Chrome: カラーマネジメントされない ( sRGB は適用されない)
  • Firefox: デフォルカラーマネジメントされない (後述。オプションによる)
  • Safari: sRGB が適用される

Firefox の場合

gfx.color_management.mode

によって挙動が変わる。2がデフォルトだが、2の場合は sRGB が適用されない。1の場合は sRGB が適用される。

  • カラープロファイルがない画像
  • CSS の色指定
  • canvas の色指定

に影響する。

CSS の色と画像の色をあわせるには

現状では画像に ICC Profile をつけないようにするのがベスト。色の再現を捨ててあわせにいく感じ。

CSS の色を sRGB にあわせたい場合は

CSS も含めてあわせるのは無理 (ということにしておくと吉)

備考

Firefox Chrome ともに起動時にディスプレイプロファイルを読みこむので、あとから変えても反映されない。また、プライマリディスプレイのプロファイルしか読みこまないので注意。

CSS の色を sRGB にあわせるには

実は少し可能なことがわかったので「(黒魔術) CSS の色を sRGB にあわせるには」というのをあとで書く → 書いた https://lowreal.net/2017/02/07/4

  1. トップ
  2. tech
  3. CSS の色空間は sRGB のはずだけど…

Chrome と Firefox では CSS の色にカラーマネジメントが適用されず、sRGB の画像と色をあわせることが基本的に無理です。

で、無理なんですが無理ではなくて、実は頑張れば sRGB にあわせることができることがわかりました。

デモ

以下のような感じになっていて、書いてある通りです。Chrome と Firefox だと上3つと下3つの色が異なります。Safari だと全て sRGB 扱いされるので全部同じに見えるはずです。ただしカラーマネジメントが有効かどうかの判定を入れてないので、カラーマネジメントに対応してないシステムでも全部同じになっています。

一番下の色が JS で CSS のルールを書きかえて sRGB にしたものです。

やっていること

要は使う色をあらかじめ sRGB プロファイルの PNG に描いておき、この画像のレンダリング結果を canvas に drawImage して、getPixelData を行うとディスプレイプロファイルが適用されたRGB値を取得することができるので、これを動的に CSS の色として適用すれば sRGB にできます。

sRGB の画像を canvas に描くってところがポイントです。

自動的にCSSから色を抽出して sRGB を適用する

が、これは手動でやろうとすると面倒なので、CSSから色を抽出し、動的に sRGB PNG を作ってRGB値を変換してやるというのをやってみました。実用的かというと実用的ではないんですが、できそうですねってところです。

  1. CSS から色を抽出 (cssRules から)
  2. canvas に全部の色を描く
  3. canvas から toDataURL で PNG を得る
  4. この PNG に sRGB プロファイルを埋めこむ
  5. img 要素で読みこませる
  6. canvas に img 要素を drawImage する
  7. canvas の色を読む
  8. CSS に色を書き戻す

という手順でやります。

document.styleSheets の内容を書きかえているので、要素個別に書かれたスタイルについては対応できてません。

CSS の色を抽出

雑に以下のようにしました。当然完璧ではありませんが…

function scanStyleSheetColors (cb) {
	for (var i = 0, stylesheet; (stylesheet = document.styleSheets[i]); i++) {
		for (var j = 0, rule; (rule = stylesheet.cssRules[j]); j++) {
			for (var k = 0, name; (name = rule.style[k]); k++) {
				var val = rule.style.getPropertyValue(name);
				if (/rgb\((\d+),\s*(\d+),\s*(\d+)\)/.test(val)) {
					var r = RegExp.$1;
					var g = RegExp.$2;
					var b = RegExp.$2;
					var ret = cb(r, g, b);
					if (ret) {
						var newVal = 'rgb(' + ret.join(',') + ')';
						console.log(rule, name, val, '->', newVal);
						rule.style.setProperty(name, newVal, rule.style.getPropertyPriority(name));
					}
				}
			}
		}
	}
}

canvas に sRGB プロファイルを適用して PNG の data URL 化

// to PNG data URL with sRGB profile
function applyProfile (canvas) {
	function pngChunk (type, data) {
		var LEN_LENGTH = 4
		var LEN_TYPE = 4;
		var LEN_CRC = 4;
		var buf = new ArrayBuffer(LEN_LENGTH + LEN_TYPE + data.length + LEN_CRC);
		var view = new DataView(buf);

		var pos = 0;
		view.setUint32(0, data.length);
		pos += LEN_LENGTH;
		for (var i = 0, len = type.length; i < len; i++) {
			view.setUint8(pos++, type.charCodeAt(i));
		}
		for (var i = 0, len = data.length; i < len; i++) {
			view.setUint8(pos++, data.charCodeAt(i));
		}
		var crc = CRC32.bstr(type + data);
		view.setUint32(pos, crc);

		return String.fromCharCode.apply(null, new Uint8Array(buf));
	}

	var dataURL = canvas.toDataURL('image/png');
	var matched = dataURL.match(/^data:image\/png;base64,(.+)/);
	var base64 = matched[1];
	var png = atob(base64);
	// sRGB with Perceptual (0) rendering intent
	png = png.replace(/(....IDAT)/, pngChunk("sRGB", "\x00") + "$1");
	return 'data:image/png;base64,' + btoa(png);
}

こんなんでできます。やってることは sRGB チャンクを追加してるだけです。PNG は sRGB に関しては ICC プロファイルを埋めこむ必要なく、13バイト追加するだけですみます。

備考

Safari だと drawImage がうまくいかないです。ちゃんと追ってません。Safari はそもそも sRGB なのでやる必要ないです。

  1. トップ
  2. tech
  3. (黒魔術) CSS の色を sRGB にあわせるには