HarmonyOS 鸿蒙Next canvas绘制图像时,缩放图像显示有问题

发布于 1周前 作者 h691938207 最后一次编辑是 5天前 来自 鸿蒙OS

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 ()=&gt;{
          <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)=&gt;{
            <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&lt;<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(()=&gt;{
                <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) } }) } }

5 回复

代码里看不出画布组件绘制图片的逻辑流程,以及画布尺寸变化与图片刷新的关联逻辑,只能给些概念性建议:

1、画布绘制操作需要单独创建一个方法来实现,然后初始画面绘制一般可在画布组件的onReady()中调用绘制方法;

2、如果是单一内容,如一张图片绘制在画布上,可直接使用CanvasRenderingContext2D对象的drawImage方法操作, 其中参数较多的重载方法可定义绘制区域大小实现缩放效果;

3、如果绘制多项内容,想实现统一缩放则建议先使用OffscreenCanvasRenderingContext2D对象进行正常绘制,然后用 offContext.transferToImageBitmap() 整体转换成图像位图数据,再用CanvasRenderingContext2D的translate(), scale()等方法对画面进行平移、缩放等操作后transferFromImageBitmap(imgageData)将上面从offContext导出的图像绘制到画面上进行显示;这样对于整体图像的变换操作更加方便,也节省了各个绘制内容单独进行变换操作的麻烦。

4、对于图像跟随画布变化进行动态刷新,则可以考虑画面组件的onAreaChange()事件,在其中更新和绘制关联的变量,然后调用前面所述画面绘制方法进行刷新。

感觉像是刷新没更上

不然if消失一下再出来试试?

但是我已经清空画布,重新绘制图像了

不然setTimeout(()=>{},0)试一下?

针对HarmonyOS 鸿蒙Next canvas绘制图像时缩放显示有问题的情况,以下是一些可能的解决方案:

  1. 检查缩放逻辑

    • 确保在缩放图像时,正确地更新了图像的显示尺寸和位置。
    • 检查缩放因子是否正确应用,避免出现比例失调。
  2. 优化Canvas性能

    • 在进行缩放操作时,避免频繁创建新的离屏画布(OffscreenCanvas),以减少内存占用和性能损耗。
    • 使用clearRect方法清空画布后,再对当前已有路径进行重绘,以确保缩放后的图像显示正确。
  3. 检查图像资源

    • 确保图像资源本身没有损坏,且分辨率适合缩放操作。
    • 如果图像是从外部加载的,确保加载过程中没有发生错误。
  4. 利用HarmonyOS特性

    • 利用HarmonyOS提供的手势识别功能(如PinchGesture),实现更平滑的缩放体验。
    • 确保在缩放过程中,图像的宽高比保持不变,以保持图像的完整性。

如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html

回到顶部