How to resolve the issue of images not being displayed when setting drawImage under the Canvas component ?
Problem Description
There are three images named icon1, icon2, and icon3 respectively. A random number is generated, and the corresponding image is selected. However, the Canvas is unable to draw the image using drawImage. The running result is as follows:
The problem code is as follows:
private drawImage() {
// Generate 1-3 random numbers
let random: number = RandomUtil.randomNumber(1, 3);
this.bgViweName = `app.media.icon${random}`;
const context: Context = getContext(this);
const resourceManager: resourceManager.ResourceManager = context.resourceManager;
resourceManager.getMediaContent($r(this.bgViweName)).then((data: Uint8Array) => {
const buffer = data.buffer.slice(0);
const imageSource: image.ImageSource = image.createImageSource(buffer);
let decodingOptions: image.DecodingOptions = {
editable: true,
desiredPixelFormat: 3,
}
imageSource.createPixelMap(decodingOptions).then((pixelMap: image.PixelMap) => {
this.img = new ImageBitmap(pixelMap);
// Draw an image.
this.drawContext.drawImage(this.img, 0, 0, PuzzleSize, PuzzleSize + BezierOffset)
}).catch((err: BusinessError) => {
console.error("create PixelMap error: " + err.toString())
});
}).catch((err: BusinessError) => {
console.error("getMediaContent error: " + err.toString())
})
}
Background Knowledge
- The Canvas component can be used for custom drawing of graphics.
- The resource management module provides an interface for retrieving application resource information. The
[getMediaByName](https://developer.huawei.com/consumer/en/doc/harmonyos-references/js-apis-resource-manager#getmediabyname9-1)interface can obtain the media file content corresponding to a specified resource name, while the[getMediaContent](https://developer.huawei.com/consumer/en/doc/harmonyos-references/js-apis-resource-manager#getmediacontent9-1)interface can retrieve the media file content corresponding to a specified resource ID. - In engineering, application resources can be referenced in the form of "$r('app.type.name')". Here, "app" represents the resources defined in the resources directory within the application; "type" denotes the resource type (or the location where the resource is stored), which can be color, float, string, plural, or media; and "name" refers to the name of the resource.
Troubleshooting Process
- First, it was verified that the randomly generated image names were correct, and no exceptions were reported during the execution process.
- By commenting out other code and passing in images with fixed names, it was found that the images could be loaded normally.
resourceManager.getMediaContent($r('app.media.icon1')).then((data: Uint8Array) => {
const buffer = data.buffer.slice(0);
const imageSource: image.ImageSource = image.createImageSource(buffer);
let decodingOptions: image.DecodingOptions = {
editable: true,
desiredPixelFormat: 3,
}
imageSource.createPixelMap(decodingOptions).then((pixelMap: image.PixelMap) => {
this.img = new ImageBitmap(pixelMap);
//Draw an image.
this.drawContext.drawImage(this.img, 0, 0, PuzzleSize, PuzzleSize + BezierOffset)
}).catch((err: BusinessError) => {
console.error("create PixelMap error: " + err.toString())
});
}).catch((err: BusinessError) => {
console.error("getMediaContent error: " + err.toString())
})
Analysis Conclusion
Based on the issue identification, it was confirmed that the problem lies with the parameter passed as $r. If a string variable is passed, it cannot be loaded.
Solution
Option 1: Replace the original getMediaContent method with getMediaByName.
The parameter of getMediaByName is a string, so it can be used for getMediaContent. The code example is as follows:
private drawImage() {
// Generate 1-3 random numbers
let random: number = RandomUtil.randomNumber(1, 3);
// Passing the parameter by name is sufficient; there's no need to add app.media.
this.bgViweName = `icon${random}`
// ...
const context: Context = getContext(this);
const resourceManager: resourceManager.ResourceManager = context.resourceManager;
resourceManager.getMediaByName(this.bgViweName).then((data: Uint8Array) => {
// ...
}).catch((err: BusinessError) => {
console.error("create PixelMap error: " + err.toString())
});
}).catch((err: BusinessError) => {
console.error("getMediaContent error: " + err.toString())
})
Option 2: Use a map to associate image names with Resources.
Create a map that links names to Resources, retrieve the Resource corresponding to the name generated by a random number from the map, and pass it to the getMediaContent method. The code example is as follows:
// Convert the name into a resource
let viewResource = this.map.get(this.bgViweName);
resourceManager.getMediaContent(viewResource).then((data: Uint8Array) => {
// ...
}).catch((err: BusinessError) => {
console.error("getMediaContent error: " + err.toString())
})
Verification Result
Summary
Using $r to obtain a Resource can make the code more concise and convenient. However, it is important to note that although the parameter type passed to $r is string, since it is processed at compile time, it does not support dynamic changes during program execution. Therefore, variables cannot be passed. If you want to achieve the requirement of dynamic changes, you can try to find the corresponding method in the resourceManager to replace it.
Related Documents or Links
https://developer.huawei.com/consumer/en/doc/harmonyos-references/ts-components-canvas-canvas
https://developer.huawei.com/consumer/en/doc/harmonyos-references/js-apis-resource-manager


Top comments (0)