Image Capturer - Flutter
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. - The
captureImage()
function returns the image in the form of abase64
string.
void imageCapture() async {
// captureImage will return base64 string
String? base64 = await room.localParticipant.captureImage(
height: 400,
width: 400,
);
print("Base64 Image captured $base64Image");
}
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.
class MeetingScreen extends StatefulWidget {
const MeetingScreen({Key? key}) : super(key: key);
@override
_MeetingScreenState createState() => _MeetingScreenState();
}
class _MeetingScreenState extends State<MeetingScreen> {
late Room _room;
// send Request to participant
void sendRequest(String participantId) {
// 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
if (participantId != meeting.localParticipant.id) {
var publishOptions = PubSubPublishOptions(
persist: false,
sendOnly: [participantId],
);
// create pubsub topic to send Request
_room.pubSub.publish(
"IMAGE_CAPTURE",
"Sending request to capture image",
publishOptions,
);
}
}
@override
Widget build(BuildContext context) {
return Column(children: [
ElevatedButton(
onPressed: () {
sendRequest("enter the participant ID to send image capture request");
},
child: Text("Capture Image"),
),
]);
}
}
Step 2 : Capture and Upload File​
- To capture an image from a remote participant [Participant B] . you need to subscribe to a topic called
IMAGE_CAPTURE
. When you receive an image capture request, you will capture the image using thecaptureImage()
method of theParticipant
class.
class MeetingScreen extends StatefulWidget {
const MeetingScreen({Key? key}) : super(key: key);
@override
_MeetingScreenState createState() => _MeetingScreenState();
}
class _MeetingScreenState extends State<MeetingScreen> {
late Room _room;
void messageHandler(PubSubMessage message) {
if (message.senderId != _room.localParticipant.id) {
captureAndStoreImage(message.senderId);
}
}
// capture and store image when message received
void captureAndStoreImage(String senderId) async {
// capture image
String? base64Data = await _room.localParticipant.captureImage(
height: 400,
width: 400,
);
print("base64Data : $base64Data");
}
// subscribe to receive request
void registerMeetingEvents(Room _room) {
_room.on(
Events.roomJoined,
() async {
_room.pubSub.subscribe("IMAGE_CAPTURE", messageHandler);
},
);
}
}
- The captured image is then stored in VideoSDK's temporary file storage system using the
uploadBase64File()
function of theRoom
class. This operation returns a uniquefileUrl
of the stored image.
void captureAndStoreImage(String senderId) async {
// capture image
String? base64Data = await meeting.localParticipant.captureImage(
height: 400,
width: 400,
);
String token = "<VIDEOSDK_TOKEN>";
String fileName = "myCapture.jpeg"; // specify a name for image file with extension
// upload image to videosdk storage system
String? url = await meeting.uploadBase64File(
base64Data: base64Data!,
token: token,
fileName: fileName,
);
print("Image URL: $url");
}
- Next, the
fileUrl
is sent back to the participant who initiated the request using theIMAGE_TRANSFER
topic.
void captureAndStoreImage(String senderId) async {
String? base64Data = await meeting.localParticipant.captureImage(
height: 400,
width: 400,
);
String token = "<VIDEOSDK_TOKEN>";
String fileName = "myCapture.jpeg";
String? url = await meeting.uploadBase64File(
base64Data: base64Data!,
token: token,
fileName: fileName,
);
// publish image Transfer
PubSubPublishOptions options = PubSubPublishOptions(
persist: false,
sendOnly: [senderId],
);
meeting.pubSub.publish(
"IMAGE_TRANSFER",
url!,
options,
);
}
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 theRoom
class to retrieve the file inbase64
format from VideoSDK's temporary storage.
void showCapturedImage() async {
PubSubMessages messages = await meeting.pubSub.subscribe(
"IMAGE_TRANSFER",
(PubSubMessage message) async {
if (message.senderId != meeting.localParticipant.id) {
String url = message.message;
String token = "<VIDEOSDK_TOKEN>";
String? base64 = await meeting.fetchBase64File(
url: url, // pass fileUrl to fetch the file
token: token,
);
print("base64 $base64"); // here is your image in the form of base64
}
},
);
}
- With the
base64
data in hand. we can convert it intoUint8List
using Dart'sbase64Decode()
method. ThisUint8List
can then be used to render the image on the screen usingImage.memory()
widget.
class MeetingScreen extends StatefulWidget {
const MeetingScreen({Key? key}) : super(key: key);
@override
_MeetingScreenState createState() => _MeetingScreenState();
}
class _MeetingScreenState extends State<MeetingScreen> {
Uint8List? _capturedImage;
void showCapturedImage() async {
PubSubMessages messages = await meeting.pubSub.subscribe(
"IMAGE_TRANSFER",
(PubSubMessage message) async {
if (message.senderId != meeting.localParticipant.id) {
String url = message.message;
String token = "<VIDEOSDK_TOKEN>";
String? base64 = await meeting.fetchBase64File(
url: url, // pass fileUrl to fetch the file
token: token,
);
// set state to set _capturedImage to the obtain base64 string
setState(() {
_capturedImage = base64Decode(base64!);
});
}
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("Captured Image")),
body: Center(
// Display the image
child: _capturedImage != null
? Image.memory(_capturedImage!)
: const Text("Waiting for image..."),
),
);
}
}
The file stored in the 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