63

Android の (2D) Canvas 描画パイプラインのコンポーネントがどのように組み合わされるかについて、よりよく理解したいと思います。

たとえば、XferModeShaderMaskFilter、およびColorFilterはどのように相互作用しますか? これらのクラスのリファレンス ドキュメントはかなりまばらで、CanvasPaintのドキュメントには有用な説明がまったく追加されていません。

また、固有の色を持つ描画操作 (例:drawBitmapと のような「ベクトル」プリミティブdrawRect) がこれらすべてにどのように適合するかは、私には完全には明らかではありません。それらは常に の色を無視し、Paint代わりに固有の色を使用しますか?

また、次のようなことができるという事実にも驚きました。

Paint eraser = new Paint();
eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawOval(rectF, eraser);

これにより、楕円が消去されます。これに気付く前に、私のメンタルモデルは、キャンバスへの描画は(概念的に)別の「レイヤー」に描画され、そのレイヤーはペイントの転送モードを使用してキャンバスのビットマップで構成されるというものでした。CLEAR はソースのアルファに関係なく常に色 (およびアルファ) を 0 に設定するため、それがそれほど単純である場合、上記のコードはビットマップ全体 (クリッピング領域内) を消去します。したがって、これは、消去を楕円形に制限するために、追加の種類のマスキングが行われていることを意味します。

私はAPI デモを見つけましたが、各デモは「真空状態で」動作し、焦点を当てているもの (例: XferModes) が他のもの (例: ColorFilters) とどのように相互作用するかを示していません。

十分な時間と労力をかけて、これらの部分がどのように関連しているか、ソースを解読するかを経験的に理解することができましたが、他の誰かがすでにこれを解決しているか、パイプライン/描画モデルの実際のドキュメントがあることを願っています.私は逃した。

この質問は、別の SO question に対するこの回答のコードを見て触発されました。

アップデート

いくつかのドキュメントを探しているときに、ここで私が興味を持っているものの多くはskiaの上にあるかなり薄いベニヤのように見えるので、役立つスキーのドキュメントがいくつかあることに気づきました。私が見つけることができる最高のものは、次のようなドキュメントですSkPaint

ペイントに割り当てることができる効果には 6 種類あります。

  • SkPathEffect - アルファ マスクを生成する前のジオメトリ (パス) への変更 (ダッシュなど)
  • SkRasterizer - カスタム マスク レイヤー (シャドウなど) の作成
  • SkMaskFilter - 色付けして描画する前のアルファ マスクの変更 (ぼかし、エンボスなど)
  • SkShader - グラデーション (リニア、ラジアル、スイープ)、ビットマップ パターン (クランプ、リピート、ミラー) など
  • SkColorFilter - xfermode を適用する前にソース カラーを変更します (カラー マトリックスなど)。
  • SkXfermode - 例: porter-duff 転送モード、ブレンド モード

明示的には述べられていませんが、ここでの効果の順序は、パイプラインに表示される順序であると推測しています。

4

3 に答える 3

50

Romain Guy が言ったように、「この質問は StackOverflow では答えにくい」。完全なドキュメントは実際にはありませんでした。完全なドキュメントは、ここに含めるにはかなりの量になります。

私はソースを読んで、たくさんの実験をしました。途中でメモを取り、最終的にそれらをドキュメントに変換しました。ここで見ることができます:

この図と同様に:

ここに画像の説明を入力

明らかに「非公式」なので、通常の警告が適用されます。

上記に基づいて、「サブ質問」のいくつかに対する回答を次に示します。

また、固有の色を持つ描画操作 (たとえばdrawBitmap、 と のような「ベクトル」プリミティブdrawRect) がこれらすべてにどのように適合するかは、完全には明らかではありません。それらは常に の色を無視し、Paint代わりに固有の色を使用しますか?

「ソース カラー」はShader. 非が使用されている場合drawBitmap、inShaderは一時的に a に置き換えられます。それ以外の場合、 noが指定されている場合は、単色を生成するだけの の色が使用されます。BitmapShaderALPHA_8 BitmapShaderShaderPaint

また、次のようなことができるという事実にも驚きました。

Paint eraser = new Paint();
eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
canvas.drawOval(rectF, eraser);

これにより、楕円が消去されます。これに気付く前に、私のメンタルモデルは、キャンバスへの描画は(概念的に)別の「レイヤー」に描画され、そのレイヤーはペイントの転送モードを使用してキャンバスのビットマップで構成されるというものでした。CLEAR はソースのアルファに関係なく常に色 (およびアルファ) を 0 に設定するため、それがそれほど単純である場合、上記のコードはビットマップ全体 (クリッピング領域内) を消去し ます。したがって、これは、消去を楕円形に制限するために、追加の種類のマスキングが行われていることを意味します。

XferMode、「ソース カラー」( からShader) と「宛先カラー」( から) にCanvas適用されBitmapます。次に、ラスタライズで計算されたマスクを使用して、結果がデスティネーションとブレンドされます。詳細については、上記のドキュメントの転送フェーズを参照してください。

于 2011-05-09T21:35:06.773 に答える
12

この質問は、StackOverflow で回答するのが困難です。ただし、始める前に、図形 (たとえば drawRect()) には固有の色がないことに注意してください。色情報は常にPaint オブジェクトから取得されます。

これにより、楕円が消去されます。これに気付く前に、私のメンタルモデルは、キャンバスへの描画は(概念的に)別の「レイヤー」に描画され、そのレイヤーはペイントの転送モードを使用してキャンバスのビットマップで構成されるというものでした。CLEAR はソースのアルファに関係なく常に色 (およびアルファ) を 0 に設定するため、それがそれほど単純である場合、上記のコードはビットマップ全体 (クリッピング領域内) を消去します。したがって、これは、消去を楕円形に制限するために、追加の種類のマスキングが行われていることを意味します。

あなたのモデルは少しずれています。楕円形は別のレイヤーに描画されず (Canvas.saveLayer() を呼び出さない限り)、Canvas のバッキング ビットマップに直接描画されます。ペイントの転送モードは、プリミティブによって描画されるすべてのピクセルに適用されます。この場合、楕円のラスタライズの結果のみがビットマップに影響します。特別なマスキングは行われず、楕円自体マスクです。

とにかく、これはパイプラインの簡略図です。

  1. プリミティブ (rect、oval、path など)
  2. パス効果
  3. ラスタライズ
  4. マスクフィルター
  5. カラー/シェーダー/カラーフィルター
  6. Xfermode

(私はちょうどあなたの更新を見ました。はい、あなたが見つけたものは、パイプラインの段階を順番に説明しています。)

レイヤー (Canvas.saveLayer()) を使用すると、パイプラインが 2 倍になるため、パイプラインは少しだけ複雑になります。最初にパイプラインを通過して、プリミティブをオフスクリーン ビットマップ (レイヤー) 内にレンダリングします。次に、オフスクリーン ビットマップがパイプラインを通過して Canvas に適用されます。

于 2011-05-01T18:08:11.170 に答える