HarmonyOS 鸿蒙Next canvas绘制图像时,缩放图像显示有问题
HarmonyOS 鸿蒙Next canvas绘制图像时,缩放图像显示有问题
我自定义了一个组件,其中包含一个canvas,我想在canvas上绘制一张图像,当点击下方按钮的时候使画布可以自适应界面大小,同时缩放图像
但是我遇到一个问题,偶尔会出现画布大小变化了,但是图像并没有缩放,偶尔出现,非必现
代码如下:
import { image } from ‘@kit.ImageKit’;
import { HashMap } from ‘@kit.ArkTS’;
import { hilog } from ‘@kit.PerformanceAnalysisKit’;
import { resourceManager } from ‘@kit.LocalizationKit’;
import { BusinessError } from ‘@kit.BasicServicesKit’;
import { drawing } from ‘@kit.ArkGraphics2D’;
import { componentUtils, window } from ‘@kit.ArkUI’;
const entryContext: Context = getContext(this);
const resourceMgr : resourceManager.ResourceManager = entryContext.resourceManager;
@Preview
@Component
export struct RightCanvas{
private settings: RenderingContextSettings = new RenderingContextSettings(true);
private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
@State canvasWidth:number = 400
@State canvasHeight:number = 200
@State pixelMap: PixelMap | undefined = undefined;
canvasDraw: drawing.Canvas|undefined=undefined;
@State selectImage:string=’’
aboutToAppear(): void {
getContext(this).eventHub.on(“loadImage”,(imageName:string)=>{
this.loadImage(imageName)
})
}
aboutToDisappear(): void {
getContext(this).eventHub.off(“loadImage”)
}
private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)
// private staticCanvas:StaticCanvas = new StaticCanvas()
build() {
Column(){
Row(){
Scroll(){
Scroll() {
Canvas(this.context)
.width(this.canvasWidth)
.height(this.canvasHeight)
.border({
width:this.pixelMap!=undefined?1:0,
color:Color.Red
})
.onReady(()=>{
})
.onClick((event)=>{
console.log(`${event.x},${event.y}`)
})
}
.scrollable(ScrollDirection.Vertical)
.scrollBar(BarState.On)
}
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.On)
<span class="hljs-comment">// Text("预览")</span>
<span class="hljs-comment">// Image(this.pixelMap).width(200).height(200)</span>
}
.layoutWeight(<span class="hljs-number">1</span>)
.width(<span class="hljs-string">'100%'</span>)
.justifyContent(FlexAlign.Center)
.alignItems(VerticalAlign.Center)
.id(<span class="hljs-string">"canvasContainer"</span>)
Row({space: <span class="hljs-number">5</span>}){
Image($r(<span class="hljs-string">'app.media.auto'</span>))
.width(<span class="hljs-number">28</span>).height(<span class="hljs-number">28</span>)
.onClick(async ()=>{
<span class="hljs-keyword">let</span> textRange = componentUtils.getRectangleById(<span class="hljs-string">"canvasContainer"</span>)
<span class="hljs-keyword">let</span> width = textRange.size.width
<span class="hljs-keyword">let</span> height = textRange.size.height
console.log(`组件宽${width},组件高${height}`)
<span class="hljs-keyword">if</span>(<span class="hljs-keyword">this</span>.pixelMap==<span class="hljs-literal">undefined</span>){
<span class="hljs-keyword">return</span>
}
<span class="hljs-keyword">this</span>.pixelMap.getImageInfo().then((imageInfo)=>{
<span class="hljs-keyword">let</span> imageWidth = imageInfo.size.width
<span class="hljs-keyword">let</span> imageHeight = imageInfo.size.height
<span class="hljs-keyword">let</span> zoom = <span class="hljs-built_in">Math</span>.min(width/imageWidth, height/imageHeight)
<span class="hljs-keyword">if</span>(zoom<<span class="hljs-number">1</span>){
<span class="hljs-keyword">this</span>.context.reset()
<span class="hljs-keyword">this</span>.context.clearRect(<span class="hljs-number">0</span>,<span class="hljs-number">0</span>,<span class="hljs-keyword">this</span>.canvasWidth,<span class="hljs-keyword">this</span>.canvasHeight)
<span class="hljs-keyword">this</span>.pixelMap?.scale(zoom,zoom).then(()=>{
<span class="hljs-keyword">this</span>.flushPixelMap()
<span class="hljs-keyword">this</span>.canvasWidth=px2vp(imageWidth)*zoom
<span class="hljs-keyword">this</span>.canvasHeight=px2vp(imageHeight)*zoom
console.log(`缩放后的图像宽${<span class="hljs-keyword">this</span>.pixelMap?.getImageInfoSync().size.width},缩放比例${zoom}`)
<span class="hljs-keyword">this</span>.context.drawImage(<span class="hljs-keyword">this</span>.pixelMap,<span class="hljs-number">0</span>,<span class="hljs-number">0</span>)
console.log(<span class="hljs-string">"缩放完成"</span>)
})
}
})
})
}
.justifyContent(FlexAlign.Center)
.backgroundColor(<span class="hljs-string">'#eaeaea'</span>)
.height(<span class="hljs-number">45</span>)
.flexGrow(<span class="hljs-number">0</span>)
.width(<span class="hljs-string">'100%'</span>)
}
.justifyContent(FlexAlign.SpaceBetween)
.width(<span class="hljs-string">'100%'</span>)
.height(<span class="hljs-string">'100%'</span>)
}
flushPixelMap() {
let temp = this.pixelMap;
this.pixelMap = undefined;
this.pixelMap = temp;
}
loadImage(imageName:string){
// this.context.reset();
if(hilog.isLoggable(0x001,“canvas”,hilog.LogLevel.DEBUG)){
hilog.debug(0x0001,“canvas”,“画布尺寸为(宽:%{public}d,高:%{public}d)”,this.context.width,this.context.height)
}
if(hilog.isLoggable(0x001,“canvas”,hilog.LogLevel.INFO)){
hilog.info(0x0001,“canvas”,“加载图像,图像名称为[%{public}s]”,imageName)
}
let fd = resourceMgr.getRawFdSync(imageName)
let imageSource:image.ImageSource = image.createImageSource(fd);
imageSource.createPixelMap((err: BusinessError, pixelMap: image.PixelMap) => {
if (err) {
hilog.error(0x0001,“canvas”,“加载图像失败,错误码[%{public}d],错误信息[%{public}s]”,err.code,err.message);
} else {
this.context.reset()
this.context.clearRect(0,0,this.canvasWidth,this.canvasHeight)
this.pixelMap = pixelMap
this.canvasWidth = px2vp(this.pixelMap.getImageInfoSync().size.width)
this.canvasHeight = px2vp(this.pixelMap.getImageInfoSync().size.height)
this.context.drawImage(this.pixelMap,0,0)
}
})
}
}
代码里看不出画布组件绘制图片的逻辑流程,以及画布尺寸变化与图片刷新的关联逻辑,只能给些概念性建议:
1、画布绘制操作需要单独创建一个方法来实现,然后初始画面绘制一般可在画布组件的onReady()中调用绘制方法;
2、如果是单一内容,如一张图片绘制在画布上,可直接使用CanvasRenderingContext2D对象的drawImage方法操作, 其中参数较多的重载方法可定义绘制区域大小实现缩放效果;
3、如果绘制多项内容,想实现统一缩放则建议先使用OffscreenCanvasRenderingContext2D对象进行正常绘制,然后用 offContext.transferToImageBitmap() 整体转换成图像位图数据,再用CanvasRenderingContext2D的translate(), scale()等方法对画面进行平移、缩放等操作后transferFromImageBitmap(imgageData)将上面从offContext导出的图像绘制到画面上进行显示;这样对于整体图像的变换操作更加方便,也节省了各个绘制内容单独进行变换操作的麻烦。
4、对于图像跟随画布变化进行动态刷新,则可以考虑画面组件的onAreaChange()事件,在其中更新和绘制关联的变量,然后调用前面所述画面绘制方法进行刷新。
感觉像是刷新没更上
不然if消失一下再出来试试?
但是我已经清空画布,重新绘制图像了
不然setTimeout(()=>{},0)试一下?
针对HarmonyOS 鸿蒙Next canvas绘制图像时缩放显示有问题的情况,以下是一些可能的解决方案:
-
检查缩放逻辑:
- 确保在缩放图像时,正确地更新了图像的显示尺寸和位置。
- 检查缩放因子是否正确应用,避免出现比例失调。
-
优化Canvas性能:
- 在进行缩放操作时,避免频繁创建新的离屏画布(OffscreenCanvas),以减少内存占用和性能损耗。
- 使用
clearRect
方法清空画布后,再对当前已有路径进行重绘,以确保缩放后的图像显示正确。
-
检查图像资源:
- 确保图像资源本身没有损坏,且分辨率适合缩放操作。
- 如果图像是从外部加载的,确保加载过程中没有发生错误。
-
利用HarmonyOS特性:
- 利用HarmonyOS提供的手势识别功能(如PinchGesture),实现更平滑的缩放体验。
- 确保在缩放过程中,图像的宽高比保持不变,以保持图像的完整性。
如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html 。