Search code examples
pythonscanningsanepyinsane

Setting scan coordinates in device options on pyinsane


I use Sane's command line utility (scanimage) in order to scan films from the transparency unit of my scanner. Here is the command that I have been using with success:

scanimage --device-name pixma:04A9190D \
--source 'Transparency Unit' \
--resolution "4800" \
--format "tiff" \
--mode "color" \
-l "80.6" -x "56.2" -t "25.8" -y "219.2" \
> scan.tiff

I have decided to move this to Python code, using pyinsane in order to enable further integration with my image-processing workflow. This should supposedly give the following in Python code:

import pyinsane.abstract as pyinsane
device = pyinsane.get_devices()[0]

device.options['resolution'].value = 4800
device.options['mode'].value = 'Color'
device.options['source'].value = 'Transparency Unit'

# Setting coordinates to non-integers fails
device.options['tl-y'].value = 25.8
device.options['tl-x'].value = 80.6
device.options['br-y'].value = 219.2
device.options['br-x'].value = 56.2

scan_session = device.scan(multiple=False)
try:
    while True:
        scan_session.scan.read()
except EOFError:
    pass
image = scan_session.images[0]

But my first trials have been unsuccessful because I can not figure out how to set the scan coordinates pyinsane. As you see, I have found the appropriate options, but I don't know what unit they are in. scanimage takes the coordinates in millimetres by default, but pyinsane only takes integers. I have tried using pixel coordinates to no avail. I wonder what units the coordinate parameters take, and whether I am using them in the right order.


Solution

  • pyinsane's option descriptions actually say the values are in milimeters:

    Option: br-x
      Title: Bottom-right x
      Desc: Bottom-right x position of scan area.
      Type: <class 'pyinsane.rawapi.SaneValueType'> : Fixed (2)
      Unit: <class 'pyinsane.rawapi.SaneUnit'> : Mm (3)
      Size: 4
      Capabilities: <class 'pyinsane.rawapi.SaneCapabilities'> :[ Automatic, Soft_select, Soft_detect,]
      Constraint type: <class 'pyinsane.rawapi.SaneConstraintType'> : Range (1)
      Constraint: (0, 14160319, 0)
      Value: 20
    

    But they are not! I divided the range maximum for br-x variable by the width of the scanning area of my scanner, and I got to the number 65536 (which is 2^16). Setting the coordinates to the millimetre value times 65536 works. Maybe these values define the number of steps of the stepper motor?

    Also not that while scanimage interprets the -x and -y switches as width and length, and the -l and -t switches as offset, pyinsane takes bottom-right x (br-x), top-left y (tl-y), etc.