在HarmonyOS NEXT开发中图片怎么调用系统的裁剪功能?

在HarmonyOS NEXT开发中图片怎么调用系统的裁剪功能?

阅读 495
1 个回答

图片裁剪需要对PixelMap进行相关的操作。参考文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides...

Button('图像裁剪').fancy() 
  .onClick(() => { 
    let region: image.Region = { x: 300, y: 0, size: { height: 500, width: 700 } }; 
    if (this.imagePixelMap != undefined) { 
      this.imagePixelMap.crop(region).then(async () => { 
        if (this.imagePixelMap != undefined) { 
          let pixel = await copyPixelMap(this.imagePixelMap); 
          this.imagePixelMap.release(); 
          this.imagePixelMap = pixel; 
          console.info('Sucessed in setting crop.'); 
        } 
      }).catch((err: BusinessError) => { 
        console.error('Failed to crop pixelmap.'); 
      }) 
    } 
  }) 
 
async function copyPixelMap(imagePixel: PixelMap): Promise<image.PixelMap> { 
  let imageInfo: image.ImageInfo = await imagePixel.getImageInfo(); 
  console.info(`copyPixelMapSize: width:${imageInfo?.size.width} height:${imageInfo?.size.height}`); 
  let newRegion: image.Region = { 
    size: { height: imageInfo.size.height, width: imageInfo.size.width }, 
    x: 0, 
    y: 0 
  } 
  let newArea: image.PositionArea = { 
    pixels: new ArrayBuffer(imageInfo.size.height * imageInfo.size.width * 4), 
    offset: 0, 
    stride: imageInfo.stride, 
    region: newRegion 
  } 
  await imagePixel.readPixels(newArea); 
  let opts: image.InitializationOptions = { editable: true, pixelFormat: 4, size: imageInfo.size }; 
  let imagePixelCache = await image.createPixelMap(newArea.pixels, opts); 
  return imagePixelCache; 
}

简易示例参考如下。第三方库的图片裁剪可以参考ImageKnife,里面提供裁剪接口request.crop(),文档:https://gitee.com/openharmony-tpc/ImageKnife

import { photoAccessHelper } from '@kit.MediaLibraryKit'; 
import { fileIo, picker } from '@kit.CoreFileKit'; 
import { BusinessError } from '@kit.BasicServicesKit'; 
import { image } from '@kit.ImageKit'; 
 
@Entry 
@Component 
struct Index { 
  @State origin: PixelMap | undefined = undefined 
  @State origin2: PixelMap | undefined = undefined 
  private uri:string = '' 
 
  private async decodeImage(uri: string) { 
    try { 
      let file = fileIo.openSync(uri, fileIo.OpenMode.READ_ONLY) 
      const imageSourceApi = image.createImageSource(file.fd) 
      imageSourceApi.getImageInfo(0, (error: BusinessError, imageInfo) => { 
        if (imageInfo == undefined) { 
          // log.e(error) 
        } 
        console.log(`imageInfo:  ${JSON.stringify(imageInfo)}`) 
      }) 
      return await imageSourceApi.createPixelMap() 
    } catch (error) { 
      // log.e(error) 
      return undefined 
    } 
  } 
  build() { 
    Column() { 
      Button('添加照片') 
        .onClick(async () => { 
          let uris = await selectPhoto({ 
            MIMEType: picker.PhotoViewMIMETypes.IMAGE_TYPE, 
            maxSelectNumber: 1, 
            isPhotoTakingSupported: false, 
            recommendationOptions: { 
              recommendationType: photoAccessHelper.RecommendationType.PROFILE_PICTURE, 
            } 
          }) 
          if (uris.length == 0) { 
            return 
          } 
          this.uri = uris[0]; 
          this.origin = await this.decodeImage(uris[0]) 
 
        }) 
      Image(this.origin) 
        .width('100%') 
        .height('100%') 
        .layoutWeight(1) 
        .objectFit(ImageFit.Contain) 
 
 
      Button('裁剪照片') 
        .onClick(async () => { 
          this.origin2 = await this.decodeImage(this.uri) 
          if (this.origin2) { 
            let info = await this.origin2.getImageInfo() 
            this.origin2.crop({ 
              x: 0, y: 0, 
              size: { 
                width: info.size.width, 
                height: info.size.height / 2 
              } 
            }) 
            let pixel = await copyPixelMap(this.origin2); 
            this.origin2.release(); 
            this.origin2 = pixel; 
          } 
        }) 
 
      Image(this.origin2) 
        .width('100%') 
        .height('100%') 
        .layoutWeight(1) 
        .objectFit(ImageFit.Contain) 
    } 
    .width(`100%`) 
  } 
} 
 
 
const PHOTO_DEFAULT_SELECT_NUMBER: number = 9; //数量 
 
async function copyPixelMap(imagePixel: PixelMap): Promise<image.PixelMap> { 
  let imageInfo: image.ImageInfo = await imagePixel.getImageInfo(); 
  console.info(`copyPixelMapSize: width:${imageInfo?.size.width} height:${imageInfo?.size.height}`); 
  let newRegion: image.Region = { 
    size: { height: imageInfo.size.height, width: imageInfo.size.width }, 
    x: 0, 
    y: 0 
  } 
  let newArea: image.PositionArea = { 
    pixels: new ArrayBuffer(imageInfo.size.height * imageInfo.size.width * 4), 
    offset: 0, 
    stride: imageInfo.stride, 
    region: newRegion 
  } 
  await imagePixel.readPixels(newArea); 
  let opts: image.InitializationOptions = { editable: true, pixelFormat: 4, size: imageInfo.size }; 
  let imagePixelCache = await image.createPixelMap(newArea.pixels, opts); 
  return imagePixelCache; 
} 
 
/** 
 
 通过选择模式拉起photoPicker界面,用户可以选择一个或多个图片/视频。 
 @param options 
 @returns 
 
 */ 
async function selectPhoto(options?: PhotoSelectOptions): Promise<Array<string>> { 
  try { 
    if (!options) { 
      options = new PhotoSelectOptions(); 
    } 
    if (!options.MIMEType) { //可选择的媒体文件类型,若无此参数,则默认为图片和视频类型。 
      options.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE; 
    } 
    if (!options.maxSelectNumber) { //选择媒体文件数量的最大值,默认9 
      options.maxSelectNumber = PHOTO_DEFAULT_SELECT_NUMBER; 
    } 
    if (options.isPhotoTakingSupported == undefined) { 
      options.isPhotoTakingSupported = true; //支持拍照。 
    } 
    if (options.isEditSupported == undefined) { 
      options.isEditSupported = true; //支持编辑照片。 
    } 
    if (options.isSearchSupported == undefined) { 
      options.isSearchSupported = true; //支持编辑照片。 
    } 
    let photoSelectOptions: photoAccessHelper.PhotoSelectOptions = { 
      MIMEType: options.MIMEType, 
      maxSelectNumber: options.maxSelectNumber, 
      isPhotoTakingSupported: options.isPhotoTakingSupported, 
      isEditSupported: options.isEditSupported, 
      isSearchSupported: options.isSearchSupported, 
      recommendationOptions: options.recommendationOptions, 
      preselectedUris: options.preselectedUris 
    } 
    let photoPicker = new photoAccessHelper.PhotoViewPicker(); 
    let photoSelectResult: photoAccessHelper.PhotoSelectResult = await photoPicker.select(photoSelectOptions) 
    if (photoSelectResult && photoSelectResult.photoUris && photoSelectResult.photoUris.length > 0) { 
      return photoSelectResult.photoUris 
    } else { 
      return []; 
    } 
  } catch (err) { 
    console.error(err) 
    return []; 
  } 
} 
class PhotoSelectOptions { 
  MIMEType?: photoAccessHelper.PhotoViewMIMETypes = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE; //可选择的媒体文件类型,若无此参数,则默认为图片和视频类型。 
  maxSelectNumber?: number = PHOTO_DEFAULT_SELECT_NUMBER; //选择媒体文件数量的最大值(默认值为50,最大值为500)。 
  isPhotoTakingSupported?: boolean = true; //支持拍照。 
  isEditSupported?: boolean = true; //支持编辑照片。 
  isSearchSupported?: boolean = true; //支持搜索。 
  recommendationOptions?: photoAccessHelper.RecommendationOptions; //支持照片推荐。 
  preselectedUris?: Array<string>; //预选择图片的uri数据。 
}

可以使用gesture实现放大缩小图片,参考demo:https://developer.huawei.com/consumer/cn/codelabsPortal/cardd...
结合ImageKnife实现图片裁剪:https://gitee.com/openharmony-tpc/ImageKnife

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题