from mvIMPACT import acquire

# This sample program does two things:
#
# First, it lists all the devices on your system for which a driver
# has been installed. The output looks like:
#
#    GX000002 : mvBlueCOUGAR-X120bG
#    GX000042 : mvBlueCOUGAR-X123C
#    VD000001 : VirtualDevice
#    VD000002 : VirtualDevice
#
# Then, it takes a snap from the last device in the list (VD000002 in the
# case above), and dumps it as a PNG file. The file is called demo.png.
#
# For the sample to work, you need the PIL and numpy packages.
# On Ubuntu, install them by typing
#
#    sudo apt-get install python-imaging python-numpy

import ctypes
import Image
import numpy

devMgr = acquire.DeviceManager()

nrOfDevices = devMgr.deviceCount()

if nrOfDevices == 0:
    print "No devices found"
    exit()

# list all the devices on the system for which a driver has been installed
for i in range(nrOfDevices):
    dev = devMgr[i];
    print dev.serial.read() + " : " + dev.product.read()

print

# method dummyRequest returns an object of class Request if all is fine,
# or a string specifying the error if not
def dummyRequest(fi, irc):
    prevMode = irc.mode.read()
    irc.mode.write(acquire.ircmTrial)

    res = fi.imageRequestSingle(irc)
    if res != acquire.DMR_NO_ERROR:
        return "imageRequestSingle error : %d" % res

    reqNr = fi.imageRequestWaitFor(-1)
    if reqNr < 0:
        return "imageRequestWaitFor error : %d" % reqNr

    req = fi.getRequest(reqNr)
    rr = req.requestResult.read()
    if rr != acquire.rrOK:
       return "getRequest error : %d" % rr

    irc.mode.write(prevMode)
    return req

def unlock(fi, req):
    res = fi.imageRequestUnlock(req.number) # reverts requestState to idle
    if res != acquire.DMR_NO_ERROR:
        closeAndExit(dev, "imageRequestUnlock error : %d" % res)
    if req.requestState.read() != acquire.rsIdle:
        closeAndExit(dev, "wrong request state : %d" % req.requestState.read())

# to ensure that the device is properly closed before the program exits
def closeAndExit(dev, errStr):
    print errStr
    dev.close()
    exit()

# dev = devMgr.getDeviceBySerial("VD000001")

dev.open() # dev still points to the last device (cf. line 35)

if not dev.isOpen:
    print "Device %s could not be opened" % dev.serial.read()
    exit()

fi = acquire.FunctionInterface(dev)
irc = acquire.ImageRequestControl(dev, "Base")
req = dummyRequest(fi, irc)
if type(req) == str:
    closeAndExit(dev, req)

width = req.imageWidth.read()
height = req.imageHeight.read()
stride = req.imageLinePitch.read(0)
imageSize = req.imageSize.read()
pixelFormat = req.imagePixelFormat.read()
alpha = pixelFormat == acquire.ibpfRGBx888Packed
channelCount = 4 if alpha else req.imageChannelCount.read()
channelBitDepth = req.imageChannelBitDepth.read(0) # no need to read further channels, if any, as we forbid YUV

unlock(fi, req)

if pixelFormat in (acquire.ibpfRGBx888Planar, acquire.ibpfYUV444Planar, acquire.ibpfYUV422Planar):
    closeAndExit(dev, "No planar pixel formats supported")
if pixelFormat in (acquire.ibpfYUV422_UYVYPacked, acquire.ibpfYUV422Packed):
    closeAndExit(dev, "No YUV pixel formats supported")

channelType = numpy.uint16 if channelBitDepth > 8 else numpy.uint8

# now use the same Request object for a real grab
requestNr = req.number
irc.requestToUse.write(requestNr)

res = fi.imageRequestSingle(irc)
if res == acquire.DMR_NO_ERROR:
    reqNr = fi.imageRequestWaitFor(2500)
    if reqNr == requestNr:
        if req.requestState.read() == acquire.rsReady:
            cbuf = (ctypes.c_char * imageSize).from_address(long(req.imageData.read()))
            arr = numpy.fromstring(cbuf, dtype = channelType)
            arr.shape = (height, width, channelCount)

            if channelCount == 1:
                img = Image.fromarray(arr)
            else:
                img = Image.fromarray(arr, 'RGBA' if alpha else 'RGB')
        else:
            closeAndExit(dev, "wrong request state : %d" % req.requestState.read())
    else:
        closeAndExit(dev, "imageRequestWaitFor error : %d" % reqNr)
else:
    closeAndExit(dev, "imageRequestSingle error : %d" % res)

unlock(fi, req)

img.save('demo.png') # use png, as it also supports RGBA

dev.close()
