Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix duplex ADF #1088

Merged
merged 13 commits into from
Jan 30, 2025
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ It has been developed and tested with the following HP All-in-One Printers:
- HP DeskJet 3520
- HP OfficeJet 6500A Plus
- HP Smart Tank Plus 570 series
- HP OfficeJet Pro 9019e

Additionally, it has been reported to work on several other HP printer models.
- HP DeskJet 3050 All-in-One - J610a
Expand Down Expand Up @@ -59,7 +60,7 @@ Please note that the `node-hp-scan-to` project is not endorsed by nor affiliated
- ✔️ Customizable resolution
- ✔️ Customizable label on the device
- ✔️ Multi platform: Linux, Windows and most probably macOS
- ✔️ Mutile target supported: folder, [paperless-ngx](https://docs.paperless-ngx.com/) api upload, nextcloud webdav upload
- ✔️ Mutiple target supported: folder, [paperless-ngx](https://docs.paperless-ngx.com/) api upload, nextcloud webdav upload
- ✔️ Clear all registered target
- ✔️ Automatic scan when automatic document feeder is getting loaded

Expand Down Expand Up @@ -135,7 +136,7 @@ Exhaustive list of supported environment variables and their meaning, or corresp
- `NEXTCLOUD_USERNAME`: nextcloud user name
- `NEXTCLOUD_PASSWORD`: password of nextcloud user. Either this or `NEXTCLOUD_PASSWORD_FILE` is required. If both are provided, value of `NEXTCLOUD_PASSWORD_FILE` is used.
- `NEXTCLOUD_PASSWORD_FILE`: file name containing password of nextcloud user. Either this or `NEXTCLOUD_PASSWORD` is required. If both are provided, this value is used. For example: `NEXTCLOUD_PASSWORD_FILE=./nextcloud_password.secret`. Preferably for use in [docker compose secrets](https://docs.docker.com/reference/compose-file/secrets/)
- `$KEEP_FILES`: if set the scanned files will not be deleted, after uploading to paperless-ngx or nextcloud
- `KEEP_FILES`: if set the scanned files will not be deleted, after uploading to paperless-ngx or nextcloud
- `CMDLINE`: additional command-line flags that will be put at the end of the command.

__To enable debug logs set the environment variable `CMDLINE` to `-D`.__
Expand Down
2 changes: 2 additions & 0 deletions src/DeviceCapabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ export interface DeviceCapabilities {
platenMaxHeight: number | null;
adfMaxWidth: number | null;
adfMaxHeight: number | null;
adfDuplexMaxWidth: number | null;
adfDuplexMaxHeight: number | null;
}
42 changes: 42 additions & 0 deletions src/ScanCaps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ export interface ScanCapsData {
MaxWidth: string[];
MaxHeight: string[];
}[];
AdfDuplexer: {
AdfDuplexMaxWidth: string[];
AdfDuplexMaxHeight: string[];
}[];
}[];
};
}
Expand Down Expand Up @@ -78,4 +82,42 @@ export default class ScanCaps {
return null;
}
}

get adfDuplexMaxWidth(): number | null {
if (
Object.prototype.hasOwnProperty.call(this.data["ScanCaps"], "Adf") &&
Object.prototype.hasOwnProperty.call(
this.data["ScanCaps"]["Adf"][0],
"AdfDuplexer",
)
) {
return Number.parseInt(
this.data["ScanCaps"]["Adf"][0]["AdfDuplexer"][0][
"AdfDuplexMaxWidth"
][0],
10,
);
} else {
return this.adfMaxWidth;
}
}

get adfDuplexMaxHeight(): number | null {
if (
Object.prototype.hasOwnProperty.call(this.data["ScanCaps"], "Adf") &&
Object.prototype.hasOwnProperty.call(
this.data["ScanCaps"]["Adf"][0],
"AdfDuplexer",
)
) {
return Number.parseInt(
this.data["ScanCaps"]["Adf"][0]["AdfDuplexer"][0][
"AdfDuplexMaxHeight"
][0],
10,
);
} else {
return this.adfMaxHeight;
}
}
}
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,9 +424,9 @@ function getScanConfiguration(option: OptionValues) {
? Number.MAX_SAFE_INTEGER
: parseInt(configWidth, 10);

const configHeight = (option.width || getConfig("height") || "0").toString();
const configHeight = (option.height || getConfig("height") || 0).toString();
const height =
configWidth.toLowerCase() === "max"
configHeight.toLowerCase() === "max"
? Number.MAX_SAFE_INTEGER
: parseInt(configHeight, 10);

Expand Down
2 changes: 2 additions & 0 deletions src/readDeviceCapabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,7 @@ export async function readDeviceCapabilities(): Promise<DeviceCapabilities> {
platenMaxHeight: scanCaps?.platenMaxHeight || null,
adfMaxWidth: scanCaps?.adfMaxWidth || null,
adfMaxHeight: scanCaps?.adfMaxHeight || null,
adfDuplexMaxWidth: scanCaps?.adfDuplexMaxWidth || null,
manuc66 marked this conversation as resolved.
Show resolved Hide resolved
adfDuplexMaxHeight: scanCaps?.adfDuplexMaxHeight || null,
};
}
50 changes: 32 additions & 18 deletions src/scanProcessing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,45 +310,47 @@ export function getScanWidth(
scanConfig: ScanConfig,
inputSource: InputSource,
deviceCapabilities: DeviceCapabilities,
isDuplex: boolean,
): number | null {
if (scanConfig.width && scanConfig.width > 0) {
const maxWidth =
inputSource === InputSource.Adf
? deviceCapabilities.adfMaxWidth
: deviceCapabilities.platenMaxWidth;
const maxWidth =
inputSource === InputSource.Adf
? isDuplex
? deviceCapabilities.adfDuplexMaxWidth
: deviceCapabilities.adfMaxWidth
: deviceCapabilities.platenMaxWidth;

if (scanConfig.width && scanConfig.width > 0) {
if (maxWidth && scanConfig.width > maxWidth) {
return maxWidth;
} else {
return scanConfig.width;
}
} else {
return inputSource === InputSource.Adf
? deviceCapabilities.adfMaxWidth
: deviceCapabilities.platenMaxWidth;
return maxWidth;
}
}

export function getScanHeight(
scanConfig: ScanConfig,
inputSource: InputSource,
deviceCapabilities: DeviceCapabilities,
isDuplex: boolean,
): number | null {
if (scanConfig.height && scanConfig.height > 0) {
const maxHeight =
inputSource === InputSource.Adf
? deviceCapabilities.adfMaxHeight
: deviceCapabilities.platenMaxHeight;
const maxHeight =
inputSource === InputSource.Adf
? isDuplex
? deviceCapabilities.adfDuplexMaxHeight
: deviceCapabilities.adfMaxHeight
: deviceCapabilities.platenMaxHeight;

if (scanConfig.height && scanConfig.height > 0) {
if (maxHeight && scanConfig.height > maxHeight) {
return maxHeight;
} else {
return scanConfig.height;
}
} else {
return inputSource === InputSource.Adf
? deviceCapabilities.adfMaxHeight
: deviceCapabilities.platenMaxHeight;
return maxHeight;
}
}

Expand Down Expand Up @@ -403,8 +405,18 @@ export async function saveScanFromEvent(
console.log("Afd is : " + scanStatus.adfState);

const inputSource = scanStatus.getInputSource();
const scanWidth = getScanWidth(scanConfig, inputSource, deviceCapabilities);
const scanHeight = getScanHeight(scanConfig, inputSource, deviceCapabilities);
const scanWidth = getScanWidth(
scanConfig,
inputSource,
deviceCapabilities,
isDuplex,
);
const scanHeight = getScanHeight(
scanConfig,
inputSource,
deviceCapabilities,
isDuplex,
);

const scanJobSettings = new ScanJobSettings(
inputSource,
Expand Down Expand Up @@ -495,11 +507,13 @@ export async function scanFromAdf(
adfAutoScanConfig,
InputSource.Adf,
deviceCapabilities,
adfAutoScanConfig.isDuplex,
);
const scanHeight = getScanHeight(
adfAutoScanConfig,
InputSource.Adf,
deviceCapabilities,
adfAutoScanConfig.isDuplex,
);

const scanJobSettings = new ScanJobSettings(
Expand Down
51 changes: 51 additions & 0 deletions test/ScanCaps.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ describe("ScanCaps", () => {
it("AdfMaxHeight", async () => {
expect(scanCaps.adfMaxHeight).to.be.eq(4200);
});
it("AdfDuplexMaxWidth", async () => {
expect(scanCaps.adfDuplexMaxWidth).to.be.eq(2550);
});
it("AdfDuplexMaxHeight", async () => {
expect(scanCaps.adfDuplexMaxHeight).to.be.eq(4200);
});
it("PlatenMaxWidth", async () => {
expect(scanCaps.platenMaxWidth).to.be.eq(2550);
});
Expand Down Expand Up @@ -52,6 +58,12 @@ describe("ScanCaps", () => {
it("AdfMaxHeight", async () => {
expect(scanCaps.adfMaxHeight).to.be.eq(null);
});
it("AdfDuplexMaxWidth", async () => {
expect(scanCaps.adfDuplexMaxWidth).to.be.eq(null);
});
it("AdfDuplexMaxHeight", async () => {
expect(scanCaps.adfDuplexMaxHeight).to.be.eq(null);
});
it("PlatenMaxWidth", async () => {
expect(scanCaps.platenMaxWidth).to.be.eq(2550);
});
Expand Down Expand Up @@ -79,11 +91,50 @@ describe("ScanCaps", () => {
it("AdfMaxHeight", async () => {
expect(scanCaps.adfMaxHeight).to.be.eq(5100);
});
it("AdfDuplexMaxWidth", async () => {
expect(scanCaps.adfDuplexMaxWidth).to.be.eq(2550);
});
it("AdfDuplexMaxHeight", async () => {
expect(scanCaps.adfDuplexMaxHeight).to.be.eq(5100);
});
it("PlatenMaxWidth", async () => {
expect(scanCaps.platenMaxWidth).to.be.eq(null);
});
it("PlatenMaxHeight", async () => {
expect(scanCaps.platenMaxHeight).to.be.eq(null);
});
});
describe("Parsing ScanCaps_with_duplex_adf.xml", async () => {
let scanCaps: ScanCaps;

before(async () => {
const content: string = await fs.readFile(
path.resolve(
__dirname,
"./asset/ScanCaps_with_duplex_adf.xml"
),
{ encoding: "utf8" } //
);
scanCaps = await ScanCaps.createScanCaps(content);
});

it("AdfMaxWidth", async () => {
expect(scanCaps.adfMaxWidth).to.be.eq(2550);
});
it("AdfMaxHeight", async () => {
expect(scanCaps.adfMaxHeight).to.be.eq(4200);
});
it("AdfDuplexMaxWidth", async () => {
expect(scanCaps.adfDuplexMaxWidth).to.be.eq(2550);
});
it("AdfDuplexMaxHeight", async () => {
expect(scanCaps.adfDuplexMaxHeight).to.be.eq(3508);
});
it("PlatenMaxWidth", async () => {
expect(scanCaps.platenMaxWidth).to.be.eq(2550);
});
it("PlatenMaxHeight", async () => {
expect(scanCaps.platenMaxHeight).to.be.eq(3534);
});
});
});
Loading
Loading