#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <cstring>
#include "public.h"
#include "CapPicture.h"
#include "rapidjson/document.h" / Core JSON parsing
#include "rapidjson/error/en.h" / Error handling (optional)
#include "unistd.h"
#include <iostream>
#include <fstream>
#include <curl/curl.h>
#include <string>
#define DVR_IP "10.0.0.10" / Replace with your device IP
#define DVR_PORT 8000 / Replace with your device port
#define USERNAME "admin" / Replace with your device username
#define PASSWORD "Ambition" / Replace with your device password
using namespace std;
LONG lUserID = -1; / Global User ID for login session
#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
#include <iomanip>
/ Base64 encoding table
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
/ Function to encode binary data to Base64
std::string base64_encode(const std::vector<unsigned char> &data) {
std::string encoded;
int val = 0, valb = -6;
for (unsigned char c : data) {
val = (val << 8) + c;
valb += 8;
while (valb >= 0) {
encoded.push_back(base64_chars[(val >> valb) & 0x3F]);
valb -= 6;
}
}
if (valb > -6) {
encoded.push_back(base64_chars[((val << 8) >> (valb + 8)) & 0x3F]);
}
while (encoded.size() % 4) {
encoded.push_back('=');
}
return encoded;
}
/ Function to read an image file and encode it as Base64 Data URL
std::string image_to_base64(const std::string &file_path) {
/ Open the image file in binary mode
std::ifstream file(file_path, std::ios::binary);
if (!file) {
std::cerr << "Error: Could not open file " << file_path << std::endl;
return "";
}
/ Read file contents into a byte vector
std::vector<unsigned char> buffer(std::istreambuf_iterator<char>(file), {});
/ Encode the binary data into Base64
std::string base64_str = base64_encode(buffer);
/ Construct the Data URL
return "data:image/jpeg;base64," + base64_str;
}
bool SendFaceImageToFDLib(const std::string& deviceIP, const std::string& username, const std::string& password,
const std::string& fdid, const std::string& fpid, const std::string& faceImagePath) {
CURL* curl = curl_easy_init();
if (!curl) {
std::cerr << "Failed to initialize cURL" << std::endl;
return false;
}
/ API URL
std::string url = "http://" + deviceIP + "/ISAPI/Intelligent/FDLib/FDSetUp?format=json";
/ Setup authentication
std::string authHeader = username + ":" + password;
/ JSON metadata (FaceDataRecord)
std::string faceDataRecord = "{\"faceLibType\":\"blackFD\",\"FDID\":\"" + fdid + "\",\"FPID\":\"" + fpid + "\"}";
/ Create multipart form-data
curl_mime* mime = curl_mime_init(curl);
curl_mimepart* part;
/ Add FaceDataRecord JSON
part = curl_mime_addpart(mime);
curl_mime_name(part, "FaceDataRecord");
curl_mime_data(part, faceDataRecord.c_str(), CURL_ZERO_TERMINATED);
curl_mime_type(part, "application/json");
/ Add Image File
part = curl_mime_addpart(mime);
curl_mime_name(part, "img");
curl_mime_filedata(part, faceImagePath.c_str());
curl_mime_type(part, "image/jpeg");
/ Set cURL options
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_easy_setopt(curl, CURLOPT_USERPWD, authHeader.c_str());
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); / Enable debug output
/ Perform the request
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK) {
std::cerr << "Failed to upload face image: " << curl_easy_strerror(res) << std::endl;
curl_mime_free(mime);
curl_easy_cleanup(curl);
return false;
}
std::cout << "Face image uploaded successfully!" << std::endl;
/ Cleanup
curl_mime_free(mime);
curl_easy_cleanup(curl);
return true;
}
void CheckAndPrintError() {
DWORD err = NET_DVR_GetLastError();
if (err != 0) {
std::cout << "Error: " << err << std::endl;
}
}
bool SendXMLRequest(const char* method, const char* url, const char* xmlData, char* responseBuffer, DWORD responseSize) {
NET_DVR_XML_CONFIG_INPUT inputParam = {0};
NET_DVR_XML_CONFIG_OUTPUT outputParam = {0};
std::string fullRequest = std::string(method) + " " + url;
inputParam.dwSize = sizeof(inputParam);
inputParam.lpRequestUrl = (void*)(fullRequest.c_str());
inputParam.dwRequestUrlLen = strlen(fullRequest.c_str());
inputParam.lpInBuffer = (void*)xmlData;
inputParam.dwInBufferSize = xmlData ? strlen(xmlData) : 0;
outputParam.dwSize = sizeof(outputParam);
outputParam.lpOutBuffer = responseBuffer;
outputParam.dwOutBufferSize = responseSize;
if (!NET_DVR_STDXMLConfig(lUserID, &inputParam, &outputParam)) {
std::cout << fullRequest << " request failed!" << std::endl;
CheckAndPrintError();
return false;
}
std::cout << fullRequest << " request successful!" << std::endl;
return true;
}
/ Convert image file to Base64
std::string ConvertImageToBase64(const std::string& imagePath) {
std::ifstream file(imagePath, std::ios::binary);
if (!file) {
std::cerr << "Error: Unable to open image file: " << imagePath << std::endl;
return "";
}
std::ostringstream base64Stream;
base64Stream << file.rdbuf();
std::string imageData = base64Stream.str();
/ Convert to Base64 (Use a proper Base64 encoder here if required)
return imageData;
}
/ Send person details and image to Hikvision FDLib
bool SendPersonWithPicture(const std::string& name, const std::string& personID, const std::string& imagePath) {
char responseBuffer[8192] = {0};
/ Convert image to Base64
std::string base64Image = ConvertImageToBase64(imagePath);
if (base64Image.empty()) {
std::cerr << "Error: Failed to convert image to Base64!" << std::endl;
return false;
}
/ Construct XML payload
std::string xmlPayload = R"(
<FaceAppendData version="2.0" xmlns="http://www.isapi.org/ver20/XMLSchema">
<bornTime>1990-01-01</bornTime>
<name>)" + name + R"(</name>
<sex>male</sex>
<province>California</province>
<city>Los Angeles</city>
<certificateType>ID</certificateType>
<certificateNumber>)" + personID + R"(</certificateNumber>
<PersonInfoExtendList>
<PersonInfoExtend>
<id>1</id>
<enable>true</enable>
<name>Company</name>
<value>XYZ Corp</value>
</PersonInfoExtend>
</PersonInfoExtendList>
<caseInfo>Security Alert</caseInfo>
<customHumanID>)" + personID + R"(</customHumanID>
<phoneNumber>+1234567890</phoneNumber>
<RegionCoordinatesList>
<RegionCoordinates>
<positionX>100</positionX>
<positionY>150</positionY>
</RegionCoordinates>
</RegionCoordinatesList>
<faceLibType>blackFD</faceLibType>
<faceURL>data:image/jpeg;base64,)" + base64Image + R"(</faceURL>
</FaceAppendData>)";
/ Send request to add person to blackFD
bool success = SendXMLRequest("POST", "/ISAPI/Intelligent/FDLib/blackFD/picture", xmlPayload.c_str(), responseBuffer, sizeof(responseBuffer));
if (success) {
std::cout << "Person successfully added to blackFD: " << name << std::endl;
} else {
std::cerr << "Failed to add person to blackFD!" << std::endl;
}
return success;
}
bool InitAndLogin() {
/ Initialize SDK
if (!NET_DVR_Init()) {
std::cout << "SDK Initialization Failed!" << std::endl;
return false;
}
/ Set connection timeout and reconnection options
NET_DVR_SetConnectTime(2000, 1);
NET_DVR_SetReconnect(10000, true);
/ Login to the device
NET_DVR_USER_LOGIN_INFO loginInfo = {0};
NET_DVR_DEVICEINFO_V40 deviceInfo = {0};
strcpy(loginInfo.sDeviceAddress, DVR_IP);
strcpy(loginInfo.sUserName, USERNAME);
strcpy(loginInfo.sPassword, PASSWORD);
loginInfo.wPort = DVR_PORT;
loginInfo.bUseAsynLogin = false;
lUserID = NET_DVR_Login_V40(&loginInfo, &deviceInfo);
if (lUserID < 0) {
std::cout << "Login failed!" << std::endl;
CheckAndPrintError();
return false;
}
std::cout << "Login successful!" << std::endl;
return true;
}
void GetSystemCapabilities() {
char response[4194304] = {0};
SendXMLRequest("GET", "/ISAPI/System/capabilities", nullptr, response, sizeof(response));
std::cout << "System Capabilities Response: " << response << std::endl;
}
void GetFaceLibraryCapabilities() {
char response[2048] = {0};
SendXMLRequest("GET", "/ISAPI/Intelligent/FDLib/capabilities", nullptr, response, sizeof(response));
std::cout << "Capabilities Response: " << response << std::endl;
}
void GetDeviceCapabilities() {
char response[2048] = {0};
std::string XmlPayload = R"(<AcsAbility version="2.0">
<!--opt, specify child nodes about access control capabilities to be returned-->
</AcsAbility>)";
bool res = NET_DVR_GetDeviceAbility(lUserID,
ACS_ABILITY,
nullptr,
0,
response,
sizeof(response));
std::cout << "Capabilities Response: " << response << std::endl;
}
void getFaceLibInfo(int lUserID) {
/ Construct the request URL
/std::string url = "/ISAPI/Intelligent/FDLib";
std::string url = "/ISAPI/FaceRecognition/FDLib";
/ Prepare the input parameters structure
NET_DVR_XML_CONFIG_INPUT netDvrXmlConfigInput = {0};
netDvrXmlConfigInput.lpRequestUrl = (void*) (malloc((url.length()+ 1) * sizeof(char)));
strcpy((char*)(netDvrXmlConfigInput.lpRequestUrl), url.c_str());
netDvrXmlConfigInput.dwRequestUrlLen = url.length();
netDvrXmlConfigInput.lpInBuffer = nullptr; / No additional input data
netDvrXmlConfigInput.dwInBufferSize = 0;
netDvrXmlConfigInput.dwSize = sizeof(netDvrXmlConfigInput);
/ Prepare output structures
char responseBuffer[8192] = {0}; / Allocate buffer for the response
char statusBuffer[1024] = {0}; / Allocate buffer for status message
NET_DVR_XML_CONFIG_OUTPUT struXMLOutput = {0};
struXMLOutput.dwSize = sizeof(struXMLOutput);
struXMLOutput.lpOutBuffer = responseBuffer;
struXMLOutput.dwOutBufferSize = sizeof(responseBuffer);
struXMLOutput.lpStatusBuffer = statusBuffer;
struXMLOutput.dwStatusSize = sizeof(statusBuffer);
SendXMLRequest("GET", "/ISAPI/Intelligent/FDLib?count=1", nullptr, responseBuffer, sizeof(responseBuffer));
/ Execute ISAPI request
if (!NET_DVR_STDXMLConfig(lUserID,&netDvrXmlConfigInput, &struXMLOutput)) {
std::cout << "NET_DVR_STDXMLConfig failed! Error: " << NET_DVR_GetLastError() << std::endl;
return;
}
/ Print the response
std::cout << "Device Face Library Info Response: " << responseBuffer << std::endl;
std::cout << "Response Status: " << statusBuffer << std::endl;
}
void CreateFaceLibrary() {
char response1[8192] = {0};
char response2[2048] = {0};
const char* createXML = R"(<FaceLibrary><name>TestLib</name><type>ordinary</type></FaceLibrary>)";
SendXMLRequest("GET", "/ISAPI/Intelligent/FDLib?start=0&count=5", nullptr, response1, sizeof(response1));
std::cout << "Get Library Response: " << response1 << std::endl;
SendXMLRequest("POST", "/ISAPI/Intelligent/FDLib", createXML, response2, sizeof(response2));
std::cout << "Create Library Response: " << response2 << std::endl;
}
string SearchFaceLibrary() {
char response1[2048] = {0};
char response2[2048] = {0};
char response3[32768] = {0};
char response4[2048] = {0};
char response5[2048] = {0};
char response6[2048] = {0};
char response7[2048] = {0};
SendXMLRequest("GET", "/ISAPI/Intelligent/FDLib?start=0&count=5", nullptr, response1, sizeof(response1));
std::cout << "Search Library Response: " << response1 << std::endl;
/SendXMLRequest("GET", "/ISAPI/Intelligent/FDLib/2?start=0&count=5", nullptr, response2, sizeof(response2));
/std::cout << "Search Library Response: " << response2 << std::endl;
char* createJSON = R"({
"searchResultPosition":0,
"maxResults":5,
"faceLibType":"blackFD",
"FDID":"1",
"FPID":"2"
})";
SendXMLRequest("POST", "/ISAPI/Intelligent/FDLib/FDSearch?format=json", createJSON, response2, sizeof(response2));
std::cout << "Search Library Response: " << response2 << std::endl;
createJSON = R"({
"UserInfoSearchCond":{
"searchID":"1",
"searchResultPosition": 0,
"maxResults": 10
}
})";
SendXMLRequest("POST", "/ISAPI/AccessControl/UserInfo/Search?format=json", createJSON, response3, sizeof(response3));
std::cout << "Search Library Response: " << response3 << std::endl;
SendXMLRequest("GET", "/ISAPI/AccessControl/UserInfo/capabilities?format=json", nullptr, response4, sizeof(response4));
std::cout << "Search Library Response: " << response4 << std::endl;
SendXMLRequest("GET", "/ISAPI/AccessControl/FaceRecognizeMode?format=json", nullptr, response5, sizeof(response5));
std::cout << "Search Library Response: " << response5 << std::endl;
SendXMLRequest("GET", "/ISAPI/Intelligent/FDLib/capabilities?format=json", nullptr, response6, sizeof(response6));
std::cout << "Search Library Response: " << response6 << std::endl;
createJSON = R"({
"UserInfo":{
"employeeNo":"000132",
"name":"John Tukey",
"userType":"normal",
"doorRight":"1",
"RightPlan":[{"doorNo":1,"planTemplateNo":"1"}],
"gender":"male",
"localUIRight":false,
"maxOpenDoorTime":0,
"userVerifyMode":"",
"Valid":{
"enable":true,
"beginTime":"2025-02-22T00:00:00",
"endTime":"2035-02-22T23:59:59",
"timeType":"local"
}}
})";
SendXMLRequest("POST", "/ISAPI/AccessControl/UserInfo/Record?format=json", createJSON, response6, sizeof(response6));
std::cout << "Search Library Response: " << response6 << std::endl;
std::string file_path = "./face.jpg"; / Change this to your image path
std::string base64_url = image_to_base64(file_path);
if (!base64_url.empty()) {
std::cout << "Base64 Data URL:\n" << base64_url << std::endl;
}
/ Correct JSON string
std::string imgJSON = R"({
"faceURL": ")" + base64_url + R"(",
"faceLibType": "blackFD",
"FDID": "1",
"FPID": "000132"
})";
SendXMLRequest("POST", "/ISAPI/Intelligent/FDLib/FaceDataRecord?format=json", imgJSON.c_str(), response7, sizeof(response7));
std::cout << "Search Library Response: " << response7 << std::endl;
rapidjson::Document doc;
doc.Parse(response1);
if (!doc.HasMember("FDLib") || !doc["FDLib"].IsArray()) {
std::cerr << "Invalid response format!" << std::endl;
return "";
}
for (const auto& lib : doc["FDLib"].GetArray()) {
if (lib.HasMember("FDID") && lib["FDID"].IsString()) {
std::cout << "Found Face Library ID: " << lib["FDID"].GetString() << std::endl;
return lib["FDID"].GetString(); / Return first FDID found
}
}
return "";
}
void EditFaceLibrary(const char* fdID) {
char response[2048] = {0};
std::string url = "/ISAPI/Intelligent/FDLib/" + std::string(fdID);
const char* editXML = R"(<FaceLibrary><name>UpdatedLib</name></FaceLibrary>)";
SendXMLRequest("PUT", url.c_str(), editXML, response, sizeof(response));
std::cout << "Edit Library Response: " << response << std::endl;
}
void DeleteFaceLibrary(const char* fdID) {
char response[2048] = {0};
std::string url = "/ISAPI/Intelligent/FDLib/" + std::string(fdID);
SendXMLRequest("DELETE", url.c_str(), nullptr, response, sizeof(response));
std::cout << "Delete Library Response: " << response << std::endl;
}
void LogoutAndCleanup() {
if (lUserID >= 0) {
NET_DVR_Logout(lUserID);
std::cout << "Logged out successfully!" << std::endl;
}
NET_DVR_Cleanup();
}
bool UploadFacePicture(LONG userID, const std::string& imagePath, const std::string& faceLibId) {
if (userID < 0) {
std::cerr << "Invalid user ID!" << std::endl;
return false;
}
if (faceLibId.empty()) {
std::cerr << "No valid Face Library found!" << std::endl;
return false;
}
/ Open image file
std::ifstream file(imagePath, std::ios::binary | std::ios::ate);
if (!file.is_open()) {
std::cerr << "Error: Unable to open image file: " << imagePath << std::endl;
return false;
}
size_t fileSize = file.tellg();
file.seekg(0, std::ios::beg);
std::vector<char> imageData(fileSize);
file.read(imageData.data(), fileSize);
file.close();
/ Step 1: Initialize upload
NET_DVR_FACELIB_COND faceLibCond = {0};
faceLibCond.dwSize = sizeof(NET_DVR_FACELIB_COND);
/ Assign the retrieved Face Library ID
/strncpy(faceLibCond.szFDID, faceLibId.c_str(), sizeof(faceLibCond.szFDID) - 1);
/strncpy(faceLibCond.szFDID, faceLibId.c_str(), NET_SDK_MAX_FDID_LEN); / FDID dynamically retrieved
strncpy(faceLibCond.szFDID, faceLibId.c_str(), faceLibId.length()); / FDID dynamically retrieved
/faceLibCond.dwFaceLibType = 0; / Default type
/faceLibCond.dwUploadType = 39; / IMPORT_DATA_TO_FACELIB
/ Set other parameters
faceLibCond.byConcurrent = 0; / Disable concurrent processing
faceLibCond.byCover = 1; / Enable overwriting if full
faceLibCond.byCustomFaceLibID = 0; / Use system-generated FaceLibID
/ Identity Key (if required, else set to empty)
memset(faceLibCond.byIdentityKey, 0, sizeof(faceLibCond.byIdentityKey));
LONG uploadHandle = NET_DVR_UploadFile_V40(
userID, / From NET_DVR_Login_V40
39, / dwUploadType: IMPORT_DATA_TO_FACELIB
&faceLibCond, / lpInBuffer: Pointer to our condition structure
sizeof(NET_DVR_FACELIB_COND), / dwInBufferSize: Size of structure
imageData.data(), / sFileName: Path to image file
nullptr, / lpOutBuffer: Optional output buffer (nullptr if not used)
0 / dwOutBufferSize: 0 since we are not using an output buffer
);
if (uploadHandle < 0) {
std::cerr << "Upload init failed! Error: " << NET_DVR_GetLastError() << std::endl;
return false;
}
/ Step 2: Send face data using NET_DVR_UploadSend
NET_DVR_SEND_PARAM_IN sendParam = {0};
/ Fill sendParam with the data to upload
int result = NET_DVR_UploadSend(uploadHandle, &sendParam, NULL);
if (result < 0) {
std::cerr << "UploadSend failed! Error: " << NET_DVR_GetLastError() << std::endl;
NET_DVR_UploadClose(uploadHandle);
return false;
}
/ Step 3: Monitor upload progress
DWORD progress = 0;
while (progress != 1) {
if (!NET_DVR_GetUploadState(uploadHandle, &progress)) {
std::cerr << "Error getting upload state: " << NET_DVR_GetLastError() << std::endl;
NET_DVR_UploadClose(uploadHandle);
return false;
}
std::cout << "Upload progress: " << progress * 100 << "%" << std::endl;
sleep(500);
}
/ Step 4: Retrieve upload result
char resultBuffer[256] = {0}; / Buffer to receive upload result
if (!NET_DVR_GetUploadResult(uploadHandle, resultBuffer, sizeof(resultBuffer))) {
std::cerr << "Error retrieving upload result: " << NET_DVR_GetLastError() << std::endl;
NET_DVR_UploadClose(uploadHandle);
return false;
} else {
std::cout << "Upload successful! Picture ID: " << resultBuffer << std::endl;
}
/ Step 5: Close upload session
NET_DVR_UploadClose(uploadHandle);
return true;
}
int Demo_Capture()
{
if (!InitAndLogin()) return -1;
GetSystemCapabilities();
GetFaceLibraryCapabilities();
string faceLibID = SearchFaceLibrary();
if (faceLibID.empty()) {
std::cerr << "No valid Face Library found!" << std::endl;
return false;
}
/GetDeviceCapabilities();
/UploadFacePicture(lUserID, "./face.jpg", faceLibID);
/ Add a person to the blackFD library
std::string deviceIP = "10.0.0.10"; / Replace with your device IP
std::string username = "admin";
std::string password = "Ambition";
std::string fdid = "1"; / Face Library ID
std::string fpid = "000132"; / Unique Face ID
std::string faceImagePath = "face.jpg"; / Image file path
/bool success = SendFaceImageToFDLib(deviceIP, username, password, fdid, fpid, faceImagePath);
/return success ? 0 : 1;
/SendPersonWithPicture("John Doe", "123456", "face.jpg");
/ SearchFaceLibrary();
/ Assuming an FDLib ID is retrieved from the search response
/ const char* testFDID = "3"; / Replace with actual ID
/ EditFaceLibrary(testFDID);
/DeleteFaceLibrary(testFDID);
LogoutAndCleanup();
return 0;
}