manuc66 / node-hp-scan-to

Allow to send scan from device to computer for some HP All-in-One Printers - Scan to computer
https://manuc66.github.io/node-hp-scan-to/
MIT License
163 stars 25 forks source link

Add Error handling in ScanCaps.ts for printers without ADF #805

Closed ibrummel closed 11 months ago

ibrummel commented 11 months ago

Catches the TypeError that is thrown when a printer without an ADF feature is queried for capabilities. The printer returns nothing under the "ADF" header, which crashes the application. Error handling returns null if this situation is caught.

ibrummel commented 11 months ago

I should have put this in the commit description but this is an issue that I ran into using an HP ENVY PHOTO 6255. Please let me know if I can improve the style or approach in this code. I am not very familiar with node or JS in general.

Cheers

manuc66 commented 11 months ago

Hi @ibrummel thanks for submitting this pr and sorry for the regression

Could you provide the payload sample that is causing the issue so that we can try to implement the fix without relying on Exception catch control flow

ibrummel commented 11 months ago

Hi @manuc66,

Best I can tell this issue is coming up because my printer returns information that just doesn't include an ADF block in the XML. The returned XML is here:

<?xml version="1.0" encoding="UTF-8"?>
<!-- THIS DATA SUBJECT TO DISCLAIMER(S) INCLUDED WITH THE PRODUCT OF ORIGIN. -->
<ScanCaps xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.hp.com/schemas/imaging/con/cnx/scan/2008/08/19">
        <DeviceCaps>
                <ModelName>ENVY Photo 6200 All-in-One Printer series</ModelName>
                <DerivativeNumber>0</DerivativeNumber>
        </DeviceCaps>
        <ColorEntries>
                <ColorEntry>
                        <ColorType>K1</ColorType>
                        <Formats>
                                <Format>Raw</Format>
                        </Formats>
                        <ImageTransforms>
                                <ImageTransform>ToneMap</ImageTransform>
                                <ImageTransform>Sharpening</ImageTransform>
                                <ImageTransform>BwThreshold</ImageTransform>
                        </ImageTransforms>
                </ColorEntry>
                <ColorEntry>
                        <ColorType>Gray8</ColorType>
                        <Formats>
                                <Format>Raw</Format>
                                <Format>Jpeg</Format>
                        </Formats>
                        <ImageTransforms>
                                <ImageTransform>ToneMap</ImageTransform>
                                <ImageTransform>Sharpening</ImageTransform>
                        </ImageTransforms>
                </ColorEntry>
                <ColorEntry>
                        <ColorType>Color8</ColorType>
                        <Formats>
                                <Format>Raw</Format>
                                <Format>Jpeg</Format>
                        </Formats>
                        <ImageTransforms>
                                <ImageTransform>ToneMap</ImageTransform>
                                <ImageTransform>Sharpening</ImageTransform>
                        </ImageTransforms>
                </ColorEntry>
        </ColorEntries>
        <Platen>
                <InputSourceCaps>
                        <MinWidth>8</MinWidth>
                        <MinHeight>8</MinHeight>
                        <MaxWidth>2550</MaxWidth>
                        <MaxHeight>3508</MaxHeight>
                        <RiskyLeftMargin>34</RiskyLeftMargin>
                        <RiskyRightMargin>34</RiskyRightMargin>
                        <RiskyTopMargin>42</RiskyTopMargin>
                        <RiskyBottomMargin>45</RiskyBottomMargin>
                        <MinResolution>75</MinResolution>
                        <MaxOpticalXResolution>1200</MaxOpticalXResolution>
                        <MaxOpticalYResolution>1200</MaxOpticalYResolution>
                        <SupportedResolutions>
                                <Resolution>
                                        <XResolution>75</XResolution>
                                        <YResolution>75</YResolution>
                                        <NumCcd>1</NumCcd>
                                        <ColorTypes>
                                                <ColorType>K1</ColorType>
                                                <ColorType>Gray8</ColorType>
                                                <ColorType>Color8</ColorType>
                                        </ColorTypes>
                                </Resolution>
                                <Resolution>
                                        <XResolution>100</XResolution>
                                        <YResolution>100</YResolution>
                                        <NumCcd>1</NumCcd>
                                        <ColorTypes>
                                                <ColorType>K1</ColorType>
                                                <ColorType>Gray8</ColorType>
                                                <ColorType>Color8</ColorType>
                                        </ColorTypes>
                                </Resolution>
                                <Resolution>
                                        <XResolution>150</XResolution>
                                        <YResolution>150</YResolution>
                                        <NumCcd>1</NumCcd>
                                        <ColorTypes>
                                                <ColorType>K1</ColorType>
                                                <ColorType>Gray8</ColorType>
                                                <ColorType>Color8</ColorType>
                                        </ColorTypes>
                                </Resolution>
                                <Resolution>
                                        <XResolution>200</XResolution>
                                        <YResolution>200</YResolution>
                                        <NumCcd>1</NumCcd>
                                        <ColorTypes>
                                                <ColorType>K1</ColorType>
                                                <ColorType>Gray8</ColorType>
                                                <ColorType>Color8</ColorType>
                                        </ColorTypes>
                                </Resolution>
                                <Resolution>
                                        <XResolution>300</XResolution>
                                        <YResolution>300</YResolution>
                                        <NumCcd>1</NumCcd>
                                        <ColorTypes>
                                                <ColorType>K1</ColorType>
                                                <ColorType>Gray8</ColorType>
                                                <ColorType>Color8</ColorType>
                                        </ColorTypes>
                                </Resolution>
                                <Resolution>
                                        <XResolution>400</XResolution>
                                        <YResolution>400</YResolution>
                                        <NumCcd>1</NumCcd>
                                        <ColorTypes>
                                                <ColorType>K1</ColorType>
                                                <ColorType>Gray8</ColorType>
                                                <ColorType>Color8</ColorType>
                                        </ColorTypes>
                                </Resolution>
                                <Resolution>
                                        <XResolution>600</XResolution>
                                        <YResolution>600</YResolution>
                                        <NumCcd>1</NumCcd>
                                        <ColorTypes>
                                                <ColorType>K1</ColorType>
                                                <ColorType>Gray8</ColorType>
                                                <ColorType>Color8</ColorType>
                                        </ColorTypes>
                                </Resolution>
                                <Resolution>
                                        <XResolution>1200</XResolution>
                                        <YResolution>1200</YResolution>
                                        <NumCcd>1</NumCcd>
                                        <ColorTypes>
                                                <ColorType>K1</ColorType>
                                                <ColorType>Gray8</ColorType>
                                                <ColorType>Color8</ColorType>
                                        </ColorTypes>
                                </Resolution>
                        </SupportedResolutions>
                </InputSourceCaps>
        </Platen>
</ScanCaps>

The parsed version before createScanCaps returns to the constructor looks like this, without an ADF block:

{
  ScanCaps: {

    '$': {

      \'xmlns:xsi\': 'http://www.w3.org/2001/XMLSchema-instance',

      xmlns: 'http://www.hp.com/schemas/imaging/con/cnx/scan/2008/08/19'

    },

    DeviceCaps: [ [Object] ],

    ColorEntries: [ [Object] ],

    Platen: [ [Object] ]

  }

}

When I was originally looking at the code, I thought the structure of the return statement in get AdfMaxWidth(): number | null and get AdfMaxHeight(): number | null would handle this, but it throws a TypeError as below:

TypeError: Cannot read properties of undefined (reading '0')

    at get AdfMaxWidth [as AdfMaxWidth] (/app/ScanCaps.js:28:45)

    at readDeviceCapabilities (/app/readDeviceCapabilities.js:41:84)

    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

    at async listenCmd (/app/index.js:27:32)

    at async Command.<anonymous> (/app/index.js:211:9)

    at async Command.parseAsync (/app/node_modules/commander/lib/command.js:936:5)

    at async main (/app/index.js:251:5)

Please let me know if I can help out with any other info, and sorry about going to exception catching, I come from the land of hobbyist Python where that seems to be pretty widely accepted practice.