Androidの(2D)Canvas描画パイプラインのコンポーネントがどのように組み合わされるかについて、もっと理解したいと思います。
たとえば、 XferMode 、 Shader 、 MaskFilter および ColorFilter はどのように相互作用しますか?これらのクラスのリファレンスドキュメントはかなりまばらで、 Canvas および Paint のドキュメントは、実際に役立つ説明を追加していません。
また、固有の色を持つ描画操作(例:drawBitmap
、またはdrawRect
のような「ベクター」プリミティブ)がどのようにこれに当てはまるかは、私には完全に明らかではありません。 Paint
の色を使用して、代わりに固有の色を使用しますか?
また、次のようなことができることにも驚きました。
Paint eraser = new Paint();
eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawOval(rectF, eraser);
これにより、楕円が消去されます。これに気付く前の私のメンタルモデルは、キャンバスに描画すると(概念的には)別の "レイヤー"に描画され、そのレイヤーは、ペイントの転送モードを使用してキャンバスのビットマップで構成されるというものでした。 CLEARalwaysが色(およびアルファ)を設定するので、それがそのように単純であれば、上記のコードはビットマップ全体(クリッピング領域内)を消去します。ソースのアルファに関係なく0に。したがって、これは、消去を楕円形に制限するために行われている追加の種類のマスキングがあることを意味します。
私は APIデモ を見つけましたが、各デモは「真空」で動作し、それが焦点を当てているもの(例:XferModes)が他のもの(例:ColorFilters)とどのように相互作用するかを示していません。
十分な時間と労力で、これらの部分がどのように関連しているか、またはソースを解読できるかを経験的に理解できますが、誰か他の人がすでにこれを解決しているか、またはさらに良いことに、パイプライン/図面モデルの実際のドキュメントがあることを願っています私は逃した。
この質問は、コードを この回答は別のSO質問 で参照してください。
いくつかのドキュメントを探していると、ここで私が興味を持っているものの多くは skia の上にかなり薄いベニアのように見えるので、役に立つであろういくつかのskiaドキュメントがあるかもしれません。私が見つけることができる最高のものは SkPaint
のドキュメント です:
ペイントに割り当てることができる効果には6つのタイプがあります。
- SkPathEffect-アルファマスク(ダッシュなど)を生成する前のジオメトリ(パス)の変更
- SkRasterizer-カスタムマスクレイヤー(シャドウなど)の作成
- SkMaskFilter-色を付けて描画する前のアルファマスクの変更(ぼかし、エンボスなど)
- SkShader-例グラデーション(線形、放射状、スイープ)、ビットマップパターン(クランプ、繰り返し、ミラー)
- SkColorFilter-xfermodeを適用する前にソースカラーを変更します(例:カラーマトリックス)
- SkXfermode-例ポーターダフ転送モード、ブレンドモード
明示的には述べられていませんが、ここでの効果の順序は、パイプラインに現れる順序であると推測しています。
Romain Guyが言ったように、「この質問はStackOverflowで答えるのは困難です」。実際には完全なドキュメンテーションはありませんでした。完全なドキュメンテーションは、ここに含めるにはかなり大きなものになります。
結局、ソースを読んで、たくさんの実験をしました。私は途中でメモを取って、それらをここで見ることができるドキュメントに変えました:
この図と同様に:
これは明らかに「非公式」なので、通常の警告が適用されます。
上記に基づいて、ここに「サブ質問」のいくつかへの回答があります:
また、固有の色を持つ描画操作(例:
drawBitmap
、またはdrawRect
のような「ベクター」プリミティブ)がどのようにこれに当てはまるかは、私には完全に明らかではありません。Paint
の色を使用して、代わりに固有の色を使用しますか?
「ソースカラー」はShader
に由来します。 drawBitmap
では、ALPHA_8
Shader
以外が使用されている場合、BitmapShader
は一時的にBitmap
に置き換えられます。他の場合では、Shader
が指定されていない場合、単色を生成するShader
のみが使用され、Paint
の色が使用されます。
また、次のようなことができることにも驚きました。
Paint eraser = new Paint(); eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); canvas.drawOval(rectF, eraser);
これにより、楕円が消去されます。これに気付く前の私のメンタルモデルは、キャンバスに描画すると(概念的には)別の "レイヤー"に描画され、そのレイヤーは、ペイントの転送モードを使用してキャンバスのビットマップで構成されるというものでした。 CLEARalwaysが色(およびアルファ)を設定するので、それがそのように単純であれば、上記のコードはビットマップ全体(クリッピング領域内)を消去します。ソースのアルファに関係なく0に。したがって、これは、消去を楕円形に制限するために行われている追加の種類のマスキングがあることを意味します。
XferMode
は、「ソースカラー」(Shader
から)および「デスティネーションカラー」(Canvas
のBitmap
から)に適用されます。次に、ラスタライズで計算されたマスクを使用して、結果を宛先とブレンドします。詳細については、上記のドキュメントの転送フェーズを参照してください。
StackOverflowでこの質問に答えることは困難です。ただし、始める前に、形状(たとえば、drawRect())には固有の色がないことに注意してください。色情報alwaysはPaintオブジェクトから取得されます。
これにより、楕円が消去されます。これに気付く前の私のメンタルモデルは、キャンバスに描画すると(概念的には)別の "レイヤー"に描画され、そのレイヤーは、ペイントの転送モードを使用してキャンバスのビットマップで構成されるというものでした。 CLEARはソースのアルファに関係なく常に色(およびアルファ)を0に設定するため、それがそのように単純であれば、上記のコードはビットマップ全体(クリッピング領域内)を消去します。したがって、これは、消去を楕円形に制限するために行われている追加の種類のマスキングがあることを意味します。
モデルが少しずれています。楕円は別のレイヤーに描画されません(Canvas.saveLayer()を呼び出さない限り)。楕円はCanvasのバッキングビットマップに直接描画されます。ペイントの転送モードは、プリミティブによって描画されるすべてのピクセルに適用されます。この場合、楕円のラスタライズの結果のみがビットマップに影響します。特別なマスキングは行われていません。楕円自体isマスクです。
とにかく、ここにパイプラインの簡略図があります。
(私はあなたの更新を見たばかりで、はい、あなたが見つけたものはパイプラインのステージを順番に説明しています。)
レイヤー(Canvas.saveLayer())を使用すると、パイプラインが2倍になるため、パイプラインが少し複雑になります。最初にパイプラインを経由してプリミティブをオフスクリーンビットマップ(レイヤー)内にレンダリングし、パイプラインを経由してオフスクリーンビットマップをキャンバスに適用します。
SkPathEffect-アルファマスクを生成する前のジオメトリ(パス)の変更(例:ダッシュ)SkRasterizer-構成するカスタムマスクレイヤー(例:シャドウ)SkMaskFilter-色付けして描画する前のアルファマスクの変更(例:ぼかし)SkShader-例グラデーション(線形、放射状、掃引)、ビットマップパターン(クランプ、繰り返し、ミラー)SkColorFilter-xfermode(カラーマトリックスなど)を適用する前にソースカラーを変更しますSkXfermode-たとえばポーターダフ転送モード、ブレンドモード