HarmonyOS鸿蒙Next中想要把图片画满Canvas,需要怎么设置drawImage的参数

HarmonyOS鸿蒙Next中想要把图片画满Canvas,需要怎么设置drawImage的参数

想要在canvas上绘制网络图片,但是绘制的图片没有撑满Canvas, api16, 请赐教

// TestPage.ets
import { util } from '@kit.ArkTS';
import { image } from '@kit.ImageKit';

async function loadImageToBitmap(url: string): Promise<ImageBitmap> {
  // 1. 发起网络请求获取图片数据
  const httpRequest = http.createHttp();
  const response = await httpRequest.request(url, {
    method: http.RequestMethod.GET,
    expectDataType: http.HttpDataType.ARRAY_BUFFER // 接收二进制数据
  });

  // 2. 获取二进制数据
  const arrayBuffer = response.result as ArrayBuffer;
  if (!arrayBuffer) {
    throw new Error('Failed to download image');
  }

  // 3. 创建 ImageSource 对象并解码为 PixelMap
  const imageSource = image.createImageSource(arrayBuffer);
  const pixelMap: PixelMap = await imageSource.createPixelMap();

  pixelMap.getImageInfo().then(res => {
    console.log("pixel imageInfo: ", JSON.stringify(res.size))
  })

  // 4. 将 PixelMap 转换为 ImageBitmap
  const imageBitmap: ImageBitmap = new ImageBitmap(pixelMap)
  return imageBitmap;
}

const imageUrl = 'https://img2.baidu.com/it/u=3826169544,1465685839&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=1309'

const COMPONENT_WIDTH = 600;
const COMPONENT_HEIGHT = 400;

@ObservedV2
class Pos {
  @Trace
  x: number = 0;
  @Trace
  y: number = 0;
  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }
}

@Entry
@ComponentV2
struct Sliver {
  @Local startPos: Pos = new Pos(10, 50); // 移动方块起始点
  @Local targetPos: Pos = new Pos(130, 50)
  @Local x: number = 0;
  @Local intervalId: number = -1;
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  @Local outSetValueOne: number = 0;
  @Local message: string = 'Base64ToPixelMap';
  @Local private pixelMap: PixelMap | null = null;

  private offCanvas: OffscreenCanvas = new OffscreenCanvas(600, 600)

  init = async () => {
    try {
      const res = await loadImageToBitmap(imageUrl)

      let offContext: OffscreenCanvasRenderingContext2D = this.offCanvas.getContext("2d", this.settings)

      offContext.save() // save the default state
      // 绘制底图
      offContext.drawImage(res,
        0, 0, COMPONENT_WIDTH, COMPONENT_HEIGHT /COMPONENT_WIDTH *(COMPONENT_WIDTH),
        0, 0, COMPONENT_WIDTH, COMPONENT_HEIGHT,
      )

      let image = this.offCanvas.transferToImageBitmap()
      this.context.transferFromImageBitmap(image)
      res.close()
    } catch (e) {
      console.log('draw sliver fail: ', e.message)
    }
  }

  aboutToAppear(): void {
    this.init()
  }

  build() {
    Row({space: 50}) {
      Image(imageUrl).width(300)
      Column() {
        RelativeContainer() {
          Canvas(this.context)
            .width(600)
            .height(400)
            .backgroundColor('#aaff00')
        }
        .width(COMPONENT_WIDTH).height(COMPONENT_HEIGHT)
        .backgroundColor(Color.Blue)
      }
      // .width(700)
      .alignItems(HorizontalAlign.Start)
    }.width('100%').justifyContent(FlexAlign.Center)
  }
}

更多关于HarmonyOS鸿蒙Next中想要把图片画满Canvas,需要怎么设置drawImage的参数的实战教程也可以访问 https://www.itying.com/category-93-b0.html

3 回复

设置图片宽高和画布宽高一致就可以将图片铺满画布:

// 设置图片宽为canvas_width,设置图片高为canvas_heith
this.contextFull.drawImage(pixelMap, 0, 0, canvas_width, canvas_heith * 2, 0, 0, canvas_width, canvas_heith)
Canvas(this.context)
  .backgroundColor('#F5DC62')
  .onReady(() => {
    this.drawImage()
  })
  .width(canvas_width) // 设置画布宽为canvas_width
  .height(canvas_heith) // 设置画布高为canvas_heith

完整demo如下:

import { resourceManager } from '@kit.LocalizationKit'
import { image } from '@kit.ImageKit'

const canvas_width = 400
const canvas_heith = canvas_width / 2
@Entry
@Component
export struct Index {
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  private contextFull: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)

  async drawImage() {
    // 获取资源管理器实例
    const resourceMgr: resourceManager.ResourceManager = getContext(this).resourceManager
    // 获取媒体内容(这里是启动图标)
    const fileData: Uint8Array = await resourceMgr.getMediaContent($r('app.media.startIcon'))
    // 将文件数据转换为缓冲区
    const buffer = fileData.buffer
    // 创建图像源对象
    const imageSource: image.ImageSource = image.createImageSource(buffer)
    // 设置解码选项
    let opts: image.DecodingOptions = {
      // 是否可编辑
      editable: true,
      // 目标大小
      desiredSize: {
        height: 400,
        width: 400
      }
    };
    // 创建像素映射对象
    const pixelMap: image.PixelMap = await imageSource.createPixelMap(opts)
    // 在画布上绘制图像
    this.context.drawImage(pixelMap, 100, 0)
    // 设置图片铺满画布
    this.contextFull.drawImage(pixelMap, 0, 0, canvas_width, canvas_heith * 2, 0, 0, canvas_width, canvas_heith)
  }

  build() {
    Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Start }) {
      Canvas(this.context)
        .backgroundColor('#F5DC62')
        .height('30%')
      Row().height('30%')
      Canvas(this.contextFull)
        .backgroundColor('#F5DC62')
        .onReady(() => {
          this.drawImage()
        })
        .width(canvas_width)
        .height(canvas_heith)
    }
  }
}

更多关于HarmonyOS鸿蒙Next中想要把图片画满Canvas,需要怎么设置drawImage的参数的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,要将图片画满Canvas,使用drawImage方法时需设置目标绘制区域参数。具体参数为:drawImage(image, 0, 0, canvas.width, canvas.height)。其中image为图片资源对象,后四个参数分别表示目标绘制的起始坐标(0,0)和结束坐标(canvas的宽高)。这样设置会拉伸图片至Canvas的完整尺寸。需确保图片已加载完成再调用绘制。

在HarmonyOS Next中,要让图片填满Canvas,需要正确设置drawImage方法的参数。根据你的代码,问题出在drawImage的源矩形参数计算上。

修改建议:

  1. 获取图片的实际宽高信息
  2. 使用正确的宽高比计算来填充Canvas

修正后的drawImage调用应该是:

// 先获取图片信息
const imageInfo = await res.getImageInfo();
const imgWidth = imageInfo.size.width;
const imgHeight = imageInfo.size.height;

// 计算适合Canvas的缩放比例
const scale = Math.max(COMPONENT_WIDTH/imgWidth, COMPONENT_HEIGHT/imgHeight);

// 绘制图片填满Canvas
offContext.drawImage(
  res,
  0, 0, imgWidth, imgHeight,  // 源图区域
  0, 0, COMPONENT_WIDTH, COMPONENT_HEIGHT  // 目标Canvas区域
);

关键点:

  1. 使用getImageInfo()获取图片原始尺寸
  2. drawImage后四个参数直接使用Canvas的宽高(COMPONENT_WIDTH/HEIGHT)
  3. 这样会自动进行缩放填充整个Canvas区域

注意:这种方式会保持图片原始比例,如果图片比例与Canvas不一致,会有部分内容被裁剪。如果需要完全填充不保持比例,可以分别设置宽高缩放。

回到顶部