#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]
#![allow(clippy::too_many_arguments)]
use std::ffi::{c_char, c_void, CStr};
#[cfg(not(photodna_no_sdk))]
use std::ffi::CString;
pub const PHOTODNA_HASH_SIZE_EDGE_V2: usize = 0x39c;
pub const PHOTODNA_HASH_SIZE_EDGE_V2_BASE64: usize = 0x4d0;
pub const PHOTODNA_HASH_SIZE_MAX: usize = 0x4d0;
pub const PHOTODNA_LIBRARY_VERSION: &str = "1.05";
#[cfg(all(
any(target_os = "windows", target_os = "linux", target_os = "macos"),
not(photodna_no_sdk)
))]
pub const PHOTODNA_SDK_ROOT: &str = env!("PHOTODNA_SDK_ROOT");
#[cfg(all(
any(target_os = "windows", target_os = "linux", target_os = "macos"),
not(photodna_no_sdk)
))]
pub const PHOTODNA_LIB_DIR: &str = env!("PHOTODNA_LIB_DIR");
pub type ErrorCode = u32;
pub const PhotoDna_ErrorUnknown: i32 = -7000;
pub const PhotoDna_ErrorMemoryAllocationFailed: i32 = -7001;
pub const PhotoDna_ErrorHostMemoryAllocationFailed: i32 = -7001;
pub const PhotoDna_ErrorLibraryFailure: i32 = -7002;
pub const PhotoDna_ErrorMemoryAccess: i32 = -7003;
pub const PhotoDna_ErrorInvalidHash: i32 = -7004;
pub const PhotoDna_ErrorHashFormatInvalidCharacters: i32 = -7005;
pub const PhotoDna_ErrorImageTooSmall: i32 = -7006;
pub const PhotoDna_ErrorNoBorder: i32 = -7007;
pub const PhotoDna_ErrorBadArgument: i32 = -7008;
pub const PhotoDna_ErrorImageIsFlat: i32 = -7009;
pub const PhotoDna_ErrorNoBorderImageTooSmall: i32 = -7010;
pub const PhotoDna_ErrorSourceFormatUnknown: i32 = -7011;
pub const PhotoDna_ErrorInvalidStride: i32 = -7012;
pub const PhotoDna_ErrorInvalidSubImage: i32 = -7013;
pub type HashSize = u32;
pub const PhotoDna_EdgeV2: HashSize = 0x0000039c;
pub const PhotoDna_EdgeV2Base64: HashSize = 0x000004d0;
pub const PhotoDna_MaxSize: HashSize = 0x000004d0;
pub type PhotoDnaOptions = u32;
pub const PhotoDna_OptionNone: PhotoDnaOptions = 0x00000000;
pub const PhotoDna_Default: PhotoDnaOptions = 0x00000000;
pub const PhotoDna_HashFormatMask: PhotoDnaOptions = 0x000000f0;
pub const PhotoDna_HashFormatEdgeV2: PhotoDnaOptions = 0x00000080;
pub const PhotoDna_HashFormatEdgeV2Base64: PhotoDnaOptions = 0x00000090;
pub const PhotoDna_PixelLayoutMask: PhotoDnaOptions = 0x00001f00;
pub const PhotoDna_Rgb: PhotoDnaOptions = 0x00000000;
pub const PhotoDna_Bgr: PhotoDnaOptions = 0x00000000;
pub const PhotoDna_Rgba: PhotoDnaOptions = 0x00000100;
pub const PhotoDna_RgbaPm: PhotoDnaOptions = 0x00000700;
pub const PhotoDna_Bgra: PhotoDnaOptions = 0x00000100;
pub const PhotoDna_Argb: PhotoDnaOptions = 0x00000200;
pub const PhotoDna_Abgr: PhotoDnaOptions = 0x00000200;
pub const PhotoDna_Cmyk: PhotoDnaOptions = 0x00000300;
pub const PhotoDna_Grey8: PhotoDnaOptions = 0x00000400;
pub const PhotoDna_Grey32: PhotoDnaOptions = 0x00000500;
pub const PhotoDna_YCbCr: PhotoDnaOptions = 0x00000600;
pub const PhotoDna_Yuv420p: PhotoDnaOptions = 0x00000800;
pub const PhotoDna_RemoveBorder: PhotoDnaOptions = 0x00200000;
pub const PhotoDna_NoRotateFlip: PhotoDnaOptions = 0x01000000;
pub const PhotoDna_CheckMemory: PhotoDnaOptions = 0x20000000;
pub const PhotoDna_Verbose: PhotoDnaOptions = 0x40000000;
pub const PhotoDna_Test: PhotoDnaOptions = 0x60000000;
pub const PhotoDna_Other: PhotoDnaOptions = 0xffffffff;
#[repr(C, packed)]
#[derive(Copy, Clone)]
pub struct HashResult {
pub result: i32,
pub hash_format: i32,
pub header_dimensions_image_x: i32,
pub header_dimensions_image_y: i32,
pub header_dimensions_image_w: i32,
pub header_dimensions_image_h: i32,
pub hash: [u8; PHOTODNA_HASH_SIZE_MAX],
pub reserved0: i32,
pub reserved1: i32,
pub reserved2: i32,
pub reserved3: i32,
pub reserved4: i32,
pub reserved5: i32,
}
impl Default for HashResult {
fn default() -> Self {
Self {
result: 0,
hash_format: 0,
header_dimensions_image_x: 0,
header_dimensions_image_y: 0,
header_dimensions_image_w: 0,
header_dimensions_image_h: 0,
hash: [0u8; PHOTODNA_HASH_SIZE_MAX],
reserved0: 0,
reserved1: 0,
reserved2: 0,
reserved3: 0,
reserved4: 0,
reserved5: 0,
}
}
}
impl core::fmt::Debug for HashResult {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let result = self.result;
let hash_format = self.hash_format;
let x = self.header_dimensions_image_x;
let y = self.header_dimensions_image_y;
let w = self.header_dimensions_image_w;
let h = self.header_dimensions_image_h;
f.debug_struct("HashResult")
.field("result", &result)
.field("hash_format", &hash_format)
.field("x", &x)
.field("y", &y)
.field("w", &w)
.field("h", &h)
.field("hash", &"[...]")
.finish()
}
}
pub type FnEdgeHashGeneratorInit =
unsafe extern "C" fn(library_path: *const c_char, max_threads: i32) -> *mut c_void;
pub type FnEdgeHashGeneratorRelease = unsafe extern "C" fn(library_instance: *mut c_void);
pub type FnGetErrorNumber = unsafe extern "C" fn(library_instance: *mut c_void) -> i32;
pub type FnGetErrorString =
unsafe extern "C" fn(library_instance: *mut c_void, error: i32) -> *const c_char;
pub type FnLibraryVersion = unsafe extern "C" fn(library_instance: *mut c_void) -> i32;
pub type FnLibraryVersionMajor = unsafe extern "C" fn(library_instance: *mut c_void) -> i32;
pub type FnLibraryVersionMinor = unsafe extern "C" fn(library_instance: *mut c_void) -> i32;
pub type FnLibraryVersionPatch = unsafe extern "C" fn(library_instance: *mut c_void) -> i32;
pub type FnLibraryVersionText =
unsafe extern "C" fn(library_instance: *mut c_void) -> *const c_char;
pub type FnPhotoDnaEdgeHash = unsafe extern "C" fn(
library_instance: *mut c_void,
image_data: *const u8,
hash_value: *mut u8,
width: i32,
height: i32,
stride: i32,
options: PhotoDnaOptions,
) -> i32;
pub type FnPhotoDnaEdgeHashBorder = unsafe extern "C" fn(
library_instance: *mut c_void,
image_data: *const u8,
hash_results: *mut HashResult,
max_hash_count: i32,
width: i32,
height: i32,
stride: i32,
options: PhotoDnaOptions,
) -> i32;
pub type FnPhotoDnaEdgeHashBorderSub = unsafe extern "C" fn(
library_instance: *mut c_void,
image_data: *const u8,
hash_results: *mut HashResult,
max_hash_count: i32,
width: i32,
height: i32,
stride: i32,
x: i32,
y: i32,
w: i32,
h: i32,
options: PhotoDnaOptions,
) -> i32;
pub type FnPhotoDnaEdgeHashSub = unsafe extern "C" fn(
library_instance: *mut c_void,
image_data: *const u8,
hash_value: *mut u8,
width: i32,
height: i32,
stride: i32,
x: i32,
y: i32,
w: i32,
h: i32,
options: PhotoDnaOptions,
) -> i32;
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
mod native {
use super::*;
pub fn get_library_filename() -> String {
#[cfg(target_os = "windows")]
{
#[cfg(target_arch = "x86_64")]
{
format!("libEdgeHashGenerator.{}.dll", PHOTODNA_LIBRARY_VERSION)
}
#[cfg(target_arch = "aarch64")]
{
format!(
"libEdgeHashGenerator-arm64.{}.dll",
PHOTODNA_LIBRARY_VERSION
)
}
#[cfg(target_arch = "x86")]
{
format!("libEdgeHashGenerator-x86.{}.dll", PHOTODNA_LIBRARY_VERSION)
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "x86")))]
{
format!("libEdgeHashGenerator.{}.dll", PHOTODNA_LIBRARY_VERSION)
}
}
#[cfg(target_os = "linux")]
{
#[cfg(target_arch = "x86_64")]
{
format!("libEdgeHashGenerator.so.{}", PHOTODNA_LIBRARY_VERSION)
}
#[cfg(target_arch = "aarch64")]
{
format!("libEdgeHashGenerator-arm64.so.{}", PHOTODNA_LIBRARY_VERSION)
}
#[cfg(target_arch = "x86")]
{
format!("libEdgeHashGenerator-x86.so.{}", PHOTODNA_LIBRARY_VERSION)
}
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64", target_arch = "x86")))]
{
format!("libEdgeHashGenerator.so.{}", PHOTODNA_LIBRARY_VERSION)
}
}
#[cfg(target_os = "macos")]
{
#[cfg(target_arch = "aarch64")]
{
format!(
"libEdgeHashGenerator-arm64-macos.so.{}",
PHOTODNA_LIBRARY_VERSION
)
}
#[cfg(not(target_arch = "aarch64"))]
{
format!("libEdgeHashGenerator-macos.so.{}", PHOTODNA_LIBRARY_VERSION)
}
}
}
}
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
pub use native::*;
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
pub struct EdgeHashGenerator {
_library: libloading::Library,
library_instance: *mut c_void,
fn_release: libloading::Symbol<'static, FnEdgeHashGeneratorRelease>,
fn_get_error_number: libloading::Symbol<'static, FnGetErrorNumber>,
fn_get_error_string: libloading::Symbol<'static, FnGetErrorString>,
fn_library_version: libloading::Symbol<'static, FnLibraryVersion>,
fn_library_version_major: libloading::Symbol<'static, FnLibraryVersionMajor>,
fn_library_version_minor: libloading::Symbol<'static, FnLibraryVersionMinor>,
fn_library_version_patch: libloading::Symbol<'static, FnLibraryVersionPatch>,
fn_library_version_text: libloading::Symbol<'static, FnLibraryVersionText>,
fn_photo_dna_edge_hash: libloading::Symbol<'static, FnPhotoDnaEdgeHash>,
fn_photo_dna_edge_hash_border: libloading::Symbol<'static, FnPhotoDnaEdgeHashBorder>,
fn_photo_dna_edge_hash_border_sub: libloading::Symbol<'static, FnPhotoDnaEdgeHashBorderSub>,
fn_photo_dna_edge_hash_sub: libloading::Symbol<'static, FnPhotoDnaEdgeHashSub>,
}
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
impl EdgeHashGenerator {
pub fn new(library_dir: Option<&str>, max_threads: i32) -> Result<Self, String> {
#[cfg(photodna_no_sdk)]
{
let _ = (library_dir, max_threads); Err(
"PhotoDNA SDK not available: PHOTODNA_SDK_ROOT was not set at build time. \
Please rebuild with PHOTODNA_SDK_ROOT environment variable set to the SDK directory."
.to_string(),
)
}
#[cfg(not(photodna_no_sdk))]
{
let lib_dir = library_dir.unwrap_or(PHOTODNA_LIB_DIR);
let lib_filename = get_library_filename();
let lib_path = format!("{}/{}", lib_dir, lib_filename);
unsafe {
let library = libloading::Library::new(&lib_path)
.map_err(|e| format!("Failed to load library '{}': {}", lib_path, e))?;
let fn_init: libloading::Symbol<FnEdgeHashGeneratorInit> = library
.get(b"EdgeHashGeneratorInit\0")
.map_err(|e| format!("Failed to find symbol 'EdgeHashGeneratorInit': {}", e))?;
let fn_release: libloading::Symbol<FnEdgeHashGeneratorRelease> = library
.get(b"EdgeHashGeneratorRelease\0")
.map_err(|e| {
format!("Failed to find symbol 'EdgeHashGeneratorRelease': {}", e)
})?;
let fn_get_error_number: libloading::Symbol<FnGetErrorNumber> = library
.get(b"GetErrorNumber\0")
.map_err(|e| format!("Failed to find symbol 'GetErrorNumber': {}", e))?;
let fn_get_error_string: libloading::Symbol<FnGetErrorString> = library
.get(b"GetErrorString\0")
.map_err(|e| format!("Failed to find symbol 'GetErrorString': {}", e))?;
let fn_library_version: libloading::Symbol<FnLibraryVersion> = library
.get(b"LibraryVersion\0")
.map_err(|e| format!("Failed to find symbol 'LibraryVersion': {}", e))?;
let fn_library_version_major: libloading::Symbol<FnLibraryVersionMajor> = library
.get(b"LibraryVersionMajor\0")
.map_err(|e| format!("Failed to find symbol 'LibraryVersionMajor': {}", e))?;
let fn_library_version_minor: libloading::Symbol<FnLibraryVersionMinor> = library
.get(b"LibraryVersionMinor\0")
.map_err(|e| format!("Failed to find symbol 'LibraryVersionMinor': {}", e))?;
let fn_library_version_patch: libloading::Symbol<FnLibraryVersionPatch> = library
.get(b"LibraryVersionPatch\0")
.map_err(|e| format!("Failed to find symbol 'LibraryVersionPatch': {}", e))?;
let fn_library_version_text: libloading::Symbol<FnLibraryVersionText> = library
.get(b"LibraryVersionText\0")
.map_err(|e| format!("Failed to find symbol 'LibraryVersionText': {}", e))?;
let fn_photo_dna_edge_hash: libloading::Symbol<FnPhotoDnaEdgeHash> = library
.get(b"PhotoDnaEdgeHash\0")
.map_err(|e| format!("Failed to find symbol 'PhotoDnaEdgeHash': {}", e))?;
let fn_photo_dna_edge_hash_border: libloading::Symbol<FnPhotoDnaEdgeHashBorder> =
library.get(b"PhotoDnaEdgeHashBorder\0").map_err(|e| {
format!("Failed to find symbol 'PhotoDnaEdgeHashBorder': {}", e)
})?;
let fn_photo_dna_edge_hash_border_sub: libloading::Symbol<
FnPhotoDnaEdgeHashBorderSub,
> = library
.get(b"PhotoDnaEdgeHashBorderSub\0")
.map_err(|e| {
format!("Failed to find symbol 'PhotoDnaEdgeHashBorderSub': {}", e)
})?;
let fn_photo_dna_edge_hash_sub: libloading::Symbol<FnPhotoDnaEdgeHashSub> =
library.get(b"PhotoDnaEdgeHashSub\0").map_err(|e| {
format!("Failed to find symbol 'PhotoDnaEdgeHashSub': {}", e)
})?;
let c_lib_dir = CString::new(lib_dir).map_err(|e| e.to_string())?;
let library_instance = fn_init(c_lib_dir.as_ptr(), max_threads);
if library_instance.is_null() {
return Err("Failed to initialize PhotoDNA library".to_string());
}
#[allow(clippy::missing_transmute_annotations)]
let fn_release = std::mem::transmute(fn_release);
#[allow(clippy::missing_transmute_annotations)]
let fn_get_error_number = std::mem::transmute(fn_get_error_number);
#[allow(clippy::missing_transmute_annotations)]
let fn_get_error_string = std::mem::transmute(fn_get_error_string);
#[allow(clippy::missing_transmute_annotations)]
let fn_library_version = std::mem::transmute(fn_library_version);
#[allow(clippy::missing_transmute_annotations)]
let fn_library_version_major = std::mem::transmute(fn_library_version_major);
#[allow(clippy::missing_transmute_annotations)]
let fn_library_version_minor = std::mem::transmute(fn_library_version_minor);
#[allow(clippy::missing_transmute_annotations)]
let fn_library_version_patch = std::mem::transmute(fn_library_version_patch);
#[allow(clippy::missing_transmute_annotations)]
let fn_library_version_text = std::mem::transmute(fn_library_version_text);
#[allow(clippy::missing_transmute_annotations)]
let fn_photo_dna_edge_hash = std::mem::transmute(fn_photo_dna_edge_hash);
#[allow(clippy::missing_transmute_annotations)]
let fn_photo_dna_edge_hash_border =
std::mem::transmute(fn_photo_dna_edge_hash_border);
#[allow(clippy::missing_transmute_annotations)]
let fn_photo_dna_edge_hash_border_sub =
std::mem::transmute(fn_photo_dna_edge_hash_border_sub);
#[allow(clippy::missing_transmute_annotations)]
let fn_photo_dna_edge_hash_sub = std::mem::transmute(fn_photo_dna_edge_hash_sub);
Ok(Self {
_library: library,
library_instance,
fn_release,
fn_get_error_number,
fn_get_error_string,
fn_library_version,
fn_library_version_major,
fn_library_version_minor,
fn_library_version_patch,
fn_library_version_text,
fn_photo_dna_edge_hash,
fn_photo_dna_edge_hash_border,
fn_photo_dna_edge_hash_border_sub,
fn_photo_dna_edge_hash_sub,
})
}
}
}
pub fn raw_instance(&self) -> *mut c_void {
self.library_instance
}
pub fn get_error_number(&self) -> i32 {
unsafe { (self.fn_get_error_number)(self.library_instance) }
}
pub fn get_error_string(&self, error: i32) -> Option<&str> {
unsafe {
let ptr = (self.fn_get_error_string)(self.library_instance, error);
if ptr.is_null() {
None
} else {
CStr::from_ptr(ptr).to_str().ok()
}
}
}
pub fn library_version(&self) -> i32 {
unsafe { (self.fn_library_version)(self.library_instance) }
}
pub fn library_version_major(&self) -> i32 {
unsafe { (self.fn_library_version_major)(self.library_instance) }
}
pub fn library_version_minor(&self) -> i32 {
unsafe { (self.fn_library_version_minor)(self.library_instance) }
}
pub fn library_version_patch(&self) -> i32 {
unsafe { (self.fn_library_version_patch)(self.library_instance) }
}
pub fn library_version_text(&self) -> Option<&str> {
unsafe {
let ptr = (self.fn_library_version_text)(self.library_instance);
if ptr.is_null() {
None
} else {
CStr::from_ptr(ptr).to_str().ok()
}
}
}
pub unsafe fn photo_dna_edge_hash(
&self,
image_data: *const u8,
hash_value: *mut u8,
width: i32,
height: i32,
stride: i32,
options: PhotoDnaOptions,
) -> i32 {
(self.fn_photo_dna_edge_hash)(
self.library_instance,
image_data,
hash_value,
width,
height,
stride,
options,
)
}
pub unsafe fn photo_dna_edge_hash_border(
&self,
image_data: *const u8,
hash_results: *mut HashResult,
max_hash_count: i32,
width: i32,
height: i32,
stride: i32,
options: PhotoDnaOptions,
) -> i32 {
(self.fn_photo_dna_edge_hash_border)(
self.library_instance,
image_data,
hash_results,
max_hash_count,
width,
height,
stride,
options,
)
}
pub unsafe fn photo_dna_edge_hash_border_sub(
&self,
image_data: *const u8,
hash_results: *mut HashResult,
max_hash_count: i32,
width: i32,
height: i32,
stride: i32,
x: i32,
y: i32,
w: i32,
h: i32,
options: PhotoDnaOptions,
) -> i32 {
(self.fn_photo_dna_edge_hash_border_sub)(
self.library_instance,
image_data,
hash_results,
max_hash_count,
width,
height,
stride,
x,
y,
w,
h,
options,
)
}
pub unsafe fn photo_dna_edge_hash_sub(
&self,
image_data: *const u8,
hash_value: *mut u8,
width: i32,
height: i32,
stride: i32,
x: i32,
y: i32,
w: i32,
h: i32,
options: PhotoDnaOptions,
) -> i32 {
(self.fn_photo_dna_edge_hash_sub)(
self.library_instance,
image_data,
hash_value,
width,
height,
stride,
x,
y,
w,
h,
options,
)
}
}
#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))]
impl Drop for EdgeHashGenerator {
fn drop(&mut self) {
unsafe {
(self.fn_release)(self.library_instance);
}
}
}
#[cfg(any(
all(
feature = "wasm",
not(any(target_os = "windows", target_os = "linux", target_os = "macos"))
),
target_os = "openbsd",
target_os = "freebsd",
target_os = "netbsd",
target_os = "dragonfly",
))]
pub mod wasm {
pub const PHOTODNA_WASM_BYTES: &[u8] = include_bytes!(env!("PHOTODNA_WASM_PATH"));
pub const PHOTODNA_WASM_SIZE: usize = PHOTODNA_WASM_BYTES.len();
}
#[cfg(any(
all(
feature = "wasm",
not(any(target_os = "windows", target_os = "linux", target_os = "macos"))
),
target_os = "openbsd",
target_os = "freebsd",
target_os = "netbsd",
target_os = "dragonfly",
))]
pub use wasm::*;
pub const fn error_code_description(code: i32) -> &'static str {
match code {
0 => "Success",
PhotoDna_ErrorUnknown => "An undetermined error occurred",
PhotoDna_ErrorMemoryAllocationFailed => "Failed to allocate memory",
PhotoDna_ErrorLibraryFailure => "General failure within the library",
PhotoDna_ErrorMemoryAccess => "System memory exception occurred",
PhotoDna_ErrorInvalidHash => "Hash does not conform to PhotoDNA specifications",
PhotoDna_ErrorHashFormatInvalidCharacters => "Invalid character in Base64 or Hex hash",
PhotoDna_ErrorImageTooSmall => "Image dimension is less than 50 pixels",
PhotoDna_ErrorNoBorder => "No border was detected for the image",
PhotoDna_ErrorBadArgument => "An invalid argument was passed to the function",
PhotoDna_ErrorImageIsFlat => "Image has few or no gradients",
PhotoDna_ErrorNoBorderImageTooSmall => "No border; image too small after border removal",
PhotoDna_ErrorSourceFormatUnknown => "Not a known source image format",
PhotoDna_ErrorInvalidStride => "Stride should be 0 or >= width in bytes",
PhotoDna_ErrorInvalidSubImage => "Sub region is not within image boundaries",
_ => "Unknown error code",
}
}
pub const fn hash_size_for_options(options: PhotoDnaOptions) -> usize {
let format = options & PhotoDna_HashFormatMask;
if format == PhotoDna_HashFormatEdgeV2Base64 {
PHOTODNA_HASH_SIZE_EDGE_V2_BASE64
} else {
PHOTODNA_HASH_SIZE_EDGE_V2
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hash_result_size() {
assert_eq!(
core::mem::size_of::<HashResult>(),
4 + 4 + 4 + 4 + 4 + 4 + PHOTODNA_HASH_SIZE_MAX + 4 * 6
);
}
#[test]
fn test_error_code_descriptions() {
assert_eq!(error_code_description(0), "Success");
assert_eq!(
error_code_description(PhotoDna_ErrorImageTooSmall),
"Image dimension is less than 50 pixels"
);
}
#[test]
fn test_hash_size_for_options() {
assert_eq!(
hash_size_for_options(PhotoDna_Default),
PHOTODNA_HASH_SIZE_EDGE_V2
);
assert_eq!(
hash_size_for_options(PhotoDna_HashFormatEdgeV2Base64),
PHOTODNA_HASH_SIZE_EDGE_V2_BASE64
);
}
#[test]
fn test_constants() {
assert_eq!(PHOTODNA_HASH_SIZE_EDGE_V2, 924);
assert_eq!(PHOTODNA_HASH_SIZE_EDGE_V2_BASE64, 1232);
assert_eq!(PhotoDna_EdgeV2 as usize, PHOTODNA_HASH_SIZE_EDGE_V2);
}
#[test]
#[cfg(all(
any(target_os = "windows", target_os = "linux", target_os = "macos"),
not(photodna_no_sdk)
))]
fn test_sdk_paths() {
assert!(!PHOTODNA_SDK_ROOT.is_empty());
assert!(!PHOTODNA_LIB_DIR.is_empty());
}
}