.netwindowspowershellwia

How to change scanner DPI settings in powershell?


I am making updates to an old image processing app I wrote back when I first got hired on. One request that I have received is to have a "Scan" button on the app so that images can be both scanned and processed without having to open the Epson Scan Manager or push the button (some of the imaging techs have difficulty reaching their scan button from their seats). I have hacked something together in powershell that does the job and can be easily linked to a button in the python app, but I can't select a value for DPI. Resolution matters for these scans, both for customer facing and programmatic reasons, and they have to be at least 300 DPI, but they always save at a much lower resolution and I can't seem to figure out how to get in and alter the WIA settings for the scanner. I can control the compression once the file is saved but I can't control the resolution the scanner uses when it actually scans the picture. I have located this resource but don't know how to actually implement the changing of these settings. We only work with jpegs and these scanners are only used to scan products, with no filters or masks applied, so it should be pretty simple, but I just need to get this DPI thing figured out. This is what I have so far:

Set-ExecutionPolicy RemoteSigned

$deviceManager = new-object -ComObject WIA.DeviceManager
$device = $deviceManager.DeviceInfos.Item(1).Connect()

$imageProcess = new-object -ComObject WIA.ImageProcess

$wiaFormatJPEG = "{B96B3CAE-0728-11D3-9D7B-0000F81EF32E}"

foreach ($item in $device.Items) {
    $image = $item.Transfer() 
}

$Basepath = Join-Path -Path "C:\Users" -ChildPath $env:username
$NewPath = Join-Path -Path $BasePath -ChildPath "Pictures\My Scans\scan daemon"
$filename = Join-Path -Path $NewPath -ChildPath "Scan {0}.jpg"

$index = 0
while (test-path ($filename -f $index)) {[void](++$index)}
$filename = $filename -f $index

$image.SaveFile($filename)

I can get the scan and save the file, but it always gets saved in low res. This is a problem both because our customers want to see high res images and because my image processing app is expecting images of a certain size, and so won't even work correctly on these images if we were willing to use them. I feel like this should be pretty simple, possibly even a single line of code, but I'm not super familiar with Windows or powershell and am currently at a loss concerning what that line of code is or how to find it.

essentially I just want a way to do this:

SetWIAProperty(scannnerItem.Properties, WIA_HORIZONTAL_SCAN_RESOLUTION_DPI, 300);
SetWIAProperty(scannnerItem.Properties, WIA_VERTICAL_SCAN_RESOLUTION_DPI, 300);

in powershell. No matter where I look I can't seem to find a syntax guide for running .net commands in powershell that don't just deal with basic networking.


Solution

  • So I'm answering this question, not because it's solved, strictly speaking, but because I ended up solving the underlying problem in a different way. I rewrote the app that needs to do this in C#, using WIA directly to accomplish the scanning task. There are new issues with this approach but I can get the scan and adjust the image size and resolution. Since Powershell can make use of .Net assemblies, even custom ones, it would have been possible to run the scanning code via powershell if I had decided to keep using powershell, but it was just more sensible to rewrite everything in .Net, since doing so also improved other features of the program. Anyway, here is my .Net code, in case anyone else wants to do something like this:

        private static void AdjustScannerSettings(IItem scannerItem, int scanResolutionDPI, int scanStartLeftPixel, int scanStartTopPixel, int scanWidthPixels, int scanHeightPixels, int brightnessPercents, int contrastPercents, int colorMode)
        {
            const string WIA_SCAN_COLOR_MODE = "6146";
            const string WIA_HORIZONTAL_SCAN_RESOLUTION_DPI = "6147";
            const string WIA_VERTICAL_SCAN_RESOLUTION_DPI = "6148";
            const string WIA_HORIZONTAL_SCAN_START_PIXEL = "6149";
            const string WIA_VERTICAL_SCAN_START_PIXEL = "6150";
            const string WIA_HORIZONTAL_SCAN_SIZE_PIXELS = "6151";
            const string WIA_VERTICAL_SCAN_SIZE_PIXELS = "6152";
            const string WIA_SCAN_BRIGHTNESS_PERCENTS = "6154";
            const string WIA_SCAN_CONTRAST_PERCENTS = "6155";
            SetWIAProperty(scannerItem.Properties, "4104", 24);
            SetWIAProperty(scannerItem.Properties, WIA_HORIZONTAL_SCAN_RESOLUTION_DPI, scanResolutionDPI);
            SetWIAProperty(scannerItem.Properties, WIA_VERTICAL_SCAN_RESOLUTION_DPI, scanResolutionDPI);
            SetWIAProperty(scannerItem.Properties, WIA_HORIZONTAL_SCAN_START_PIXEL, scanStartLeftPixel);
            SetWIAProperty(scannerItem.Properties, WIA_VERTICAL_SCAN_START_PIXEL, scanStartTopPixel);
            SetWIAProperty(scannerItem.Properties, WIA_HORIZONTAL_SCAN_SIZE_PIXELS, scanWidthPixels);
            SetWIAProperty(scannerItem.Properties, WIA_VERTICAL_SCAN_SIZE_PIXELS, scanHeightPixels);
            SetWIAProperty(scannerItem.Properties, WIA_SCAN_BRIGHTNESS_PERCENTS, brightnessPercents);
            SetWIAProperty(scannerItem.Properties, WIA_SCAN_CONTRAST_PERCENTS, contrastPercents);
            SetWIAProperty(scannerItem.Properties, WIA_SCAN_COLOR_MODE, colorMode);
        }
        private static void SetWIAProperty(IProperties properties, object propName, object propValue)
        {
            Property prop = properties.get_Item(ref propName);
            prop.set_Value(ref propValue);
        }
        private void buttonScan_Click(object sender, EventArgs e)
        {
            var deviceManager = new DeviceManager();
            DeviceInfo firstScannerAvailable = null;
            for (int i = 1; i <= deviceManager.DeviceInfos.Count; i++)
            {
                if (deviceManager.DeviceInfos[i].Type != WiaDeviceType.ScannerDeviceType)
                {
                    continue;
                }
                firstScannerAvailable = deviceManager.DeviceInfos[i];
                break;
            }
            var device = firstScannerAvailable.Connect();
            var scannerItem = device.Items[1];
            int resolution = 300;
            int width_pixel = 3510;
            int height_pixel = 5100;
            int color_mode = 1;
            AdjustScannerSettings(scannerItem, resolution, 0, 0, width_pixel, height_pixel, 0, 0, color_mode);
    
            var imageFile = (ImageFile)scannerItem.Transfer("{B96B3CAE-0728-11D3-9D7B-0000F81EF32E}");
    
            var pathbase = Path.Combine(pictures, basedaemonpath);
            string filebase = DateTime.Now.ToString("dd-MM-yyyy-hh-mm-ss-fffffff") + ".jpg";
            var path = Path.Combine(pathbase, filebase);
    
            WIA.ImageProcess myip = new WIA.ImageProcess();  // use to compress jpeg.
            myip.Filters.Add(myip.FilterInfos["Convert"].FilterID);
            myip.Filters[1].Properties["FormatID"].set_Value("{B96B3CAE-0728-11D3-9D7B-0000F81EF32E}");
            myip.Filters[1].Properties["Quality"].set_Value(84);
    
            ImageFile image = myip.Apply(imageFile);
    
            image.SaveFile(path);
        }
    

    This has some problems of its own that I am still trying to deal with, but unless you need truly photo-quality images, this will work fine. Of course you need to change your path and variable names to fit your project, then, if you want to call the module in powershell, you can either compile this as an .exe file, and then just call it directly like any other file, or you can work with it directly as a .Net object:

    Create-Object -TypeName AdjustScannerSettings
    

    Again, I didn't end up doing this so I wouldn't call this problem "solved" per se, but this code works in my C# app and would work in powershell if I had decided to keep using that to call the settings changes. If anyone else is trying to scan with powershell, this should work if you are willing to deal with writing .Net code to do it. If you want a pure powershell solution, that's still waiting on someone better at this than myself to provide it. I will happily reallocate the check mark when and if that happens. ;)