You can perform the following steps to draw a mosaic on an image.
import { DrawPathType, DrawViewModel } from '../viewmodel/DrawViewModel';
@Component
export struct DrawView {
@ObjectLink viewModel: DrawViewModel;
build() {
Column({ space: 8 }) {
Text('Please select the brush type')
.fontColor(Color.Red)
.textAlign(TextAlign.Center)
.fontSize(30)
.width('80%')
.margin('10%')
Canvas(this.viewModel.context)
.width('100%')
.height('75%')
.onAreaChange((oldValue: Area, newValue: Area) => {
this.viewModel.canvasAreaChange(newValue);
})
.gesture(
GestureGroup(GestureMode.Exclusive,
PanGesture()
.onActionStart((event: GestureEvent) => {
let finger: FingerInfo = event.fingerList[0];
if (finger == undefined) {
return;
}
let x = finger.localX;
let y = finger.localY;
this.viewModel.moveStart(x, y);
})
.onActionUpdate((event: GestureEvent) => {
let finger: FingerInfo = event.fingerList[0];
if (finger == undefined) {
return;
}
let x = finger.localX;
let y = finger.localY;
this.viewModel.moveUpdate(x, y);
})
.onActionEnd((event: GestureEvent) => {
let finger: FingerInfo = event.fingerList[0];
if (finger == undefined) {
return;
}
this.viewModel.moveEnd();
})
)
)
Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.SpaceAround }) {
Button('Ordinary paintbrush')
.onClick(() => {
this.viewModel.drawModel.pathType = DrawPathType.pen;
})
Button('Mosaic brush')
.onClick(() => {
this.viewModel.drawModel.pathType = DrawPathType.pattern;
})
Button('Clear the content')
.onClick(() => {
this.viewModel.clearPath();
})
}
}
}
} export class DrawPathPointModel {
x: number = 0;
y: number = 0;
}
export enum DrawPathType {
pen = 0, // Brush
pattern // Mosaic
}
// Configure the brush
export class DrawPathModel {
public pathType: DrawPathType = DrawPathType.pen;
public color: string = '#ED1B1B';
public lineWidth: number = 8;
public img: ImageBitmap = new ImageBitmap('Images/startIcon.png');
}
@Observed
export class DrawViewModel {
public settings: RenderingContextSettings = new RenderingContextSettings(true);
public context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
public drawModel: DrawPathModel = new DrawPathModel();
public canvasHeight: number = 0;
public canvasWidth: number = 0;
private pattern: CanvasPattern | null = null;
private points: DrawPathPointModel[] = [];
// Draw a path
private drawPath = new Path2D();
constructor() {
this.pattern = this.context.createPattern(this.drawModel.img, 'repeat');
}
moveStart(x: number, y: number) {
this.points.push({ x: x, y: y });
this.drawPath.moveTo(x, y);
this.drawCurrentPathModel();
}
moveUpdate(x: number, y: number) {
let lastPoint = this.points[this.points.length - 1];
this.points.push({ x: x, y: y });
this.drawPath.quadraticCurveTo((x + lastPoint.x) / 2, (y + lastPoint.y) / 2, x, y);
this.drawCurrentPathModel();
}
moveEnd() {
this.points = [];
this.drawPath = new Path2D();
}
clearPath() {
this.points = [];
this.drawPath = new Path2D();
this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
}
canvasAreaChange(area: Area) {
this.canvasHeight = area.height as number;
this.canvasWidth = area.width as number;
}
private drawCurrentPathModel() {
this.context.globalCompositeOperation = 'source-over';
this.context.lineWidth = this.drawModel.lineWidth;
if (this.drawModel.pathType == DrawPathType.pen) {
this.context.strokeStyle = this.drawModel.color;
} else {
if (this.pattern) {
this.context.strokeStyle = this.pattern;
}
}
this.context.lineJoin = 'round';
this.context.stroke(this.drawPath);
}
} import { DrawView } from './MosaicEffect';
import { DrawViewModel } from '../viewmodel/DrawViewModel';
@Entry
@Component
struct Index {
@State viewModel: DrawViewModel = new DrawViewModel();
build() {
Stack() {
Image($rawfile('test.jpg'))
.objectFit(ImageFit.Fill)
.width('100%')
.height('100%')
DrawView({ viewModel: this.viewModel })
.width('100%')
.height('100%')
}
}
}