//--------------------------------------------------------------------------------------------------
// Copyright (c) id3 Technologies
// All Rights Reserved.
//--------------------------------------------------------------------------------------------------
// ignore_for_file: unused_import
import 'dart:ffi';
import 'dart:typed_data';
import 'package:ffi/ffi.dart';
import 'face_sdk_generated_bindings.dart';
import 'face_native.dart';

import '../id3_face.dart';

final _finalizer = NativeFinalizer(faceSDK.addresses.id3FaceAnalyser_Dispose.cast());

/// Provides methods for analysing the characteristics of portrait image.
class FaceAnalyser implements Finalizable {
  /// Native handle.
  late Pointer<Pointer<id3FaceAnalyser>> _pHandle;
  bool _disposable = true;

  /// Gets the native handle.
  /// return The native handle.
  Pointer<id3FaceAnalyser> get handle => _pHandle.value;

  /// Creates a new instance of the FaceAnalyser class.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  FaceAnalyser() {
    _pHandle = calloc();
    try {
      var err = faceSDK.id3FaceAnalyser_Initialize(_pHandle);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      _finalizer.attach(this, _pHandle.cast(), detach: this);
    } finally {}
  }

  /// Creates a new instance of the FaceAnalyser class.
  ///
  /// param handle     Handle to the FaceAnalyser.
  /// throws FaceException An error has occurred during Face Library execution.
  FaceAnalyser.fromHandle(Pointer<id3FaceAnalyser> handle) {
    _pHandle = calloc();
    _pHandle.value = handle;
    _disposable = false;
  }

  /// Releases all resources used by this FaceAnalyser.
  void dispose() {
    if (_disposable) {
      faceSDK.id3FaceAnalyser_Dispose(_pHandle);
      calloc.free(_pHandle);
      _finalizer.detach(this);
    }
  }


  ///
  /// Sensibility of the expression classifier.
  /// The higher the value, the more sensitive the algorithm will be, meaning that it will be less likely to estimate neutral expression out of the detected face.
  /// Hint: Default value is 60.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get expressionSensibility => getExpressionSensibility();
  set expressionSensibility(int value) => setExpressionSensibility(value);

  ///
  /// Sensibility of the over-exposure classifier, from 0 to 255.
  /// The lower the value, the more sensitive the algorithm will be, meaning that it will be more likely to estimate over-exposed face images.
  /// Hint: Default value is 188.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get overExposureSensibility => getOverExposureSensibility();
  set overExposureSensibility(int value) => setOverExposureSensibility(value);

  ///
  /// Number of threads to be used for face analysis.
  /// Hint: Default value is 1. Allocating more than one thread can increase the speed of the process.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get threadCount => getThreadCount();
  set threadCount(int value) => setThreadCount(value);

  ///
  /// Sensibility of the under-exposure classifier, from 0 to 255.
  /// The higher the value, the more sensitive the algorithm will be, meaning that it will be more likely to estimate under-exposed face images.
  /// Hint: Default value is 66.
  ///
  /// throws FaceException An error has occurred during Face Library execution.
  int get underExposureSensibility => getUnderExposureSensibility();
  set underExposureSensibility(int value) => setUnderExposureSensibility(value);

  // Public methods
  /// Gets the sensibility of the expression classifier.
  /// The higher the value, the more sensitive the algorithm will be, meaning that it will be less likely to estimate neutral expression out of the detected face.
  /// Hint: Default value is 60.
  ///
  /// return Sensibility of the expression classifier.
  /// throws FaceException An error has occurred during Face Library execution.
  int getExpressionSensibility() {
    Pointer<Int> pExpressionSensibility = calloc();
    try {
      var err = faceSDK.id3FaceAnalyser_GetExpressionSensibility(_pHandle.value, pExpressionSensibility);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vExpressionSensibility = pExpressionSensibility.value;
      return vExpressionSensibility;
    } finally {
      calloc.free(pExpressionSensibility);
    }
  }

  /// Sets the sensibility of the expression classifier.
  /// The higher the value, the more sensitive the algorithm will be, meaning that it will be less likely to estimate neutral expression out of the detected face.
  /// Hint: Default value is 60.
  ///
  /// param expressionSensibility Sensibility of the expression classifier.
  /// throws FaceException An error has occurred during Face Library execution.
  void setExpressionSensibility(int expressionSensibility) {
    var err = faceSDK.id3FaceAnalyser_SetExpressionSensibility(_pHandle.value, expressionSensibility);
    if (err != FaceError.success.value) {
      throw FaceException(err);
    }
  }

  /// Gets the sensibility of the over-exposure classifier, from 0 to 255.
  /// The lower the value, the more sensitive the algorithm will be, meaning that it will be more likely to estimate over-exposed face images.
  /// Hint: Default value is 188.
  ///
  /// return Sensibility of the over-exposure classifier, from 0 to 255.
  /// throws FaceException An error has occurred during Face Library execution.
  int getOverExposureSensibility() {
    Pointer<Int> pOverExposureSensibility = calloc();
    try {
      var err = faceSDK.id3FaceAnalyser_GetOverExposureSensibility(_pHandle.value, pOverExposureSensibility);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vOverExposureSensibility = pOverExposureSensibility.value;
      return vOverExposureSensibility;
    } finally {
      calloc.free(pOverExposureSensibility);
    }
  }

  /// Sets the sensibility of the over-exposure classifier, from 0 to 255.
  /// The lower the value, the more sensitive the algorithm will be, meaning that it will be more likely to estimate over-exposed face images.
  /// Hint: Default value is 188.
  ///
  /// param overExposureSensibility Sensibility of the over-exposure classifier, from 0 to 255.
  /// throws FaceException An error has occurred during Face Library execution.
  void setOverExposureSensibility(int overExposureSensibility) {
    var err = faceSDK.id3FaceAnalyser_SetOverExposureSensibility(_pHandle.value, overExposureSensibility);
    if (err != FaceError.success.value) {
      throw FaceException(err);
    }
  }

  /// Gets the number of threads to be used for face analysis.
  /// Hint: Default value is 1. Allocating more than one thread can increase the speed of the process.
  ///
  /// return Number of threads to be used for face analysis.
  /// throws FaceException An error has occurred during Face Library execution.
  int getThreadCount() {
    Pointer<Int> pThreadCount = calloc();
    try {
      var err = faceSDK.id3FaceAnalyser_GetThreadCount(_pHandle.value, pThreadCount);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vThreadCount = pThreadCount.value;
      return vThreadCount;
    } finally {
      calloc.free(pThreadCount);
    }
  }

  /// Sets the number of threads to be used for face analysis.
  /// Hint: Default value is 1. Allocating more than one thread can increase the speed of the process.
  ///
  /// param threadCount Number of threads to be used for face analysis.
  /// throws FaceException An error has occurred during Face Library execution.
  void setThreadCount(int threadCount) {
    var err = faceSDK.id3FaceAnalyser_SetThreadCount(_pHandle.value, threadCount);
    if (err != FaceError.success.value) {
      throw FaceException(err);
    }
  }

  /// Gets the sensibility of the under-exposure classifier, from 0 to 255.
  /// The higher the value, the more sensitive the algorithm will be, meaning that it will be more likely to estimate under-exposed face images.
  /// Hint: Default value is 66.
  ///
  /// return Sensibility of the under-exposure classifier, from 0 to 255.
  /// throws FaceException An error has occurred during Face Library execution.
  int getUnderExposureSensibility() {
    Pointer<Int> pUnderExposureSensibility = calloc();
    try {
      var err = faceSDK.id3FaceAnalyser_GetUnderExposureSensibility(_pHandle.value, pUnderExposureSensibility);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vUnderExposureSensibility = pUnderExposureSensibility.value;
      return vUnderExposureSensibility;
    } finally {
      calloc.free(pUnderExposureSensibility);
    }
  }

  /// Sets the sensibility of the under-exposure classifier, from 0 to 255.
  /// The higher the value, the more sensitive the algorithm will be, meaning that it will be more likely to estimate under-exposed face images.
  /// Hint: Default value is 66.
  ///
  /// param underExposureSensibility Sensibility of the under-exposure classifier, from 0 to 255.
  /// throws FaceException An error has occurred during Face Library execution.
  void setUnderExposureSensibility(int underExposureSensibility) {
    var err = faceSDK.id3FaceAnalyser_SetUnderExposureSensibility(_pHandle.value, underExposureSensibility);
    if (err != FaceError.success.value) {
      throw FaceException(err);
    }
  }

  /// Applies an alpha mask to suppress the background and returns a 32-bit BGRA image.
  ///
  /// param image Source image to process.
  /// param mask Mask of segmented face.
  /// return The output image.
  /// throws FaceException An error has occurred during Face Library execution.
  Image applyAlphaMask(Image image, Image mask) {
    Image segmentedFace = Image();
    var err = faceSDK.id3FaceAnalyser_ApplyAlphaMask(_pHandle.value, image.handle, mask.handle, segmentedFace.handle);
    if (err != FaceError.success.value) {
      segmentedFace.dispose();
      throw FaceException(err);
    }
    return segmentedFace;
  }

  /// Applies a mask to replace the background with the specified color and returns a 24-bit BGR image.
  ///
  /// param image Source image to process.
  /// param mask Mask to be applied. Must be a 8-bit greyscale image of same size as the input image.
  /// param red Green channel of the background color. Must be a value from 0 to 255.
  /// param green Red channel of the background color. Must be a value from 0 to 255.
  /// param blue Blue channel of the background color. Must be a value from 0 to 255.
  /// return The output image.
  /// throws FaceException An error has occurred during Face Library execution.
  Image applyMask(Image image, Image mask, int red, int green, int blue) {
    Image segmentedFace = Image();
    var err = faceSDK.id3FaceAnalyser_ApplyMask(_pHandle.value, image.handle, mask.handle, red, green, blue, segmentedFace.handle);
    if (err != FaceError.success.value) {
      segmentedFace.dispose();
      throw FaceException(err);
    }
    return segmentedFace;
  }

  /// Verifies if an image is colorized or grayscale.
  ///
  /// param image Source image to process.
  /// return The boolean decision: True if colorized, False if grayscale.
  /// throws FaceException An error has occurred during Face Library execution.
  bool checkColorizedImage(Image image) {
    Pointer<Bool> pIsColorized = calloc();
    try {
      var err = faceSDK.id3FaceAnalyser_CheckColorizedImage(_pHandle.value, image.handle, pIsColorized);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vIsColorized = pIsColorized.value;
      return vIsColorized;
    } finally {
      calloc.free(pIsColorized);
    }
  }

  /// Computes the age of a detected face.
  /// Important: Loading the ``FaceAgeEstimator`` model is required to use this function.
  ///
  /// param image Source image to process.
  /// param detectedFace Detected face to process.
  /// return The estimated age of the detected face.
  /// throws FaceException An error has occurred during Face Library execution.
  int computeAge(Image image, DetectedFace detectedFace) {
    Pointer<Int> pAge = calloc();
    try {
      var err = faceSDK.id3FaceAnalyser_ComputeAge(_pHandle.value, image.handle, detectedFace.handle, pAge);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vAge = pAge.value;
      return vAge;
    } finally {
      calloc.free(pAge);
    }
  }

  /// Computes the attributes of a detected face.
  /// Important: Loading the model ``FaceAttributesClassifier`` is required to use this function.
  ///
  /// param image Source image to process.
  /// param detectedFace Detected face to process.
  /// return The estimated attributes of the detected face.
  /// throws FaceException An error has occurred during Face Library execution.
  FaceAttributes computeAttributes(Image image, DetectedFace detectedFace) {
    Pointer<id3FaceAttributes> pAttributes = calloc();
    var err = faceSDK.id3FaceAnalyser_ComputeAttributes(_pHandle.value, image.handle, detectedFace.handle, pAttributes);
    if (err != FaceError.success.value) {
    	calloc.free(pAttributes);
    	throw FaceException(err);
    }
    return FaceAttributes(pAttributes);
  }

  /// Computes the background uniformity behind a detected face.
  /// This function must be used for a portrait image with only one face in it. A high uniformity score means that the background is uniform.
  /// Important: Loading the model ``FaceBackgroundUniformity`` is required to use this function.
  ///
  /// param image Source image to process.
  /// param detectedFace Detected face to process.
  /// return The estimated background uniformity. Both color and texture scores are in the range (0:100). The minimum recommended thresholds are respectively 80 for color and 80 for texture.
  /// throws FaceException An error has occurred during Face Library execution.
  BackgroundUniformity computeBackgroundUniformity(Image image, DetectedFace detectedFace) {
    Pointer<id3FaceBackgroundUniformity> pBackgroundUniformity = calloc();
    var err = faceSDK.id3FaceAnalyser_ComputeBackgroundUniformity(_pHandle.value, image.handle, detectedFace.handle, pBackgroundUniformity);
    if (err != FaceError.success.value) {
    	calloc.free(pBackgroundUniformity);
    	throw FaceException(err);
    }
    return BackgroundUniformity(pBackgroundUniformity);
  }

  /// Computes the expression of a detected face.
  /// Important: Loading the ``FaceExpressionClassifier`` model is required to use this function.
  ///
  /// param image Source image to process.
  /// param detectedFace Detected face to process.
  /// return The estimated expression of the detected face.
  /// throws FaceException An error has occurred during Face Library execution.
  FaceExpression computeExpression(Image image, DetectedFace detectedFace) {
    Pointer<Int32> pExpression = calloc();
    try {
      var err = faceSDK.id3FaceAnalyser_ComputeExpression(_pHandle.value, image.handle, detectedFace.handle, pExpression);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vExpression = FaceExpressionX.fromValue(pExpression.value);
      return vExpression;
    } finally {
      calloc.free(pExpression);
    }
  }

  /// Computes the eye gaze of a detected face.
  /// Important: Loading the ``EyeGazeEstimator`` model is required to use this function.
  ///
  /// param image Source image to process.
  /// param detectedFace Detected face to process.
  /// param landmarks Estimated landmarks of the detected face. Must be computed with the face analyser.
  /// return The estimated gaze of left and right eyes of the detected face.
  /// throws FaceException An error has occurred during Face Library execution.
  EyeGaze computeEyeGaze(Image image, DetectedFace detectedFace, PointList landmarks) {
    Pointer<id3FaceEyeGaze> pEyeGaze = calloc();
    var err = faceSDK.id3FaceAnalyser_ComputeEyeGaze(_pHandle.value, image.handle, detectedFace.handle, landmarks.handle, pEyeGaze);
    if (err != FaceError.success.value) {
    	calloc.free(pEyeGaze);
    	throw FaceException(err);
    }
    return EyeGaze(pEyeGaze);
  }

  /// Computes the eye openness of a detected face.
  /// The minimum recommanded value for is 90.
  /// Important: Loading the ``EyeOpennessDetector`` model is required to use this function.
  ///
  /// param image Source image to process.
  /// param detectedFace Detected face to process.
  /// param landmarks Estimated landmarks of the detected face. Must be computed with the face analyser.
  /// return The estimated openness scores of left and right eyes of the detected face in this order.
  /// throws FaceException An error has occurred during Face Library execution.
  List<int> computeEyeOpenness(Image image, DetectedFace detectedFace, PointList landmarks) {
    Pointer<Int> pEyeOpennessScores = calloc.allocate(2);
    Pointer<Int> pEyeOpennessScoresSize = calloc.allocate(1);
    pEyeOpennessScoresSize[0] = 2;
    try {
      var err = faceSDK.id3FaceAnalyser_ComputeEyeOpenness(_pHandle.value, image.handle, detectedFace.handle, landmarks.handle, pEyeOpennessScores, pEyeOpennessScoresSize);
      if (err == FaceError.insufficientBuffer.value) {
        calloc.free(pEyeOpennessScores);
        pEyeOpennessScores = calloc.allocate(pEyeOpennessScoresSize.value);
        err = faceSDK.id3FaceAnalyser_ComputeEyeOpenness(_pHandle.value, image.handle, detectedFace.handle, landmarks.handle, pEyeOpennessScores, pEyeOpennessScoresSize);
      }
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vEyeOpennessScores = Int32List.fromList(pEyeOpennessScores.cast<Int32>().asTypedList(pEyeOpennessScoresSize.value));
      return vEyeOpennessScores;
    } finally {
      calloc.free(pEyeOpennessScores);
      calloc.free(pEyeOpennessScoresSize);
    }
  }

  /// Computes the eye redness of a detected face.
  /// The maximum recommanded value for an ICAO-compliant portrait is 10.
  /// Important: Loading the ``EyeRednessDetector`` model is required to use this function.
  ///
  /// param image Source image to process.
  /// param detectedFace Detected face to process.
  /// param landmarks Estimated landmarks of the detected face. Must be computed with the face analyser.
  /// return The estimated redness scores of left and right eyes of the detected face in this order.
  /// throws FaceException An error has occurred during Face Library execution.
  List<int> computeEyeRedness(Image image, DetectedFace detectedFace, PointList landmarks) {
    Pointer<Int> pEyeRednessScores = calloc.allocate(2);
    Pointer<Int> pEyeRednessScoresSize = calloc.allocate(1);
    pEyeRednessScoresSize[0] = 2;
    try {
      var err = faceSDK.id3FaceAnalyser_ComputeEyeRedness(_pHandle.value, image.handle, detectedFace.handle, landmarks.handle, pEyeRednessScores, pEyeRednessScoresSize);
      if (err == FaceError.insufficientBuffer.value) {
        calloc.free(pEyeRednessScores);
        pEyeRednessScores = calloc.allocate(pEyeRednessScoresSize.value);
        err = faceSDK.id3FaceAnalyser_ComputeEyeRedness(_pHandle.value, image.handle, detectedFace.handle, landmarks.handle, pEyeRednessScores, pEyeRednessScoresSize);
      }
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vEyeRednessScores = Int32List.fromList(pEyeRednessScores.cast<Int32>().asTypedList(pEyeRednessScoresSize.value));
      return vEyeRednessScores;
    } finally {
      calloc.free(pEyeRednessScores);
      calloc.free(pEyeRednessScoresSize);
    }
  }

  /// Computes the geometric attributes of a detected face. This function must be used for a portrait image with only one face in it.
  ///
  /// param image Source image to process.
  /// param detectedFace Detected face to process.
  /// param landmarks Estimated landmarks of the detected face. Must be computed with the face analyser.
  /// return The estimated geometric attributes of the detected face.
  /// throws FaceException An error has occurred during Face Library execution.
  GeometricAttributes computeGeometricAttributes(Image image, DetectedFace detectedFace, PointList landmarks) {
    Pointer<id3FaceGeometricAttributes> pGeometricAttributes = calloc();
    var err = faceSDK.id3FaceAnalyser_ComputeGeometricAttributes(_pHandle.value, image.handle, detectedFace.handle, landmarks.handle, pGeometricAttributes);
    if (err != FaceError.success.value) {
    	calloc.free(pGeometricAttributes);
    	throw FaceException(err);
    }
    return GeometricAttributes(pGeometricAttributes);
  }

  /// Computes the glasses attributes of a detected face. This function must be used for a portrait image with only one face in it.
  ///
  /// param image Source image to process.
  /// param detectedFace Detected face to process.
  /// param landmarks Estimated landmarks of the detected face. Must be computed with the face analyser.
  /// return The estimated glasses attributes of the detected face.
  /// throws FaceException An error has occurred during Face Library execution.
  GlassesAttributes computeGlassesAttributes(Image image, DetectedFace detectedFace, PointList landmarks) {
    Pointer<id3FaceGlassesAttributes> pGlassesAttributes = calloc();
    var err = faceSDK.id3FaceAnalyser_ComputeGlassesAttributes(_pHandle.value, image.handle, detectedFace.handle, landmarks.handle, pGlassesAttributes);
    if (err != FaceError.success.value) {
    	calloc.free(pGlassesAttributes);
    	throw FaceException(err);
    }
    return GlassesAttributes(pGlassesAttributes);
  }

  /// Computes 68 landmarks of a detected face.
  /// Important: Loading the ``FaceLandmarksEstimator`` model is required to use this function.
  ///
  /// param image Source image to process.
  /// param detectedFace Detected face to process.
  /// return The estimated landmarks of the detected face.
  /// throws FaceException An error has occurred during Face Library execution.
  PointList computeLandmarks(Image image, DetectedFace detectedFace) {
    PointList landmarks = PointList();
    var err = faceSDK.id3FaceAnalyser_ComputeLandmarks(_pHandle.value, image.handle, detectedFace.handle, landmarks.handle);
    if (err != FaceError.success.value) {
      landmarks.dispose();
      throw FaceException(err);
    }
    return landmarks;
  }

  /// Measures the image noise.
  ///
  /// param image Source image to process.
  /// return The estimated noise score. 0 means no noise, 100 means no signal.
  /// throws FaceException An error has occurred during Face Library execution.
  int computeNoise(Image image) {
    Pointer<Int> pNoiseScore = calloc();
    try {
      var err = faceSDK.id3FaceAnalyser_ComputeNoise(_pHandle.value, image.handle, pNoiseScore);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vNoiseScore = pNoiseScore.value;
      return vNoiseScore;
    } finally {
      calloc.free(pNoiseScore);
    }
  }

  /// Computes the photographic attributes of a detected face. This function must be used for a portrait image with only one face in it.
  ///
  /// param image Source image to process.
  /// param detectedFace Detected face to process.
  /// param landmarks Estimated landmarks of the detected face. Must be computed with the face analyser.
  /// return The estimated photographic attributes of the detected face.
  /// throws FaceException An error has occurred during Face Library execution.
  PhotographicAttributes computePhotographicAttributes(Image image, DetectedFace detectedFace, PointList landmarks) {
    Pointer<id3FacePhotographicAttributes> pPhotographicAttributes = calloc();
    var err = faceSDK.id3FaceAnalyser_ComputePhotographicAttributes(_pHandle.value, image.handle, detectedFace.handle, landmarks.handle, pPhotographicAttributes);
    if (err != FaceError.success.value) {
    	calloc.free(pPhotographicAttributes);
    	throw FaceException(err);
    }
    return PhotographicAttributes(pPhotographicAttributes);
  }

  /// Computes the pose of a detected face.
  /// Important: Loading the ``FacePoseEstimator`` model is required to use this function.
  ///
  /// param detectedFace Detected face to process.
  /// return The estimated pose of the detected face.
  /// throws FaceException An error has occurred during Face Library execution.
  FacePose computePose(DetectedFace detectedFace) {
    Pointer<id3FacePose> pPose = calloc();
    var err = faceSDK.id3FaceAnalyser_ComputePose(_pHandle.value, detectedFace.handle, pPose);
    if (err != FaceError.success.value) {
    	calloc.free(pPose);
    	throw FaceException(err);
    }
    return FacePose(pPose);
  }

  /// Computes the pose of a detected face using the specified 68-point landmarks.
  /// Loading the model ``FacePoseEstimator1A`` is required to use this function.
  ///
  /// param detectedFace Detected face to process.
  /// param landmarks Estimated landmarks of the detected face. Must be computed with the face analyser.
  /// return The estimated pose of the detected face.
  /// throws FaceException An error has occurred during Face Library execution.
  FacePose computePoseWithLandmarks(DetectedFace detectedFace, PointList landmarks) {
    Pointer<id3FacePose> pPose = calloc();
    var err = faceSDK.id3FaceAnalyser_ComputePoseWithLandmarks(_pHandle.value, detectedFace.handle, landmarks.handle, pPose);
    if (err != FaceError.success.value) {
    	calloc.free(pPose);
    	throw FaceException(err);
    }
    return FacePose(pPose);
  }

  /// Detects the presence of a face mask on a detected face.
  /// A high score means that there is a high chance that the person is wearing a mask.
  /// The minimum recommended threshold is 15.
  /// Important: Loading the ``FaceMaskClassifier``, model is required to use this function.
  ///
  /// param image Source image to process.
  /// param detectedFace Detected face to process.
  /// return The face mask presence score of the detected face.
  /// throws FaceException An error has occurred during Face Library execution.
  int detectFaceMask(Image image, DetectedFace detectedFace) {
    Pointer<Int> pScore = calloc();
    try {
      var err = faceSDK.id3FaceAnalyser_DetectFaceMask(_pHandle.value, image.handle, detectedFace.handle, pScore);
      if (err != FaceError.success.value) {
        throw FaceException(err);
      }
      final vScore = pScore.value;
      return vScore;
    } finally {
      calloc.free(pScore);
    }
  }

  /// Detects occlusions on the subject's face.
  /// Important: This function requires the ``FaceOcclusionDetector`` model to be loaded.
  ///
  /// param image Source image to process.
  /// param detectedFace Detected face to process.
  /// return The occlusion scores of the detected face.
  /// throws FaceException An error has occurred during Face Library execution.
  FaceOcclusionScores detectOcclusions(Image image, DetectedFace detectedFace) {
    Pointer<id3FaceOcclusionScores> pScores = calloc();
    var err = faceSDK.id3FaceAnalyser_DetectOcclusions(_pHandle.value, image.handle, detectedFace.handle, pScores);
    if (err != FaceError.success.value) {
    	calloc.free(pScores);
    	throw FaceException(err);
    }
    return FaceOcclusionScores(pScores);
  }

  /// Upscale and enhance the image of a face.
  /// Important: This methods requires the ``CompressionArtifactRemover`` model to be loaded.
  ///
  /// param image Source image to process.
  /// return The enhanced face.
  /// throws FaceException An error has occurred during Face Library execution.
  Image removeCompressionArtifacts(Image image) {
    Image enhancedImage = Image();
    var err = faceSDK.id3FaceAnalyser_RemoveCompressionArtifacts(_pHandle.value, image.handle, enhancedImage.handle);
    if (err != FaceError.success.value) {
      enhancedImage.dispose();
      throw FaceException(err);
    }
    return enhancedImage;
  }

  /// Computes face segmentation mask for background removal.
  /// Important: This methods requires the ``FaceBackgroundSegmenter`` model to be loaded.
  ///
  /// param image Source image to process.
  /// return The mask of segmented face.
  /// throws FaceException An error has occurred during Face Library execution.
  Image segmentBackground(Image image) {
    Image segmentationMask = Image();
    var err = faceSDK.id3FaceAnalyser_SegmentBackground(_pHandle.value, image.handle, segmentationMask.handle);
    if (err != FaceError.success.value) {
      segmentationMask.dispose();
      throw FaceException(err);
    }
    return segmentationMask;
  }

  /// Computes a segmentation map of a face.
  /// Important: This methods requires the ``FaceSegmenter`` model to be loaded.
  ///
  /// param image Source image to process.
  /// return The map of segmented face.
  /// throws FaceException An error has occurred during Face Library execution.
  Image segmentFace(Image image) {
    Image segmentationMap = Image();
    var err = faceSDK.id3FaceAnalyser_SegmentFace(_pHandle.value, image.handle, segmentationMap.handle);
    if (err != FaceError.success.value) {
      segmentationMap.dispose();
      throw FaceException(err);
    }
    return segmentationMap;
  }

}

