From 7abd0c2afdb14296f6008ec30364e82f8ebaa76b Mon Sep 17 00:00:00 2001 From: reng Date: Wed, 30 Jul 2025 12:09:28 +0800 Subject: [PATCH] fix pdf convert --- src-tauri/Cargo.lock | 418 ++++++++++++++++++++++++++++++++++- src-tauri/Cargo.toml | 2 + src-tauri/src/lib.rs | 77 +++++-- src-tauri/src/raw_convert.rs | 198 +++++++++++++++++ src-tauri/src/util.rs | 39 ++-- src-tauri/tauri.conf.json | 4 +- src/App.jsx | 20 ++ 7 files changed, 719 insertions(+), 39 deletions(-) create mode 100644 src-tauri/src/raw_convert.rs diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index b736001..3aa95c0 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -43,6 +43,15 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" +[[package]] +name = "aligned-vec" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc890384c8602f339876ded803c97ad529f3842aba97f6392b3dba0dd171769b" +dependencies = [ + "equator", +] + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -72,7 +81,7 @@ dependencies = [ "encoding_rs", "flate2", "glyph-names", - "itertools", + "itertools 0.10.5", "lazy_static", "log", "num-traits", @@ -107,6 +116,23 @@ version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "arrayref" version = "0.3.9" @@ -306,6 +332,29 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "av1-grain" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3efb2ca85bc610acfa917b5aaa36f3fcbebed5b3182d7f877b02531c4b80c8" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ea8ef51aced2b9191c08197f55450d830876d9933f8f48a429b354f1d496b42" +dependencies = [ + "arrayvec", +] + [[package]] name = "azul-core" version = "0.0.5" @@ -381,6 +430,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + [[package]] name = "bitflags" version = "1.3.2" @@ -405,6 +460,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "bitstream-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" + [[package]] name = "block-buffer" version = "0.10.4" @@ -485,6 +546,12 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "built" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ed6191a7e78c36abdb16ab65341eefd73d64d303fffccdbb00d51e4205967b" + [[package]] name = "bumpalo" version = "3.19.0" @@ -606,6 +673,8 @@ version = "1.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" dependencies = [ + "jobserver", + "libc", "shlex", ] @@ -798,12 +867,37 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-common" version = "0.1.6" @@ -1128,6 +1222,26 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "equator" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" +dependencies = [ + "equator-macro", +] + +[[package]] +name = "equator-macro" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -1184,6 +1298,21 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "exr" +version = "1.73.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +dependencies = [ + "bit_field", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + [[package]] name = "fastrand" version = "2.3.0" @@ -1782,6 +1911,16 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" +dependencies = [ + "cfg-if", + "crunchy", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -2124,9 +2263,16 @@ dependencies = [ "bytemuck", "byteorder-lite", "color_quant", + "exr", "gif", + "image-webp", "num-traits", "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", "zune-core", "zune-jpeg", ] @@ -2147,6 +2293,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" +[[package]] +name = "imgref" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0263a3d970d5c054ed9312c0057b4f3bde9c0b33836d3637361d4a9e6e7a408" + [[package]] name = "indexmap" version = "1.9.3" @@ -2188,6 +2340,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "io-uring" version = "0.7.9" @@ -2243,6 +2406,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "0.4.8" @@ -2300,6 +2472,22 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jobserver" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00810f1d8b74be64b13dbf3db89ac67740615d6c891f0e7b6179326533011a07" + [[package]] name = "js-sys" version = "0.3.77" @@ -2384,6 +2572,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + [[package]] name = "libappindicator" version = "0.9.0" @@ -2414,6 +2608,16 @@ version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +[[package]] +name = "libfuzzer-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404" +dependencies = [ + "arbitrary", + "cc", +] + [[package]] name = "libloading" version = "0.7.4" @@ -2469,6 +2673,15 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + [[package]] name = "lopdf" version = "0.35.0" @@ -2542,6 +2755,16 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + [[package]] name = "md-5" version = "0.10.6" @@ -2733,12 +2956,59 @@ dependencies = [ "nom", ] +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.104", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -3149,6 +3419,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "pathdiff" version = "0.2.3" @@ -3451,6 +3727,8 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" name = "printer" version = "0.1.0" dependencies = [ + "flate2", + "image", "printers", "printpdf", "serde", @@ -3566,6 +3844,34 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "profiling" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" +dependencies = [ + "quote", + "syn 2.0.104", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + [[package]] name = "quick-error" version = "2.0.1" @@ -3721,12 +4027,82 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93e7e49bb0bf967717f7bd674458b3d6b0c5f48ec7e3038166026a69fc22223" +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools 0.12.1", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand 0.8.5", + "rand_chacha 0.3.1", + "simd_helpers", + "system-deps", + "thiserror 1.0.69", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5825c26fddd16ab9f515930d49028a630efec172e903483c94796cfe31893e6b" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error", + "rav1e", + "rayon", + "rgb", +] + [[package]] name = "raw-window-handle" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "redox_syscall" version = "0.5.15" @@ -4381,6 +4757,15 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + [[package]] name = "simplecss" version = "0.2.2" @@ -5124,6 +5509,17 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + [[package]] name = "time" version = "0.3.41" @@ -5705,6 +6101,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "v_frame" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "666b7727c8875d6ab5db9533418d7c764233ac9c0cff1d469aec8fa127597be2" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + [[package]] name = "vcpkg" version = "0.2.15" @@ -6819,6 +7226,15 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + [[package]] name = "zune-jpeg" version = "0.4.19" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index efe8039..1ef7f11 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -27,3 +27,5 @@ winprint = "0.2.0" tauri-plugin-dialog = "2" printpdf = { version="0.8.2", features= ["png"] } tauri-plugin-fs = "2" +image = "0.25.6" +flate2 = "1.1.2" diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 480b322..1a18696 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -8,7 +8,8 @@ use winprint::ticket::{ }; // use util::imageToPdf; -mod util; +// mod util; +mod raw_convert; #[tauri::command] fn get_all_printers() -> Vec { @@ -24,6 +25,28 @@ fn get_my_device(device_name: String) -> Option { printers.into_iter().find(|x| x.name() == device_name) } +#[tauri::command] +fn convert_pdf(document_path: String) -> Result { + let path = Path::new(&document_path); + if !path.exists() { + return Err(format!("File does not exist: {}", document_path)); + } + + + match raw_convert::imageToPdf2(document_path.clone()) { + Ok(pdf_path) => { + // Print the converted PDF using the printer + // printer.print(Path::new(&pdf_path), ticket).unwrap(); + println!("PDF converted successfully to {}", pdf_path); + Ok(pdf_path) + } + Err(e) => { + println!("Error converting image to PDF: {}", e); + Err(e) + } + } +} + #[tauri::command] fn get_printer_capabilities(device_name: String) -> HashMap> { let my_device = match get_my_device(device_name) { @@ -117,6 +140,31 @@ fn print_document( document_path, size, dpi, color ); + let path = Path::new(&document_path); + if path + .extension() + .map(|ext| !ext.eq_ignore_ascii_case("pdf")) + .unwrap_or(true) + { + match raw_convert::imageToPdf2(document_path.clone()) { + Ok(pdf_path) => { + print_document( + device_name, + pdf_path, + dpi, + color, + size, + ); + } + Err(e) => { + println!("Error converting image to PDF: {}", e); + } + } + return; + } + + + let my_device = match get_my_device(device_name.clone()) { Some(device) => device, None => { @@ -182,30 +230,12 @@ fn print_document( let path = Path::new(&document_path); let printer = PdfiumPrinter::new(my_device); + // let theprinter = ImagePrinter::new(my_device); - if path - .extension() - .map(|ext| ext.eq_ignore_ascii_case("pdf")) - .unwrap_or(false) - { - - printer.print(path, ticket).unwrap(); + printer.print(path, ticket).unwrap(); - } else { - match util::imageToPdf(document_path.clone()) { - Ok(pdf_path) => { - // Print the converted PDF using the printer - printer.print(Path::new(&pdf_path), ticket).unwrap(); - } - Err(e) => { - println!("Error converting image to PDF: {}", e); - } - } - }; + - // let theprinter = PdfiumPrinter::new(my_device); - // let theprinter = ImagePrinter::new(my_device); - // theprinter.print(path, ticket).unwrap(); } #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { @@ -216,7 +246,8 @@ pub fn run() { .invoke_handler(tauri::generate_handler![ get_all_printers, print_document, - get_printer_capabilities + get_printer_capabilities, + convert_pdf ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src-tauri/src/raw_convert.rs b/src-tauri/src/raw_convert.rs new file mode 100644 index 0000000..6f8b71c --- /dev/null +++ b/src-tauri/src/raw_convert.rs @@ -0,0 +1,198 @@ +use std::path::Path; +use flate2::write::ZlibEncoder; +use flate2::Compression; +use image::{DynamicImage, GenericImageView}; +use std::fs::File; +use std::io::{self, Read, Write}; + + +pub fn imageToPdf2(path: String) -> Result { + + let image_data = std::fs::read(&path).expect("Failed to read image"); + let pdf_data = img2pdf_from_bytes(&image_data, 300.0).expect("Failed to convert image to PDF"); + + + let pdf_path = Path::new(&path).with_extension("pdf"); + + match std::fs::write(&pdf_path, pdf_data) { + Ok(_) => Ok(pdf_path.display().to_string()), + Err(e) => Err(format!("Failed to write PDF file: {}", e)), + } + +} + + + + +/// Converts an image from binary data to a PDF as binary data. +/// +/// # Arguments +/// +/// * `img_data` - A slice of bytes representing the image data. +/// +/// # Returns +/// +/// A `Result` containing the PDF data as a `Vec` on success, or an `io::Error` on failure. +pub fn img2pdf_from_bytes(img_data: &[u8], dpi: f64) -> io::Result> { + + let img = image::load_from_memory(img_data).expect("Failed to open image"); + let (width, height) = img.dimensions(); + + let (page_width, page_height) = ( + ((width as f64) / dpi * 72.0).round() as u32, + ((height as f64) / dpi * 72.0).round() as u32, + ); + + println!("Image size in pixels: {}x{}", width, height); + println!("Dest Image size in points: {}x{}", page_width, page_height); + + let (rgb_img, mask_img) = separate_rgb_and_alpha(img); + + let mut encoder = ZlibEncoder::new(Vec::new(), Compression::best()); + encoder.write_all(&rgb_img)?; + let rgb_data = encoder.finish()?; + + let mut encoder = ZlibEncoder::new(Vec::new(), Compression::best()); + encoder.write_all(&mask_img)?; + let mask_data = encoder.finish()?; + + let mut pdf_data = Vec::new(); + + writeln!(pdf_data, "%PDF-1.4")?; + + let image_object_id = 2; + let image_object_pos = pdf_data.len(); + writeln!( + pdf_data, + "{} 0 obj\n<< /Type /XObject /Subtype /Image /Width {} /Height {} /ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /FlateDecode /Length {} /SMask {} 0 R >>", + image_object_id, + width, + height, + // page_width, + // page_height, + rgb_data.len(), + image_object_id + 1 + )?; + writeln!(pdf_data, "stream")?; + pdf_data.extend(&rgb_data); + writeln!(pdf_data, "endstream\nendobj")?; + + let mask_object_id = image_object_id + 1; + let mask_object_pos = pdf_data.len(); + writeln!( + pdf_data, + "{} 0 obj\n<< /Type /XObject /Subtype /Image /Width {} /Height {} /ColorSpace /DeviceGray /BitsPerComponent 8 /Filter /FlateDecode /Length {} >>", + mask_object_id, + width, + height, + // page_width, + // page_height, + mask_data.len() + )?; + writeln!(pdf_data, "stream")?; + pdf_data.extend(&mask_data); + writeln!(pdf_data, "endstream\nendobj")?; + + let content_stream_object_id = 5; + let content_stream_pos = pdf_data.len(); + let content = format!( + "q\n{} 0 0 {} 0 0 cm\n/Im{} Do\nQ", + // width, height, image_object_id + page_width, page_height, image_object_id + ); + writeln!( + pdf_data, + "{} 0 obj\n<< /Length {} >>", + content_stream_object_id, + content.len() + )?; + writeln!(pdf_data, "stream\n{}\nendstream\nendobj", content)?; + + let page_object_id = 4; + let page_object_pos = pdf_data.len(); + writeln!( + pdf_data, + "{} 0 obj\n<< /Type /Page /Parent 1 0 R /MediaBox [0 0 {} {}] /Contents {} 0 R /Resources << /XObject << /Im{} {} 0 R >> >> >>", + page_object_id, + // width, height, + page_width, page_height, + content_stream_object_id, image_object_id, image_object_id + )?; + writeln!(pdf_data, "endobj")?; + + let pages_object_pos = pdf_data.len(); + writeln!( + pdf_data, + "1 0 obj\n<< /Type /Pages /Kids [ {} 0 R ] /Count 1 >>", + page_object_id + )?; + writeln!(pdf_data, "endobj")?; + + let catalog_object_pos = pdf_data.len(); + writeln!(pdf_data, "6 0 obj\n<< /Type /Catalog /Pages 1 0 R >>")?; + writeln!(pdf_data, "endobj")?; + + let xref_start = pdf_data.len(); + writeln!(pdf_data, "xref")?; + writeln!(pdf_data, "0 7")?; + writeln!(pdf_data, "0000000000 65535 f ")?; + writeln!(pdf_data, "{:010} 00000 n ", pages_object_pos)?; + writeln!(pdf_data, "{:010} 00000 n ", image_object_pos)?; + writeln!(pdf_data, "{:010} 00000 n ", mask_object_pos)?; + writeln!(pdf_data, "{:010} 00000 n ", page_object_pos)?; + writeln!(pdf_data, "{:010} 00000 n ", content_stream_pos)?; + writeln!(pdf_data, "{:010} 00000 n ", catalog_object_pos)?; + + writeln!(pdf_data, "trailer\n<< /Size 7 /Root 6 0 R >>")?; + writeln!(pdf_data, "startxref\n{}", xref_start)?; + writeln!(pdf_data, "%%EOF")?; + + Ok(pdf_data) +} + +/// Separates the RGB and alpha channels of an image. +/// +/// # Arguments +/// +/// * `img` - The `DynamicImage` to be processed. +/// +/// # Returns +/// +/// A tuple containing the RGB data and the alpha channel data. +fn separate_rgb_and_alpha(img: DynamicImage) -> (Vec, Vec) { + let rgba = img.to_rgba8(); + let mut rgb = Vec::with_capacity(rgba.len() / 4 * 3); + let mut alpha = Vec::with_capacity(rgba.len() / 4); + + for pixel in rgba.pixels() { + rgb.push(pixel[0]); + rgb.push(pixel[1]); + rgb.push(pixel[2]); + alpha.push(pixel[3]); + } + + (rgb, alpha) +} + +/// Converts an image from a file to a PDF file. +/// +/// # Arguments +/// +/// * `input_path` - The path to the input image file. +/// * `output_path` - The path to the output PDF file. +/// +/// # Returns +/// +/// An `io::Result` indicating success or failure. +pub fn img2pdf_from_file>(input_path: P, output_path: P, dpi: f64) -> io::Result<()> { + let mut input_file = File::open(input_path)?; + let mut img_data = Vec::new(); + input_file.read_to_end(&mut img_data)?; + + let pdf_data = img2pdf_from_bytes(&img_data, dpi)?; + + let mut output_file = File::create(output_path)?; + output_file.write_all(&pdf_data)?; + + Ok(()) +} \ No newline at end of file diff --git a/src-tauri/src/util.rs b/src-tauri/src/util.rs index e28a505..c4cddcb 100644 --- a/src-tauri/src/util.rs +++ b/src-tauri/src/util.rs @@ -2,27 +2,28 @@ use printpdf::*; use std::path::Path; - pub fn imageToPdf(path: String) -> Result { let mut doc = PdfDocument::new("image_to_pdf"); let image_bytes = std::fs::read(&path).map_err(|e| e.to_string())?; let image = RawImage::decode_from_bytes(&image_bytes, &mut Vec::new()).unwrap(); + let mut ops = Vec::new(); // In the PDF, an image is an `XObject`, identified by a unique `ImageId` let image_xobject_id = doc.add_image(&image); // Calculate image size in points (1 point = 1/72 inch) - // let dpi = 300.0; - // let output_width= 105.0; // A6 width in mm - // let output_height = 148.0; // A6 height in mm - // let mm_to_pt = 1.0 / 25.4; // Conversion factor - // let width_pt = output_width * mm_to_pt * dpi / image.width as f64; - // let height_pt = output_height * mm_to_pt * dpi / image.height as f64; + let dpi = 300.0; + let output_width= 105.0; // A6 width in mm + let output_height = 148.0; // A6 height in mm + let mm_to_pt = dpi / 25.4; // Conversion factor + let width_pt = output_width * mm_to_pt; + let height_pt = output_height * mm_to_pt; - // println!("Image size in points: {}x{}", width_pt, height_pt); + println!("Image size in pixels: {}x{}", image.width, image.height); + println!("Dest Image size in points: {}x{}", width_pt, height_pt); // Place the image at (0,0) with the calculated size ops.push(Op::UseXobject { @@ -30,17 +31,28 @@ pub fn imageToPdf(path: String) -> Result { transform: XObjectTransform { translate_x: Some(Pt(0.0)), translate_y: Some(Pt(0.0)), - scale_x: Some(1.0), - scale_y: Some(1.0), - dpi: Some(300.0), + dpi: Some(dpi), ..Default::default() }, + }); - let page1 = PdfPage::new(Mm(105.0), Mm(148.0), ops); + let save_options= PdfSaveOptions { + optimize: false, + image_optimization: Some(ImageOptimizationOptions { + quality: Some(1.0), + auto_optimize: Some(false), + format: Some(ImageCompression::None), + ..ImageOptimizationOptions::default() + }), + ..Default::default() + }; + + + let page1 = PdfPage::new(Mm(output_width), Mm(output_height), ops); let pdf_bytes: Vec = doc .with_pages(vec![page1]) - .save(&PdfSaveOptions::default(), &mut Vec::new()); + .save(&save_options, &mut Vec::new()); let pdf_path = Path::new(&path).with_extension("pdf"); @@ -55,3 +67,4 @@ pub fn imageToPdf(path: String) -> Result { Err(e) => Err(format!("Failed to write PDF: {}", e)), } } + diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index c63ca07..15f226f 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -13,8 +13,8 @@ "windows": [ { "title": "printer", - "width": 350, - "height": 480 + "width": 400, + "height": 560 } ], "security": { diff --git a/src/App.jsx b/src/App.jsx index e0516dd..ca38992 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -42,6 +42,22 @@ function App() { console.error("Error fetching printers:", error); }); } + function convertPdf() { + const file = selectedFile; + if (!file) { + console.error("No document selected for conversion."); + return; + } + invoke("convert_pdf", { documentPath: file }) + .then((convertedFilePath) => { + console.log("Converted file path:", convertedFilePath); + document.getElementById("pdf_path_label").textContent = convertedFilePath; + }) + .catch((error) => { + console.error("Error converting PDF:", error); + }); + } + function printDocument() { @@ -143,6 +159,10 @@ function App() { + + + + );