开天辟地 HarmonyOS(鸿蒙) - canvas: 通过 CanvasRenderingContext2D 绘制图形(图像滤镜,叠加绘制,图层,清除指定的区域,画布转图片,上下文的保存和加载)

源码 https://github.com/webabcd/HarmonyDemo
作者 webabcd

开天辟地 HarmonyOS(鸿蒙) - canvas: 通过 CanvasRenderingContext2D 绘制图形(图像滤镜,叠加绘制,图层,清除指定的区域,画布转图片,上下文的保存和加载)

示例如下:

pages\canvas\CanvasRenderingContext2DDemo3.ets

/*
 * CanvasRenderingContext2D - 按照 W3C 标准封装了本地绘图接口(效率比 DrawingRenderingContext 低)
 *
 * 本例用于演示通过 CanvasRenderingContext2D 绘制时,如何实现图像滤镜,叠加绘制,图层,清除指定的区域,画布转图片,上下文的保存和加载
 */

import { MyLog, TitleBar } from '../TitleBar';
import { LengthMetricsUnit } from '@kit.ArkUI';

@Entry
@Component
struct CanvasRenderingContext2DDemo3 {

  build() {
    Column() {
      TitleBar()
      Tabs() {
        TabContent() { MySample1() }.tabBar('图像滤镜').align(Alignment.Top)
        TabContent() { MySample2() }.tabBar('叠加绘制').align(Alignment.Top)
        TabContent() { MySample3() }.tabBar('图层').align(Alignment.Top)
        TabContent() { MySample4() }.tabBar('清除指定的区域').align(Alignment.Top)
        TabContent() { MySample5() }.tabBar('画布转图片').align(Alignment.Top)
        TabContent() { MySample6() }.tabBar('上下文的保存和加载').align(Alignment.Top)
      }
      .scrollable(true)
      .barMode(BarMode.Scrollable)
      .layoutWeight(1)
    }
  }
}

// 图像滤镜
@Component
struct MySample1 {

  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(new RenderingContextSettings(true))
  private imageBitmap = new ImageBitmap("resources/base/media/son.jpg", LengthMetricsUnit.DEFAULT)

  build() {
    Column({ space: 10 }) {

      /*
       * CanvasRenderingContext2D - 按照 W3C 标准封装了本地绘图接口
       *   filter - 指定图像的滤镜
       *     none - 无滤镜
       */
      Canvas(this.context).width('100%').height('100%').backgroundColor(Color.Yellow)
        .onReady(() => {

          this.context.filter = 'none';
          this.context.drawImage(this.imageBitmap, 0, 0, 100, 100);

          this.context.filter = 'grayscale(50%)'; // 灰度效果
          this.context.drawImage(this.imageBitmap, 100, 0, 100, 100);

          this.context.filter = 'sepia(60%)'; // 深褐色效果
          this.context.drawImage(this.imageBitmap, 200, 0, 100, 100);

          this.context.filter = 'saturate(30%)'; // 饱和度效果
          this.context.drawImage(this.imageBitmap, 0, 100, 100, 100);

          this.context.filter = 'hue-rotate(90deg)'; // 色相旋转效果
          this.context.drawImage(this.imageBitmap, 100, 100, 100, 100);

          this.context.filter = 'invert(100%)'; // 颜色反转效果
          this.context.drawImage(this.imageBitmap, 200, 100, 100, 100);

          this.context.filter = 'opacity(25%)'; // 不透透明度效果
          this.context.drawImage(this.imageBitmap, 0, 200, 100, 100);

          this.context.filter = 'brightness(0.4)'; // 亮度效果
          this.context.drawImage(this.imageBitmap, 100, 200, 100, 100);

          this.context.filter = 'contrast(200%)'; // 对比度效果
          this.context.drawImage(this.imageBitmap, 200, 200, 100, 100);

          this.context.filter = 'blur(5px)'; // 模糊效果
          this.context.drawImage(this.imageBitmap, 0, 300, 100, 100);

          this.context.filter = 'opacity(50%) contrast(200%) grayscale(50%)'; // 复合效果
          this.context.drawImage(this.imageBitmap, 100, 300, 100, 100);
        })
    }
  }
}

// 叠加绘制
@Component
struct MySample2 {

  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(new RenderingContextSettings(true))

  build() {
    Column({ space: 10 }) {

      /*
       * CanvasRenderingContext2D - 按照 W3C 标准封装了本地绘图接口
       *   globalCompositeOperation - 叠加绘制的方式(默认值为 source-over)
       *     source-over - 在现有内容的前面绘制新内容
       *     destination-over - 在现有内容的后面绘制新内容
       */
      Canvas(this.context).width('100%').height('100%').backgroundColor(Color.Yellow)
        .onReady(() => {

          this.context.fillStyle = Color.Red
          this.context.fillRect(20, 20, 100, 100)

          this.context.globalCompositeOperation = 'source-over'
          this.context.fillStyle = Color.Green
          this.context.fillRect(20, 20, 40, 40)

          this.context.globalCompositeOperation = 'destination-over'
          this.context.fillStyle = Color.Blue
          this.context.fillRect(50, 50, 100, 100)
        })
    }
  }
}

// 图层
@Component
struct MySample3 {

  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(new RenderingContextSettings(true))

  build() {
    Column({ space: 10 }) {

      /*
       * CanvasRenderingContext2D - 按照 W3C 标准封装了本地绘图接口
       *   saveLayer() - 新建图层
       *   restoreLayer() - 将当前图层的内容绘制到画布上
       */
      Canvas(this.context).width('100%').height('100%').backgroundColor(Color.Yellow)
        .onReady(() => {

          this.context.fillStyle = Color.Red
          this.context.fillRect(0, 0, 100, 400)

          this.context.globalCompositeOperation = 'source-over'
          this.context.saveLayer() // 在当前内容的上方新建一个图层

          this.context.fillStyle = Color.Green
          this.context.fillRect(0, 0, 200, 300)
          this.context.restoreLayer() // 绘制当前图层

          this.context.globalCompositeOperation = 'destination-over'
          this.context.saveLayer() // 在当前内容的下方新建一个图层

          this.context.globalCompositeOperation = 'source-over'
          this.context.fillStyle = Color.Blue
          this.context.fillRect(0, 0, 300, 200)
          this.context.fillStyle = Color.Orange
          this.context.fillRect(0, 0, 400, 100)
          this.context.restoreLayer() // 绘制当前图层
        })
    }
  }
}

// 清除指定的区域
@Component
struct MySample4 {

  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(new RenderingContextSettings(true))

  build() {
    Column({ space: 10 }) {

      Button("reset").onClick(() => {
        this.context.reset()
      })

      /*
       * CanvasRenderingContext2D - 按照 W3C 标准封装了本地绘图接口
       *   reset() - 清除全部内容
       *   clearRect() - 清除画布上指定的矩形区域中的内容
       *   clip() - 指定一个 Path2D 对象
       *     在 clip() 之后绘制内容时,只有在 clip() 区域内的会被显示,在 clip() 区域外的会被清除
       */
      Canvas(this.context).width('100%').height('100%').backgroundColor(Color.Yellow)
        .onReady(() => {

          this.context.strokeStyle = Color.Red
          this.context.lineWidth = 20

          this.context.strokeRect(20, 20, 200, 200)
          this.context.clearRect(0, 0, 300, 100)

          let path2D: Path2D = new Path2D()
          path2D.moveTo(0, 280)
          path2D.lineTo(300, 280)
          path2D.lineTo(300, 380)
          path2D.lineTo(0, 380)
          path2D.closePath()
          this.context.clip(path2D)
          this.context.strokeRect(20, 300, 200, 200)
        })
    }
  }
}

// 画布转图片
@Component
struct MySample5 {

  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(new RenderingContextSettings(true))
  @State imageBase64: string = ""

  build() {
    Column({ space: 10 }) {

      Image(this.imageBase64).width(200).height(200)

      /*
       * CanvasRenderingContext2D - 按照 W3C 标准封装了本地绘图接口
       *   toDataURL() - 将画布内容转为 base64 方式的图片
       *     type - 图片格式
       *       image/png, image/jpeg, image/webp
       *     quality - 图片质量
       *       0 - 1 之间,仅 image/jpeg, image/webp 时有效
       */
      Canvas(this.context).width('200').height('200').backgroundColor(Color.Yellow)
        .onReady(() => {

          this.context.fillStyle = Color.Red
          this.context.fillRect(50, 50, 100, 100)

          this.imageBase64 = this.context.toDataURL("image/jpeg", 0.92)
        })
    }
  }
}

// 上下文的保存和加载
@Component
struct MySample6 {

  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(new RenderingContextSettings(true))

  build() {
    Column({ space: 10 }) {

      /*
       * CanvasRenderingContext2D - 按照 W3C 标准封装了本地绘图接口
       *   save() - 保存当前的上下文
       *   restore() - 加载之前保存的上下文
       */
      Canvas(this.context).width('100%').height('100%').backgroundColor(Color.Yellow)
        .onReady(() => {

          this.context.fillStyle = Color.Red
          this.context.save() // 保存当前的上下文

          this.context.fillStyle = Color.Green
          this.context.fillRect(0, 0, 100, 100) // 绿色矩形

          this.context.restore() // 加载之前保存的上下文(即 fillStyle = Color.Red)
          this.context.fillRect(200, 200, 100, 100) // 红色矩形
        })
    }
  }
}

源码 https://github.com/webabcd/HarmonyDemo
作者 webabcd

posted @ 2025-03-21 16:26  webabcd  阅读(122)  评论(0)    收藏  举报