//--------------------------------------------------------------------------------------------------
// 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 'document_sdk_generated_bindings.dart';
import 'document_native.dart';

import '../id3_document.dart';

final _finalizer = NativeFinalizer(documentSDK.addresses.id3DocumentImage_Dispose.cast());

/// Represents a document image.
class DocumentImage implements Finalizable {
  /// Native handle.
  late Pointer<Pointer<id3DocumentImage>> _pHandle;
  bool _disposable = true;

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

  /// Creates a new instance of the DocumentImage class.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentImage() {
    _pHandle = calloc();
    try {
      var err = documentSDK.id3DocumentImage_Initialize(_pHandle);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      _finalizer.attach(this, _pHandle.cast(), detach: this);
    } finally {}
  }

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

  /// Releases all resources used by this DocumentImage.
  void dispose() {
    if (_disposable) {
      documentSDK.id3DocumentImage_Dispose(_pHandle);
      calloc.free(_pHandle);
      _finalizer.detach(this);
    }
  }

  // Copyable methods

  /// Creates a copy of the DocumentImage object.
  ///
  /// return The newly created DocumentImage object.
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentImage clone() {
    DocumentImage clone = DocumentImage();
    var err = documentSDK.id3DocumentImage_CopyTo(_pHandle.value, clone.handle);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
    return clone;
  }


  ///
  /// Raw data buffer of the image.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  Uint8List get data => getData();

  ///
  /// Height in pixels.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  int get height => getHeight();

  ///
  /// Pixel depth.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  int get pixelDepth => getPixelDepth();

  ///
  /// Pixel format.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  PixelFormat get pixelFormat => getPixelFormat();

  ///
  /// Stride in bytes.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  int get stride => getStride();

  ///
  /// Width in pixels.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  int get width => getWidth();

  // Public methods
  /// Gets the raw data buffer of the image.
  ///
  /// return Raw data buffer of the image.
  /// throws DocumentException An error has occurred during Document Library execution.
  Uint8List getData() {
    Pointer<UnsignedChar> pData = nullptr;
    Pointer<Int> pDataSize = calloc();
    pDataSize[0] = -1;
    try {
      var err = documentSDK.id3DocumentImage_GetData(_pHandle.value, pData, pDataSize);
      if (err == DocumentError.insufficientBuffer.value) {
        pData = calloc.allocate(pDataSize.value);
        err = documentSDK.id3DocumentImage_GetData(_pHandle.value, pData, pDataSize);
      }
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vData = Uint8List.fromList(pData.cast<Uint8>().asTypedList(pDataSize.value));
      return vData;
    } finally {
      calloc.free(pData);
      calloc.free(pDataSize);
    }
  }

  /// Gets the height in pixels.
  ///
  /// return Height in pixels.
  /// throws DocumentException An error has occurred during Document Library execution.
  int getHeight() {
    Pointer<Int> pHeight = calloc();
    try {
      var err = documentSDK.id3DocumentImage_GetHeight(_pHandle.value, pHeight);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vHeight = pHeight.value;
      return vHeight;
    } finally {
      calloc.free(pHeight);
    }
  }

  /// Gets the pixel depth.
  ///
  /// return Pixel depth.
  /// throws DocumentException An error has occurred during Document Library execution.
  int getPixelDepth() {
    Pointer<Int> pPixelDepth = calloc();
    try {
      var err = documentSDK.id3DocumentImage_GetPixelDepth(_pHandle.value, pPixelDepth);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vPixelDepth = pPixelDepth.value;
      return vPixelDepth;
    } finally {
      calloc.free(pPixelDepth);
    }
  }

  /// Gets the pixel format.
  ///
  /// return Pixel format.
  /// throws DocumentException An error has occurred during Document Library execution.
  PixelFormat getPixelFormat() {
    Pointer<Int32> pPixelFormat = calloc();
    try {
      var err = documentSDK.id3DocumentImage_GetPixelFormat(_pHandle.value, pPixelFormat);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vPixelFormat = PixelFormatX.fromValue(pPixelFormat.value);
      return vPixelFormat;
    } finally {
      calloc.free(pPixelFormat);
    }
  }

  /// Gets the stride in bytes.
  ///
  /// return Stride in bytes.
  /// throws DocumentException An error has occurred during Document Library execution.
  int getStride() {
    Pointer<Int> pStride = calloc();
    try {
      var err = documentSDK.id3DocumentImage_GetStride(_pHandle.value, pStride);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vStride = pStride.value;
      return vStride;
    } finally {
      calloc.free(pStride);
    }
  }

  /// Gets the width in pixels.
  ///
  /// return Width in pixels.
  /// throws DocumentException An error has occurred during Document Library execution.
  int getWidth() {
    Pointer<Int> pWidth = calloc();
    try {
      var err = documentSDK.id3DocumentImage_GetWidth(_pHandle.value, pWidth);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vWidth = pWidth.value;
      return vWidth;
    } finally {
      calloc.free(pWidth);
    }
  }

  /// Computes the difference with another image.
  ///
  /// param cmpDocumentImage The image to compare.
  /// return Comparison result in percent (0% is same, 100% is full different).
  /// throws DocumentException An error has occurred during Document Library execution.
  double compare(DocumentImage cmpDocumentImage) {
    Pointer<Float> pResult = calloc();
    try {
      var err = documentSDK.id3DocumentImage_Compare(_pHandle.value, cmpDocumentImage.handle, pResult);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vResult = pResult.value;
      return vResult;
    } finally {
      calloc.free(pResult);
    }
  }

  /// Applies a gamma correction to the image.
  ///
  /// param contrast Contrast coefficient, from -255 to 255, to be applied to the image.
  /// param brightness Brightness coefficient, from -255 to 255, to be applid to the image.
  /// param gamma Gamma coefficient, from 0.25 to 2.50, to be applied to the image.
  /// throws DocumentException An error has occurred during Document Library execution.
  void correctGamma(int contrast, int brightness, double gamma) {
    var err = documentSDK.id3DocumentImage_CorrectGamma(_pHandle.value, contrast, brightness, gamma);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

  /// Crop a rectangular region of interest in the image according to the given bounds.
  ///
  /// param left Left bound of the crop to extract.
  /// param top Top bound of the crop to extract.
  /// param width Width of the crop to extract.
  /// param height Height of the crop to extract.
  /// return The extracted region of interest.
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentImage crop(int left, int top, int width, int height) {
    DocumentImage documentImageCrop = DocumentImage();
    var err = documentSDK.id3DocumentImage_Crop(_pHandle.value, left, top, width, height, documentImageCrop.handle);
    if (err != DocumentError.success.value) {
      documentImageCrop.dispose();
      throw DocumentException(err);
    }
    return documentImageCrop;
  }

  /// Downscales the image in-place so that its maximum dimension is equal to the given maximum size, while preserving the aspect ratio.
  /// Note: If the maximum dimension is already smaller than the given maximum size, the function does nothing and the scaling ration returned is 1.
  ///
  /// param maxSize Maximum image size, in pixels. The value must be greater than 0.
  /// return The scaling ratio applied to the image. Range is )0:1).
  /// throws DocumentException An error has occurred during Document Library execution.
  double downscale(int maxSize) {
    Pointer<Float> pScaleRatio = calloc();
    try {
      var err = documentSDK.id3DocumentImage_Downscale(_pHandle.value, maxSize, pScaleRatio);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vScaleRatio = pScaleRatio.value;
      return vScaleRatio;
    } finally {
      calloc.free(pScaleRatio);
    }
  }

  /// Downscales the image so that its maximum dimension equals the given maximum size, while preserving the aspect ratio.
  /// Note: If the maximum dimension is already smaller than the given maximum size, the function does nothing and the returned scale ratio is 1.
  ///
  /// param dstDocumentImage Destination image.
  /// param maxSize Maximum image size, in pixels. The value must be greater than 0.
  /// return The scaling ratio applied to the image. Range is )0:1).
  /// throws DocumentException An error has occurred during Document Library execution.
  double downscaleTo(DocumentImage dstDocumentImage, int maxSize) {
    Pointer<Float> pScaleRatio = calloc();
    try {
      var err = documentSDK.id3DocumentImage_DownscaleTo(_pHandle.value, dstDocumentImage.handle, maxSize, pScaleRatio);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vScaleRatio = pScaleRatio.value;
      return vScaleRatio;
    } finally {
      calloc.free(pScaleRatio);
    }
  }

  /// Extracts a region of interest in the image according to the given bounds.
  ///
  /// param bounds Bounds of the crop to extract.
  /// return The extracted region of interest.
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentImage extractRoi(Rectangle bounds) {
    DocumentImage documentImageRoi = DocumentImage();
    var err = documentSDK.id3DocumentImage_ExtractRoi(_pHandle.value, bounds.handle, documentImageRoi.handle);
    if (err != DocumentError.success.value) {
      documentImageRoi.dispose();
      throw DocumentException(err);
    }
    return documentImageRoi;
  }

  /// Extracts a region of interest in the image according to the given bounds.
  ///
  /// param bounds Bounds of the crop to extract.
  /// param colorRed Background color red (from 0 to 255)
  /// param colorGreen Background color green (from 0 to 255)
  /// param colorBlue Background color blue (from 0 to 255)
  /// return The extracted region of interest.
  /// throws DocumentException An error has occurred during Document Library execution.
  DocumentImage extractRoiWithColor(Rectangle bounds, int colorRed, int colorGreen, int colorBlue) {
    DocumentImage documentImageRoi = DocumentImage();
    var err = documentSDK.id3DocumentImage_ExtractRoiWithColor(_pHandle.value, bounds.handle, colorRed, colorGreen, colorBlue, documentImageRoi.handle);
    if (err != DocumentError.success.value) {
      documentImageRoi.dispose();
      throw DocumentException(err);
    }
    return documentImageRoi;
  }

  /// Flips the image in-place.
  ///
  /// param flipHorizontally Value indicating whether the image should be flipped horizontally.
  /// param flipVertically Value indicating whether the image should be flipped vertically.
  /// throws DocumentException An error has occurred during Document Library execution.
  void flip(bool flipHorizontally, bool flipVertically) {
    var err = documentSDK.id3DocumentImage_Flip(_pHandle.value, flipHorizontally, flipVertically);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

  /// Flips the image.
  ///
  /// param flipHorizontally Value indicating whether the image should be flipped horizontally.
  /// param flipVertically Value indicating whether the image should be flipped vertically.
  /// param dstDocumentImage The destination Image object that receives the flipped image.
  /// throws DocumentException An error has occurred during Document Library execution.
  void flipTo(bool flipHorizontally, bool flipVertically, DocumentImage dstDocumentImage) {
    var err = documentSDK.id3DocumentImage_FlipTo(_pHandle.value, flipHorizontally, flipVertically, dstDocumentImage.handle);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

  /// Creates an Image from the specified data buffer.
  ///
  /// param data A buffer that contains the image data.
  /// param pixelFormat The destination pixel format to convert the input to.
  /// return The newly created document image.
  /// throws DocumentException An error has occurred during Document Library execution.
  static DocumentImage fromBuffer(Uint8List? data, PixelFormat pixelFormat) {
    DocumentImage documentImage = DocumentImage();
    Pointer<UnsignedChar>? pData;
    if (data != null) {
    	pData = calloc.allocate<UnsignedChar>(data.length);
    	pData.cast<Uint8>().asTypedList(data.length).setAll(0, data);
    }
    try {
      var err = documentSDK.id3DocumentImage_FromBuffer(documentImage.handle, pData ?? nullptr, data?.length ?? 0, pixelFormat.value);
      if (err != DocumentError.success.value) {
        documentImage.dispose();
        throw DocumentException(err);
      }
      return documentImage;
    } finally {
      if (pData != null) {
        calloc.free(pData);
      }
    }
  }

  /// Creates an Image from the specified file.
  ///
  /// param filepath A string that contains the name of the file from which to create the Image.
  /// param pixelFormat The pixel format into which to convert the input image.
  /// return The newly created document image.
  /// throws DocumentException An error has occurred during Document Library execution.
  static DocumentImage fromFile(String? filepath, PixelFormat pixelFormat) {
    DocumentImage documentImage = DocumentImage();
    Pointer<Char>? pFilepath = filepath?.toNativeUtf8().cast<Char>();
    try {
      var err = documentSDK.id3DocumentImage_FromFile(documentImage.handle, pFilepath ?? nullptr, pixelFormat.value);
      if (err != DocumentError.success.value) {
        documentImage.dispose();
        throw DocumentException(err);
      }
      return documentImage;
    } finally {
      if (pFilepath != null) {
        calloc.free(pFilepath);
      }
    }
  }

  /// Creates an Image from the specified raw data buffer.
  ///
  /// param pixels A buffer that contains image pixels.
  /// param width The width, in pixels, of the image.
  /// param height The height, in pixels, of the image.
  /// param stride The stride, in pixels, of the image.
  /// param srcPixelFormat The pixel format of the input image.
  /// param dstPixelFormat The pixel format into which to convert the input image.
  /// return The newly created document image.
  /// throws DocumentException An error has occurred during Document Library execution.
  static DocumentImage fromRawBuffer(Uint8List? pixels, int width, int height, int stride, PixelFormat srcPixelFormat, PixelFormat dstPixelFormat) {
    DocumentImage documentImage = DocumentImage();
    Pointer<UnsignedChar>? pPixels;
    if (pixels != null) {
    	pPixels = calloc.allocate<UnsignedChar>(pixels.length);
    	pPixels.cast<Uint8>().asTypedList(pixels.length).setAll(0, pixels);
    }
    try {
      var err = documentSDK.id3DocumentImage_FromRawBuffer(documentImage.handle, pPixels ?? nullptr, pixels?.length ?? 0, width, height, stride, srcPixelFormat.value, dstPixelFormat.value);
      if (err != DocumentError.success.value) {
        documentImage.dispose();
        throw DocumentException(err);
      }
      return documentImage;
    } finally {
      if (pPixels != null) {
        calloc.free(pPixels);
      }
    }
  }

  /// Creates an Image from the specified YUV planes.
  ///
  /// param yPlane A buffer that contains the Y plane.
  /// param uPlane A buffer that contains the U plane.
  /// param vPlane A buffer that contains the V plane.
  /// param yWidth The width, in pixels, of the Y plane.
  /// param yHeight The height, in pixels, of the Y plane.
  /// param uvPixelStride The pixel-level stride, in pixels, of the U and V planes.
  /// param uvRowStride The row-level stride, in pixels, of the U and V planes.
  /// param dstPixelFormat The pixel format into which to convert the input image.
  /// return The newly created document image.
  /// throws DocumentException An error has occurred during Document Library execution.
  static DocumentImage fromYuvPlanes(Uint8List? yPlane, Uint8List? uPlane, Uint8List? vPlane, int yWidth, int yHeight, int uvPixelStride, int uvRowStride, PixelFormat dstPixelFormat) {
    DocumentImage documentImage = DocumentImage();
    Pointer<UnsignedChar>? pYPlane;
    if (yPlane != null) {
    	pYPlane = calloc.allocate<UnsignedChar>(yPlane.length);
    	pYPlane.cast<Uint8>().asTypedList(yPlane.length).setAll(0, yPlane);
    }
    Pointer<UnsignedChar>? pUPlane;
    if (uPlane != null) {
    	pUPlane = calloc.allocate<UnsignedChar>(uPlane.length);
    	pUPlane.cast<Uint8>().asTypedList(uPlane.length).setAll(0, uPlane);
    }
    Pointer<UnsignedChar>? pVPlane;
    if (vPlane != null) {
    	pVPlane = calloc.allocate<UnsignedChar>(vPlane.length);
    	pVPlane.cast<Uint8>().asTypedList(vPlane.length).setAll(0, vPlane);
    }
    try {
      var err = documentSDK.id3DocumentImage_FromYuvPlanes(documentImage.handle, pYPlane ?? nullptr, yPlane?.length ?? 0, pUPlane ?? nullptr, uPlane?.length ?? 0, pVPlane ?? nullptr, vPlane?.length ?? 0, yWidth, yHeight, uvPixelStride, uvRowStride, dstPixelFormat.value);
      if (err != DocumentError.success.value) {
        documentImage.dispose();
        throw DocumentException(err);
      }
      return documentImage;
    } finally {
      if (pYPlane != null) {
        calloc.free(pYPlane);
      }
      if (pUPlane != null) {
        calloc.free(pUPlane);
      }
      if (pVPlane != null) {
        calloc.free(pVPlane);
      }
    }
  }

  /// Add padding around the image
  /// Only works for BGR 24 bits, RGB 24 bits and Grayscale 8bits images.
  /// For grayscale image, the padding color is the red component.
  ///
  /// param top Padding on top.
  /// param left Padding on left.
  /// param bottom Padding on bottom.
  /// param right Padding on right.
  /// param colorRed Padding color red (from 0 to 255)
  /// param colorGreen Padding color green (from 0 to 255)
  /// param colorBlue Padding color blue (from 0 to 255)
  /// throws DocumentException An error has occurred during Document Library execution.
  void pad(int top, int left, int bottom, int right, int colorRed, int colorGreen, int colorBlue) {
    var err = documentSDK.id3DocumentImage_Pad(_pHandle.value, top, left, bottom, right, colorRed, colorGreen, colorBlue);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

  /// Reallocates the internal memory of the Image from parameters.
  /// Note: If the given parameters are the same as the ones of the object, then there is nothing done in this function.
  ///
  /// param width The new width, in pixels.
  /// param height The new height, in pixels.
  /// param pixelFormat The new pixel format.
  /// throws DocumentException An error has occurred during Document Library execution.
  void reallocate(int width, int height, PixelFormat pixelFormat) {
    var err = documentSDK.id3DocumentImage_Reallocate(_pHandle.value, width, height, pixelFormat.value);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

  /// Resizes the image in-place to the required width and height.
  ///
  /// param width The new width, in pixels.
  /// param height The new height, in pixels.
  /// throws DocumentException An error has occurred during Document Library execution.
  void resize(int width, int height) {
    var err = documentSDK.id3DocumentImage_Resize(_pHandle.value, width, height);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

  /// Resizes the image to the specified width and height.
  ///
  /// param width The new width, in pixels.
  /// param height The new height, in pixels.
  /// param dstDocumentImage The destination image that receives the resized image.
  /// throws DocumentException An error has occurred during Document Library execution.
  void resizeTo(int width, int height, DocumentImage dstDocumentImage) {
    var err = documentSDK.id3DocumentImage_ResizeTo(_pHandle.value, width, height, dstDocumentImage.handle);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

  /// Rotates the image in-place to the specified angle.
  /// Note: The rotation is performed counter-clockwise.
  ///
  /// param angle The rotation angle, in degree. Supported values are (0, 90, 180, 270).
  /// throws DocumentException An error has occurred during Document Library execution.
  void rotate(int angle) {
    var err = documentSDK.id3DocumentImage_Rotate(_pHandle.value, angle);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

  /// Rotates the image to the specified angle.
  /// Note: The rotation is performed counter-clockwise.
  ///
  /// param angle The rotation angle, in degree. Supported values are (0, 90, 180, 270).
  /// param dstDocumentImage The destination Image that receives the rotated image.
  /// throws DocumentException An error has occurred during Document Library execution.
  void rotateTo(int angle, DocumentImage dstDocumentImage) {
    var err = documentSDK.id3DocumentImage_RotateTo(_pHandle.value, angle, dstDocumentImage.handle);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

  /// Exports the image to a buffer.
  /// The compression level meaning depends on the algorithm used:
  /// - For JPEG compression, the value is the expected quality and may vary from 1 to 100.
  /// - For JPEG2000 compression, the value is the compression rate and may vary from 1 to 512.
  /// - For PNG compression, the value is the compression rate and may vary from 1 to 10.
  /// - For all other formats, the value is ignored.
  ///
  /// param documentImageFormat The image format to export the image to.
  /// param compressionLevel The compression level to be applied.
  /// return Buffer that receives the image data.
  /// throws DocumentException An error has occurred during Document Library execution.
  Uint8List toBuffer(ImageFormat documentImageFormat, double compressionLevel) {
    Pointer<UnsignedChar> pData = nullptr;
    Pointer<Int> pDataSize = calloc();
    pDataSize[0] = -1;
    try {
      var err = documentSDK.id3DocumentImage_ToBuffer(_pHandle.value, documentImageFormat.value, compressionLevel, pData, pDataSize);
      if (err == DocumentError.insufficientBuffer.value) {
        pData = calloc.allocate(pDataSize.value);
        err = documentSDK.id3DocumentImage_ToBuffer(_pHandle.value, documentImageFormat.value, compressionLevel, pData, pDataSize);
      }
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
      final vData = Uint8List.fromList(pData.cast<Uint8>().asTypedList(pDataSize.value));
      return vData;
    } finally {
      calloc.free(pData);
      calloc.free(pDataSize);
    }
  }

  /// Copies the image to a buffer in the specified format.
  /// The compression level meaning depends on the algorithm used:
  /// - For JPEG compression, the value is the expected quality and may vary from 1 to 100.
  /// - For JPEG2000 compression, the value is the compression rate and may vary from 1 to 512.
  /// - For PNG compression, the value is the compression rate and may vary from 1 to 10.
  /// - For all other formats, the value is ignored.
  ///
  /// param documentImageFormat The output image format.
  /// param compressionLevel The compression level to be applied.
  /// param buffer The image buffer that receives the image data.
  /// throws DocumentException An error has occurred during Document Library execution.
  void toBufferObject(ImageFormat documentImageFormat, double compressionLevel, ImageBuffer buffer) {
    var err = documentSDK.id3DocumentImage_ToBufferObject(_pHandle.value, documentImageFormat.value, compressionLevel, buffer.handle);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

  /// Saves the image to the specified file.
  /// The compression level meaning depends on the algorithm used:
  /// - For JPEG compression, the value is the expected quality and may vary from 1 to 100.
  /// - For JPEG2000 compression, the value is the compression rate and may vary from 1 to 512.
  /// - For PNG compression, the value is the compression rate and may vary from 1 to 10.
  /// - For all other formats, the value is ignored.
  ///
  /// param filepath A string that contains the name of the file to which to save the image.
  /// param compressionLevel The compression level to be applied.
  /// throws DocumentException An error has occurred during Document Library execution.
  void toFile(String? filepath, double compressionLevel) {
    Pointer<Char>? pFilepath = filepath?.toNativeUtf8().cast<Char>();
    try {
      var err = documentSDK.id3DocumentImage_ToFile(_pHandle.value, pFilepath ?? nullptr, compressionLevel);
      if (err != DocumentError.success.value) {
        throw DocumentException(err);
      }
    } finally {
      if (pFilepath != null) {
        calloc.free(pFilepath);
      }
    }
  }

  /// Copies image pixels in the specified format into a buffer.
  ///
  /// param pixelFormat The pixel format.
  /// param buffer Buffer that receives the raw image data.
  /// throws DocumentException An error has occurred during Document Library execution.
  void toRawBuffer(PixelFormat pixelFormat, ImageBuffer buffer) {
    var err = documentSDK.id3DocumentImage_ToRawBuffer(_pHandle.value, pixelFormat.value, buffer.handle);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

  /// Transposes the image object.
  ///
  /// throws DocumentException An error has occurred during Document Library execution.
  void transpose() {
    var err = documentSDK.id3DocumentImage_Transpose(_pHandle.value);
    if (err != DocumentError.success.value) {
      throw DocumentException(err);
    }
  }

}

