HarmonyOS 鸿蒙Next图片合并问题咨询

HarmonyOS 鸿蒙Next图片合并问题咨询

请问一下如何合并两张图片,一张在上,一张在下,拼接成一张图片

2 回复
参考此demo:
//index

import { common } from ‘@kit.AbilityKit’;

import { BusinessError, request } from ‘@kit.BasicServicesKit’;

import fs from ‘@ohos.file.fs’;

import { fileUri } from ‘@kit.CoreFileKit’;

import { joinPicture } from ‘./JoinPicture’

import { photoAccessHelper } from ‘@kit.MediaLibraryKit’;

import { image } from ‘@kit.ImageKit’;

@Entry

@Component

struct Index {

  @State imageUri: string = ‘’;

  @State combineImageUri: string = ‘’;

  context = getContext(this) as common.UIAbilityContext;

  filePath = this.context.filesDir + ‘/test.jpg’;

  combinePath = this.context.filesDir + ‘/combine.jpg’;

  saveButtonOptions: SaveButtonOptions = {

    icon: SaveIconStyle.FULL_FILLED,

    text: SaveDescription.SAVE_IMAGE,

    buttonType: ButtonType.Capsule

  } // 设置安全控件按钮属性

  onPageShow(): void {

    this.checkImageExist()

  }

  checkImageExist(notExistCallback?: Function) {

    fs.access(this.filePath).then((res: boolean) => {

      if (res) {

        console.info(“PictureJoinTogether file exists”);

        this.imageUri = fileUri.getUriFromPath(this.filePath);

      } else {

        console.info(“PictureJoinTogether file not exists”);

        if (notExistCallback) {

          notExistCallback()

        }

      }

    }).catch((err: BusinessError) => {

      console.info("PictureJoinTogether access failed with error message: " + err.message + ", error code: " + err.code);

    });

  }

  // 只是为了分享图片,随便找个图片下载

  downloadFile(callback: Function) {

    this.checkImageExist(() => {

      request.downloadFile(this.context, {

        url: https://image.baidu.com/search/down?tn=download&word=download&ie=utf8&fr=detail&url=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F2019-11-22%2F5dd7afa7df0fc.jpg&thumburl=https%3A%2F%2Fimg1.baidu.com%2Fit%2Fu%3D2205810988%2C4283060315%26fm%3D253%26fmt%3Dauto%26app%3D138%26f%3DJPEG%3Fw%3D800%26h%3D500,

        filePath: this.filePath,

        background: true

      }).then((downloadTask: request.DownloadTask) => {

        downloadTask.on(‘progress’, (receivedSize: number, totalSize: number) => {

          console.info(“PictureJoinTogether download receivedSize:” + receivedSize + " totalSize:" + totalSize);

        });

        downloadTask.on(‘complete’, () => {

          console.info(‘PictureJoinTogether download complete’);

          callback()

        })

      }).catch((err: BusinessError) => {

        console.error(PictureJoinTogether Invoke downloadTask failed, code is ${err.code}, message is ${err.message});

      });

    })

  }

  build() {

    Column({space: 10}) {

      Button(‘下载图片’)

        .onClick(() => {

          if (this.imageUri !== ‘’) {

            return;

          }

          this.downloadFile(() => {

            this.imageUri = fileUri.getUriFromPath(this.filePath);

          })

        })

      Image(this.imageUri)

        .width(200)

        .height(200)

        .backgroundColor(Color.Gray)

      Button(‘合并图片并保存到应用内’)

        .onClick(() => {

          joinPicture.join([this.filePath, this.filePath], this.combinePath, () => {

            this.combineImageUri = fileUri.getUriFromPath(this.combinePath);

          })

        })

      Image(this.combineImageUri)

        .width(400)

        .height(200)

        .backgroundColor(Color.Gray)

      // 通过安全控件保存应用图片到图库

      SaveButton(this.saveButtonOptions)

        .onClick(async (event, result: SaveButtonOnClickResult) => {

          if (result === SaveButtonOnClickResult.SUCCESS) {

            try {

              const context = getContext();

              const phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);

              const uri = await phAccessHelper.createAsset(photoAccessHelper.PhotoType.IMAGE, ‘jpg’);

              console.info('createAsset successfully, uri: ’ + uri);

              const file = await fs.open(uri, fs.OpenMode.READ_WRITE);

              const imageSource = image.createImageSource(this.combinePath);

              const imageInfo = await imageSource.getImageInfo();

              const opts: image.DecodingOptions = {

                editable: true,

                // 注意和拼接图片时的格式统一

                desiredPixelFormat: image.PixelMapFormat.BGRA_8888,

                desiredSize: { width: imageInfo.size.width, height: imageInfo.size.height }

              };

              // 需要通过packing打包图片,直接获取buffer并写入会导致图库中图片无法显示

              const pixelMap = await imageSource.createPixelMap(opts);

              const imagePackerApi: image.ImagePacker = image.createImagePacker();

              let packOpts: image.PackingOption = { format: “image/jpeg”, quality: 100 };

              const packingArrayBuffer = await imagePackerApi.packing(pixelMap, packOpts);

              console.info(‘packing succeeded.’);

              fs.writeSync(file.fd, packingArrayBuffer, { offset: 0 })

              fs.closeSync(file.fd)

            } catch (err) {

              console.error('createAsset failed, message = ', err);

            }

          } else {

            console.error(‘SaveButtonOnClickResult createAsset failed’);

          }

        })

    }

    .width(‘100%’)

    .height(‘100%’)

    .justifyContent(FlexAlign.Center)

  }

}<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

//JoinPicture.ets

import { image } from ‘@kit.ImageKit’;

import fs from ‘@ohos.file.fs’;

class JoinPicture {

  /**

   * RGBA与BGRA编码互换,前后统一编码后,就不需要转换了

   * @param data

   * @returns

   */

  rgba2BGRA(data: ArrayBuffer): ArrayBuffer {

    let length: number = data.byteLength;

    let tempBuffer: ArrayBuffer = new ArrayBuffer(length);

    let rgbaData = new DataView(data);

    let bgraData = new DataView(tempBuffer);

    for (let i = 0; i < length; i += 4) {

      bgraData.setUint8(i, rgbaData.getUint8(i + 2));

      bgraData.setUint8(i + 1, rgbaData.getUint8(i + 1));

      bgraData.setUint8(i + 2, rgbaData.getUint8(i));

      bgraData.setUint8(i + 3, rgbaData.getUint8(i + 3));

    }

    return bgraData.buffer

  }

  // 这里只考虑横向排列拼接,且每张小图的高度一致

  async join(picturePaths: Array<string>, joinPath: string, callback: Function) {

    try {

      if (picturePaths.length < 2) {

        console.info(‘PictureJoinTogether 需要拼接的图片数量不足’)

        return;

      }

      const tempPath = picturePaths[0];

      const imageSource = image.createImageSource(tempPath);

      const imageInfo = await imageSource.getImageInfo();

      const singleWidth = imageInfo.size.width;

      const singleHeight = imageInfo.size.height;

      const combineOpts: image.InitializationOptions = {

        alphaType: 0,

        editable: true,

        // 注意上下格式统一

        pixelFormat: image.PixelMapFormat.BGRA_8888,

        size: { width: singleWidth * picturePaths.length, height: singleHeight }

      }

      const singleOpts: image.DecodingOptions = {

        editable: true,

        desiredPixelFormat: image.PixelMapFormat.BGRA_8888,

        desiredSize: { width: singleWidth, height: singleHeight }

      };

      const combineColor = new ArrayBuffer(combineOpts.size.width * combineOpts.size.height * 4);

      let singleColor = new ArrayBuffer(singleOpts.desiredSize!.width * singleOpts.desiredSize!.height * 4);

      const newPixelMap = await image.createPixelMap(combineColor, combineOpts);

      for (let x = 0; x < picturePaths.length; x++) {

        //读取小图

        //图片应用沙箱路径

        let singlePath = picturePaths[x];

        let imageSource = image.createImageSource(singlePath);

        const singlePixelMap = await imageSource.createPixelMap(singleOpts);

        await singlePixelMap.readPixelsToBuffer(singleColor);

        //写入大图

        let area: image.PositionArea = {

          pixels: singleColor,

          offset: 0,

          stride: singleWidth * 4,

          region: {

            size: { height: singleHeight, width: singleWidth },

            x: singleWidth * x,

            y: 0

          }

        }

        await newPixelMap.writePixels(area);

      }

      let combinePixelMap = newPixelMap;

      //保存大图

      const saveResult = await this.save(combinePixelMap, joinPath)

      saveResult && callback();

    } catch (err) {

      console.error('PictureJoinTogether join error: ’ + JSON.stringify(err))

    }

  }

  async save(pixelMap: image.PixelMap | undefined, path: string) {

    if (pixelMap === undefined) {

      return false;

    }

    const imagePackerApi: image.ImagePacker = image.createImagePacker();

    let packOpts: image.PackingOption = { format: “image/jpeg”, quality: 100 };

    const packingArrayBuffer = await imagePackerApi.packing(pixelMap, packOpts);

    console.info(‘packing succeeded.’);

    let file = fs.openSync(path, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);

    fs.writeSync(file.fd, packingArrayBuffer, { offset: 0 })

    fs.closeSync(file.fd)

    return true

  }

}

export const joinPicture = new JoinPicture()<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

let area: image.PositionArea = {

            pixels: singleColor,

            offset: 0,

            stride: singleWidth * 4,

            region: {

              size: { height: singleHeight, width: singleWidth },

              x: 0,

              y: singleHeight * x

            }

          }<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button>

看下area参数设置规则:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5/js-apis-image-V5#region8

更多关于HarmonyOS 鸿蒙Next图片合并问题咨询的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


针对HarmonyOS 鸿蒙Next图片合并问题,以下是直接的技术指导:

在HarmonyOS鸿蒙Next系统中,图片合并通常涉及图像处理库或系统API的调用。你可以使用系统提供的多媒体框架或第三方图像处理库来完成此任务。

  1. 使用系统API

    • 鸿蒙系统提供了丰富的多媒体处理能力,你可以查阅鸿蒙开发文档,了解如何使用相关API进行图片拼接。
    • 需要注意的是,API的使用可能会受到系统版本和设备兼容性的限制。
  2. 第三方库

    • 你可以引入第三方图像处理库,如OpenCV或Pillow(Python Imaging Library的分支),这些库提供了强大的图像处理功能,包括图片合并。
    • 在鸿蒙应用中使用第三方库时,需确保库与鸿蒙系统的兼容性,并遵循相应的集成步骤。
  3. 实现步骤

    • 加载图片资源。
    • 根据需要调整图片大小、位置等属性。
    • 使用合并函数或方法将图片合并成一张。
    • 保存或显示合并后的图片。

请注意,具体实现细节可能因鸿蒙系统版本和API更新而有所变化。如果问题依旧没法解决请联系官网客服,官网地址是:https://www.itying.com/category-93-b0.html。

回到顶部