# CanvasRenderingContext2D是否可以绘制GIF动画

#### 问题现象

CanvasRenderingContext2D对象中的drawImage方法是否可以绘制GIF动画，如果可以，绘制的动画转成PixelMap是否依然有效？

#### 效果预览

#### 背景知识

*   CanvasRenderingContext2D可用于在Canvas画布组件上进行绘制，绘制对象可以是图形、文本、线段、图片等。
*   CanvasRenderingContext2D中drawImage方法用于在Canvas上绘制图片。它可以接受多种参数形式的图片资源，包括ImageBitmap、Image、PixelMap等。CanvasRenderingContext2D中getPixelMap方法可以以当前Canvas指定区域内的像素创建PixelMap对象。
*   packToFileFromPixelmapSequence可以将多个PixelMap编码成GIF文件。

#### 解决方案

drawImage方法本身可以用于绘制静态图片，而对于GIF动画文件，通常需要使用其他方法来实现动画效果。例如，可以通过定时器和定期刷新Canvas上的图像内容。或者使用专门的动画库来管理动画帧的绘制。

*   设置定时器：使用定时器（如setTimeout或setInterval）来定期更新画布的内容。
*   更新图像：在定时器的回调函数中，更改画布上的图像或图形元素的位置或其他属性，以反映动画的变化。
*   重新绘制：每次更新属性后，重新绘制整个场景或仅更新部分图像，显示新的状态。

以下示例通过渐变色定时刷新来实现绘制GIF动画效果：

```
@Entry
@Component
struct Picture {
  private settings: RenderingContextSettings = new RenderingContextSettings(true);
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
  private timerId: number | null = null;
  n: number = 0;

  draw() {
    this.context.clearRect(0, 0, 400, 400);
    this.context.beginPath();
    let grad = this.context.createConicGradient(Math.PI * this.n, 150, 150);
    grad.addColorStop(0.0, '#00ffffff');
    grad.addColorStop(0.95, '#254FF7');
    grad.addColorStop(0.95, '#00ffffff');
    grad.addColorStop(1, '#00ffffff');
    this.context.strokeStyle = grad;
    this.context.arc(150, 150, 75, Math.PI * this.n, Math.PI * (this.n + 1.8));
    this.context.stroke();
  }

  play() {
    this.timerId = setInterval(() => {
      if (this.n >= 6) {
        clearInterval(this.timerId);
        console.info('动画结束！');
        this.timerId = null;
        this.n = 0;
      }
      this.n += 0.04;
      this.draw();
    }, 50);
  }

  build() {
    Column({ space: 20 }) {
      Canvas(this.context)
        .onReady(() => {
          this.context.lineWidth = 30;
          this.context.lineCap = 'round';
          this.play();
        })
        .width(300)
        .height(300);
      Button('开始播放GIF')
        .onClick(() => {
          if (this.timerId === null) {
            this.play();
          } else {
            clearInterval(this.timerId);
            this.n = 0;
            this.play();
          }
        });
    }
    .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
    .backgroundColor('#f1f3f5')
    .padding(16)
    .height('100%')
    .width('100%');
  }
}
```

如果想将GIF动画保存至沙箱中，可以通过getPixelMap截取每一帧的像素，对像素进行转码png格式图片，获取图片的PixelMap，再通过packToFileFromPixelmapSequence将多个PixelMap编码成GIF文件。可参考多张图片合成GIF动图。