feat(print): Windows Native Raw Print Spooler (GDI/ICM Bypass) (#26) #29
@@ -14,6 +14,10 @@ jobs:
|
|||||||
build-linux:
|
build-linux:
|
||||||
name: Build Linux
|
name: Build Linux
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
APPIMAGE_EXTRACT_AND_RUN: 1
|
||||||
|
NO_STRIP: "true"
|
||||||
|
RUST_BACKTRACE: "1"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
@@ -37,7 +41,8 @@ jobs:
|
|||||||
- name: Install Tauri Linux dependencies
|
- name: Install Tauri Linux dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y libwebkit2gtk-4.1-dev build-essential curl wget file libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev patchelf xdg-utils
|
sudo apt-get install -y libwebkit2gtk-4.1-dev build-essential curl wget file libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev patchelf xdg-utils squashfs-tools zsync libxss-dev libxinerama-dev libxrandr-dev libxxf86vm-dev libxcursor-dev libxi-dev
|
||||||
|
sudo apt-get install -y libfuse2 || sudo apt-get install -y libfuse2t64 || true
|
||||||
|
|
||||||
- name: Install Node dependencies
|
- name: Install Node dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
@@ -56,7 +61,7 @@ jobs:
|
|||||||
- name: Build Tauri App
|
- name: Build Tauri App
|
||||||
env:
|
env:
|
||||||
APPIMAGE_EXTRACT_AND_RUN: 1
|
APPIMAGE_EXTRACT_AND_RUN: 1
|
||||||
run: npm run tauri build
|
run: npm run tauri build -- -v
|
||||||
|
|
||||||
- name: Upload Debian Package
|
- name: Upload Debian Package
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
|
|||||||
Generated
+202
-14
@@ -334,6 +334,12 @@ version = "1.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder-lite"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.12.1"
|
version = "1.12.1"
|
||||||
@@ -567,6 +573,12 @@ version = "0.8.22"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17"
|
checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crunchy"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-common"
|
name = "crypto-common"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
@@ -965,6 +977,12 @@ version = "2.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
|
checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fax"
|
||||||
|
version = "0.2.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "caf1079563223d5d59d83c85886a56e586cfd5c1a26292e971a0fa266531ac5a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fdeflate"
|
name = "fdeflate"
|
||||||
version = "0.3.7"
|
version = "0.3.7"
|
||||||
@@ -1423,6 +1441,17 @@ dependencies = [
|
|||||||
"syn 2.0.119",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "half"
|
||||||
|
version = "2.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crunchy",
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.12.3"
|
version = "0.12.3"
|
||||||
@@ -1580,6 +1609,7 @@ name = "iccery"
|
|||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
|
"image",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri",
|
"tauri",
|
||||||
@@ -1587,6 +1617,7 @@ dependencies = [
|
|||||||
"tauri-plugin-dialog",
|
"tauri-plugin-dialog",
|
||||||
"tauri-plugin-opener",
|
"tauri-plugin-opener",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"windows 0.58.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1709,6 +1740,22 @@ dependencies = [
|
|||||||
"icu_properties",
|
"icu_properties",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "image"
|
||||||
|
version = "0.25.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
"byteorder-lite",
|
||||||
|
"moxcms",
|
||||||
|
"num-traits",
|
||||||
|
"png 0.18.1",
|
||||||
|
"tiff",
|
||||||
|
"zune-core",
|
||||||
|
"zune-jpeg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.9.3"
|
version = "1.9.3"
|
||||||
@@ -2074,6 +2121,16 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "moxcms"
|
||||||
|
version = "0.8.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
"pxfm",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "muda"
|
name = "muda"
|
||||||
version = "0.19.3"
|
version = "0.19.3"
|
||||||
@@ -2678,6 +2735,18 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pxfm"
|
||||||
|
version = "0.1.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-error"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-xml"
|
name = "quick-xml"
|
||||||
version = "0.41.0"
|
version = "0.41.0"
|
||||||
@@ -3384,7 +3453,7 @@ dependencies = [
|
|||||||
"tao-macros",
|
"tao-macros",
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
"url",
|
"url",
|
||||||
"windows",
|
"windows 0.61.3",
|
||||||
"windows-core 0.61.2",
|
"windows-core 0.61.2",
|
||||||
"windows-version",
|
"windows-version",
|
||||||
"x11-dl",
|
"x11-dl",
|
||||||
@@ -3455,7 +3524,7 @@ dependencies = [
|
|||||||
"webkit2gtk",
|
"webkit2gtk",
|
||||||
"webview2-com",
|
"webview2-com",
|
||||||
"window-vibrancy",
|
"window-vibrancy",
|
||||||
"windows",
|
"windows 0.61.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3596,7 +3665,7 @@ dependencies = [
|
|||||||
"tauri-plugin",
|
"tauri-plugin",
|
||||||
"thiserror 2.0.20",
|
"thiserror 2.0.20",
|
||||||
"url",
|
"url",
|
||||||
"windows",
|
"windows 0.61.3",
|
||||||
"zbus",
|
"zbus",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3622,7 +3691,7 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
"webkit2gtk",
|
"webkit2gtk",
|
||||||
"webview2-com",
|
"webview2-com",
|
||||||
"windows",
|
"windows 0.61.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3647,7 +3716,7 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
"webkit2gtk",
|
"webkit2gtk",
|
||||||
"webview2-com",
|
"webview2-com",
|
||||||
"windows",
|
"windows 0.61.3",
|
||||||
"wry",
|
"wry",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3762,6 +3831,20 @@ dependencies = [
|
|||||||
"syn 3.0.3",
|
"syn 3.0.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tiff"
|
||||||
|
version = "0.11.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b63feaf3343d35b6ca4d50483f94843803b0f51634937cc2ec519fc32232bc52"
|
||||||
|
dependencies = [
|
||||||
|
"fax",
|
||||||
|
"flate2",
|
||||||
|
"half",
|
||||||
|
"quick-error",
|
||||||
|
"weezl",
|
||||||
|
"zune-jpeg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.55"
|
version = "0.3.55"
|
||||||
@@ -4409,10 +4492,10 @@ checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"webview2-com-macros",
|
"webview2-com-macros",
|
||||||
"webview2-com-sys",
|
"webview2-com-sys",
|
||||||
"windows",
|
"windows 0.61.3",
|
||||||
"windows-core 0.61.2",
|
"windows-core 0.61.2",
|
||||||
"windows-implement",
|
"windows-implement 0.60.2",
|
||||||
"windows-interface",
|
"windows-interface 0.59.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4433,10 +4516,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c"
|
checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror 2.0.20",
|
"thiserror 2.0.20",
|
||||||
"windows",
|
"windows 0.61.3",
|
||||||
"windows-core 0.61.2",
|
"windows-core 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "weezl"
|
||||||
|
version = "0.1.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
@@ -4483,6 +4572,16 @@ dependencies = [
|
|||||||
"windows-version",
|
"windows-version",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows"
|
||||||
|
version = "0.58.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
|
||||||
|
dependencies = [
|
||||||
|
"windows-core 0.58.0",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows"
|
name = "windows"
|
||||||
version = "0.61.3"
|
version = "0.61.3"
|
||||||
@@ -4505,14 +4604,27 @@ dependencies = [
|
|||||||
"windows-core 0.61.2",
|
"windows-core 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-core"
|
||||||
|
version = "0.58.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
|
||||||
|
dependencies = [
|
||||||
|
"windows-implement 0.58.0",
|
||||||
|
"windows-interface 0.58.0",
|
||||||
|
"windows-result 0.2.0",
|
||||||
|
"windows-strings 0.1.0",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-core"
|
name = "windows-core"
|
||||||
version = "0.61.2"
|
version = "0.61.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
|
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-implement",
|
"windows-implement 0.60.2",
|
||||||
"windows-interface",
|
"windows-interface 0.59.3",
|
||||||
"windows-link 0.1.3",
|
"windows-link 0.1.3",
|
||||||
"windows-result 0.3.4",
|
"windows-result 0.3.4",
|
||||||
"windows-strings 0.4.2",
|
"windows-strings 0.4.2",
|
||||||
@@ -4524,8 +4636,8 @@ version = "0.62.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
|
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-implement",
|
"windows-implement 0.60.2",
|
||||||
"windows-interface",
|
"windows-interface 0.59.3",
|
||||||
"windows-link 0.2.1",
|
"windows-link 0.2.1",
|
||||||
"windows-result 0.4.1",
|
"windows-result 0.4.1",
|
||||||
"windows-strings 0.5.1",
|
"windows-strings 0.5.1",
|
||||||
@@ -4542,6 +4654,17 @@ dependencies = [
|
|||||||
"windows-threading",
|
"windows-threading",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-implement"
|
||||||
|
version = "0.58.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.119",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-implement"
|
name = "windows-implement"
|
||||||
version = "0.60.2"
|
version = "0.60.2"
|
||||||
@@ -4553,6 +4676,17 @@ dependencies = [
|
|||||||
"syn 2.0.119",
|
"syn 2.0.119",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-interface"
|
||||||
|
version = "0.58.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.119",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-interface"
|
name = "windows-interface"
|
||||||
version = "0.59.3"
|
version = "0.59.3"
|
||||||
@@ -4586,6 +4720,15 @@ dependencies = [
|
|||||||
"windows-link 0.1.3",
|
"windows-link 0.1.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-result"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-result"
|
name = "windows-result"
|
||||||
version = "0.3.4"
|
version = "0.3.4"
|
||||||
@@ -4604,6 +4747,16 @@ dependencies = [
|
|||||||
"windows-link 0.2.1",
|
"windows-link 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-strings"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
|
||||||
|
dependencies = [
|
||||||
|
"windows-result 0.2.0",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-strings"
|
name = "windows-strings"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
@@ -4946,7 +5099,7 @@ dependencies = [
|
|||||||
"webkit2gtk",
|
"webkit2gtk",
|
||||||
"webkit2gtk-sys",
|
"webkit2gtk-sys",
|
||||||
"webview2-com",
|
"webview2-com",
|
||||||
"windows",
|
"windows 0.61.3",
|
||||||
"windows-core 0.61.2",
|
"windows-core 0.61.2",
|
||||||
"windows-version",
|
"windows-version",
|
||||||
"x11-dl",
|
"x11-dl",
|
||||||
@@ -5066,6 +5219,26 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.8.56"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.8.56"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.119",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerofrom"
|
name = "zerofrom"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
@@ -5126,6 +5299,21 @@ version = "1.0.23"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zune-core"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zune-jpeg"
|
||||||
|
version = "0.5.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296"
|
||||||
|
dependencies = [
|
||||||
|
"zune-core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zvariant"
|
name = "zvariant"
|
||||||
version = "5.15.0"
|
version = "5.15.0"
|
||||||
|
|||||||
@@ -25,4 +25,13 @@ serde_json = "1"
|
|||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
||||||
tauri-plugin-dialog = "2.7.2"
|
tauri-plugin-dialog = "2.7.2"
|
||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
|
image = { version = "0.25", default-features = false, features = ["tiff", "png", "jpeg"] }
|
||||||
|
|
||||||
|
[target.'cfg(windows)'.dependencies]
|
||||||
|
windows = { version = "0.58", features = [
|
||||||
|
"Win32_Foundation",
|
||||||
|
"Win32_Graphics_Gdi",
|
||||||
|
"Win32_Graphics_Printing",
|
||||||
|
"Win32_Storage_FileSystem",
|
||||||
|
"Win32_UI_WindowsAndMessaging",
|
||||||
|
] }
|
||||||
|
|||||||
@@ -342,6 +342,16 @@ pub async fn run_profcheck(
|
|||||||
state.spawn(app, id, binary, args, cwd).await
|
state.spawn(app, id, binary, args, cwd).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn get_windows_printers() -> Result<Vec<String>, String> {
|
||||||
|
crate::print::get_printers()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn print_target_windows(printer_name: String, tiff_path: String) -> Result<(), String> {
|
||||||
|
crate::print::print_target(&printer_name, &tiff_path)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
mod commands;
|
mod commands;
|
||||||
mod events;
|
mod events;
|
||||||
|
mod print;
|
||||||
mod process_manager;
|
mod process_manager;
|
||||||
mod settings;
|
mod settings;
|
||||||
|
|
||||||
@@ -23,6 +24,8 @@ pub fn run() {
|
|||||||
commands::run_chartread,
|
commands::run_chartread,
|
||||||
commands::run_colprof,
|
commands::run_colprof,
|
||||||
commands::run_profcheck,
|
commands::run_profcheck,
|
||||||
|
commands::get_windows_printers,
|
||||||
|
commands::print_target_windows,
|
||||||
settings::load_settings,
|
settings::load_settings,
|
||||||
settings::save_settings,
|
settings::save_settings,
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#[cfg(windows)]
|
||||||
|
pub mod windows;
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub use windows::*;
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
pub fn get_printers() -> Result<Vec<String>, String> {
|
||||||
|
Err("Direct native printer querying is only supported on Windows in this build.".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
pub fn print_target(printer_name: &str, tiff_path: &str) -> Result<(), String> {
|
||||||
|
let _ = (printer_name, tiff_path);
|
||||||
|
Err("Direct native raw printing is currently implemented for Windows. macOS/Linux CUPS support is planned for the next sub-task.".to_string())
|
||||||
|
}
|
||||||
@@ -0,0 +1,309 @@
|
|||||||
|
use std::ffi::{c_void, OsStr};
|
||||||
|
use std::os::windows::ffi::OsStrExt;
|
||||||
|
use std::path::Path;
|
||||||
|
use windows::core::{PCWSTR, PWSTR};
|
||||||
|
use windows::Win32::Foundation::{HANDLE, HWND};
|
||||||
|
use windows::Win32::Graphics::Gdi::{
|
||||||
|
CreateDCW, DeleteDC, GetDeviceCaps, SetICMMode, StretchDIBits,
|
||||||
|
BITMAPINFO, BITMAPINFOHEADER, BI_RGB, DIB_RGB_COLORS, HDC, HORZRES,
|
||||||
|
ICM_OFF, LOGPIXELSX, LOGPIXELSY, SRCCOPY, VERTRES,
|
||||||
|
};
|
||||||
|
use windows::Win32::Graphics::Printing::{
|
||||||
|
ClosePrinter, DocumentPropertiesW, EndDoc, EndPage, EnumPrintersW,
|
||||||
|
OpenPrinterW, StartDocW, StartPage, DEVMODEW, DMICMMETHOD_NONE,
|
||||||
|
DM_ICMMETHOD, DM_OUT_BUFFER, DOCINFOW, PRINTER_ENUM_CONNECTIONS,
|
||||||
|
PRINTER_ENUM_LOCAL, PRINTER_INFO_2W, PRINTER_INFO_4W,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn to_wide(s: &str) -> Vec<u16> {
|
||||||
|
OsStr::new(s).encode_wide().chain(std::iter::once(0)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enumerate available printers on the system
|
||||||
|
pub fn get_printers() -> Result<Vec<String>, String> {
|
||||||
|
unsafe {
|
||||||
|
let flags = PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS;
|
||||||
|
let mut bytes_needed = 0u32;
|
||||||
|
let mut count = 0u32;
|
||||||
|
|
||||||
|
// Query buffer size using Level 4 (fast local & network connections)
|
||||||
|
let _ = EnumPrintersW(
|
||||||
|
flags,
|
||||||
|
PCWSTR::null(),
|
||||||
|
4,
|
||||||
|
None,
|
||||||
|
0,
|
||||||
|
&mut bytes_needed,
|
||||||
|
&mut count,
|
||||||
|
);
|
||||||
|
|
||||||
|
if bytes_needed == 0 {
|
||||||
|
// Fallback to Level 2
|
||||||
|
let _ = EnumPrintersW(
|
||||||
|
flags,
|
||||||
|
PCWSTR::null(),
|
||||||
|
2,
|
||||||
|
None,
|
||||||
|
0,
|
||||||
|
&mut bytes_needed,
|
||||||
|
&mut count,
|
||||||
|
);
|
||||||
|
|
||||||
|
if bytes_needed == 0 {
|
||||||
|
return Ok(Vec::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut buffer = vec![0u8; bytes_needed as usize];
|
||||||
|
let success = EnumPrintersW(
|
||||||
|
flags,
|
||||||
|
PCWSTR::null(),
|
||||||
|
2,
|
||||||
|
Some(buffer.as_mut_ptr()),
|
||||||
|
bytes_needed,
|
||||||
|
&mut bytes_needed,
|
||||||
|
&mut count,
|
||||||
|
);
|
||||||
|
|
||||||
|
if !success.as_bool() {
|
||||||
|
return Err("Failed to enumerate printers (Level 2)".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let p_info = buffer.as_ptr() as *const PRINTER_INFO_2W;
|
||||||
|
let mut printers = Vec::new();
|
||||||
|
for i in 0..count as usize {
|
||||||
|
let info = *p_info.add(i);
|
||||||
|
if !info.pPrinterName.is_null() {
|
||||||
|
let name = info.pPrinterName.to_string().map_err(|e| e.to_string())?;
|
||||||
|
printers.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(printers);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut buffer = vec![0u8; bytes_needed as usize];
|
||||||
|
let success = EnumPrintersW(
|
||||||
|
flags,
|
||||||
|
PCWSTR::null(),
|
||||||
|
4,
|
||||||
|
Some(buffer.as_mut_ptr()),
|
||||||
|
bytes_needed,
|
||||||
|
&mut bytes_needed,
|
||||||
|
&mut count,
|
||||||
|
);
|
||||||
|
|
||||||
|
if !success.as_bool() {
|
||||||
|
return Err("Failed to enumerate printers (Level 4)".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let p_info = buffer.as_ptr() as *const PRINTER_INFO_4W;
|
||||||
|
let mut printers = Vec::new();
|
||||||
|
for i in 0..count as usize {
|
||||||
|
let info = *p_info.add(i);
|
||||||
|
if !info.pPrinterName.is_null() {
|
||||||
|
let name = info.pPrinterName.to_string().map_err(|e| e.to_string())?;
|
||||||
|
printers.push(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(printers)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Print target TIFF file to printer with GDI ICM bypass and DIB drawing
|
||||||
|
pub fn print_target(printer_name: &str, tiff_path: &str) -> Result<(), String> {
|
||||||
|
let path = Path::new(tiff_path);
|
||||||
|
if !path.exists() {
|
||||||
|
return Err(format!("Target TIFF file not found: {}", tiff_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load and convert the TIFF image
|
||||||
|
let dyn_img = image::open(path).map_err(|e| format!("Failed to open TIFF image: {}", e))?;
|
||||||
|
let rgb_img = dyn_img.to_rgb8();
|
||||||
|
let img_width = rgb_img.width();
|
||||||
|
let img_height = rgb_img.height();
|
||||||
|
|
||||||
|
if img_width == 0 || img_height == 0 {
|
||||||
|
return Err("Image has zero dimensions".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare 24-bit BGR DIB buffer with 4-byte row stride alignment
|
||||||
|
let row_stride = ((img_width as usize * 3 + 3) / 4) * 4;
|
||||||
|
let mut dib_bytes = vec![0u8; row_stride * img_height as usize];
|
||||||
|
|
||||||
|
for y in 0..img_height as usize {
|
||||||
|
for x in 0..img_width as usize {
|
||||||
|
let pixel = rgb_img.get_pixel(x as u32, y as u32);
|
||||||
|
let dst_idx = y * row_stride + x * 3;
|
||||||
|
dib_bytes[dst_idx] = pixel[2]; // Blue
|
||||||
|
dib_bytes[dst_idx + 1] = pixel[1]; // Green
|
||||||
|
dib_bytes[dst_idx + 2] = pixel[0]; // Red
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let printer_wide = to_wide(printer_name);
|
||||||
|
let doc_name = format!("ICCery Target - {}", path.file_name().and_then(|n| n.to_str()).unwrap_or("Profiling Target"));
|
||||||
|
let doc_name_wide = to_wide(&doc_name);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// Open printer handle
|
||||||
|
let mut h_printer = HANDLE::default();
|
||||||
|
let open_res = OpenPrinterW(PCWSTR(printer_wide.as_ptr()), &mut h_printer, None);
|
||||||
|
if !open_res.as_bool() || h_printer.is_invalid() {
|
||||||
|
return Err(format!("Failed to open printer '{}'", printer_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure DEVMODE if possible
|
||||||
|
let devmode_size = DocumentPropertiesW(
|
||||||
|
HWND::default(),
|
||||||
|
h_printer,
|
||||||
|
PCWSTR(printer_wide.as_ptr()),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut devmode_buf = if devmode_size > 0 {
|
||||||
|
let mut buf = vec![0u8; devmode_size as usize];
|
||||||
|
let res = DocumentPropertiesW(
|
||||||
|
HWND::default(),
|
||||||
|
h_printer,
|
||||||
|
PCWSTR(printer_wide.as_ptr()),
|
||||||
|
Some(buf.as_mut_ptr() as *mut DEVMODEW),
|
||||||
|
None,
|
||||||
|
DM_OUT_BUFFER,
|
||||||
|
);
|
||||||
|
if res >= 0 {
|
||||||
|
let p_devmode = buf.as_mut_ptr() as *mut DEVMODEW;
|
||||||
|
// Attempt to explicitly disable driver ICM if supported in DEVMODE
|
||||||
|
(*p_devmode).dmFields |= DM_ICMMETHOD;
|
||||||
|
(*p_devmode).dmICMMethod = DMICMMETHOD_NONE as i32;
|
||||||
|
Some(buf)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let p_devmode_ptr = devmode_buf
|
||||||
|
.as_mut()
|
||||||
|
.map(|b| b.as_mut_ptr() as *const DEVMODEW);
|
||||||
|
|
||||||
|
// Create printer Device Context (DC)
|
||||||
|
let hdc = CreateDCW(
|
||||||
|
PCWSTR::null(),
|
||||||
|
PCWSTR(printer_wide.as_ptr()),
|
||||||
|
PCWSTR::null(),
|
||||||
|
p_devmode_ptr,
|
||||||
|
);
|
||||||
|
|
||||||
|
if hdc.is_invalid() {
|
||||||
|
let _ = ClosePrinter(h_printer);
|
||||||
|
return Err(format!("Failed to create Device Context for printer '{}'", printer_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
// STRICT ICM BYPASS: Turn off Windows GDI Image Color Management
|
||||||
|
let prev_icm = SetICMMode(hdc, ICM_OFF as i32);
|
||||||
|
if prev_icm == 0 {
|
||||||
|
// Note: Some printer drivers report 0 if ICM is unsupported or already off
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start Document
|
||||||
|
let doc_info = DOCINFOW {
|
||||||
|
cbSize: std::mem::size_of::<DOCINFOW>() as i32,
|
||||||
|
lpszDocName: PCWSTR(doc_name_wide.as_ptr()),
|
||||||
|
lpszOutput: PCWSTR::null(),
|
||||||
|
lpszDatatype: PCWSTR::null(),
|
||||||
|
fwType: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
let start_doc_res = StartDocW(hdc, &doc_info);
|
||||||
|
if start_doc_res <= 0 {
|
||||||
|
let _ = DeleteDC(hdc);
|
||||||
|
let _ = ClosePrinter(h_printer);
|
||||||
|
return Err("Failed to start print document (StartDocW)".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start Page
|
||||||
|
let start_page_res = StartPage(hdc);
|
||||||
|
if start_page_res <= 0 {
|
||||||
|
let _ = EndDoc(hdc);
|
||||||
|
let _ = DeleteDC(hdc);
|
||||||
|
let _ = ClosePrinter(h_printer);
|
||||||
|
return Err("Failed to start print page (StartPage)".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query DC dimensions and DPI
|
||||||
|
let dpi_x = GetDeviceCaps(hdc, LOGPIXELSX);
|
||||||
|
let dpi_y = GetDeviceCaps(hdc, LOGPIXELSY);
|
||||||
|
let page_width = GetDeviceCaps(hdc, HORZRES);
|
||||||
|
let page_height = GetDeviceCaps(hdc, VERTRES);
|
||||||
|
|
||||||
|
// Calculate destination dimensions assuming standard 300 DPI target
|
||||||
|
let target_dpi = 300.0f64;
|
||||||
|
let mut dest_width = ((img_width as f64 / target_dpi) * dpi_x as f64).round() as i32;
|
||||||
|
let mut dest_height = ((img_height as f64 / target_dpi) * dpi_y as f64).round() as i32;
|
||||||
|
|
||||||
|
// If target exceeds page bounds, scale proportionally to fit printable area
|
||||||
|
if dest_width > page_width || dest_height > page_height {
|
||||||
|
let scale_x = page_width as f64 / dest_width as f64;
|
||||||
|
let scale_y = page_height as f64 / dest_height as f64;
|
||||||
|
let scale = scale_x.min(scale_y);
|
||||||
|
dest_width = (dest_width as f64 * scale).round() as i32;
|
||||||
|
dest_height = (dest_height as f64 * scale).round() as i32;
|
||||||
|
}
|
||||||
|
|
||||||
|
let dest_x = (page_width - dest_width).max(0) / 2;
|
||||||
|
let dest_y = (page_height - dest_height).max(0) / 2;
|
||||||
|
|
||||||
|
// Build BITMAPINFO structure for top-down 24-bit DIB
|
||||||
|
let mut bmi = BITMAPINFO {
|
||||||
|
bmiHeader: BITMAPINFOHEADER {
|
||||||
|
biSize: std::mem::size_of::<BITMAPINFOHEADER>() as u32,
|
||||||
|
biWidth: img_width as i32,
|
||||||
|
biHeight: -(img_height as i32), // Negative height denotes top-down DIB
|
||||||
|
biPlanes: 1,
|
||||||
|
biBitCount: 24,
|
||||||
|
biCompression: BI_RGB.0,
|
||||||
|
biSizeImage: dib_bytes.len() as u32,
|
||||||
|
biXPelsPerMeter: ((dpi_x as f64 / 0.0254).round()) as i32,
|
||||||
|
biYPelsPerMeter: ((dpi_y as f64 / 0.0254).round()) as i32,
|
||||||
|
biClrUsed: 0,
|
||||||
|
biClrImportant: 0,
|
||||||
|
},
|
||||||
|
bmiColors: [windows::Win32::Graphics::Gdi::RGBQUAD::default()],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Draw unmanaged DIB to printer device context
|
||||||
|
let lines_drawn = StretchDIBits(
|
||||||
|
hdc,
|
||||||
|
dest_x,
|
||||||
|
dest_y,
|
||||||
|
dest_width,
|
||||||
|
dest_height,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
img_width as i32,
|
||||||
|
img_height as i32,
|
||||||
|
Some(dib_bytes.as_ptr() as *const c_void),
|
||||||
|
&bmi,
|
||||||
|
DIB_RGB_COLORS,
|
||||||
|
SRCCOPY,
|
||||||
|
);
|
||||||
|
|
||||||
|
if lines_drawn <= 0 {
|
||||||
|
let _ = EndPage(hdc);
|
||||||
|
let _ = EndDoc(hdc);
|
||||||
|
let _ = DeleteDC(hdc);
|
||||||
|
let _ = ClosePrinter(h_printer);
|
||||||
|
return Err("Failed to draw DIB bitmap to printer DC (StretchDIBits)".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish Page and Document
|
||||||
|
let _ = EndPage(hdc);
|
||||||
|
let _ = EndDoc(hdc);
|
||||||
|
let _ = DeleteDC(hdc);
|
||||||
|
let _ = ClosePrinter(h_printer);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user