Rendering Resource Images on Canvas in HarmonyOS NEXT
To render image resources stored in the application package using the Canvas component, the image data must first be converted into a PixelMap or ImageBitmap object. Once converted, the drawImage method of the rendering context can be utilized to display the visual content.
Direct Initialization of ImageBitmap
If image assets are placed directly within the project's ets/common directory structure, they can be instantiated directly as an ImageBitmap.
private bitmapAsset: ImageBitmap = new ImageBitmap('common/assets/logo.png');Converting Resource Manager Data to PixelMap
For resources managed by the system, a multi-step conversion process is required. The workflow involves retrieving the media content as a buffer via the ResourceManager, creating an ImageSource, and finally decoding it into a PixelMap.
@Entry
@Component
struct ResourceRenderer {
private renderConfig: RenderingContextSettings = new RenderingContextSettings(true);
private canvasCtx: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.renderConfig);
async loadAndRenderImage() {
const appContext = getContext(this);
const resMgr: resourceManager.ResourceManager = appContext.resourceManager;
// Retrieve the buffer for the specified resource ID
const rawData: Uint8Array = await resMgr.getMediaContent($r('app.media.sample_image'));
const sourceBuffer = rawData.buffer;
// Create ImageSource and decode to PixelMap
const imgSource: image.ImageSource = image.createImageSource(sourceBuffer);
const targetMap: image.PixelMap = await imgSource.createPixelMap();
// Draw the image onto the canvas context
this.canvasCtx.drawImage(targetMap, 0, 0);
}
build() {
Column({ space: 10 }) {
Canvas(this.canvasCtx)
.width(320)
.height(320)
.border({ width: 2, color: Color.Blue })
.onReady(() => {
this.loadAndRenderImage();
})
}
.width('100%')
.height('100%')
}
}Handling Touch Events on Canvas
The following example demonstrates how to interact with the rendered image by logging touch coordinates and event types. It extends the previous logic to include event handling.
import resourceManager from '@ohos.resourceManager';
import image from '@ohos.multimedia.image';
@Entry
@Component
struct CanvasInteractionDemo {
private renderConfig: RenderingContextSettings = new RenderingContextSettings(true);
private canvasCtx: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.renderConfig);
@State touchLog: string = '';
@State currentAction: string = '';
async renderScene() {
const appContext = getContext(this);
const resMgr: resourceManager.ResourceManager = appContext.resourceManager;
const rawData: Uint8Array = await resMgr.getMediaContent($r('app.media.sample_image'));
const imgSource: image.ImageSource = image.createImageSource(rawData.buffer);
const pixelMap: image.PixelMap = await imgSource.createPixelMap();
this.canvasCtx.drawImage(pixelMap, 0, 0);
}
build() {
Column({ space: 15 }) {
Canvas(this.canvasCtx)
.width(300)
.height(300)
.border({ width: 1, color: Color.Gray })
.onReady(() => {
this.renderScene();
})
.onTouch((event: TouchEvent) => {
console.info(`Canvas Touch Event: ${JSON.stringify(event)}`);
if (event) {
switch (event.type) {
case TouchType.Down:
this.currentAction = 'Down';
break;
case TouchType.Up:
this.currentAction = 'Up';
break;
case TouchType.Move:
this.currentAction = 'Move';
break;
}
const touchPoint = event.touches[0];
const componentArea = event.target.area;
this.touchLog = `Action: ${this.currentAction}\nPoint (x,y): ${touchPoint.x}, ${touchPoint.y}\n` +
`Global Pos: (${componentArea.globalPosition.x}, ${componentArea.globalPosition.y})\n` +
`Dimensions: ${componentArea.width} x ${componentArea.height}`;
}
})
Text(this.touchLog)
.fontSize(12)
.fontColor(Color.Black)
}
.width('100%')
.height('100%')
.padding(10)
}
}