图片尺寸约束
======

#### 问题现象

在使用Image组件时，如何实现以下场景：

1.  图片不进行任何缩放、裁剪或拉伸，直接按图源宽度和高度渲染。
2.  如何自定义图片的显示尺寸，使其按相应比例进行缩放。

#### 背景知识

*   [objectFit](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-image#objectfit)：设置图片的填充效果，使图片按照对应宽高比进行缩小或者放大。
*   [PixelMap](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-image-pixelmap)：图像像素类，用于读取或写入图像数据以及获取图像信息。
*   [fitOriginalSize](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-image#fitoriginalsize)：设置图片的显示尺寸是否跟随图源尺寸，当图片组件已设置width、height属性时，该属性不生效。

#### 解决方案

*   **场景一**：通过将Image的fitoriginalsize属性设为true，可以在Image组件未设置宽高的情况下适应图源尺寸。具体参考[Column宽高自适应背景图片大小](https://developer.huawei.com/consumer/cn/doc/harmonyos-faqs/faqs-arkui-1275)。
*   **场景二**：定义[DecodingOptions](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-image-i#decodingoptions7)，通过[ImageSource](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-image-imagesource)构建PixelMap对象，并基于目标尺寸计算缩放比例后调用scaleSync方法实现动态图片缩放。
    
    1.  获取原始尺寸，通过pixelMap.getImageInfo获取图片的原始宽度和高度。
    2.  计算缩放比例，分别计算宽度和高度需要缩放的比例。
    3.  调用scaleSync方法，按照计算出的比例进行缩放。缩放操作会直接修改PixelMap对象本身。
    
    具体代码如下：
    
    import image from '@ohos.multimedia.image';
    import fs from '@ohos.file.fs';
    
    @Entry
    @Component
    struct Index {
      @State pixelMap: PixelMap | undefined = undefined;
      context: Context = this.getUIContext().getHostContext() as Context;
      path: string = this.context.filesDir + '/hehe.jpg';
      decodingOptions: image.DecodingOptions = {
        editable: true,
        desiredPixelFormat: 3,
      };
    
      async aboutToAppear(): Promise<void> {
        let resourceManager = this.context.resourceManager;
        let imageArray =
          await resourceManager.getMediaContent($r('app.media.BigImage').id); _// 需开发者自行更换图片_
        let file = fs.openSync(this.path, fs.OpenMode.READ\_WRITE | fs.OpenMode.CREATE);
        try {
          fs.writeSync(file.fd, imageArray.buffer);
        } catch (err) {
        } finally {
          fs.closeSync(file);
        }
      }
    
      async packingDetail(targetWidth: number, targetHeight: number) {
        if (this.pixelMap) {
          let imageInfo = await this.pixelMap.getImageInfo();
          _// 计算压缩比_
          let scaleX: number = targetWidth / imageInfo.size.width;
          let scaleY: number = targetHeight / imageInfo.size.height;
          this.pixelMap.scaleSync(scaleX, scaleY);
        }
      }
    
      build() {
        Row() {
          Column() {
            Image(this.pixelMap)
              .width(200)
              .height(200)
              .backgroundColor(Color.Gray)
              .margin({ bottom: 40 })
              .objectFit(ImageFit.Contain)
    
            Button('1:3').onClick(async () => {
              const imageSource: image.ImageSource = image.createImageSource(this.path);
             _ // 创建pixelMap_
              this.pixelMap = await imageSource.createPixelMap(this.decodingOptions);
            _  // 指定压缩宽、高_
              this.packingDetail(100, 300);
            }).margin({ bottom: 20 })
    
            Button('1:2').onClick(async () => {
             _ // path为已获得的沙箱路径_
              const imageSource: image.ImageSource = image.createImageSource(this.path);
            _  // 创建pixelMap_
              this.pixelMap = await imageSource.createPixelMap(this.decodingOptions);
            _  // 指定压缩宽、高_
              this.packingDetail(100, 200);
            })
          }
          .width('100%')
        }
        .height('100%')
      }
    }
    

#### 常见FAQ

Q：[ImageAnimator](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-imageanimator)在设置了[fixedSize](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-imageanimator#fixedsize)之后，图片不会跟随组件宽高做拉伸。

A：设置fixedSize属性后，ImageAnimator将维持图片的原始宽高比。当图片原始尺寸与组件尺寸不一致时，图片会适配至ImageAnimator的宽高范围内显示，而不会被拉伸变形。