Skip to main content
Version: 0.1.x

Image Capturer - Android

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

This capability proves particularly valuable in Video KYC scenarios, enabling the capture of images where users can hold up their identity for verification.

captureImage()

  • By using the captureImage() method of the Participant class, you can capture image of a local participant from their video stream.
  • You have the option to specify the desired height and width in the captureImage() method; however, these parameters are optional. If not provided, the VideoSDK will automatically use the dimensions of the local participant's webcamStream.
  • You need to pass an implementation of TaskCompletionListener as a parameter in the captureImage() method. This listener will handle the result of the image capture task.
  • When the image capture task is complete, the onComplete() method will provide the image in the form of a base64 string. If an error occurs, the onError() method will provide the error details.
private fun imageCapture() {
meeting!!.localParticipant.
.captureImage(400, 400, object : TaskCompletionListener<String?, String?> {
override fun onComplete(data: String?) {
Log.d("VideoSDK", "capturedImage in base64 format: $data")
}

override fun onError(error: String?) {
Log.d("VideoSDK", "Error in imageCapture $error")
}
})
}
note

You can only capture an image of the local participant. If you called captureImage() method on a remote participant, you will receive an error. To capture an image of a remote participant, refer to the documentation below.

How to capture image of a remote participant ?

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, you have to publish a message. Here, IMAGE_CAPTURE pubsub topic is used.
  • Also, you will be using the sendOnly property of the PubSubPublishOptions class. Therefore, the request will be sent to that participant only.
class MainActivity : AppCompatActivity() {

//..

private fun sendRequest(participantId: String) {
if (participantId != meeting.localParticipant.id) {
val publishOptions = PubSubPublishOptions()
publishOptions.isPersist = false
// Pass the participantId of the participant whose image you want to capture
// Here, it will be Participant B's id, as you want to capture the the image of Participant B
val sendOnly = arrayOf(participantId)
publishOptions.setSendOnly(sendOnly)

// send request to participant using the publish method
meeting.pubSub.publish("IMAGE_CAPTURE", "Sending request to capture image", publishOptions)
}
}
}

Step 2 : Capture and Upload File

  • To capture an image from a remote participant [Participant B], you will filter out the request from the onMessageReceived event of the PubSubMessageListener. For that, you need to subscribe to a topic called IMAGE_CAPTURE. When you receive an image capture request, you will capture the image using the captureImage() method of the Participant class.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

//...

// add listener to meeting
meeting!!.addEventListener(meetingEventListener)
}

private val meetingEventListener: MeetingEventListener = object : MeetingEventListener() {

override fun onMeetingJoined() {
Log.d("#meeting", "onMeetingJoined()")
val pubSubMessageListener =
PubSubMessageListener { message ->
if (message.senderId != meeting!!.localParticipant.id) {
// capture and store image when message received
captureAndStoreImage(message.senderId)
}
}
// subscribe for 'IMAGE_CAPTURE' topic to receive request
meeting!!.pubSub.subscribe("IMAGE_CAPTURE", pubSubMessageListener)
}

//...
}

private fun captureAndStoreImage(senderId: String) {
// capture image
meeting!!.localParticipant
.captureImage(object : TaskCompletionListener<String?, String?> {
override fun onComplete(@Nullable base64Data: String?) {
Log.d("VideoSDK", "capturedImage in base64 format: $base64Data")
}

override fun onError(@Nullable error: String?) {
Log.d("VideoSDK", "Error in image capture: $error")
}
})
}
}
  • After capturing the image of the remote participant, you need to store this image in VideoSDK's temporary file storage system. This will allow you to send the image to the participant who initiated the request.
  • Utilize the uploadBase64File() method of the Meeting class to store the captured image in VideoSDK's temporary file storage system.
  • When the upload is complete, the onComplete() method of TaskCompletionListener will provide the corresponding fileUrl, which can be used to retrieve the uploaded file.
  • If an error occurs during the upload process, the onError() method of TaskCompletionListener will provide the error details.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//...
}

private fun captureAndStoreImage(senderId: String) {
// listener for file-upload
val fileUploadListener: TaskCompletionListener<String, String> =
object : TaskCompletionListener<String?, String?> {
override fun onComplete(@Nullable fileUrl: String?) {
Log.d("VideoSDK", "Uploaded file url: $fileUrl")
}

override fun onError(@Nullable error: String?) {
Log.d("VideoSDK", "Error in upload file: $error")
}
}

// capture image
meeting!!.localParticipant
.captureImage(object : TaskCompletionListener<String?, String?> {
override fun onComplete(@Nullable base64Data: String?) {
Log.d("VideoSDK", "capturedImage in base64 format: $base64Data")
val token = "<VIDEOSDK_TOKEN>"
val fileName = "myCapture.jpeg" // specify a name for image file with extension
// upload image to videosdk storage system
meeting!!.uploadBase64File(base64Data, token, fileName, fileUploadListener)
}

override fun onError(@Nullable error: String?) {
Log.d("VideoSDK", "Error in image capture: $error")
}
})
}
}
  • Next, the fileUrl is sent back to the participant who initiated the request using the IMAGE_TRANSFER topic.
class MainActivity : AppCompatActivity() {

//..

private fun captureAndStoreImage(senderId: String) {
// listener for file-upload
val fileUploadListener: TaskCompletionListener<String, String> =
object : TaskCompletionListener<String?, String?> {
override fun onComplete(@Nullable fileUrl: String?) {
Log.d("VideoSDK", "Uploaded file url: $fileUrl")
imageTransfer(fileUrl, senderId)
}

override fun onError(@Nullable error: String?) {
Log.d("VideoSDK", "Error in upload file: $error")
}
}

//...
}

private fun imageTransfer(fileUrl: String?, senderId: String) {
val publishOptions = PubSubPublishOptions()
publishOptions.isPersist = false
// Pass the participantId who initiated the request
val sendOnly = arrayOf(senderId)
publishOptions.setSendOnly(sendOnly)

// send fileUrl to the participant who request for image using the publish method
meeting!!.pubSub.publish("IMAGE_TRANSFER", fileUrl, publishOptions)
}
}

Step 3 : Fetch and Display Image

  • To display a captured image, the showCapturedImage() method is used. Here's how it works:

  • Within the showCapturedImage() method, subscribe to the IMAGE_TRANSFER topic to receive the fileUrl associated with the captured image.

  • Once the fileUrl is obtained, use the fetchBase64File() method from the Meeting class to retrieve the file in base64 format from VideoSDK's temporary storage.

class MainActivity : AppCompatActivity() {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

showCapturedImage()
}

private fun showCapturedImage() {
val pubSubMessageListener =
PubSubMessageListener { message: PubSubMessage ->
if (message.senderId != meeting!!.localParticipant.id) {
// fetch the image when message received
val url = message.message
val token = "<VIDEOSDK_TOKEN>"
meeting!!.fetchBase64File(
url,
token,
object : TaskCompletionListener<String?, String?> {
override fun onComplete(@Nullable base64Data: String?) {
// here is your image in the form of base64
Log.d("VideoSDK", "Fetched file in base64:$base64Data")
// coverting base64 to bitmap to display an image in the imageView
val capturedImage =
findViewById<ImageView>(R.id.capturedImage)
val decodedString: ByteArray =
Base64.decode(base64Data, Base64.DEFAULT)
val decodedByte =
BitmapFactory.decodeByteArray(
decodedString,
0,
decodedString.size
)
capturedImage.setImageBitmap(decodedByte)
}

override fun onError(@Nullable error: String?) {
Log.d("VideoSDK", "Error in fetch file: $error")
}
}
)
}
}

// Subscribe for 'IMAGE_TRANSFER' topic to receive fileUrl
meeting!!.pubSub.subscribe("IMAGE_TRANSFER", pubSubMessageListener)
}
}
note

The file stored in the VideoSDK's temporary file storage system will be automatically deleted once the current room/meeting 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