カラーフィルター
ColorMatrix・BlendColor・Lerp・ガンマ変換フィルターなど、既存の色に対して変換をかけるカラーフィルター(color filter)の使い方をまとめて解説します。
これまでの章では図形や画像そのものの形・配置を扱ってきましたが、ここからは色に手を加える仕組みを見ていきます。カラーフィルター(color filter)は、描画される各ピクセルの色を変換するエフェクトです。Paintの子要素として渡すことで、CircleやImageなど任意の描画コンポーネントに適用できます。
ColorMatrix: 行列で色を変換する
ColorMatrixは5x4の行列を使って、RGBAの各チャンネルを線形変換するフィルターです。行列の各行がR・G・B・Aの出力チャンネルに対応し、入力のR・G・B・A・定数項との積和で新しい値を計算します。
| Name | Type | Description |
|---|---|---|
| matrix | number[] |
5x4のカラー行列(20要素) |
| children? | ColorFilter |
先に適用する別のカラーフィルター |
import { Canvas, ColorMatrix, Image, useImage } from "@shopify/react-native-skia";
const MatrixColorFilter = () => {
const image = useImage(require("./assets/photo.jpg"));
return (
<Canvas style={{ flex: 1 }}>
{image && (
<Image x={0} y={0} width={256} height={256} image={image} fit="cover">
<ColorMatrix
matrix={[
-0.578, 0.99, 0.588, 0, 0, 0.469, 0.535, -0.003, 0, 0, 0.015,
1.69, -0.703, 0, 0, 0, 0, 0, 1, 0,
]}
/>
</Image>
)}
</Canvas>
);
};
行列を手作業で組み立てるのは大変なので、fecolormatrix.comのようなプレイグラウンドで値を作ってから貼り付けるのが現実的です。以下のデモでは彩度(saturation)を操作できます。使っているのはSVGのfeColorMatrix(type="saturate")と同じ式で、彩度0が完全なグレースケール、1が元の色です。
BlendColor: 色とブレンドモードで塗る
BlendColorは指定した色を、指定したブレンドモード(blend mode)で元の色と合成するフィルターです。ブレンドモードの一覧と挙動は次章でまとめて扱いますが、上のデモのhueスライダーもこのBlendColorをmode="hue"で使っています。ここではmultiply(乗算)を使った例を見てみます。
| Name | Type | Description |
|---|---|---|
| color | Color |
合成する色 |
| mode | BlendMode |
ブレンドモード |
| children? | ColorFilter |
先に適用する別のカラーフィルター |
import { Canvas, BlendColor, Group, Circle } from "@shopify/react-native-skia";
const MatrixColorFilter = () => {
const r = 128;
return (
<Canvas style={{ flex: 1 }}>
<Group>
<BlendColor color="cyan" mode="multiply" />
<Circle cx={r} cy={r} r={r} color="yellow" />
<Circle cx={2 * r} cy={r} r={r} color="magenta" />
</Group>
</Canvas>
);
};
Groupに対してBlendColorを適用すると、配下のすべての描画に同じ色フィルターがかかります。黄色の円はシアンと乗算されて緑に、マゼンタの円は青に近い色になります。
Lerp: 2つのフィルターを補間する
Lerpは2つのColorFilterをt(0〜1)の値で線形補間します。フィルター強度をスライダーで滑らかに変化させたい場合に便利です。
| Name | Type | Description |
|---|---|---|
| t | number |
0〜1の補間係数 |
| children | ColorFilter |
補間元となる2つのフィルター |
import {
Canvas,
ColorMatrix,
Image,
useImage,
Lerp,
} from "@shopify/react-native-skia";
const blackAndWhite = [0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0];
const purple = [1, -0.2, 0, 0, 0, 0, 1, 0, -0.1, 0, 0, 1.2, 1, 0.1, 0, 0, 0, 1.7, 1, 0];
const LerpDemo = () => {
const image = useImage(require("./assets/photo.jpg"));
return (
<Canvas style={{ flex: 1 }}>
{image && (
<Image x={0} y={0} width={256} height={256} image={image} fit="cover">
<Lerp t={0.5}>
<ColorMatrix matrix={purple} />
<ColorMatrix matrix={blackAndWhite} />
</Lerp>
</Image>
)}
</Canvas>
);
};
tを動かすと、2つのColorMatrix(白黒とパープル調)の間を滑らかに補間できます。
LinearToSRGBGamma / SRGBToLinearGamma
LinearToSRGBGammaとSRGBToLinearGammaは、リニア色空間とsRGB色空間の間でガンマ変換を行うフィルターです。他のカラーフィルターと組み合わせて色計算をリニア空間で行いたい場合に使います。
import {
Canvas,
BlendColor,
Group,
Circle,
LinearToSRGBGamma,
} from "@shopify/react-native-skia";
const GammaDemo = () => {
const r = 128;
return (
<Canvas style={{ flex: 1 }}>
<Group>
<LinearToSRGBGamma>
<BlendColor color="lightblue" mode="srcIn" />
</LinearToSRGBGamma>
<Circle cx={r} cy={r} r={r} />
</Group>
</Canvas>
);
};
日常的な色調整ではあまり出番はありませんが、シェーダーでリニア空間の計算結果をそのまま表示に使いたいときなどに役立ちます。以下は同じBlendColor(lightblue・srcIn)を、LinearToSRGBGammaで包むかどうかだけを変えた比較です。
注意点
カラーフィルターはPaintの子要素として複数組み合わせられます。childrenpropに別のフィルターを渡すと、そちらが先に適用されてから自分自身が適用される点に注意してください。ColorMatrixとBlendColorを両方使う場合、ネストの順序で見た目が変わります。
公式ドキュメントのColor Filtersも参照してください。