Skip to main content
Version: 4.x.x

Image Capturer - iOS

This guide provides instructions on capturing images of participants from a video stream.

Use it in Video KYC, for example to capture an image of a user holding up their ID for verification.

captureImage()​

  • By using the captureImage() function of the Participant class, you can capture an image of a participant from their video stream. It works for the local participant, and for a remote participant whose video your device receives.
  • You have the option to specify the desired width and height in the captureImage() function; however, these parameters are optional. The image is scaled down to fit within them and keeps its aspect ratio. If not provided, the SDK uses the dimensions of the participant's video.
  • The captureImage() function is async throws, so call it with try await inside a Task. It returns the image in the form of a base64 string.
  • If the image was not captured, captureImage() throws a VideoSDKError:
    • ERROR_WEBCAM_NOT_ENABLED (3062) when the participant's camera is off, or your device does not receive their video.
    • ERROR_CAPTURE_IMAGE_FAILED (3069) when the capture fails. This error is also sent to onError(error:).
extension RoomViewController {
// Button when tapped will capture image
@IBAction func captureImageTapped(_ sender: Any) {

guard let participant = room?.localParticipant else { return }

Task {
do {
let base64Data = try await participant.captureImage(width: 200, height: 200)
print("base64: ", base64Data)
} catch {
print("Image was not captured: \(error)")
}
}
}
}

Capture with flash​

  • Pass flash: .ON to light up the scene while the image is captured. The default is .OFF. The SDK uses the torch of the camera in use. A capture with flash takes about half a second longer.
  • Most front cameras have no torch. For them, set a screen flash with VideoSDK.setScreenFlash(_:). WhiteOverlayScreenFlash covers the window in warm white at full brightness while the image is captured.
  • If there is no torch and no screen flash, the image is captured without flash.
  • Flash works only for the local participant. With flash: .ON, captureImage() throws ERROR_CAPTURE_IMAGE_FAILED for a remote participant, and while another capture with flash is running.
extension RoomViewController {
// Button when tapped will capture image with flash
@IBAction func captureWithFlashTapped(_ sender: Any) {

// lights up the user's face when the front camera has no torch
VideoSDK.setScreenFlash(WhiteOverlayScreenFlash(window: view.window))

Task {
do {
let base64Data = try await room?.localParticipant.captureImage(flash: .ON)
print("base64: ", base64Data ?? "")
} catch {
print("Image was not captured: \(error)")
}
}
}
}
note

For a remote participant, the image is taken from the video your device receives from them, so its size depends on the video quality you receive. To capture the image from the remote participant's own camera, ask their device to capture it and send it to you, as shown below.

How to capture image of remote participant on their device?​

Step 1 : Initiate Image Capture Request​

  • In this step, you have to first send a request to Participant B, whose image you want to capture, using pubsub.
  • In order to do that, Participant B has to subscribe to the topic called IMAGE_CAPTURE.
  • Here, we will be using the sendOnly field of PubSubPublishOptions, passed as options to the publish() method. Therefore, the request will be sent to that participant only.
extension RoomViewController {
// Call this, for example from a button, to request an image from a participant
func requestCapture(from participant: Participant) {

let options = PubSubPublishOptions(persist: false, sendOnly: [participant.id])
Task {
do {
try await room?.pubSub.publish(topic: "IMAGE_CAPTURE", message: "Sending Request to capture image", options: options)
} catch {
print("publish error: \(error)")
}
}
}
}

Step 2 : Capture and Upload File​

  • To capture image from remote participant [Participant B], we will pick out the request from the onMessageReceived event of the PubSubMessageListener. When a participant receives an image capture request, we will capture image using captureImage function of the Participant class.

  • The captured image is then stored in the VideoSDK's temporary file storage system using the uploadBase64File() function of the Room class. It is async throws and returns a unique url of the stored image.

  • Next, the url is sent back to the participant who initiated the request using the IMAGE_TRANSFER topic. For this, Participant A must be subscribed to the topic IMAGE_TRANSFER.

extension RoomViewController: PubSubMessageListener {

func onMessageReceived(_ message: PubSubMessage) {

if message.topic == "IMAGE_CAPTURE" {
print("received image request")
handleImageCapture(senderId: message.senderId)
return
}
}
}
extension RoomViewController {

func handleImageCapture(senderId: String) {
// Capture the image of the local participant (i.e. Participant B).
guard let room = self.room else {
return
}

Task {
do {
// capture the image.
let image = try await room.localParticipant.captureImage(width: 100, height: 100)

// upload it to the VideoSDK's temporary storage.
let url = try await room.uploadBase64File(base64Data: image, token: "<Your-Token>", fileName: "screenshot.jpeg")

// send url using pubsub back to Participant A.
let options = PubSubPublishOptions(persist: false, sendOnly: [senderId])
try await room.pubSub.publish(topic: "IMAGE_TRANSFER", message: url, options: options)
} catch {
print("Image capture or upload failed: \(error)")
}
}
}
}

Step 3 : Fetch and Display Image​

  • To fetch the image, you need to be subscribed to the IMAGE_TRANSFER topic, receiving the url associated with the captured image. Once obtained, use the fetchBase64File() function from the Room class to retrieve the file in base64 String format from VideoSDK's temporary storage. It is async throws.
extension RoomViewController: PubSubMessageListener {

func onMessageReceived(_ message: PubSubMessage) {

if message.topic == "IMAGE_CAPTURE" {
print("received image request")
handleImageCapture(senderId: message.senderId)
return
}
// listen for IMAGE_TRANSFER topic
if message.topic == "IMAGE_TRANSFER" {

print("received image response")
Task {
do {
// fetch image from the VideoSDK's temporary storage.
guard let base64Data = try await room?.fetchBase64File(url: message.message, token: "<Your-Token>") else {
return
}
print("base64Data: ", base64Data)
if let data = Data(base64Encoded: base64Data, options: .ignoreUnknownCharacters) {
let image = UIImage(data: data)
//<Display this image or upload to your cloud storage>
}
} catch {
print("retrieval failed: \(error)")
}
}
return
}
}
}
note

The file stored in the VideoSDK's temporary file storage system will be automatically deleted once the current room comes to an end.

API Reference​

The API references for all the methods utilized in this guide are provided below.

Got a Question? Ask us on discord