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 theParticipant
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 thecaptureImage()
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 abase64
string. If an error occurs, theonError()
method will provide the error details.
- Kotlin
- Java
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")
}
})
}
private void imageCapture() {
meeting.getLocalParticipant().captureImage(400, 400, new TaskCompletionListener<String,String>() {
@Override
public void onComplete(@Nullable String data) {
Log.d("VideoSDK", "capturedImage in base64 format: " + data);
}
@Override
public void onError(@Nullable String error) {
Log.d("VideoSDK", "Error in imageCapture " + error);
}
});
}
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 ?
-
Before proceeding, it's crucial to understand VideoSDK's temporary file storage system and the underlying pubsub mechanism.
-
Here's a break down of the steps, using the names Participant A and Participant B for clarity:
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 thePubSubPublishOptions
class. Therefore, the request will be sent to that participant only.
- Kotlin
- Java
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)
}
}
}
public class MainActivity extends AppCompatActivity {
//...
private void sendRequest(String participantId) {
if (!participantId.equals(meeting.getLocalParticipant().getId())) {
PubSubPublishOptions publishOptions = new PubSubPublishOptions();
publishOptions.setPersist(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
String[] sendOnly = {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 thePubSubMessageListener
. For that, you need to subscribe to a topic calledIMAGE_CAPTURE
. When you receive an image capture request, you will capture the image using thecaptureImage()
method of theParticipant
class.
- Kotlin
- Java
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")
}
})
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//...
// add listener to meeting
meeting.addEventListener(meetingEventListener);
}
private final MeetingEventListener meetingEventListener = new MeetingEventListener() {
@Override
public void onMeetingJoined() {
Log.d("#meeting", "onMeetingJoined()");
PubSubMessageListener pubSubMessageListener = new PubSubMessageListener() {
@Override
public void onMessageReceived(PubSubMessage message) {
if (!message.getSenderId().equals(meeting.getLocalParticipant().getId()))
{
// capture and store image when message received
captureAndStoreImage(message.getSenderId());
}
}
}
// subscribe for 'IMAGE_CAPTURE' topic to receive request
meeting.pubSub.subscribe("IMAGE_CAPTURE", pubSubMessageListener);
}
//...
};
private void captureAndStoreImage(String senderId) {
// capture image
meeting.getLocalParticipant().captureImage(new TaskCompletionListener<String, String>() {
@Override
public void onComplete(@Nullable String base64Data) {
Log.d("VideoSDK", "capturedImage in base64 format: " + base64Data);
}
@Override
public void onError(@Nullable String error) {
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 theMeeting
class to store the captured image in VideoSDK's temporary file storage system. - When the upload is complete, the
onComplete()
method ofTaskCompletionListener
will provide the correspondingfileUrl
, which can be used to retrieve the uploaded file. - If an error occurs during the upload process, the
onError()
method ofTaskCompletionListener
will provide the error details.
- Kotlin
- Java
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")
}
})
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//...
}
private void captureAndStoreImage(String senderId) {
// listener for file-upload
TaskCompletionListener<String, String> fileUploadListener = new TaskCompletionListener<>() {
@Override
public void onComplete(@Nullable String fileUrl) {
Log.d("VideoSDK", "Uploaded file url: " + fileUrl);
}
@Override
public void onError(@Nullable String error) {
Log.d("VideoSDK", "Error in upload file: " + error);
}
};
// capture image
meeting.getLocalParticipant().captureImage(new TaskCompletionListener<String, String>() {
@Override
public void onComplete(@Nullable String base64Data) {
Log.d("VideoSDK", "capturedImage in base64 format: " + base64Data);
String token = "<VIDEOSDK_TOKEN>";
String fileName = "myCapture.jpeg"; // specify a name for image file with extension
// upload image to videosdk storage system
meeting.uploadBase64File(base64Data, token, fileName, fileUploadListener);
}
@Override
public void onError(@Nullable String error) {
Log.d("VideoSDK", "Error in image capture: " + error);
}
});
}
}
- Next, the
fileUrl
is sent back to the participant who initiated the request using theIMAGE_TRANSFER
topic.
- Kotlin
- Java
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)
}
}
public class MainActivity extends AppCompatActivity {
//...
private void captureAndStoreImage(String senderId) {
// listener for file-upload
TaskCompletionListener<String, String> fileUploadListener = new TaskCompletionListener<>() {
@Override
public void onComplete(@Nullable String fileUrl) {
Log.d("VideoSDK", "Uploaded file url: " + fileUrl);
imageTransfer(fileUrl, senderId);
}
@Override
public void onError(@Nullable String error) {
Log.d("VideoSDK", "Error in upload file: " + error);
}
};
//...
}
private void imageTransfer(String fileUrl,String senderId) {
PubSubPublishOptions publishOptions = new PubSubPublishOptions();
publishOptions.setPersist(false);
// Pass the participantId who initiated the request
String[] sendOnly = {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 theIMAGE_TRANSFER
topic to receive thefileUrl
associated with the captured image. -
Once the
fileUrl
is obtained, use thefetchBase64File()
method from theMeeting
class to retrieve the file inbase64
format from VideoSDK's temporary storage.
- Kotlin
- Java
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)
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//...
showCapturedImage();
}
private void showCapturedImage(){
PubSubMessageListener pubSubMessageListener = message -> {
if (!message.getSenderId().equals(meeting.getLocalParticipant().getId())) {
// fetch the image when message received
String url = message.getMessage();
String token = "<VIDEOSDK_TOKEN>";
meeting.fetchBase64File(url, token, new TaskCompletionListener<String, String>() {
@Override
public void onComplete(@Nullable String base64Data) {
// 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
ImageView capturedImage = findViewById(R.id.capturedImage);
byte[] decodedString = Base64.decode(base64Data, Base64.DEFAULT);
Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
capturedImage.setImageBitmap(decodedByte);
}
@Override
public void onError(@Nullable String error) {
Log.d("VideoSDK", "Error in fetch file: " + error);
}
});
}
};
// Subscribe for 'IMAGE_TRANSFER' topic to receive fileUrl
meeting.pubSub.subscribe("IMAGE_TRANSFER", pubSubMessageListener);
}
}
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