Support UTF8 to UTF16 LE
This commit is contained in:
@@ -1583,7 +1583,7 @@ namespace ANSCENTER {
|
||||
}
|
||||
|
||||
LogThreadSafe("ANSFacialRecognition::UpdateUser",
|
||||
"Successfully updated user ID " + std::to_string(userId));
|
||||
"Successfully updated user ID " + std::to_string(userId), LogLevel::Info);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -2350,6 +2350,32 @@ namespace ANSCENTER {
|
||||
}
|
||||
|
||||
// Using nlohmann/json (much faster)
|
||||
static std::string DoubleEscapeUnicode(const std::string& utf8Str) {
|
||||
bool hasNonAscii = false;
|
||||
for (unsigned char c : utf8Str) {
|
||||
if (c >= 0x80) { hasNonAscii = true; break; }
|
||||
}
|
||||
if (!hasNonAscii) return utf8Str;
|
||||
std::string result;
|
||||
result.reserve(utf8Str.size() * 2);
|
||||
size_t i = 0;
|
||||
while (i < utf8Str.size()) {
|
||||
unsigned char c = static_cast<unsigned char>(utf8Str[i]);
|
||||
if (c < 0x80) { result += utf8Str[i++]; continue; }
|
||||
uint32_t cp = 0;
|
||||
if ((c & 0xE0) == 0xC0 && i + 1 < utf8Str.size()) {
|
||||
cp = ((c & 0x1F) << 6) | (static_cast<unsigned char>(utf8Str[i + 1]) & 0x3F); i += 2;
|
||||
} else if ((c & 0xF0) == 0xE0 && i + 2 < utf8Str.size()) {
|
||||
cp = ((c & 0x0F) << 12) | ((static_cast<unsigned char>(utf8Str[i + 1]) & 0x3F) << 6) | (static_cast<unsigned char>(utf8Str[i + 2]) & 0x3F); i += 3;
|
||||
} else if ((c & 0xF8) == 0xF0 && i + 3 < utf8Str.size()) {
|
||||
cp = ((c & 0x07) << 18) | ((static_cast<unsigned char>(utf8Str[i + 1]) & 0x3F) << 12) | ((static_cast<unsigned char>(utf8Str[i + 2]) & 0x3F) << 6) | (static_cast<unsigned char>(utf8Str[i + 3]) & 0x3F); i += 4;
|
||||
} else { i++; continue; }
|
||||
if (cp <= 0xFFFF) { char buf[8]; snprintf(buf, sizeof(buf), "\\u%04x", cp); result += buf; }
|
||||
else { cp -= 0x10000; char buf[16]; snprintf(buf, sizeof(buf), "\\u%04x\\u%04x", 0xD800 + (uint16_t)(cp >> 10), 0xDC00 + (uint16_t)(cp & 0x3FF)); result += buf; }
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string ANSFacialRecognition::FaceObjectsToJsonString(const std::vector<FaceResultObject>& faces) {
|
||||
START_TIMER(json_total);
|
||||
|
||||
@@ -2361,7 +2387,7 @@ namespace ANSCENTER {
|
||||
for (const auto& face : faces) {
|
||||
results.push_back({
|
||||
{"user_id", face.userId},
|
||||
{"user_name", face.userName},
|
||||
{"user_name", DoubleEscapeUnicode(face.userName)},
|
||||
{"similarity", std::to_string(face.similarity)},
|
||||
{"is_unknown", std::to_string(face.isUnknown)},
|
||||
{"prob", std::to_string(face.confidence)},
|
||||
@@ -2399,7 +2425,7 @@ namespace ANSCENTER {
|
||||
nlohmann::json detectedNode;
|
||||
detectedNode["class_id"] = std::to_string(det.classId);
|
||||
detectedNode["track_id"] = std::to_string(det.trackId);
|
||||
detectedNode["class_name"] = det.className;
|
||||
detectedNode["class_name"] = DoubleEscapeUnicode(det.className);
|
||||
detectedNode["prob"] = std::to_string(det.confidence);
|
||||
detectedNode["x"] = std::to_string(det.box.x);
|
||||
detectedNode["y"] = std::to_string(det.box.y);
|
||||
|
||||
@@ -351,4 +351,8 @@ extern "C" ANSFR_API int GetFaces(ANSCENTER::ANSFacialRecognition * *Handle,i
|
||||
extern "C" ANSFR_API int DeleteFacesByUser(ANSCENTER::ANSFacialRecognition * *Handle,int userId);
|
||||
extern "C" ANSFR_API double BlurCalculation(unsigned char* jpeg_string, unsigned int bufferLength);
|
||||
|
||||
// Unicode conversion utilities for LabVIEW wrapper classes
|
||||
extern "C" ANSFR_API int ANSFR_ConvertUTF8ToUTF16LE(const char* utf8Str, LStrHandle result);
|
||||
extern "C" ANSFR_API int ANSFR_ConvertUTF16LEToUTF8(const unsigned char* utf16leBytes, int byteLen, LStrHandle result);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -750,6 +750,103 @@ extern "C" ANSFR_API double BlurCalculation(unsigned char* jpeg_string, un
|
||||
}
|
||||
|
||||
|
||||
// Unicode conversion utilities for LabVIEW wrapper classes
|
||||
extern "C" ANSFR_API int ANSFR_ConvertUTF8ToUTF16LE(const char* utf8Str, LStrHandle result) {
|
||||
try {
|
||||
if (!utf8Str || !result) return -1;
|
||||
int len = (int)strlen(utf8Str);
|
||||
if (len == 0) return 0;
|
||||
bool hasUnicodeEscapes = false;
|
||||
bool hasNonAscii = false;
|
||||
for (int i = 0; i < len; i++) {
|
||||
if ((unsigned char)utf8Str[i] >= 0x80) hasNonAscii = true;
|
||||
if (i + 1 < len && utf8Str[i] == '\\' && utf8Str[i + 1] == 'u') hasUnicodeEscapes = true;
|
||||
}
|
||||
if (!hasNonAscii && !hasUnicodeEscapes) {
|
||||
MgErr error = DSSetHandleSize(result, sizeof(int32) + len * sizeof(uChar));
|
||||
if (error != noErr) return -2;
|
||||
(*result)->cnt = len;
|
||||
memcpy((*result)->str, utf8Str, len);
|
||||
return 1;
|
||||
}
|
||||
if (hasUnicodeEscapes) {
|
||||
std::string utf16le;
|
||||
utf16le.reserve(len * 2);
|
||||
for (int i = 0; i < len; ) {
|
||||
if (i + 5 < len && utf8Str[i] == '\\' && utf8Str[i + 1] == 'u') {
|
||||
char hex[5] = { utf8Str[i + 2], utf8Str[i + 3], utf8Str[i + 4], utf8Str[i + 5], 0 };
|
||||
uint16_t cp = (uint16_t)strtoul(hex, nullptr, 16);
|
||||
utf16le += static_cast<char>(cp & 0xFF);
|
||||
utf16le += static_cast<char>((cp >> 8) & 0xFF);
|
||||
i += 6;
|
||||
} else {
|
||||
utf16le += utf8Str[i];
|
||||
utf16le += '\0';
|
||||
i++;
|
||||
}
|
||||
}
|
||||
int size = (int)utf16le.size();
|
||||
MgErr error = DSSetHandleSize(result, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error != noErr) return -2;
|
||||
(*result)->cnt = size;
|
||||
memcpy((*result)->str, utf16le.data(), size);
|
||||
return 1;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
int wideLen = MultiByteToWideChar(CP_UTF8, 0, utf8Str, len, nullptr, 0);
|
||||
if (wideLen <= 0) return 0;
|
||||
std::wstring wideStr(wideLen, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, utf8Str, len, &wideStr[0], wideLen);
|
||||
int size = wideLen * (int)sizeof(wchar_t);
|
||||
MgErr error = DSSetHandleSize(result, sizeof(int32) + size * sizeof(uChar));
|
||||
if (error != noErr) return -2;
|
||||
(*result)->cnt = size;
|
||||
memcpy((*result)->str, wideStr.data(), size);
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
catch (...) { return -1; }
|
||||
}
|
||||
|
||||
extern "C" ANSFR_API int ANSFR_ConvertUTF16LEToUTF8(const unsigned char* utf16leBytes, int byteLen, LStrHandle result) {
|
||||
try {
|
||||
if (!utf16leBytes || byteLen <= 0 || !result) return -1;
|
||||
bool isUtf16le = (byteLen >= 2 && byteLen % 2 == 0);
|
||||
if (isUtf16le) {
|
||||
bool isAscii = true;
|
||||
for (int i = 1; i < byteLen; i += 2) {
|
||||
if (utf16leBytes[i] != 0x00) { isAscii = false; break; }
|
||||
}
|
||||
if (isAscii) {
|
||||
int asciiLen = byteLen / 2;
|
||||
MgErr error = DSSetHandleSize(result, sizeof(int32) + asciiLen * sizeof(uChar));
|
||||
if (error != noErr) return -2;
|
||||
(*result)->cnt = asciiLen;
|
||||
for (int i = 0; i < asciiLen; i++) (*result)->str[i] = utf16leBytes[i * 2];
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#ifdef _WIN32
|
||||
int wideLen = byteLen / (int)sizeof(wchar_t);
|
||||
const wchar_t* wideStr = reinterpret_cast<const wchar_t*>(utf16leBytes);
|
||||
int utf8Len = WideCharToMultiByte(CP_UTF8, 0, wideStr, wideLen, nullptr, 0, nullptr, nullptr);
|
||||
if (utf8Len <= 0) return 0;
|
||||
std::string utf8Str(utf8Len, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, wideStr, wideLen, &utf8Str[0], utf8Len, nullptr, nullptr);
|
||||
MgErr error = DSSetHandleSize(result, sizeof(int32) + utf8Len * sizeof(uChar));
|
||||
if (error != noErr) return -2;
|
||||
(*result)->cnt = utf8Len;
|
||||
memcpy((*result)->str, utf8Str.data(), utf8Len);
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
catch (...) { return -1; }
|
||||
}
|
||||
|
||||
extern "C" ANSFR_API int UpdateParameters(ANSCENTER::ANSFacialRecognition** Handle, float knownPersonThreshold, int enableAgeGender, int enableFaceEmotions, int enableHeadPose, int minFaceSize, float faceDetectorThreshold, int enableFaceliveness, int antiSpoof, int removeFakeFaces) {
|
||||
try {
|
||||
if (!Handle || !*Handle) return -1;
|
||||
|
||||
Reference in New Issue
Block a user