官方文档翻译过来的解释:

要绘图,需要4个基本组件:

  • Bitmap 保存像素的容器
  • Canvas 执行绘图命令的宿主
  • Rect/Path/text/Bitmap 要绘制的元素
  • Paint 用什么样的方式绘制

android的canvas绘图,基于skia,想要了解canvas的绘图过程,需要对canvasskia的源码有所了解。

查看Canvas源码,发现Canvas与Bitmap类似,都是对其native方法进行了封装。

真正起绘图作用的是mNativeCanvas,保存有nativeCanvas(SkCanvas)的指针。

mNativeCanvas注释上指明

assigned in constructors or setBitmap, freed in finalizer

说明mNativeCanvas(SkCanvas)是在构造函数、或者setBitmap时分配的。

继续查看源码,发现mNativeCanvas是调用native方法

initRaster(int nativeBitmapOrZero)

方法生成。

initRaster中的参数就是Canvas私有属性mBitmapnativeBitmap(SkBitmap)的指针。

查看frameworks/base/core/jni/android/graphics/下的Canvas.cpp文件,

static SkCanvas* initRaster(JNIEnv* env, jobject, SkBitmap* bitmap) {
        return bitmap ? new SkCanvas(*bitmap) : new SkCanvas;
}

发现如果指定了SkBitmapinitRaster会以指定的SkBitmap生成SkCanvas

反之会生成默认的SkCanvas

继续查看android/external/skia/src/core/下SkCanvas的源码,

默认构造函数

SkCanvas::SkCanvas()
: fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage)) {
    inc_canvas();

    this->init(NULL);
}

init方法调用setDevice方法,生成默认的SkDevice,而SkDeveice最终会生成默认的SkBitmap

总结

  • Canvas的属性mNativeCanvas(SkCanvas)是根据mBitmap生成的,如果mBitmap不为空,

    mNativeCanvas操作/修改的SkBitmap就是mBitmap

    否则会操作/修改mNativeCanvas自己的SkBitmap.

  • Canvas最终操作/修改的内存还是Bitmap(SkBitmap)中的数据.

  • Canvas(bitmap) 与 canvas.setBitmap(bitmap)中的bitmap是Canvas的mBitmap,直接操作/修改的对象。

    canvas.drawBitmap(bitmap)中的bitmap是源bitmap,draw时,不对源bitmap进行写操作,

    而是写入到mBitmapmNativeCanvas自己的SkBitmap中。

  • 源码中指明Canvas最大绘图大小为32766 * 32766。超过这个大小会直接报错。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐