9

I am currently drawing directly on the Canvas object provided to my view's onDraw method. This canvas is hardware accelerated. In particular, I can draw multiple circles using RadialGradient shaders with the OVERLAY PorterDuff mode. However, when I try to apply the same draw procedure to a canvas which I manually create, I do not get the same results. I believe this is because the canvas object created for the bitmap is NOT hardware accelerated.

The code looks something like this for the view:

public class MyView extends View {
  private Paint mPaint;
  private List<Shader> mShaders;

  public MyView(Context context) {
    super(context);

    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG|Paint.DITHER_FLAG);
    mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.OVERLAY));

    mShaders = new ArrayList<Shader>(); // assume x, y, r, and color vals are defined.
    mShaders.add(new RadialGradient(x1, y1, r1, c11, c12, Shader.TileMode.CLAMP));
    mShaders.add(new RadialGradient(x2, y2, r2, c21, c22, Shader.TileMode.CLAMP));
  }

  @Override
  protected void onDraw(Canvas canvas) {
    mPaint.setShader(mShaders.get(0));
    canvas.drawCircle(x1, y1, r1, mPaint);

    mPaint.setShader(mShaders.get(1));
    canvas.drawCircle(x2, y2, r2, mPaint);
  }
}

Up to this point, everything is well and good. The circles are drawn as expected on the hardware accelerated canvas.

However, if I do this:

...
Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
draw(canvas);

or some variation of this:

...
setDrawingCacheEnabled(true);
buildDrawingCache();
Bitmap bitmap = Bitmap.createBitmap(getDrawingCache());
destroyDrawingCache();
setDrawingCacheEnabled(false);

or if I try drawing with the very same shaders and paint flags on, say, the non-hardware accelerated canvas provided by the WallpaperService Engine, the results are just not the same as they were when I did the very same thing on the hardware accelerated canvas object of the view.

Here is a screenshot showing what happens when the circles are drawn on an accelerated view canvas. https://www.dropbox.com/s/vgvo3l6wz2d1b1c/good.png?dl=0

Here is what happens when drawn upon a manually created canvas, not associated with a view. https://www.dropbox.com/s/zuo23z2y7ik2wmg/bad.png?dl=0

While I understand that there are significant differences to expect when drawing with hardware acceleration or not, it seems like there is no way to capture even the rendered appearance of the accelerated canvas without having to re-render it in software via the drawing cache, which doesn't work. How do I capture the rendered view as-is?

Shortly after writing this, I noticed that simply commenting out the line that sets the OVERLAY Xfermode eliminates the difference between drawing on an accelerated or non-accelerated canvas, but this is not a solution. Removing the OVERLAY mode produces a completely different effect than what I am trying to capture.

Johann
  • 27,536
  • 39
  • 165
  • 279
Daniel Gabriele
  • 281
  • 2
  • 6

0 Answers0