"""
Created on Mon Nov 21 09:44:40 2016

@author: Daniel Vassmer, Stefan_Geissler
From: https://github.com/TheImagingSource/IC-Imaging-Control-Samples/tree/master/Python

modified 10/3/2019 by Gary Kane - https://github.com/gkane26
"""

"""
DeepLabCut Toolbox (deeplabcut.org)
© A. & M. Mathis Labs

Licensed under GNU Lesser General Public License v3.0
"""


from enum import Enum

import ctypes as C
import os
import sys
import numpy as np


class SinkFormats(Enum):
    Y800 = 0
    RGB24 = 1
    RGB32 = 2
    UYVY = 3
    Y16 = 4


ImageFileTypes = {"BMP": 0, "JPEG": 1}


class GrabberHandle(C.Structure):
    pass


GrabberHandle._fields_ = [("unused", C.c_int)]

##############################################################################

### GK Additions from: https://github.com/morefigs/py-ic-imaging-control


class FilterParameter(C.Structure):
    pass


FilterParameter._fields_ = [("Name", C.c_char * 30), ("Type", C.c_int)]


class FrameFilterHandle(C.Structure):
    pass


FrameFilterHandle._fields_ = [
    ("pFilter", C.c_void_p),
    ("bHasDialog", C.c_int),
    ("ParameterCount", C.c_int),
    ("Parameters", C.POINTER(FilterParameter)),
]

##############################################################################


class TIS_GrabberDLL(object):
    if sys.maxsize > 2 ** 32:
        __tisgrabber = C.windll.LoadLibrary("tisgrabber_x64.dll")
    else:
        __tisgrabber = C.windll.LoadLibrary("tisgrabber.dll")

    def __init__(self, **keyargs):
        """Initialize the Albatross from the keyword arguments."""
        self.__dict__.update(keyargs)

    GrabberHandlePtr = C.POINTER(GrabberHandle)

    ####################################

    #     Initialize the ICImagingControl class library. This function must be called
    # 	only once before any other functions of this library are called.
    # 	@param szLicenseKey IC Imaging Control license key or NULL if only a trial version is available.
    # 	@retval IC_SUCCESS on success.
    # 	@retval IC_ERROR on wrong license key or other errors.
    # 	@sa IC_CloseLibrary
    InitLibrary = __tisgrabber.IC_InitLibrary(None)

    #     Get the number of the currently available devices. This function creates an
    # 	internal array of all connected video capture devices. With each call to this
    # 	function, this array is rebuild. The name and the unique name can be retrieved
    # 	from the internal array using the functions IC_GetDevice() and IC_GetUniqueNamefromList.
    # 	They are usefull for retrieving device names for opening devices.
    #
    # 	@retval >= 0 Success, count of found devices.
    # 	@retval IC_NO_HANDLE Internal Error.
    #
    # 	@sa IC_GetDevice
    # 	@sa IC_GetUniqueNamefromList
    get_devicecount = __tisgrabber.IC_GetDeviceCount
    get_devicecount.restype = C.c_int
    get_devicecount.argtypes = None

    #     Get unique device name of a device specified by iIndex. The unique device name
    # 	consist from the device name and its serial number. It allows to differ between
    # 	more then one device of the same type connected to the computer. The unique device name
    # 	is passed to the function IC_OpenDevByUniqueName
    #
    # 	@param iIndex The number of the device whose name is to be returned. It must be
    # 				in the range from 0 to IC_GetDeviceCount(),
    # 	@return Returns the string representation of the device on success, NULL
    # 				otherwise.
    #
    # 	@sa IC_GetDeviceCount
    # 	@sa IC_GetUniqueNamefromList
    # 	@sa IC_OpenDevByUniqueName

    get_unique_name_from_list = __tisgrabber.IC_GetUniqueNamefromList
    get_unique_name_from_list.restype = C.c_char_p
    get_unique_name_from_list.argtypes = (C.c_int,)

    #     Creates a new grabber handle and returns it. A new created grabber should be
    # 	release with a call to IC_ReleaseGrabber if it is no longer needed.
    # 	@sa IC_ReleaseGrabber
    create_grabber = __tisgrabber.IC_CreateGrabber
    create_grabber.restype = GrabberHandlePtr
    create_grabber.argtypes = None

    #    Open a video capture by using its UniqueName. Use IC_GetUniqueName() to
    #    retrieve the unique name of a camera.
    #
    # 	@param hGrabber       Handle to a grabber object
    # 	@param szDisplayName  Memory that will take the display name.
    #
    # 	@sa IC_GetUniqueName
    # 	@sa IC_ReleaseGrabber
    open_device_by_unique_name = __tisgrabber.IC_OpenDevByUniqueName
    open_device_by_unique_name.restype = C.c_int
    open_device_by_unique_name.argtypes = (GrabberHandlePtr, C.c_char_p)

    set_videoformat = __tisgrabber.IC_SetVideoFormat
    set_videoformat.restype = C.c_int
    set_videoformat.argtypes = (GrabberHandlePtr, C.c_char_p)

    set_framerate = __tisgrabber.IC_SetFrameRate
    set_framerate.restype = C.c_int
    set_framerate.argtypes = (GrabberHandlePtr, C.c_float)

    #    Returns the width of the video format.
    get_video_format_width = __tisgrabber.IC_GetVideoFormatWidth
    get_video_format_width.restype = C.c_int
    get_video_format_width.argtypes = (GrabberHandlePtr,)

    #    returns the height of the video format.
    get_video_format_height = __tisgrabber.IC_GetVideoFormatHeight
    get_video_format_height.restype = C.c_int
    get_video_format_height.argtypes = (GrabberHandlePtr,)

    #    Get the number of the available video formats for the current device.
    # 	A video capture device must have been opened before this call.
    #
    # 	@param hGrabber The handle to the grabber object.
    #
    # 	@retval >= 0 Success
    # 	@retval IC_NO_DEVICE No video capture device selected.
    # 	@retval IC_NO_HANDLE No handle to the grabber object.
    #
    # 	@sa IC_GetVideoFormat
    GetVideoFormatCount = __tisgrabber.IC_GetVideoFormatCount
    GetVideoFormatCount.restype = C.c_int
    GetVideoFormatCount.argtypes = (GrabberHandlePtr,)

    #     Get a string representation of the video format specified by iIndex.
    # 	iIndex must be between 0 and IC_GetVideoFormatCount().
    # 	IC_GetVideoFormatCount() must have been called before this function,
    # 	otherwise it will always fail.
    #
    # 	@param hGrabber The handle to the grabber object.
    # 	@param iIndex Number of the video format to be used.
    #
    # 	@retval Nonnull The name of the specified video format.
    # 	@retval NULL An error occured.
    # 	@sa IC_GetVideoFormatCount
    GetVideoFormat = __tisgrabber.IC_GetVideoFormat
    GetVideoFormat.restype = C.c_char_p
    GetVideoFormat.argtypes = (GrabberHandlePtr, C.c_int)

    #    Get the number of the available input channels for the current device.
    #    A video	capture device must have been opened before this call.
    #
    # 	@param hGrabber The handle to the grabber object.
    #
    # 	@retval >= 0 Success
    # 	@retval IC_NO_DEVICE No video capture device selected.
    # 	@retval IC_NO_HANDLE No handle to the grabber object.
    #
    # 	@sa IC_GetInputChannel
    GetInputChannelCount = __tisgrabber.IC_GetInputChannelCount
    GetInputChannelCount.restype = C.c_int
    GetInputChannelCount.argtypes = (GrabberHandlePtr,)

    #     Get a string representation of the input channel specified by iIndex.
    # 	iIndex must be between 0 and IC_GetInputChannelCount().
    # 	IC_GetInputChannelCount() must have been called before this function,
    # 	otherwise it will always fail.
    # 	@param hGrabber The handle to the grabber object.
    # 	@param iIndex Number of the input channel to be used..
    #
    # 	@retval Nonnull The name of the specified input channel
    # 	@retval NULL An error occured.
    # 	@sa IC_GetInputChannelCount
    GetInputChannel = __tisgrabber.IC_GetInputChannel
    GetInputChannel.restype = C.c_char_p
    GetInputChannel.argtypes = (GrabberHandlePtr, C.c_int)

    #     Get the number of the available video norms for the current device.
    # 	A video capture device must have been opened before this call.
    #
    # 	@param hGrabber The handle to the grabber object.
    #
    # 	@retval >= 0 Success
    # 	@retval IC_NO_DEVICE No video capture device selected.
    # 	@retval IC_NO_HANDLE No handle to the grabber object.
    #
    # 	@sa IC_GetVideoNorm
    GetVideoNormCount = __tisgrabber.IC_GetVideoNormCount
    GetVideoNormCount.restype = C.c_int
    GetVideoNormCount.argtypes = (GrabberHandlePtr,)

    #     Get a string representation of the video norm specified by iIndex.
    # 	iIndex must be between 0 and IC_GetVideoNormCount().
    # 	IC_GetVideoNormCount() must have been called before this function,
    # 	otherwise it will always fail.
    #
    # 	@param hGrabber The handle to the grabber object.
    # 	@param iIndex Number of the video norm to be used.
    #
    # 	@retval Nonnull The name of the specified video norm.
    # 	@retval NULL An error occured.
    # 	@sa IC_GetVideoNormCount
    GetVideoNorm = __tisgrabber.IC_GetVideoNorm
    GetVideoNorm.restype = C.c_char_p
    GetVideoNorm.argtypes = (GrabberHandlePtr, C.c_int)

    SetFormat = __tisgrabber.IC_SetFormat
    SetFormat.restype = C.c_int
    SetFormat.argtypes = (GrabberHandlePtr, C.c_int)
    GetFormat = __tisgrabber.IC_GetFormat
    GetFormat.restype = C.c_int
    GetFormat.argtypes = (GrabberHandlePtr,)

    #    Start the live video.
    # 	@param hGrabber The handle to the grabber object.
    # 	@param iShow The parameter indicates:   @li 1 : Show the video	@li 0 : Do not show the video, but deliver frames. (For callbacks etc.)
    # 	@retval IC_SUCCESS on success
    # 	@retval IC_ERROR if something went wrong.
    # 	@sa IC_StopLive

    StartLive = __tisgrabber.IC_StartLive
    StartLive.restype = C.c_int
    StartLive.argtypes = (GrabberHandlePtr, C.c_int)

    StopLive = __tisgrabber.IC_StopLive
    StopLive.restype = C.c_int
    StopLive.argtypes = (GrabberHandlePtr,)

    SetHWND = __tisgrabber.IC_SetHWnd
    SetHWND.restype = C.c_int
    SetHWND.argtypes = (GrabberHandlePtr, C.c_int)

    #    Snaps an image. The video capture device must be set to live mode and a
    # 	sink type has to be set before this call. The format of the snapped images depend on
    # 	the selected sink type.
    #
    # 	@param hGrabber The handle to the grabber object.
    # 	@param iTimeOutMillisek The Timeout time is passed in milli seconds. A value of -1 indicates, that
    # 							no time out is set.
    #
    #
    # 	@retval IC_SUCCESS if an image has been snapped
    # 	@retval IC_ERROR if something went wrong.
    # 	@retval IC_NOT_IN_LIVEMODE if the live video has not been started.
    #
    # 	@sa IC_StartLive
    # 	@sa IC_SetFormat

    SnapImage = __tisgrabber.IC_SnapImage
    SnapImage.restype = C.c_int
    SnapImage.argtypes = (GrabberHandlePtr, C.c_int)

    #    Retrieve the properties of the current video format and sink type
    # 	@param hGrabber The handle to the grabber object.
    # 	@param *lWidth  This recieves the width of the image buffer.
    # 	@param *lHeight  This recieves the height of the image buffer.
    # 	@param *iBitsPerPixel  This recieves the count of bits per pixel.
    # 	@param *format  This recieves the current color format.
    # 	@retval IC_SUCCESS on success
    # 	@retval IC_ERROR if something went wrong.

    GetImageDescription = __tisgrabber.IC_GetImageDescription
    GetImageDescription.restype = C.c_int
    GetImageDescription.argtypes = (
        GrabberHandlePtr,
        C.POINTER(C.c_long),
        C.POINTER(C.c_long),
        C.POINTER(C.c_int),
        C.POINTER(C.c_int),
    )

    GetImagePtr = __tisgrabber.IC_GetImagePtr
    GetImagePtr.restype = C.c_void_p
    GetImagePtr.argtypes = (GrabberHandlePtr,)

    # ############################################################################
    ShowDeviceSelectionDialog = __tisgrabber.IC_ShowDeviceSelectionDialog
    ShowDeviceSelectionDialog.restype = GrabberHandlePtr
    ShowDeviceSelectionDialog.argtypes = (GrabberHandlePtr,)

    # ############################################################################

    ShowPropertyDialog = __tisgrabber.IC_ShowPropertyDialog
    ShowPropertyDialog.restype = GrabberHandlePtr
    ShowPropertyDialog.argtypes = (GrabberHandlePtr,)

    # ############################################################################
    IsDevValid = __tisgrabber.IC_IsDevValid
    IsDevValid.restype = C.c_int
    IsDevValid.argtypes = (GrabberHandlePtr,)

    # ############################################################################

    LoadDeviceStateFromFile = __tisgrabber.IC_LoadDeviceStateFromFile
    LoadDeviceStateFromFile.restype = GrabberHandlePtr
    LoadDeviceStateFromFile.argtypes = (GrabberHandlePtr, C.c_char_p)

    # ############################################################################
    SaveDeviceStateToFile = __tisgrabber.IC_SaveDeviceStateToFile
    SaveDeviceStateToFile.restype = C.c_int
    SaveDeviceStateToFile.argtypes = (GrabberHandlePtr, C.c_char_p)

    GetCameraProperty = __tisgrabber.IC_GetCameraProperty
    GetCameraProperty.restype = C.c_int
    GetCameraProperty.argtypes = (GrabberHandlePtr, C.c_int, C.POINTER(C.c_long))

    SetCameraProperty = __tisgrabber.IC_SetCameraProperty
    SetCameraProperty.restype = C.c_int
    SetCameraProperty.argtypes = (GrabberHandlePtr, C.c_int, C.c_long)

    SetPropertyValue = __tisgrabber.IC_SetPropertyValue
    SetPropertyValue.restype = C.c_int
    SetPropertyValue.argtypes = (GrabberHandlePtr, C.c_char_p, C.c_char_p, C.c_int)

    GetPropertyValue = __tisgrabber.IC_GetPropertyValue
    GetPropertyValue.restype = C.c_int
    GetPropertyValue.argtypes = (
        GrabberHandlePtr,
        C.c_char_p,
        C.c_char_p,
        C.POINTER(C.c_long),
    )

    # ############################################################################
    SetPropertySwitch = __tisgrabber.IC_SetPropertySwitch
    SetPropertySwitch.restype = C.c_int
    SetPropertySwitch.argtypes = (GrabberHandlePtr, C.c_char_p, C.c_char_p, C.c_int)

    GetPropertySwitch = __tisgrabber.IC_GetPropertySwitch
    GetPropertySwitch.restype = C.c_int
    GetPropertySwitch.argtypes = (
        GrabberHandlePtr,
        C.c_char_p,
        C.c_char_p,
        C.POINTER(C.c_long),
    )
    # ############################################################################

    IsPropertyAvailable = __tisgrabber.IC_IsPropertyAvailable
    IsPropertyAvailable.restype = C.c_int
    IsPropertyAvailable.argtypes = (GrabberHandlePtr, C.c_char_p, C.c_char_p)

    PropertyOnePush = __tisgrabber.IC_PropertyOnePush
    PropertyOnePush.restype = C.c_int
    PropertyOnePush.argtypes = (GrabberHandlePtr, C.c_char_p, C.c_char_p)

    SetPropertyAbsoluteValue = __tisgrabber.IC_SetPropertyAbsoluteValue
    SetPropertyAbsoluteValue.restype = C.c_int
    SetPropertyAbsoluteValue.argtypes = (
        GrabberHandlePtr,
        C.c_char_p,
        C.c_char_p,
        C.c_float,
    )

    GetPropertyAbsoluteValue = __tisgrabber.IC_GetPropertyAbsoluteValue
    GetPropertyAbsoluteValue.restype = C.c_int
    GetPropertyAbsoluteValue.argtypes = (
        GrabberHandlePtr,
        C.c_char_p,
        C.c_char_p,
        C.POINTER(C.c_float),
    )

    # definition of the frameready callback
    FRAMEREADYCALLBACK = C.CFUNCTYPE(
        C.c_void_p, C.c_int, C.POINTER(C.c_ubyte), C.c_ulong, C.py_object
    )

    # set callback function
    SetFrameReadyCallback = __tisgrabber.IC_SetFrameReadyCallback
    SetFrameReadyCallback.restype = C.c_int
    SetFrameReadyCallback.argtypes = [GrabberHandlePtr, FRAMEREADYCALLBACK, C.py_object]

    SetContinuousMode = __tisgrabber.IC_SetContinuousMode

    SaveImage = __tisgrabber.IC_SaveImage
    SaveImage.restype = C.c_int
    SaveImage.argtypes = [C.c_void_p, C.c_char_p, C.c_int, C.c_int]

    OpenVideoCaptureDevice = __tisgrabber.IC_OpenVideoCaptureDevice
    OpenVideoCaptureDevice.restype = C.c_int
    OpenVideoCaptureDevice.argtypes = [C.c_void_p, C.c_char_p]

    # ############################################################################

    ### GK Additions - adding frame filters. Pieces copied from: https://github.com/morefigs/py-ic-imaging-control

    CreateFrameFilter = __tisgrabber.IC_CreateFrameFilter
    CreateFrameFilter.restype = C.c_int
    CreateFrameFilter.argtypes = (C.c_char_p, C.POINTER(FrameFilterHandle))

    AddFrameFilter = __tisgrabber.IC_AddFrameFilterToDevice
    AddFrameFilter.restype = C.c_int
    AddFrameFilter.argtypes = (GrabberHandlePtr, C.POINTER(FrameFilterHandle))

    FilterGetParameter = __tisgrabber.IC_FrameFilterGetParameter
    FilterGetParameter.restype = C.c_int
    FilterGetParameter.argtypes = (C.POINTER(FrameFilterHandle), C.c_char_p, C.c_void_p)

    FilterSetParameter = __tisgrabber.IC_FrameFilterSetParameterInt
    FilterSetParameter.restype = C.c_int
    FilterSetParameter.argtypes = (C.POINTER(FrameFilterHandle), C.c_char_p, C.c_int)


# ############################################################################


class TIS_CAM(object):
    @property
    def callback_registered(self):
        return self._callback_registered

    def __init__(self):

        self._handle = C.POINTER(GrabberHandle)
        self._handle = TIS_GrabberDLL.create_grabber()
        self._callback_registered = False
        self._frame = {"num": -1, "ready": False}

    def s(self, strin):
        if sys.version[0] == "2":
            return strin
        if type(strin) == "byte":
            return strin
        return strin.encode("utf-8")

    def SetFrameReadyCallback(self, CallbackFunction, data):
        """ Set a callback function, which is called, when a new frame arrives.

            CallbackFunction : The callback function

            data : a self defined class with user data.
            """
        return TIS_GrabberDLL.SetFrameReadyCallback(
            self._handle, CallbackFunction, data
        )

    def SetContinuousMode(self, Mode):
        """ Determines, whether new frames are automatically copied into memory.

            :param Mode: If 0, all frames are copied automatically into memory. This is recommened, if the camera runs in trigger mode.
                          If 1, then snapImages must be called to get a frame into memory.
            :return: None
            """
        return TIS_GrabberDLL.SetContinuousMode(self._handle, Mode)

    def open(self, unique_device_name):
        """ Open a device

            unique_device_name : The name and serial number of the device to be opened. The device name and serial number are separated by a space.
            """
        test = TIS_GrabberDLL.open_device_by_unique_name(
            self._handle, self.s(unique_device_name)
        )

        return test

    def close(self):
        TIS_GrabberDLL.close_device(self._handle)

    def ShowDeviceSelectionDialog(self):
        self._handle = TIS_GrabberDLL.ShowDeviceSelectionDialog(self._handle)

    def ShowPropertyDialog(self):
        self._handle = TIS_GrabberDLL.ShowPropertyDialog(self._handle)

    def IsDevValid(self):
        return TIS_GrabberDLL.IsDevValid(self._handle)

    def SetHWND(self, Hwnd):
        return TIS_GrabberDLL.SetHWND(self._handle, Hwnd)

    def SaveDeviceStateToFile(self, FileName):
        return TIS_GrabberDLL.SaveDeviceStateToFile(self._handle, self.s(FileName))

    def LoadDeviceStateFromFile(self, FileName):
        self._handle = TIS_GrabberDLL.LoadDeviceStateFromFile(
            self._handle, self.s(FileName)
        )

    def SetVideoFormat(self, Format):
        return TIS_GrabberDLL.set_videoformat(self._handle, self.s(Format))

    def SetFrameRate(self, FPS):
        return TIS_GrabberDLL.set_framerate(self._handle, FPS)

    def get_video_format_width(self):
        return TIS_GrabberDLL.get_video_format_width(self._handle)

    def get_video_format_height(self):
        return TIS_GrabberDLL.get_video_format_height(self._handle)

    def GetDevices(self):
        self._Devices = []
        iDevices = TIS_GrabberDLL.get_devicecount()
        for i in range(iDevices):
            self._Devices.append(TIS_GrabberDLL.get_unique_name_from_list(i))
        return self._Devices

    def GetVideoFormats(self):
        self._Properties = []
        iVideoFormats = TIS_GrabberDLL.GetVideoFormatCount(self._handle)
        for i in range(iVideoFormats):
            self._Properties.append(TIS_GrabberDLL.GetVideoFormat(self._handle, i))
        return self._Properties

    def GetInputChannels(self):
        self.InputChannels = []
        InputChannelscount = TIS_GrabberDLL.GetInputChannelCount(self._handle)
        for i in range(InputChannelscount):
            self.InputChannels.append(TIS_GrabberDLL.GetInputChannel(self._handle, i))
        return self.InputChannels

    def GetVideoNormCount(self):
        self.GetVideoNorm = []
        GetVideoNorm_Count = TIS_GrabberDLL.GetVideoNormCount(self._handle)
        for i in range(GetVideoNorm_Count):
            self.GetVideoNorm.append(TIS_GrabberDLL.GetVideoNorm(self._handle, i))
        return self.GetVideoNorm

    def SetFormat(self, Format):
        """ SetFormat
            Sets the pixel format in memory
            @param Format Sinkformat enumeration
            """
        TIS_GrabberDLL.SetFormat(self._handle, Format.value)

    def GetFormat(self):
        val = TIS_GrabberDLL.GetFormat(self._handle)
        if val == 0:
            return SinkFormats.Y800
        if val == 2:
            return SinkFormats.RGB32
        if val == 1:
            return SinkFormats.RGB24
        if val == 3:
            return SinkFormats.UYVY
        if val == 4:
            return SinkFormats.Y16
        return SinkFormats.RGB24

    def StartLive(self, showlive=1):
        """
            Start the live video stream.

            showlive: 1 : a live video is shown, 0 : the live video is not shown.
            """
        Error = TIS_GrabberDLL.StartLive(self._handle, showlive)
        return Error

    def StopLive(self):
        """
            Stop the live video.
            """
        Error = TIS_GrabberDLL.StopLive(self._handle)
        return Error

    def SnapImage(self):
        Error = TIS_GrabberDLL.SnapImage(self._handle, 2000)
        return Error

    def GetImageDescription(self):
        lWidth = C.c_long()
        lHeight = C.c_long()
        iBitsPerPixel = C.c_int()
        COLORFORMAT = C.c_int()

        Error = TIS_GrabberDLL.GetImageDescription(
            self._handle, lWidth, lHeight, iBitsPerPixel, COLORFORMAT
        )
        return (lWidth.value, lHeight.value, iBitsPerPixel.value, COLORFORMAT.value)

    def GetImagePtr(self):
        ImagePtr = TIS_GrabberDLL.GetImagePtr(self._handle)

        return ImagePtr

    def GetImage(self):
        BildDaten = self.GetImageDescription()[:4]
        lWidth = BildDaten[0]
        lHeight = BildDaten[1]
        iBitsPerPixel = BildDaten[2] // 8

        buffer_size = lWidth * lHeight * iBitsPerPixel * C.sizeof(C.c_uint8)
        img_ptr = self.GetImagePtr()

        Bild = C.cast(img_ptr, C.POINTER(C.c_ubyte * buffer_size))

        img = np.ndarray(
            buffer=Bild.contents, dtype=np.uint8, shape=(lHeight, lWidth, iBitsPerPixel)
        )
        return img

    def GetImageEx(self):
        """ Return a numpy array with the image data tyes
            If the sink is Y16 or RGB64 (not supported yet), the dtype in the array is uint16, othereise it is uint8
            """
        BildDaten = self.GetImageDescription()[:4]
        lWidth = BildDaten[0]
        lHeight = BildDaten[1]
        iBytesPerPixel = BildDaten[2] // 8

        buffer_size = lWidth * lHeight * iBytesPerPixel * C.sizeof(C.c_uint8)
        img_ptr = self.GetImagePtr()

        Bild = C.cast(img_ptr, C.POINTER(C.c_ubyte * buffer_size))

        pixeltype = np.uint8

        if BildDaten[3] == 4:  # SinkFormats.Y16:
            pixeltype = np.uint16
            iBytesPerPixel = 1

        img = np.ndarray(
            buffer=Bild.contents,
            dtype=pixeltype,
            shape=(lHeight, lWidth, iBytesPerPixel),
        )
        return img

    def GetCameraProperty(self, iProperty):
        lFocusPos = C.c_long()
        Error = TIS_GrabberDLL.GetCameraProperty(self._handle, iProperty, lFocusPos)
        return lFocusPos.value

    def SetCameraProperty(self, iProperty, iValue):
        Error = TIS_GrabberDLL.SetCameraProperty(self._handle, iProperty, iValue)
        return Error

    def SetPropertyValue(self, Property, Element, Value):
        error = TIS_GrabberDLL.SetPropertyValue(
            self._handle, self.s(Property), self.s(Element), Value
        )
        return error

    def GetPropertyValue(self, Property, Element):
        Value = C.c_long()
        error = TIS_GrabberDLL.GetPropertyValue(
            self._handle, self.s(Property), self.s(Element), Value
        )
        return Value.value

    def PropertyAvailable(self, Property):
        Null = None
        error = TIS_GrabberDLL.IsPropertyAvailable(self._handle, self.s(Property), Null)
        return error

    def SetPropertySwitch(self, Property, Element, Value):
        error = TIS_GrabberDLL.SetPropertySwitch(
            self._handle, self.s(Property), self.s(Element), Value
        )
        return error

    def GetPropertySwitch(self, Property, Element, Value):
        lValue = C.c_long()
        error = TIS_GrabberDLL.GetPropertySwitch(
            self._handle, self.s(Property), self.s(Element), lValue
        )
        Value[0] = lValue.value
        return error

    def PropertyOnePush(self, Property, Element):
        error = TIS_GrabberDLL.PropertyOnePush(
            self._handle, self.s(Property), self.s(Element)
        )
        return error

    def SetPropertyAbsoluteValue(self, Property, Element, Value):
        error = TIS_GrabberDLL.SetPropertyAbsoluteValue(
            self._handle, self.s(Property), self.s(Element), Value
        )
        return error

    def GetPropertyAbsoluteValue(self, Property, Element, Value):
        """ Get a property value of absolute values interface, e.g. seconds or dB.
            Example code:
            ExposureTime=[0]
            Camera.GetPropertyAbsoluteValue("Exposure","Value", ExposureTime)
            print("Exposure time in secods: ", ExposureTime[0])

            :param Property: Name of the property, e.g. Gain, Exposure
            :param Element: Name of the element, e.g. "Value"
            :param Value: Object, that receives the value of the property
            :returns: 0 on success
            """
        lValue = C.c_float()
        error = TIS_GrabberDLL.GetPropertyAbsoluteValue(
            self._handle, self.s(Property), self.s(Element), lValue
        )
        Value[0] = lValue.value
        return error

    def SaveImage(self, FileName, FileType, Quality=75):
        """ Saves the last snapped image. Can by of type BMP or JPEG.
            :param FileName : Name of the mage file
            :param FileType : Determines file type, can be "JPEG" or "BMP"
            :param Quality : If file typ is JPEG, the qualitly can be given from 1 to 100.
            :return: Error code
            """
        return TIS_GrabberDLL.SaveImage(
            self._handle, self.s(FileName), IC.ImageFileTypes[self.s(FileType)], Quality
        )

    def openVideoCaptureDevice(self, DeviceName):
        """ Open the device specified by DeviceName
            :param DeviceName: Name of the device , e.g. "DFK 72AUC02"
            :returns: 1 on success, 0 otherwise.
            """
        return TIS_GrabberDLL.OpenVideoCaptureDevice(self._handle, self.s(DeviceName))

    def CreateFrameFilter(self, name):
        frame_filter_handle = FrameFilterHandle()

        err = TIS_GrabberDLL.CreateFrameFilter(
            C.c_char_p(name), C.byref(frame_filter_handle)
        )
        if err != 1:
            raise Exception("ERROR CREATING FILTER")
        return frame_filter_handle

    def AddFrameFilter(self, frame_filter_handle):
        err = TIS_GrabberDLL.AddFrameFilter(self._handle, frame_filter_handle)
        return err

    def FilterGetParameter(self, frame_filter_handle, parameter_name):
        data = C.c_int()

        err = TIS_GrabberDLL.FilterGetParameter(
            frame_filter_handle, parameter_name, C.byref(data)
        )
        return data.value

    def FilterSetParameter(self, frame_filter_handle, parameter_name, data):
        if type(data) is int:
            err = TIS_GrabberDLL.FilterSetParameter(
                frame_filter_handle, C.c_char_p(parameter_name), C.c_int(data)
            )
            return err
        else:
            raise Exception("Unknown set parameter type")
