1# Deferred Photo Delivery Sample (ArkTS) 2 3Before developing a camera application, request permissions by following the instructions provided in [Camera Development Preparations](camera-preparation.md). 4 5This topic provides sample code that covers the complete deferred photo delivery process to help you understand the complete API calling sequence. 6 7Before referring to the sample code, you are advised to read [Deferred Photo Delivery (ArkTS)](camera-deferred-capture.md), [Device Input Management](camera-device-input.md), [Camera Session Management](camera-session-management.md), and [Photo Capture](camera-shooting.md). 8 9## Development Process 10 11After obtaining the output stream capabilities supported by the camera, create a photo stream. The development process is as follows: 12 13 14 15## Sample Code 16 17For details about how to obtain the context, see [Obtaining the Context of UIAbility](../../application-models/uiability-usage.md#obtaining-the-context-of-uiability). 18 19```ts 20import { camera } from '@kit.CameraKit'; 21import { BusinessError } from '@kit.BasicServicesKit'; 22import { common } from '@kit.AbilityKit'; 23import { photoAccessHelper } from '@kit.MediaLibraryKit'; 24 25let context = getContext(this); 26let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context); 27 28class MediaDataHandler implements photoAccessHelper.MediaAssetDataHandler<ArrayBuffer> { 29 onDataPrepared(data: ArrayBuffer) { 30 if (data === undefined) { 31 console.error('Error occurred when preparing data'); 32 return; 33 } 34 console.info('on image data prepared'); 35 } 36} 37 38async function mediaLibRequestBuffer(photoAsset: photoAccessHelper.PhotoAsset) { 39 let requestOptions: photoAccessHelper.RequestOptions = { 40 deliveryMode: photoAccessHelper.DeliveryMode.HIGH_QUALITY_MODE, 41 } 42 const handler = new MediaDataHandler(); 43 await photoAccessHelper.MediaAssetManager.requestImageData(context, photoAsset, requestOptions, handler); 44 console.info('requestImageData successfully'); 45} 46 47async function mediaLibSavePhoto(photoAsset: photoAccessHelper.PhotoAsset): Promise<void> { 48 try { 49 let assetChangeRequest: photoAccessHelper.MediaAssetChangeRequest = new photoAccessHelper.MediaAssetChangeRequest(photoAsset); 50 assetChangeRequest.saveCameraPhoto(); 51 await phAccessHelper.applyChanges(assetChangeRequest); 52 console.info('apply saveCameraPhoto successfully'); 53 } catch (err) { 54 console.error(`apply saveCameraPhoto failed with error: ${err.code}, ${err.message}`); 55 } 56} 57 58function setPhotoOutputCb(photoOutput: camera.PhotoOutput): void { 59 // After the callback is set, call capture() of photoOutput to trigger the callback upon the receiving of a low-quality image. 60 photoOutput.on('photoAssetAvailable', (err: BusinessError, photoAsset: photoAccessHelper.PhotoAsset): void => { 61 console.info('getPhotoAsset start'); 62 console.info(`err: ${JSON.stringify(err)}`); 63 if ((err !== undefined && err.code !== 0) || photoAsset === undefined) { 64 console.error('getPhotoAsset failed'); 65 return; 66 } 67 // Call the mediaLibrary flush API to save the low-quality image in the first phase. After the real image in the second phase is ready, the mediaLibrary proactively replaces the image flushed. 68 mediaLibSavePhoto(photoAsset); 69 // Call the mediaLibrary API to register the buffer callback to receive low-quality or high-quality images for custom processing. 70 mediaLibRequestBuffer(photoAsset); 71 }); 72} 73 74async function deferredCaptureCase(baseContext: common.BaseContext, surfaceId: string): Promise<void> { 75 // Create a CameraManager object. 76 let cameraManager: camera.CameraManager = camera.getCameraManager(baseContext); 77 if (!cameraManager) { 78 console.error("camera.getCameraManager error"); 79 return; 80 } 81 // Listen for camera status changes. 82 cameraManager.on('cameraStatus', (err: BusinessError, cameraStatusInfo: camera.CameraStatusInfo) => { 83 if (err !== undefined && err.code !== 0) { 84 console.error('cameraStatus with errorCode = ' + err.code); 85 return; 86 } 87 console.info(`camera : ${cameraStatusInfo.camera.cameraId}`); 88 console.info(`status: ${cameraStatusInfo.status}`); 89 }); 90 91 // Obtain the camera list. 92 let cameraArray: Array<camera.CameraDevice> = cameraManager.getSupportedCameras(); 93 if (cameraArray.length <= 0) { 94 console.error("cameraManager.getSupportedCameras error"); 95 return; 96 } 97 98 for (let index = 0; index < cameraArray.length; index++) { 99 console.info('cameraId : ' + cameraArray[index].cameraId); // Obtain the camera ID. 100 console.info('cameraPosition : ' + cameraArray[index].cameraPosition); // Obtain the camera position. 101 console.info('cameraType : ' + cameraArray[index].cameraType); // Obtain the camera type. 102 console.info('connectionType : ' + cameraArray[index].connectionType); // Obtain the camera connection type. 103 } 104 105 // Create a camera input stream. 106 let cameraInput: camera.CameraInput | undefined = undefined; 107 try { 108 cameraInput = cameraManager.createCameraInput(cameraArray[0]); 109 } catch (error) { 110 let err = error as BusinessError; 111 console.error('Failed to createCameraInput errorCode = ' + err.code); 112 } 113 if (cameraInput === undefined) { 114 return; 115 } 116 117 // Listen for camera input errors. 118 let cameraDevice: camera.CameraDevice = cameraArray[0]; 119 cameraInput.on('error', cameraDevice, (error: BusinessError) => { 120 console.error(`Camera input error code: ${error.code}`); 121 }) 122 123 // Open a camera. 124 await cameraInput.open(); 125 126 // Obtain the supported modes. 127 let sceneModes: Array<camera.SceneMode> = cameraManager.getSupportedSceneModes(cameraArray[0]); 128 let isSupportPhotoMode: boolean = sceneModes.indexOf(camera.SceneMode.NORMAL_PHOTO) >= 0; 129 if (!isSupportPhotoMode) { 130 console.error('photo mode not support'); 131 return; 132 } 133 // Obtain the output streams supported by the camera. 134 let cameraOutputCap: camera.CameraOutputCapability = cameraManager.getSupportedOutputCapability(cameraArray[0], camera.SceneMode.NORMAL_PHOTO); 135 if (!cameraOutputCap) { 136 console.error("cameraManager.getSupportedOutputCapability error"); 137 return; 138 } 139 console.info("outputCapability: " + JSON.stringify(cameraOutputCap)); 140 141 let previewProfilesArray: Array<camera.Profile> = cameraOutputCap.previewProfiles; 142 if (!previewProfilesArray) { 143 console.error("createOutput previewProfilesArray == null || undefined"); 144 } 145 146 let photoProfilesArray: Array<camera.Profile> = cameraOutputCap.photoProfiles; 147 if (!photoProfilesArray) { 148 console.error("createOutput photoProfilesArray == null || undefined"); 149 } 150 151 // Create a preview output stream. For details about the surfaceId parameter, see the XComponent. The preview stream uses the surface provided by the XComponent. 152 let previewOutput: camera.PreviewOutput | undefined = undefined; 153 try { 154 previewOutput = cameraManager.createPreviewOutput(previewProfilesArray[0], surfaceId); 155 } catch (error) { 156 let err = error as BusinessError; 157 console.error(`Failed to create the PreviewOutput instance. error code: ${err.code}`); 158 } 159 if (previewOutput === undefined) { 160 return; 161 } 162 // Listen for preview output errors. 163 previewOutput.on('error', (error: BusinessError) => { 164 console.error(`Preview output error code: ${error.code}`); 165 }); 166 167 // Create a photo output stream. 168 let photoOutput: camera.PhotoOutput | undefined = undefined; 169 try { 170 photoOutput = cameraManager.createPhotoOutput(photoProfilesArray[0]); 171 } catch (error) { 172 let err = error as BusinessError; 173 console.error('Failed to createPhotoOutput errorCode = ' + err.code); 174 } 175 if (photoOutput === undefined) { 176 return; 177 } 178 179 // Register the photoAssetAvailable callback. 180 setPhotoOutputCb(photoOutput); 181 182 // Create a session. 183 let photoSession: camera.PhotoSession | undefined = undefined; 184 try { 185 photoSession = cameraManager.createSession(camera.SceneMode.NORMAL_PHOTO) as camera.PhotoSession; 186 } catch (error) { 187 let err = error as BusinessError; 188 console.error('Failed to create the session instance. errorCode = ' + err.code); 189 } 190 if (photoSession === undefined) { 191 return; 192 } 193 // Listen for session errors. 194 photoSession.on('error', (error: BusinessError) => { 195 console.error(`Capture session error code: ${error.code}`); 196 }); 197 198 // Start configuration for the session. 199 try { 200 photoSession.beginConfig(); 201 } catch (error) { 202 let err = error as BusinessError; 203 console.error('Failed to beginConfig. errorCode = ' + err.code); 204 } 205 206 // Add the camera input stream to the session. 207 try { 208 photoSession.addInput(cameraInput); 209 } catch (error) { 210 let err = error as BusinessError; 211 console.error('Failed to addInput. errorCode = ' + err.code); 212 } 213 214 // Add the preview output stream to the session. 215 try { 216 photoSession.addOutput(previewOutput); 217 } catch (error) { 218 let err = error as BusinessError; 219 console.error('Failed to addOutput(previewOutput). errorCode = ' + err.code); 220 } 221 222 // Add the photo output stream to the session. 223 try { 224 photoSession.addOutput(photoOutput); 225 } catch (error) { 226 let err = error as BusinessError; 227 console.error('Failed to addOutput(photoOutput). errorCode = ' + err.code); 228 } 229 230 // Commit the session configuration. 231 await photoSession.commitConfig(); 232 233 // Start the session. 234 await photoSession.start().then(() => { 235 console.info('Promise returned to indicate the session start success.'); 236 }); 237 // Check whether the camera has flash. 238 let flashStatus: boolean = false; 239 try { 240 flashStatus = photoSession.hasFlash(); 241 } catch (error) { 242 let err = error as BusinessError; 243 console.error('Failed to hasFlash. errorCode = ' + err.code); 244 } 245 console.info('Returned with the flash light support status:' + flashStatus); 246 247 if (flashStatus) { 248 // Check whether the auto flash mode is supported. 249 let flashModeStatus: boolean = false; 250 try { 251 let status: boolean = photoSession.isFlashModeSupported(camera.FlashMode.FLASH_MODE_AUTO); 252 flashModeStatus = status; 253 } catch (error) { 254 let err = error as BusinessError; 255 console.error('Failed to check whether the flash mode is supported. errorCode = ' + err.code); 256 } 257 if(flashModeStatus) { 258 // Set the flash mode to auto. 259 try { 260 photoSession.setFlashMode(camera.FlashMode.FLASH_MODE_AUTO); 261 } catch (error) { 262 let err = error as BusinessError; 263 console.error('Failed to set the flash mode. errorCode = ' + err.code); 264 } 265 } 266 } 267 268 // Check whether the continuous auto focus is supported. 269 let focusModeStatus: boolean = false; 270 try { 271 let status: boolean = photoSession.isFocusModeSupported(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO); 272 focusModeStatus = status; 273 } catch (error) { 274 let err = error as BusinessError; 275 console.error('Failed to check whether the focus mode is supported. errorCode = ' + err.code); 276 } 277 278 if (focusModeStatus) { 279 // Set the focus mode to continuous auto focus. 280 try { 281 photoSession.setFocusMode(camera.FocusMode.FOCUS_MODE_CONTINUOUS_AUTO); 282 } catch (error) { 283 let err = error as BusinessError; 284 console.error('Failed to set the focus mode. errorCode = ' + err.code); 285 } 286 } 287 288 // Obtain the zoom ratio range supported by the camera. 289 let zoomRatioRange: Array<number> = []; 290 try { 291 zoomRatioRange = photoSession.getZoomRatioRange(); 292 } catch (error) { 293 let err = error as BusinessError; 294 console.error('Failed to get the zoom ratio range. errorCode = ' + err.code); 295 } 296 if (zoomRatioRange.length <= 0) { 297 return; 298 } 299 // Set a zoom ratio. 300 try { 301 photoSession.setZoomRatio(zoomRatioRange[0]); 302 } catch (error) { 303 let err = error as BusinessError; 304 console.error('Failed to set the zoom ratio value. errorCode = ' + err.code); 305 } 306 let photoCaptureSetting: camera.PhotoCaptureSetting = { 307 quality: camera.QualityLevel.QUALITY_LEVEL_HIGH, // Set the photo quality to high. 308 rotation: camera.ImageRotation.ROTATION_0 // Set the rotation angle of the photo to 0. 309 } 310 // Use the current photo capture settings to take photos. 311 photoOutput.capture(photoCaptureSetting, (err: BusinessError) => { 312 if (err) { 313 console.error(`Failed to capture the photo ${err.message}`); 314 return; 315 } 316 console.info('Callback invoked to indicate the photo capture request success.'); 317 }); 318 319 // After the photo capture is complete, call the following APIs to close the camera and release the session. Do not release the session before the photo capture is complete. 320 // Stop the session. 321 await photoSession.stop(); 322 323 // Release the camera input stream. 324 await cameraInput.close(); 325 326 // Release the preview output stream. 327 await previewOutput.release(); 328 329 // Release the photo output stream. 330 await photoOutput.release(); 331 332 // Release the session. 333 await photoSession.release(); 334 335 // Set the session to null. 336 photoSession = undefined; 337} 338``` 339