1# Deferred Photo Delivery (ArkTS) 2 3As an important feature of the camera, deferred photo delivery enables the system, after receiving a photo capture task from an application, to report images of different quality levels in multiple phases. 4- In the first phase, the system promptly delivers an image that has undergone lightweight processing, offering a balance between reduced quality and swift image availability. The application receives a PhotoAsset object through the callback. Through this object, the application can call the media library APIs to read the image or flush the image to the disk. 5- In the second phase, the camera framework enhances the image to achieve full quality, either in response to the application's request for higher quality or when the system is not busy. The enhanced image is then sent back to the media library to replace the previously provided one. 6 7Deferred photo delivery further reduces the response delay, delivering a better user experience. 8 9To develop deferred photo delivery, perform the following steps: 10 11- Listen for the **photoAssetAvailable** event through **PhotoOutput** to obtain a PhotoAsset object of [photoAccessHelper](../../reference/apis-media-library-kit/js-apis-photoAccessHelper.md). 12- Call the media library APIs to read or flush images to the disk through the PhotoAsset object. 13 14> **NOTE** 15> 16> - Deferred photo delivery varies according to the device and type. Therefore, if the device or type is changed, the deferred photo delivery capability may change. 17> - Applications do not need to proactively enable deferred photo delivery. Instead, the camera framework checks whether the device and type support deferred photo delivery during stream configuration and if so, automatically enables deferred photo delivery. 18 19## How to Develop 20 21Read [Camera](../../reference/apis-camera-kit/js-apis-camera.md) for the API reference. 22 231. Import dependencies. Specifically, import the camera, image, and media library modules. 24 25 ```ts 26 import { camera } from '@kit.CameraKit'; 27 import { BusinessError } from '@kit.BasicServicesKit'; 28 import { common } from '@kit.AbilityKit'; 29 import { photoAccessHelper } from '@kit.MediaLibraryKit'; 30 ``` 31 322. Determine the photo output stream. 33 34 You can use the **photoProfiles** attribute of the [CameraOutputCapability](../../reference/apis-camera-kit/js-apis-camera.md#cameraoutputcapability) class to obtain the photo output streams supported by the device and use [createPhotoOutput](../../reference/apis-camera-kit/js-apis-camera.md#createphotooutput11) to create a photo output stream. 35 36 ```ts 37 function getPhotoOutput(cameraManager: camera.CameraManager, 38 cameraOutputCapability: camera.CameraOutputCapability): camera.PhotoOutput | undefined { 39 let photoProfilesArray: Array<camera.Profile> = cameraOutputCapability.photoProfiles; 40 if (!photoProfilesArray) { 41 console.error("createOutput photoProfilesArray == null || undefined"); 42 } 43 let photoOutput: camera.PhotoOutput | undefined = undefined; 44 try { 45 photoOutput = cameraManager.createPhotoOutput(photoProfilesArray[0]); 46 } catch (error) { 47 let err = error as BusinessError; 48 console.error(`Failed to createPhotoOutput. error: ${JSON.stringify(err)}`); 49 } 50 return photoOutput; 51 } 52 ``` 53 543. Set the **photoAssetAvailable** callback. 55 56 > **NOTE** 57 > 58 > If the **photoAssetAvailable** callback has been registered and the **photoAvailable** callback is registered after the session starts, the stream will be restarted. In this case, only the **photoAssetAvailable** callback takes effect. Therefore, you are not advised to register both **photoAvailable** and **photoAssetAvailable**. 59 60 ```ts 61 function photoAssetAvailableCallback(err: BusinessError, photoAsset: photoAccessHelper.PhotoAsset): void { 62 if (err) { 63 console.error(`photoAssetAvailable error: ${JSON.stringify(err)}.`); 64 return; 65 } 66 console.info('photoOutPutCallBack photoAssetAvailable'); 67 // You can call media library APIs through photoAsset to customize image processing. 68 // Processing method 1: Call the media library API to save the image in the first phase. After the image in the second phase is ready, the media library proactively replaces the image flushed. 69 mediaLibSavePhoto(photoAsset); 70 // Processing method 2: Call the media library API to request an image and register the buffer callback to receive the first-phase or second-phase image. 71 mediaLibRequestBuffer(photoAsset); 72 } 73 74 function onPhotoOutputPhotoAssetAvailable(photoOutput: camera.PhotoOutput): void { 75 photoOutput.on('photoAssetAvailable', photoAssetAvailableCallback); 76 } 77 78 let context = getContext(this); 79 let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context); 80 81 async function mediaLibSavePhoto(photoAsset: photoAccessHelper.PhotoAsset): Promise<void> { 82 try { 83 let assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest = new photoAccessHelper.MediaAssetChangeRequest(photoAsset); 84 assetChangeRequest.saveCameraPhoto(); 85 await phAccessHelper.applyChanges(assetChangeRequest); 86 console.info('apply saveCameraPhoto successfully'); 87 } catch (err) { 88 console.error(`apply saveCameraPhoto failed with error: ${err.code}, ${err.message}`); 89 } 90 } 91 92 class MediaDataHandler implements photoAccessHelper.MediaAssetDataHandler<ArrayBuffer> { 93 onDataPrepared(data: ArrayBuffer) { 94 if (data === undefined) { 95 console.error('Error occurred when preparing data'); 96 return; 97 } 98 // The application can customize the processing after obtaining the image buffer. 99 console.info('on image data prepared'); 100 } 101 } 102 103 async function mediaLibRequestBuffer(photoAsset: photoAccessHelper.PhotoAsset) { 104 let requestOptions: photoAccessHelper.RequestOptions = { 105 // Configure the image return mode based on service requirements. 106 // FAST_MODE: callback for receiving the first-phase image 107 // HIGH_QUALITY_MODE: callback for receiving the second-phase image 108 // BALANCE_MODE: callback for receiving both images 109 deliveryMode: photoAccessHelper.DeliveryMode.FAST_MODE, 110 } 111 const handler = new MediaDataHandler(); 112 await photoAccessHelper.MediaAssetManager.requestImageData(context, photoAsset, requestOptions, handler); 113 console.info('requestImageData successfully'); 114 } 115 ``` 116 117 For details about the API used to flush images, see [saveCameraPhoto](../../reference/apis-media-library-kit/js-apis-photoAccessHelper.md#savecameraphoto12). 118 119 For details about the APIs used to request images, see [requestImageData](../../reference/apis-media-library-kit/js-apis-photoAccessHelper.md#requestimagedata11) and [onDataPrepared](../../reference/apis-media-library-kit/js-apis-photoAccessHelper.md#ondataprepared11). 120 1214. The session configuration and photo capture triggering mode are the same as those in the common photo capture mode. For details, see steps 4-5 in [Photo Capture (ArkTS)](camera-shooting.md). 122 123## Status Listening 124 125During camera application development, you can listen for the status of the photo output stream, including the start of the photo stream, the start and end of the photo frame, and errors of the photo output stream. 126 127- Register the **'captureStart'** event to listen for photo capture start events. This event can be registered when a PhotoOutput instance is created and is triggered when the camera device starts photo capture. The capture ID is returned. 128 129 ```ts 130 function onPhotoOutputCaptureStart(photoOutput: camera.PhotoOutput): void { 131 photoOutput.on('captureStartWithInfo', (err: BusinessError, captureStartInfo: camera.CaptureStartInfo) => { 132 if (err !== undefined && err.code !== 0) { 133 return; 134 } 135 console.info(`photo capture started, captureId : ${captureStartInfo.captureId}`); 136 }); 137 } 138 ``` 139 140- Register the **'captureEnd'** event to listen for photo capture end events. This event can be registered when a PhotoOutput instance is created and is triggered when the photo capture is complete. [CaptureEndInfo](../../reference/apis-camera-kit/js-apis-camera.md#captureendinfo) is returned. 141 142 ```ts 143 function onPhotoOutputCaptureEnd(photoOutput: camera.PhotoOutput): void { 144 photoOutput.on('captureEnd', (err: BusinessError, captureEndInfo: camera.CaptureEndInfo) => { 145 if (err !== undefined && err.code !== 0) { 146 return; 147 } 148 console.info(`photo capture end, captureId : ${captureEndInfo.captureId}`); 149 console.info(`frameCount : ${captureEndInfo.frameCount}`); 150 }); 151 } 152 ``` 153 154- Register the **'captureReady'** event to obtain the result of the next photo capture. This event can be registered when a PhotoOutput instance is created and is triggered when the camera device is ready for taking a photo. The information about the next photo capture is returned. 155 156 ```ts 157 function onPhotoOutputCaptureReady(photoOutput: camera.PhotoOutput): void { 158 photoOutput.on('captureReady', (err: BusinessError) => { 159 if (err !== undefined && err.code !== 0) { 160 return; 161 } 162 console.info(`photo capture ready`); 163 }); 164 } 165 ``` 166 167- Register the **'error'** event to listen for photo output errors. The callback function returns an error code when an API is incorrectly used. For details about the error code types, see [CameraErrorCode](../../reference/apis-camera-kit/js-apis-camera.md#cameraerrorcode). 168 169 ```ts 170 function onPhotoOutputError(photoOutput: camera.PhotoOutput): void { 171 photoOutput.on('error', (error: BusinessError) => { 172 console.error(`Photo output error code: ${error.code}`); 173 }); 174 } 175 ``` 176