1e41f4b71Sopenharmony_ci# Starting an Image Editing Application 2e41f4b71Sopenharmony_ci## When to Use 3e41f4b71Sopenharmony_ciIf an application does not have the image editing capability but needs to edit an image, it can call **startAbilityByType** to start the vertical domain panel that displays available image editing applications, which can be used to edit the image. An image editing application can use the PhotoEditorExtensionAbility to implement an image editing page and register the page with the image editing panel. In this way, its image editing capability is opened to other applications. 4e41f4b71Sopenharmony_ci 5e41f4b71Sopenharmony_ciThe following figure shows the process. 6e41f4b71Sopenharmony_ci 7e41f4b71Sopenharmony_ci 8e41f4b71Sopenharmony_ci 9e41f4b71Sopenharmony_ciFor example, when a user chooses to edit an image in Gallery, the Gallery application can call **startAbilityByType** to start the image editing application panel. The user can choose an application that has implemented the PhotoEditorExtensionAbility to edit the image. 10e41f4b71Sopenharmony_ci 11e41f4b71Sopenharmony_ci## Available APIs 12e41f4b71Sopenharmony_ci 13e41f4b71Sopenharmony_ciFor details about the APIs, see [PhotoEditorExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-photoEditorExtensionAbility.md) and [PhotoEditorExtensionContext](../reference/apis-ability-kit/js-apis-app-ability-photoEditorExtensionContext.md). 14e41f4b71Sopenharmony_ci 15e41f4b71Sopenharmony_ci| **API** | **Description**| 16e41f4b71Sopenharmony_ci| -------- | -------- | 17e41f4b71Sopenharmony_ci| onStartContentEditing(uri: string, want:Want, session: UIExtensionContentSession):void | Called when content editing starts. Operations such as reading original images and loading pages can be performed in the callback.| 18e41f4b71Sopenharmony_ci| saveEditedContentWithImage(pixelMap: image.PixelMap, option: image.PackingOption): Promise\<AbilityResult\> | Saves the passed-in **PixelMap** object, which is an edited image. | 19e41f4b71Sopenharmony_ci 20e41f4b71Sopenharmony_ci## Target Application (Image Editing Application): Implementing an Image Editing Page 21e41f4b71Sopenharmony_ci 22e41f4b71Sopenharmony_ci1. Manually create a PhotoEditorExtensionAbility in the DevEco Studio project. 23e41f4b71Sopenharmony_ci 1. In the **ets** directory of the target module, right-click and choose **New > Directory** to create a directory named **PhotoEditorExtensionAbility**. 24e41f4b71Sopenharmony_ci 2. In the **PhotoEditorExtensionAbility** directory, right-click and choose **New > File** to create an .ets file, for example, **ExamplePhotoEditorAbility.ets**. 25e41f4b71Sopenharmony_ci2. Override the lifecycle callbacks of **onCreate**, **onForeground**, **onBackground**, **onDestroy**, and **onStartContentEditing** in the **ExamplePhotoEditorAbility.ets** file. 26e41f4b71Sopenharmony_ci 27e41f4b71Sopenharmony_ci Load the entry page file **pages/Index.ets** in **onStartContentEditing**, and save the session, URI, and instance objects in the LocalStorage, which passes them to the page. 28e41f4b71Sopenharmony_ci 29e41f4b71Sopenharmony_ci ```ts 30e41f4b71Sopenharmony_ci import { PhotoEditorExtensionAbility,UIExtensionContentSession,Want } from '@kit.AbilityKit'; 31e41f4b71Sopenharmony_ci import { hilog } from '@kit.PerformanceAnalysisKit'; 32e41f4b71Sopenharmony_ci 33e41f4b71Sopenharmony_ci const TAG = '[ExamplePhotoEditorAbility]'; 34e41f4b71Sopenharmony_ci export default class ExamplePhotoEditorAbility extends PhotoEditorExtensionAbility { 35e41f4b71Sopenharmony_ci onCreate() { 36e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, 'onCreate'); 37e41f4b71Sopenharmony_ci } 38e41f4b71Sopenharmony_ci 39e41f4b71Sopenharmony_ci // Obtain an image, load the page, and pass the required parameters to the page. 40e41f4b71Sopenharmony_ci onStartContentEditing(uri: string, want: Want, session: UIExtensionContentSession): void { 41e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, `onStartContentEditing want: ${JSON.stringify(want)}, uri: ${uri}`); 42e41f4b71Sopenharmony_ci 43e41f4b71Sopenharmony_ci const storage: LocalStorage = new LocalStorage({ 44e41f4b71Sopenharmony_ci "session": session, 45e41f4b71Sopenharmony_ci "uri": uri 46e41f4b71Sopenharmony_ci } as Record<string, Object>); 47e41f4b71Sopenharmony_ci 48e41f4b71Sopenharmony_ci session.loadContent('pages/Index', storage); 49e41f4b71Sopenharmony_ci } 50e41f4b71Sopenharmony_ci 51e41f4b71Sopenharmony_ci onForeground() { 52e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, 'onForeground'); 53e41f4b71Sopenharmony_ci } 54e41f4b71Sopenharmony_ci 55e41f4b71Sopenharmony_ci onBackground() { 56e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, 'onBackground'); 57e41f4b71Sopenharmony_ci } 58e41f4b71Sopenharmony_ci 59e41f4b71Sopenharmony_ci onDestroy() { 60e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, 'onDestroy'); 61e41f4b71Sopenharmony_ci } 62e41f4b71Sopenharmony_ci } 63e41f4b71Sopenharmony_ci 64e41f4b71Sopenharmony_ci ``` 65e41f4b71Sopenharmony_ci3. Implement image editing in the page. 66e41f4b71Sopenharmony_ci 67e41f4b71Sopenharmony_ci After image editing is complete, call **saveEditedContentWithImage** to save the image and return the callback result to the caller through **terminateSelfWithResult**. 68e41f4b71Sopenharmony_ci 69e41f4b71Sopenharmony_ci ```ts 70e41f4b71Sopenharmony_ci import { common } from '@kit.AbilityKit'; 71e41f4b71Sopenharmony_ci import { UIExtensionContentSession, Want } from '@kit.AbilityKit'; 72e41f4b71Sopenharmony_ci import { hilog } from '@kit.PerformanceAnalysisKit'; 73e41f4b71Sopenharmony_ci import { fileIo } from '@kit.CoreFileKit'; 74e41f4b71Sopenharmony_ci import { image } from '@kit.ImageKit'; 75e41f4b71Sopenharmony_ci 76e41f4b71Sopenharmony_ci const storage = LocalStorage.getShared() 77e41f4b71Sopenharmony_ci const TAG = '[ExamplePhotoEditorAbility]'; 78e41f4b71Sopenharmony_ci 79e41f4b71Sopenharmony_ci @Entry 80e41f4b71Sopenharmony_ci @Component 81e41f4b71Sopenharmony_ci struct Index { 82e41f4b71Sopenharmony_ci @State message: string = 'editImg'; 83e41f4b71Sopenharmony_ci @State originalImage: PixelMap | null = null; 84e41f4b71Sopenharmony_ci @State editedImage: PixelMap | null = null; 85e41f4b71Sopenharmony_ci private newWant ?: Want; 86e41f4b71Sopenharmony_ci 87e41f4b71Sopenharmony_ci aboutToAppear(): void { 88e41f4b71Sopenharmony_ci let originalImageUri = storage?.get<string>("uri") ?? ""; 89e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, `OriginalImageUri: ${originalImageUri}.`); 90e41f4b71Sopenharmony_ci 91e41f4b71Sopenharmony_ci this.readImageByUri(originalImageUri).then(imagePixMap => { 92e41f4b71Sopenharmony_ci this.originalImage = imagePixMap; 93e41f4b71Sopenharmony_ci }) 94e41f4b71Sopenharmony_ci } 95e41f4b71Sopenharmony_ci 96e41f4b71Sopenharmony_ci // Read the image based on the URI. 97e41f4b71Sopenharmony_ci async readImageByUri(uri: string): Promise < PixelMap | null > { 98e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, "uri: " + uri); 99e41f4b71Sopenharmony_ci let file: fileIo.File | undefined; 100e41f4b71Sopenharmony_ci try { 101e41f4b71Sopenharmony_ci file = await fileIo.open(uri, fileIo.OpenMode.READ_ONLY); 102e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, "Original image file id: " + file.fd); 103e41f4b71Sopenharmony_ci 104e41f4b71Sopenharmony_ci let imageSourceApi: image.ImageSource = image.createImageSource(file.fd); 105e41f4b71Sopenharmony_ci if(!imageSourceApi) { 106e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, "ImageSourceApi failed"); 107e41f4b71Sopenharmony_ci return null; 108e41f4b71Sopenharmony_ci } 109e41f4b71Sopenharmony_ci let pixmap: image.PixelMap = await imageSourceApi.createPixelMap(); 110e41f4b71Sopenharmony_ci if(!pixmap) { 111e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, "createPixelMap failed"); 112e41f4b71Sopenharmony_ci return null; 113e41f4b71Sopenharmony_ci } 114e41f4b71Sopenharmony_ci this.originalImage = pixmap; 115e41f4b71Sopenharmony_ci fileIo.closeSync(file); 116e41f4b71Sopenharmony_ci return pixmap; 117e41f4b71Sopenharmony_ci } catch(e) { 118e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, `ReadImage failed:${e}`); 119e41f4b71Sopenharmony_ci } finally { 120e41f4b71Sopenharmony_ci fileIo.close(file); 121e41f4b71Sopenharmony_ci } 122e41f4b71Sopenharmony_ci return null; 123e41f4b71Sopenharmony_ci } 124e41f4b71Sopenharmony_ci 125e41f4b71Sopenharmony_ci build() { 126e41f4b71Sopenharmony_ci Row() { 127e41f4b71Sopenharmony_ci Column() { 128e41f4b71Sopenharmony_ci Text(this.message) 129e41f4b71Sopenharmony_ci .fontSize(50) 130e41f4b71Sopenharmony_ci .fontWeight(FontWeight.Bold) 131e41f4b71Sopenharmony_ci 132e41f4b71Sopenharmony_ci Button("RotateAndSaveImg").onClick(event => { 133e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, `Start to edit image and save.`); 134e41f4b71Sopenharmony_ci // Implement image editing. 135e41f4b71Sopenharmony_ci this.originalImage?.rotate(90).then(() => { 136e41f4b71Sopenharmony_ci let packOpts: image.PackingOption = { format: "image/jpeg", quality: 98 }; 137e41f4b71Sopenharmony_ci try { 138e41f4b71Sopenharmony_ci // Call saveEditedContentWithImage to save the image. 139e41f4b71Sopenharmony_ci (getContext(this) as common.PhotoEditorExtensionContext).saveEditedContentWithImage(this.originalImage as image.PixelMap, 140e41f4b71Sopenharmony_ci packOpts).then(data => { 141e41f4b71Sopenharmony_ci if (data.resultCode == 0) { 142e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, `Save succeed.`); 143e41f4b71Sopenharmony_ci } 144e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, 145e41f4b71Sopenharmony_ci `saveContentEditingWithImage result: ${JSON.stringify(data)}`); 146e41f4b71Sopenharmony_ci this.newWant = data.want; 147e41f4b71Sopenharmony_ci // data.want.uri: URI of the edited image 148e41f4b71Sopenharmony_ci this.readImageByUri(this.newWant?.uri ?? "").then(imagePixMap => { 149e41f4b71Sopenharmony_ci this.editedImage = imagePixMap; 150e41f4b71Sopenharmony_ci }) 151e41f4b71Sopenharmony_ci }) 152e41f4b71Sopenharmony_ci } catch (e) { 153e41f4b71Sopenharmony_ci hilog.error(0x0000, TAG, `saveContentEditingWithImage failed:${e}`); 154e41f4b71Sopenharmony_ci return; 155e41f4b71Sopenharmony_ci } 156e41f4b71Sopenharmony_ci }) 157e41f4b71Sopenharmony_ci }).margin({ top: 10 }) 158e41f4b71Sopenharmony_ci 159e41f4b71Sopenharmony_ci Button("terminateSelfWithResult").onClick((event => { 160e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, `Finish the current editing.`); 161e41f4b71Sopenharmony_ci 162e41f4b71Sopenharmony_ci let session = storage.get('session') as UIExtensionContentSession; 163e41f4b71Sopenharmony_ci // Terminate the ability and return the modification result to the caller. 164e41f4b71Sopenharmony_ci session.terminateSelfWithResult({ resultCode: 0, want: this.newWant }); 165e41f4b71Sopenharmony_ci 166e41f4b71Sopenharmony_ci })).margin({ top: 10 }) 167e41f4b71Sopenharmony_ci 168e41f4b71Sopenharmony_ci Image(this.originalImage).width("100%").height(200).margin({ top: 10 }).objectFit(ImageFit.Contain) 169e41f4b71Sopenharmony_ci 170e41f4b71Sopenharmony_ci Image(this.editedImage).width("100%").height(200).margin({ top: 10 }).objectFit(ImageFit.Contain) 171e41f4b71Sopenharmony_ci } 172e41f4b71Sopenharmony_ci .width('100%') 173e41f4b71Sopenharmony_ci } 174e41f4b71Sopenharmony_ci .height('100%') 175e41f4b71Sopenharmony_ci .backgroundColor(Color.Pink) 176e41f4b71Sopenharmony_ci .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM]) 177e41f4b71Sopenharmony_ci } 178e41f4b71Sopenharmony_ci } 179e41f4b71Sopenharmony_ci 180e41f4b71Sopenharmony_ci ``` 181e41f4b71Sopenharmony_ci4. Register the PhotoEditorExtensionAbility in the **module.json5** file corresponding to the module. 182e41f4b71Sopenharmony_ci 183e41f4b71Sopenharmony_ci Set **type** to **photoEditor** and **srcEntry** to the code path of the PhotoEditorExtensionAbility. 184e41f4b71Sopenharmony_ci 185e41f4b71Sopenharmony_ci ```json 186e41f4b71Sopenharmony_ci { 187e41f4b71Sopenharmony_ci "module": { 188e41f4b71Sopenharmony_ci "extensionAbilities": [ 189e41f4b71Sopenharmony_ci { 190e41f4b71Sopenharmony_ci "name": "ExamplePhotoEditorAbility", 191e41f4b71Sopenharmony_ci "icon": "$media:icon", 192e41f4b71Sopenharmony_ci "description": "ExamplePhotoEditorAbility", 193e41f4b71Sopenharmony_ci "type": "photoEditor", 194e41f4b71Sopenharmony_ci "exported": true, 195e41f4b71Sopenharmony_ci "srcEntry": "./ets/PhotoEditorExtensionAbility/ExamplePhotoEditorAbility.ets", 196e41f4b71Sopenharmony_ci "label": "$string:EntryAbility_label", 197e41f4b71Sopenharmony_ci "extensionProcessMode": "bundle" 198e41f4b71Sopenharmony_ci }, 199e41f4b71Sopenharmony_ci ] 200e41f4b71Sopenharmony_ci } 201e41f4b71Sopenharmony_ci } 202e41f4b71Sopenharmony_ci ``` 203e41f4b71Sopenharmony_ci## Caller Application: Starting an Image Editing Application to Edit an Image 204e41f4b71Sopenharmony_ciOn the UIAbility or UIExtensionAbility page, you can use **startAbilityByType** to start the vertical domain panel of image editing applications. The system automatically searches for and displays the image editing applications that have implemented the [PhotoEditorExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-photoEditorExtensionAbility.md) on the panel. Then the user can choose an application to edit the image, and the editing result is returned to the caller. The procedure is as follows: 205e41f4b71Sopenharmony_ci1. Import the modules. 206e41f4b71Sopenharmony_ci ```ts 207e41f4b71Sopenharmony_ci import { common, wantConstant } from '@kit.AbilityKit'; 208e41f4b71Sopenharmony_ci import { fileUri, picker } from '@kit.CoreFileKit'; 209e41f4b71Sopenharmony_ci ``` 210e41f4b71Sopenharmony_ci2. (Optional) Select an image from Gallery. 211e41f4b71Sopenharmony_ci ```ts 212e41f4b71Sopenharmony_ci async photoPickerGetUri(): Promise < string > { 213e41f4b71Sopenharmony_ci try { 214e41f4b71Sopenharmony_ci let PhotoSelectOptions = new picker.PhotoSelectOptions(); 215e41f4b71Sopenharmony_ci PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE; 216e41f4b71Sopenharmony_ci PhotoSelectOptions.maxSelectNumber = 1; 217e41f4b71Sopenharmony_ci let photoPicker = new picker.PhotoViewPicker(); 218e41f4b71Sopenharmony_ci let photoSelectResult: picker.PhotoSelectResult = await photoPicker.select(PhotoSelectOptions); 219e41f4b71Sopenharmony_ci return photoSelectResult.photoUris[0]; 220e41f4b71Sopenharmony_ci } catch(error) { 221e41f4b71Sopenharmony_ci let err: BusinessError = error as BusinessError; 222e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, 'PhotoViewPicker failed with err: ' + JSON.stringify(err)); 223e41f4b71Sopenharmony_ci } 224e41f4b71Sopenharmony_ci return ""; 225e41f4b71Sopenharmony_ci } 226e41f4b71Sopenharmony_ci ``` 227e41f4b71Sopenharmony_ci3. Copy the image to the local sandbox path. 228e41f4b71Sopenharmony_ci ```ts 229e41f4b71Sopenharmony_ci let context = getContext(this) as common.UIAbilityContext; 230e41f4b71Sopenharmony_ci let file: fileIo.File | undefined; 231e41f4b71Sopenharmony_ci try { 232e41f4b71Sopenharmony_ci file = fileIo.openSync(uri, fileIo.OpenMode.READ_ONLY); 233e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, "file: " + file.fd); 234e41f4b71Sopenharmony_ci 235e41f4b71Sopenharmony_ci let timeStamp = Date.now(); 236e41f4b71Sopenharmony_ci // Copy the image to the application sandbox path. 237e41f4b71Sopenharmony_ci fileIo.copyFileSync(file.fd, context.filesDir + `/original-${timeStamp}.jpg`); 238e41f4b71Sopenharmony_ci fileIo.closeSync(file); 239e41f4b71Sopenharmony_ci 240e41f4b71Sopenharmony_ci this.filePath = context.filesDir + `/original-${timeStamp}.jpg`; 241e41f4b71Sopenharmony_ci this.originalImage = fileUri.getUriFromPath(this.filePath); 242e41f4b71Sopenharmony_ci } catch (e) { 243e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, `readImage failed:${e}`); 244e41f4b71Sopenharmony_ci } finally { 245e41f4b71Sopenharmony_ci fileIo.close(file); 246e41f4b71Sopenharmony_ci } 247e41f4b71Sopenharmony_ci ``` 248e41f4b71Sopenharmony_ci4. In the callback function of **startAbilityByType**, use **want.uri** to obtain the URI of the edited image and perform corresponding processing. 249e41f4b71Sopenharmony_ci ```ts 250e41f4b71Sopenharmony_ci let context = getContext(this) as common.UIAbilityContext; 251e41f4b71Sopenharmony_ci let abilityStartCallback: common.AbilityStartCallback = { 252e41f4b71Sopenharmony_ci onError: (code, name, message) => { 253e41f4b71Sopenharmony_ci const tip: string = `code:` + code + ` name:` + name + ` message:` + message; 254e41f4b71Sopenharmony_ci hilog.error(0x0000, TAG, "startAbilityByType:", tip); 255e41f4b71Sopenharmony_ci }, 256e41f4b71Sopenharmony_ci onResult: (result) => { 257e41f4b71Sopenharmony_ci // Obtain the URI of the edited image in the callback result and perform corresponding processing. 258e41f4b71Sopenharmony_ci let uri = result.want?.uri ?? ""; 259e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, "PhotoEditorCaller result: " + JSON.stringify(result)); 260e41f4b71Sopenharmony_ci this.readImage(uri).then(imagePixMap => { 261e41f4b71Sopenharmony_ci this.editedImage = imagePixMap; 262e41f4b71Sopenharmony_ci }); 263e41f4b71Sopenharmony_ci } 264e41f4b71Sopenharmony_ci } 265e41f4b71Sopenharmony_ci ``` 266e41f4b71Sopenharmony_ci5. Convert the image to an image URI and call **startAbilityByType** to start the image editing application panel. 267e41f4b71Sopenharmony_ci ```ts 268e41f4b71Sopenharmony_ci let uri = fileUri.getUriFromPath(this.filePath); 269e41f4b71Sopenharmony_ci context.startAbilityByType("photoEditor", { 270e41f4b71Sopenharmony_ci "ability.params.stream": [uri], // URI of the original image. Only one URI can be passed in. 271e41f4b71Sopenharmony_ci "ability.want.params.uriPermissionFlag": wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION // At least the read permission should be shared to the image editing application panel. 272e41f4b71Sopenharmony_ci } as Record<string, Object>, abilityStartCallback, (err) => { 273e41f4b71Sopenharmony_ci let tip: string; 274e41f4b71Sopenharmony_ci if (err) { 275e41f4b71Sopenharmony_ci tip = `Start error: ${JSON.stringify(err)}`; 276e41f4b71Sopenharmony_ci hilog.error(0x0000, TAG, `startAbilityByType: fail, err: ${JSON.stringify(err)}`); 277e41f4b71Sopenharmony_ci } else { 278e41f4b71Sopenharmony_ci tip = `Start success`; 279e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, "startAbilityByType: ", `success`); 280e41f4b71Sopenharmony_ci } 281e41f4b71Sopenharmony_ci }); 282e41f4b71Sopenharmony_ci ``` 283e41f4b71Sopenharmony_ci 284e41f4b71Sopenharmony_ciExample 285e41f4b71Sopenharmony_ci```ts 286e41f4b71Sopenharmony_ciimport { common, wantConstant } from '@kit.AbilityKit'; 287e41f4b71Sopenharmony_ciimport { fileUri, picker } from '@kit.CoreFileKit'; 288e41f4b71Sopenharmony_ciimport { hilog } from '@kit.PerformanceAnalysisKit'; 289e41f4b71Sopenharmony_ciimport { fileIo } from '@kit.CoreFileKit'; 290e41f4b71Sopenharmony_ciimport { image } from '@kit.ImageKit'; 291e41f4b71Sopenharmony_ciimport { BusinessError } from '@kit.BasicServicesKit'; 292e41f4b71Sopenharmony_ciimport { JSON } from '@kit.ArkTS'; 293e41f4b71Sopenharmony_ci 294e41f4b71Sopenharmony_ciconst TAG = 'PhotoEditorCaller'; 295e41f4b71Sopenharmony_ci 296e41f4b71Sopenharmony_ci@Entry 297e41f4b71Sopenharmony_ci@Component 298e41f4b71Sopenharmony_cistruct Index { 299e41f4b71Sopenharmony_ci @State message: string = 'selectImg'; 300e41f4b71Sopenharmony_ci @State originalImage: ResourceStr = ""; 301e41f4b71Sopenharmony_ci @State editedImage: PixelMap | null = null; 302e41f4b71Sopenharmony_ci private filePath: string = ""; 303e41f4b71Sopenharmony_ci 304e41f4b71Sopenharmony_ci // Read the image based on the URI. 305e41f4b71Sopenharmony_ci async readImage(uri: string): Promise < PixelMap | null > { 306e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, "image uri: " + uri); 307e41f4b71Sopenharmony_ci let file: fileIo.File | undefined; 308e41f4b71Sopenharmony_ci try { 309e41f4b71Sopenharmony_ci file = await fileIo.open(uri, fileIo.OpenMode.READ_ONLY); 310e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, "file: " + file.fd); 311e41f4b71Sopenharmony_ci 312e41f4b71Sopenharmony_ci let imageSourceApi: image.ImageSource = image.createImageSource(file.fd); 313e41f4b71Sopenharmony_ci if(!imageSourceApi) { 314e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, "imageSourceApi failed"); 315e41f4b71Sopenharmony_ci return null; 316e41f4b71Sopenharmony_ci } 317e41f4b71Sopenharmony_ci let pixmap: image.PixelMap = await imageSourceApi.createPixelMap(); 318e41f4b71Sopenharmony_ci if(!pixmap) { 319e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, "createPixelMap failed"); 320e41f4b71Sopenharmony_ci return null; 321e41f4b71Sopenharmony_ci } 322e41f4b71Sopenharmony_ci this.editedImage = pixmap; 323e41f4b71Sopenharmony_ci fileIo.closeSync(file); 324e41f4b71Sopenharmony_ci return pixmap; 325e41f4b71Sopenharmony_ci } catch(e) { 326e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, `readImage failed:${e}`); 327e41f4b71Sopenharmony_ci } finally { 328e41f4b71Sopenharmony_ci fileIo.close(file); 329e41f4b71Sopenharmony_ci } 330e41f4b71Sopenharmony_ci return null; 331e41f4b71Sopenharmony_ci } 332e41f4b71Sopenharmony_ci 333e41f4b71Sopenharmony_ci // Select an image from Gallery. 334e41f4b71Sopenharmony_ci async photoPickerGetUri(): Promise < string > { 335e41f4b71Sopenharmony_ci try { 336e41f4b71Sopenharmony_ci let PhotoSelectOptions = new picker.PhotoSelectOptions(); 337e41f4b71Sopenharmony_ci PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE; 338e41f4b71Sopenharmony_ci PhotoSelectOptions.maxSelectNumber = 1; 339e41f4b71Sopenharmony_ci let photoPicker = new picker.PhotoViewPicker(); 340e41f4b71Sopenharmony_ci let photoSelectResult: picker.PhotoSelectResult = await photoPicker.select(PhotoSelectOptions); 341e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, 342e41f4b71Sopenharmony_ci 'PhotoViewPicker.select successfully, PhotoSelectResult uri: ' + JSON.stringify(photoSelectResult)); 343e41f4b71Sopenharmony_ci return photoSelectResult.photoUris[0]; 344e41f4b71Sopenharmony_ci } catch(error) { 345e41f4b71Sopenharmony_ci let err: BusinessError = error as BusinessError; 346e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, 'PhotoViewPicker failed with err: ' + JSON.stringify(err)); 347e41f4b71Sopenharmony_ci } 348e41f4b71Sopenharmony_ci return ""; 349e41f4b71Sopenharmony_ci } 350e41f4b71Sopenharmony_ci 351e41f4b71Sopenharmony_ci build() { 352e41f4b71Sopenharmony_ci Row() { 353e41f4b71Sopenharmony_ci Column() { 354e41f4b71Sopenharmony_ci Text(this.message) 355e41f4b71Sopenharmony_ci .fontSize(50) 356e41f4b71Sopenharmony_ci .fontWeight(FontWeight.Bold) 357e41f4b71Sopenharmony_ci 358e41f4b71Sopenharmony_ci Button("selectImg").onClick(event => { 359e41f4b71Sopenharmony_ci // Select an image from Gallery. 360e41f4b71Sopenharmony_ci this.photoPickerGetUri().then(uri => { 361e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, "uri: " + uri); 362e41f4b71Sopenharmony_ci 363e41f4b71Sopenharmony_ci let context = getContext(this) as common.UIAbilityContext; 364e41f4b71Sopenharmony_ci let file: fileIo.File | undefined; 365e41f4b71Sopenharmony_ci try { 366e41f4b71Sopenharmony_ci file = fileIo.openSync(uri, fileIo.OpenMode.READ_ONLY); 367e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, "file: " + file.fd); 368e41f4b71Sopenharmony_ci 369e41f4b71Sopenharmony_ci let timeStamp = Date.now(); 370e41f4b71Sopenharmony_ci // Copy the image to the application sandbox path. 371e41f4b71Sopenharmony_ci fileIo.copyFileSync(file.fd, context.filesDir + `/original-${timeStamp}.jpg`); 372e41f4b71Sopenharmony_ci fileIo.closeSync(file); 373e41f4b71Sopenharmony_ci 374e41f4b71Sopenharmony_ci this.filePath = context.filesDir + `/original-${timeStamp}.jpg`; 375e41f4b71Sopenharmony_ci this.originalImage = fileUri.getUriFromPath(this.filePath); 376e41f4b71Sopenharmony_ci } catch (e) { 377e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, `readImage failed:${e}`); 378e41f4b71Sopenharmony_ci } finally { 379e41f4b71Sopenharmony_ci fileIo.close(file); 380e41f4b71Sopenharmony_ci } 381e41f4b71Sopenharmony_ci }) 382e41f4b71Sopenharmony_ci 383e41f4b71Sopenharmony_ci }).width('200').margin({ top: 20 }) 384e41f4b71Sopenharmony_ci 385e41f4b71Sopenharmony_ci Button("editImg").onClick(event => { 386e41f4b71Sopenharmony_ci let context = getContext(this) as common.UIAbilityContext; 387e41f4b71Sopenharmony_ci let abilityStartCallback: common.AbilityStartCallback = { 388e41f4b71Sopenharmony_ci onError: (code, name, message) => { 389e41f4b71Sopenharmony_ci const tip: string = `code:` + code + ` name:` + name + ` message:` + message; 390e41f4b71Sopenharmony_ci hilog.error(0x0000, TAG, "startAbilityByType:", tip); 391e41f4b71Sopenharmony_ci }, 392e41f4b71Sopenharmony_ci onResult: (result) => { 393e41f4b71Sopenharmony_ci // Obtain the URI of the edited image in the callback result and perform corresponding processing. 394e41f4b71Sopenharmony_ci let uri = result.want?.uri ?? ""; 395e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, "PhotoEditorCaller result: " + JSON.stringify(result)); 396e41f4b71Sopenharmony_ci this.readImage(uri).then(imagePixMap => { 397e41f4b71Sopenharmony_ci this.editedImage = imagePixMap; 398e41f4b71Sopenharmony_ci }); 399e41f4b71Sopenharmony_ci } 400e41f4b71Sopenharmony_ci } 401e41f4b71Sopenharmony_ci // Convert the image to an image URI and call startAbilityByType to start the image editing application panel. 402e41f4b71Sopenharmony_ci let uri = fileUri.getUriFromPath(this.filePath); 403e41f4b71Sopenharmony_ci context.startAbilityByType("photoEditor", { 404e41f4b71Sopenharmony_ci "ability.params.stream": [uri], // URI of the original image. Only one URI can be passed in. 405e41f4b71Sopenharmony_ci "ability.want.params.uriPermissionFlag": wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION // At least the read permission should be shared to the image editing application panel. 406e41f4b71Sopenharmony_ci } as Record<string, Object>, abilityStartCallback, (err) => { 407e41f4b71Sopenharmony_ci let tip: string; 408e41f4b71Sopenharmony_ci if (err) { 409e41f4b71Sopenharmony_ci tip = `Start error: ${JSON.stringify(err)}`; 410e41f4b71Sopenharmony_ci hilog.error(0x0000, TAG, `startAbilityByType: fail, err: ${JSON.stringify(err)}`); 411e41f4b71Sopenharmony_ci } else { 412e41f4b71Sopenharmony_ci tip = `Start success`; 413e41f4b71Sopenharmony_ci hilog.info(0x0000, TAG, "startAbilityByType: ", `success`); 414e41f4b71Sopenharmony_ci } 415e41f4b71Sopenharmony_ci }); 416e41f4b71Sopenharmony_ci 417e41f4b71Sopenharmony_ci }).width('200').margin({ top: 20 }) 418e41f4b71Sopenharmony_ci 419e41f4b71Sopenharmony_ci Image(this.originalImage).width("100%").height(200).margin({ top: 20 }).objectFit(ImageFit.Contain) 420e41f4b71Sopenharmony_ci 421e41f4b71Sopenharmony_ci Image(this.editedImage).width("100%").height(200).margin({ top: 20 }).objectFit(ImageFit.Contain) 422e41f4b71Sopenharmony_ci } 423e41f4b71Sopenharmony_ci .width('100%') 424e41f4b71Sopenharmony_ci } 425e41f4b71Sopenharmony_ci .height('100%') 426e41f4b71Sopenharmony_ci .backgroundColor(Color.Orange) 427e41f4b71Sopenharmony_ci .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.BOTTOM]) 428e41f4b71Sopenharmony_ci } 429e41f4b71Sopenharmony_ci} 430e41f4b71Sopenharmony_ci 431e41f4b71Sopenharmony_ci``` 432