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![](figures/photoEditorExtensionAbility.png)
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