可可图片编辑 HarmonyOS(4)图片裁剪-canvas
前言
可可图片编辑 实现了图片的裁剪功能,效果如图所示。这里的核心技术是使用了canvas。

Canvas 入门
Canvas提供画布组件,用于自定义绘制图形,开发者使用CanvasRenderingContext2D对象和OffscreenCanvasRenderingContext2D对象在Canvas组件上进行绘制,绘制对象可以是基础形状、文本、图片等,canvas也可以实现对图片到裁剪,并且还可以把canvas上描绘的图形下载保存成图片。本章节主要讲解下canvas的基本使用。
基本使用
canvas 的基本使用分为 4 步:
- 设置是否抗锯齿抗锯齿(Anti - aliasing)是一种在数字图形处理中使用的技术,主要用于减少图像中因为像素有限而产生的锯齿状边缘的现象
- 创建画布上下文
- 渲染画布组件
- 在画布上描绘图案
@Entry
@Component
struct Index {
// 1 用来配置CanvasRenderingContext2D对象的参数,包括是否开启抗锯齿,true表明开启抗锯齿。
private settings: RenderingContextSettings = new RenderingContextSettings(true)
// 2 用来创建CanvasRenderingContext2D对象,通过在canvas中调用CanvasRenderingContext2D对象来绘制。
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
build() {
// 3 在canvas中调用CanvasRenderingContext2D对象。
Column(){
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#F5DC62')
.onReady(() => {
// 4 可以在这里绘制内容。
this.context.strokeRect(50, 50, 200, 150);
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
}
}
- 效果

canvas 常见用法
canvas 的核心思想是将想要的图形如,直线、圆圈、矩形等图形描绘到画布上。如果想要呈现出比较酷炫的效果,做法是:
- 描绘图形
- 擦除画布
- 计算数值-重新描绘图形
- 擦除画布
- 。。。
通过以上过程实现动画效果

canvas 的坐标系
在 canvas 中画图形都是基于坐标系来进行的。 左上角为起点。

描绘图形
canvas 中内置的常见的描绘图形的方法有以下:
- 直线
- 矩形
- 弧形
- 文本
- 图像
- ...
直线
描绘直线可以使用:
- 定起点
moveTo
- 定终点
lineTo
- 开始描绘
stroke
this.context.moveTo(10, 10);
this.context.lineTo(100, 100);
this.context.stroke();

矩形
可以使用直线lineTo
自己画成一个矩形。也可以直接使用 strokeRect
直接生成矩形
lineTo 画矩形
this.context.moveTo(10, 10);
this.context.lineTo(300, 10);
this.context.lineTo(300, 300);
this.context.lineTo(10, 300);
// 自动闭环
this.context.closePath();
// 开始描述 将路径的当前点移回到路径的起点,当前点到起点间画一条直线
this.context.stroke();

strokeRect 画矩形
// this.context.strokeRect(x, y, 宽度, 高度);
this.context.strokeRect(50, 50, 200, 150);

弧形
弧形可以使用 arc
和 arcTo
来描绘
arc
arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise?: boolean)
参数名 |
类型 |
必填 |
说明 |
x |
number |
是 |
弧线圆心的 x 坐标值。默认单位:vp。 |
y |
number |
是 |
弧线圆心的 y 坐标值。默认单位:vp。 |
radius |
number |
是 |
弧线的圆半径。默认单位:vp。 |
startAngle |
number |
是 |
弧线的起始弧度。单位:弧度 |
endAngle |
number |
是 |
弧线的终止弧度。单位:弧度 |
counterclockwise |
boolean |
否 |
是否逆时针绘制圆弧。true:逆时针方向绘制椭圆。false:顺时针方向绘制椭圆。默认值:false。 |
这里需要注意的是 arc 使用的单位是弧度不是角度
一圈 = 360角度 = 2 * Math.PI
半圈 = 180角度 = Math.PI ≈ 3.14
观察以下效果

100,75 是圆心坐标
50 是半径
0 是开始的弧度
6.28 ≈ 2 * Math.PI = 一圈
arc 是从正右方向开始旋转的。
this.context.beginPath();
this.context.arc(100, 75, 50, 0, 3.14 / 2);
this.context.stroke();

arcTo
arcTo(x1: number, y1: number, x2: number, y2: number, radius: number)
参数名 |
类型 |
必填 |
说明 |
x1 |
number |
是 |
第一个控制点的 x 坐标值。默认单位:vp。 |
y1 |
number |
是 |
第一个控制点的 y 坐标值。默认单位:vp。 |
x2 |
number |
是 |
第二个控制点的 x 坐标值。默认单位:vp。 |
y2 |
number |
是 |
第二个控制点的 y 坐标值。默认单位:vp。 |
radius |
number |
是 |
圆弧的圆半径值。默认单位:vp。 |

this.context.beginPath();
this.context.strokeStyle = "#000000";
this.context.lineWidth = 3;
this.context.moveTo(360, 20);
this.context.arcTo(360, 170, 110, 170, 150);
this.context.stroke();
辅助理解
想象一下,我们有一个起点(即当前路径的最后一个点),然后有三个更多的点:两个控制点 (x1, y1) 和 (x2, y2),以及由 radius
定义的一个圆心。arcTo
会创建一条从起点到第二个控制点 (x2, y2) 的圆弧,这条圆弧是位于以 radius
为半径的圆周上的一部
分。该圆弧会在起点和第一个控制点 (x1, y1) 之间形成一个切线,并且也会在第二个控制点 (x2, y2) 和圆弧的终点之间形成一个切线。

文本
-
strokeText表示描边的图形
-
fillText 表示填充的图形,还有其他fill,fillRect等也表示填充。
strokeText
this.context.font = '55px sans-serif'
this.context.strokeText("Hello World!", 20, 60)

fillText
this.context.font = '55px sans-serif'
this.context.fillText("Hello World!", 20, 60)

图像
drawImage可以把图像描绘到画布上,很多的在线图形合成效果都可以利用该功能实现
drawImage(image: ImageBitmap | PixelMap, dx: number, dy: number): void
drawImage(image: ImageBitmap | PixelMap, dx: number, dy: number, dw: number, dh: number): void
drawImage(image: ImageBitmap | PixelMap, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void
参数名 |
类型 |
必填 |
说明 |
image |
ImageBitmap或PixelMap
|
是 |
图片资源,请参考 ImageBitmap 或 PixelMap。 |
sx |
number |
是 |
裁切源图像时距离源图像左上角的 x 坐标值。image 类型为 ImageBitmap 时,默认单位:vp。image 类型为 PixelMap 时,单位:px。 |
sy |
number |
是 |
裁切源图像时距离源图像左上角的 y 坐标值。image 类型为 ImageBitmap 时,默认单位:vp。image 类型为 PixelMap 时,单位:px。 |
sw |
number |
是 |
裁切源图像时需要裁切的宽度。image 类型为 ImageBitmap 时,默认单位:vp。image 类型为 PixelMap 时,单位:px。 |
sh |
number |
是 |
裁切源图像时需要裁切的高度。image 类型为 ImageBitmap 时,默认单位:vp。image 类型为 PixelMap 时,单位:px。 |
dx |
number |
是 |
绘制区域左上角在 x 轴的位置。默认单位:vp。 |
dy |
number |
是 |
绘制区域左上角在 y 轴的位置。默认单位:vp。 |
dw |
number |
是 |
绘制区域的宽度。当绘制区域的宽度和裁剪图像的宽度不一致时,将图像宽度拉伸或压缩为绘制区域的宽度。默认单位:vp。 |
dh |
number |
是 |
绘制区域的高度。当绘制区域的高度和裁剪图像的高度不一致时,将图像高度拉伸或压缩为绘制区域的高度。默认单位:vp。 |
@Entry
@Component
struct Index {
private settings: RenderingContextSettings = new RenderingContextSettings(true)
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
private img: ImageBitmap = new ImageBitmap("/images/example.jpg")
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Canvas(this.context)
.width('100%')
.height('100%')
.backgroundColor('#ffff00')
.onReady(() => {
this.context.drawImage(this.img, 0, 0)
this.context.drawImage(this.img, 0, 150, 300, 100)
this.context.drawImage(this.img, 0, 0, 500, 500, 0, 300, 400, 200)
})
}
.width('100%')
.height('100%')
}
}

canvas 浅尝动态效果 1
const width = px2vp(display.getDefaultDisplaySync().availableWidth) * 0.9;
const height = width;
let x = 0;
let y = 0;
setInterval(() => {
this.context.strokeRect(x, y, 100, 100);
x++;
y++;
}, 20);

canvas 浅尝动态效果 2
const width = px2vp(display.getDefaultDisplaySync().availableWidth) * 0.9;
const height = width;
let x = 0;
let y = 0;
setInterval(() => {
// 清理画布
this.context.strokeRect(x, y, 100, 100);
x++;
y++;
}, 20);

canvas 属性 一览
名称 |
说明 |
fillStyle |
设置绘制的填充色,支持多种类型及对应创建方式,有默认值。 |
lineWidth |
设置绘制线条的宽度,有默认值及取值限制。 |
strokeStyle |
设置线条的颜色,支持多种类型及对应创建方式,有默认值。 |
lineCap |
指定线端点的样式,有可选值及默认值。 |
lineJoin |
指定线段间相交的交点样式,有可选值及默认值。 |
miterLimit |
设置斜接面限制值,有默认值及取值限制。 |
font |
设置文本绘制中的字体样式,包含多种可选参数及默认值。 |
textAlign |
设置文本绘制中的文本对齐方式,有可选值及默认值。 |
textBaseline |
设置文本绘制中的水平对齐方式,有可选值及默认值。 |
globalAlpha |
设置透明度,有默认值。 |
lineDashOffset |
设置画布的虚线偏移量,有默认值。 |
globalCompositeOperation |
设置合成操作的方式,有可选值及默认值。 |
shadowBlur |
设置绘制阴影时的模糊级别,有默认值及取值限制。 |
shadowColor |
设置绘制阴影时的阴影颜色,有默认值。 |
shadowOffsetX |
设置绘制阴影时和原有对象的水平偏移值,有默认值。 |
shadowOffsetY |
设置绘制阴影时和原有对象的垂直偏移值,有默认值。 |
imageSmoothingEnabled |
设置绘制图片时是否进行图像平滑度调整,有默认值。 |
height |
表示组件高度,有默认单位。 |
width |
表示组件宽度,有默认单位。 |
imageSmoothingQuality |
设置图像平滑度,有默认值。 |
direction |
设置绘制文字时使用的文字方向,有默认值。 |
filter |
设置图像的滤镜,支持多种滤镜效果,有默认值。 |
canvas |
获取和 CanvasRenderingContext2D 关联的 Canvas 组件的 FrameNode 实例, 可监听可见状态,默认值为 null。 |
canvas 方法 一览
名称 |
说明 |
fillRect |
推测用于进行图形填充相关操作(通常是填充矩形区域) |
strokeRect |
推测用于绘制矩形边框相关操作(通常是绘制矩形的轮廓) |
clearRect |
推测用于清除指定矩形区域的内容 |
fillText |
推测用于对文本进行填充操作(比如设置文本填充颜色等相关样式填充) |
strokeText |
推测用于绘制文本的轮廓相关操作 |
measureText |
推测用于测量文本相关的尺寸等属性 |
stroke |
一般用于绘制图形的轮廓、线条等(按常规语义理解) |
beginPath |
通常用于开始定义一个新的路径,后续可基于此路径进行图形绘制等操作 |
moveTo |
常用来将画笔移动到指定坐标位置,作为绘制路径的起始点等操作 |
lineTo |
一般用于从当前画笔位置绘制直线到指定坐标位置,构建路径内容 |
closePath |
通常用于闭合当前正在绘制的路径,使路径形成封闭图形 |
createPattern |
可能用于创建某种图案(比如重复平铺的图案等)用于绘制等 |
bezierCurveTo |
大概率用于绘制贝塞尔曲线,通过控制点来定义曲线形状 |
quadraticCurveTo |
推测用于绘制二次贝塞尔曲线,指定控制点来确定曲线走向 |
arc |
一般用于绘制圆弧,通过圆心、半径、起始角度、结束角度等参数来定义 |
arcTo |
常用来绘制与两条切线相切的圆弧,按给定条件确定圆弧形状 |
ellipse |
用于绘制椭圆图形,需指定相关参数如圆心坐标、长半轴、短半轴等 |
rect |
可用于绘制矩形,指定矩形的左上角坐标、宽度、高度等参数 |
fill |
用于对已绘制的图形或者指定区域进行填充操作 |
clip |
可能用于设置裁剪区域,后续绘制内容只在裁剪区域内显示 |
reset12+ |
从名称看可能是在特定版本(12+)中用于重置某些状态或设置的操作 |
saveLayer12+ |
在特定版本(12+)里可能用于保存图层相关状态等操作 |
restoreLayer12+ |
在特定版本(12+)里对应于之前保存图层状态进行恢复的操作 |
resetTransform |
推测用于重置图形变换相关的设置(比如旋转、缩放等变换) |
rotate |
用于将图形进行旋转操作,需指定旋转角度等参数 |
scale |
用于对图形进行缩放操作,指定横向和纵向的缩放比例 |
transform |
一般用于对图形进行多种变换(如平移、旋转、缩放等组合变换)的设置 |
setTransform |
可能用于设置图形的变换矩阵,来确定图形的变换情况 |
getTransform |
推测用于获取当前图形的变换相关信息(比如变换矩阵等) |
translate |
用于将图形进行平移操作,指定在横、纵坐标方向平移的距离 |
drawImage |
通常用于在画布上绘制图像,指定图像源及绘制位置等参数 |
createImageData |
可能用于创建图像数据对象(比如像素数据等相关内容) |
getPixelMap |
推测用于获取像素映射相关的数据(比如图像像素的分布等情况) |
setPixelMap |
大概是用于设置像素映射相关数据,改变图像像素表现等 |
getImageData |
一般用于获取图像的像素数据等具体信息内容 |
putImageData |
通常是将获取到的图像数据(如像素数据)重新应用到画布等位置 |
setLineDash |
可能用于设置线条的虚线样式,指定虚线的长度、间隔等参数 |
getLineDash |
推测用于获取当前线条所设置的虚线样式相关参数 |
transferFromImageBitmap |
从名称看可能是与从图像位图进行数据转移相关操作 |
toDataURL |
通常用于将画布等内容转换为可以表示图像数据的 URL 格式 |
restore |
一般用于恢复之前保存的某些状态(如画布状态等) |
save |
常用来保存当前画布等相关的状态,以便后续恢复使用 |
createLinearGradient |
用于创建线性渐变对象,可用于图形的渐变填充等操作 |
createRadialGradient |
用于创建径向渐变对象,定义从中心向外扩散的渐变效果 |
createConicGradient |
用于创建圆锥渐变对象,实现类似圆锥形状的渐变效果 |
以往文章