chore: merge development into main (fix Windows build failure) #193
@@ -1,12 +1,9 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use crate::print::{
|
use crate::print::PrintOptions;
|
||||||
PrintOptions, Printer, PrinterCapabilities,
|
|
||||||
};
|
|
||||||
pub use crate::print::unix::{
|
pub use crate::print::unix::{
|
||||||
get_printer_capabilities, get_printers, merge_printer_info, parse_lpoptions_l,
|
get_printer_capabilities, get_printers,
|
||||||
parse_lpstat_d, parse_lpstat_e, parse_lpstat_p,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Construct `lp` command line arguments for target printing on macOS with ColorSync bypass flags.
|
/// Construct `lp` command line arguments for target printing on macOS with ColorSync bypass flags.
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod integration_tests {
|
mod integration_tests {
|
||||||
use crate::print::{
|
use crate::print::{
|
||||||
PrintOptions, Printer, PrinterCapabilities, PrinterDevModeStore, PrinterPaperSize,
|
PrintOptions, Printer, PrinterCapabilities, PrinterDevModeStore, PrinterMediaType,
|
||||||
PrinterTray,
|
PrinterPaperSize, PrinterTray,
|
||||||
};
|
};
|
||||||
use crate::print::unix::{build_lp_args, parse_lpstat_d, parse_lpstat_e, parse_lpstat_p, print_target};
|
use crate::print::unix::{build_lp_args, parse_lpstat_d, parse_lpstat_e, parse_lpstat_p, print_target};
|
||||||
|
|
||||||
@@ -46,6 +46,10 @@ mod integration_tests {
|
|||||||
name: "Letter (8.5 x 11 in)".to_string(),
|
name: "Letter (8.5 x 11 in)".to_string(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
media_types: vec![PrinterMediaType {
|
||||||
|
id: "1".to_string(),
|
||||||
|
name: "Plain Paper".to_string(),
|
||||||
|
}],
|
||||||
supports_orientation: true,
|
supports_orientation: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -53,6 +57,7 @@ mod integration_tests {
|
|||||||
assert!(json.contains("Auto Sheet Feeder"));
|
assert!(json.contains("Auto Sheet Feeder"));
|
||||||
assert!(json.contains("Rear Manual Feed"));
|
assert!(json.contains("Rear Manual Feed"));
|
||||||
assert!(json.contains("A4 (210 x 297 mm)"));
|
assert!(json.contains("A4 (210 x 297 mm)"));
|
||||||
|
assert!(json.contains("Plain Paper"));
|
||||||
|
|
||||||
let deserialized: PrinterCapabilities =
|
let deserialized: PrinterCapabilities =
|
||||||
serde_json::from_str(&json).expect("Failed to deserialize capabilities");
|
serde_json::from_str(&json).expect("Failed to deserialize capabilities");
|
||||||
@@ -65,6 +70,7 @@ mod integration_tests {
|
|||||||
paper_source: Some(2),
|
paper_source: Some(2),
|
||||||
orientation: Some("landscape".to_string()),
|
orientation: Some("landscape".to_string()),
|
||||||
paper_size: Some("A4".to_string()),
|
paper_size: Some("A4".to_string()),
|
||||||
|
media_type: Some("1".to_string()),
|
||||||
ppd_uncorrected_passthrough: Some(false),
|
ppd_uncorrected_passthrough: Some(false),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -74,6 +80,7 @@ mod integration_tests {
|
|||||||
assert_eq!(deserialized.paper_source, Some(2));
|
assert_eq!(deserialized.paper_source, Some(2));
|
||||||
assert_eq!(deserialized.orientation.as_deref(), Some("landscape"));
|
assert_eq!(deserialized.orientation.as_deref(), Some("landscape"));
|
||||||
assert_eq!(deserialized.paper_size.as_deref(), Some("A4"));
|
assert_eq!(deserialized.paper_size.as_deref(), Some("A4"));
|
||||||
|
assert_eq!(deserialized.media_type.as_deref(), Some("1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -221,6 +228,7 @@ printer Custom_Queue unknown state\n\
|
|||||||
paper_source: Some(3),
|
paper_source: Some(3),
|
||||||
orientation: Some("landscape".to_string()),
|
orientation: Some("landscape".to_string()),
|
||||||
paper_size: None,
|
paper_size: None,
|
||||||
|
media_type: Some("4".to_string()),
|
||||||
ppd_uncorrected_passthrough: None,
|
ppd_uncorrected_passthrough: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -235,6 +243,8 @@ printer Custom_Queue unknown state\n\
|
|||||||
assert_eq!((*p_work_devmode).Anonymous1.Anonymous1.dmDefaultSource, 3);
|
assert_eq!((*p_work_devmode).Anonymous1.Anonymous1.dmDefaultSource, 3);
|
||||||
// Verify orientation override
|
// Verify orientation override
|
||||||
assert_eq!((*p_work_devmode).Anonymous1.Anonymous1.dmOrientation, 2); // DMORIENT_LANDSCAPE = 2
|
assert_eq!((*p_work_devmode).Anonymous1.Anonymous1.dmOrientation, 2); // DMORIENT_LANDSCAPE = 2
|
||||||
|
// Verify media type override
|
||||||
|
assert_eq!((*p_work_devmode).dmMediaType, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify private OEM payload was NOT corrupted or overwritten
|
// Verify private OEM payload was NOT corrupted or overwritten
|
||||||
@@ -256,10 +266,8 @@ printer Custom_Queue unknown state\n\
|
|||||||
assert_eq!(args_raw[2], "-t");
|
assert_eq!(args_raw[2], "-t");
|
||||||
assert_eq!(args_raw[3], "ICCery Target - target_page_1.tif");
|
assert_eq!(args_raw[3], "ICCery Target - target_page_1.tif");
|
||||||
assert_eq!(args_raw[4], "-o");
|
assert_eq!(args_raw[4], "-o");
|
||||||
assert_eq!(args_raw[5], "raw");
|
assert_eq!(args_raw[5], "AP_ColorMatchingMode=AP_ApplicationColorMatching");
|
||||||
assert_eq!(args_raw[6], "-o");
|
assert_eq!(args_raw[6], path);
|
||||||
assert_eq!(args_raw[7], "AP_ColorMatchingMode=AP_ApplicationColorMatching");
|
|
||||||
assert_eq!(args_raw[8], path);
|
|
||||||
|
|
||||||
// PPD uncorrected passthrough mode with options
|
// PPD uncorrected passthrough mode with options
|
||||||
let opts = PrintOptions {
|
let opts = PrintOptions {
|
||||||
@@ -270,16 +278,10 @@ printer Custom_Queue unknown state\n\
|
|||||||
};
|
};
|
||||||
let args_ppd = macos_build_lp_args(printer, path, Some(&opts));
|
let args_ppd = macos_build_lp_args(printer, path, Some(&opts));
|
||||||
assert_eq!(args_ppd[4], "-o");
|
assert_eq!(args_ppd[4], "-o");
|
||||||
assert_eq!(args_ppd[5], "ColorModel=Gray");
|
assert_eq!(args_ppd[5], "AP_ColorMatchingMode=AP_ApplicationColorMatching");
|
||||||
assert_eq!(args_ppd[6], "-o");
|
assert!(args_ppd.contains(&"orientation-requested=4".to_string()));
|
||||||
assert_eq!(args_ppd[7], "cm-calibration");
|
assert!(args_ppd.contains(&"PageSize=A4".to_string()));
|
||||||
assert_eq!(args_ppd[8], "-o");
|
assert_eq!(args_ppd.last().unwrap(), path);
|
||||||
assert_eq!(args_ppd[9], "AP_ColorMatchingMode=AP_ApplicationColorMatching");
|
|
||||||
assert_eq!(args_ppd[10], "-o");
|
|
||||||
assert_eq!(args_ppd[11], "orientation-requested=4");
|
|
||||||
assert_eq!(args_ppd[12], "-o");
|
|
||||||
assert_eq!(args_ppd[13], "PageSize=A4");
|
|
||||||
assert_eq!(args_ppd[14], path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -451,7 +451,7 @@ PageSize/Media Size: *A4 Letter Legal A3\n\
|
|||||||
InputSlot/Media Source: *Auto Upper Lower Rear Manual\n\
|
InputSlot/Media Source: *Auto Upper Lower Rear Manual\n\
|
||||||
Duplex/2-Sided Printing: *None DuplexNoTumble DuplexTumble\n\
|
Duplex/2-Sided Printing: *None DuplexNoTumble DuplexTumble\n\
|
||||||
";
|
";
|
||||||
let (trays, paper_sizes, media_types) = parse_lpoptions_l(sample);
|
let (trays, paper_sizes, _media_types) = parse_lpoptions_l(sample);
|
||||||
assert_eq!(trays.len(), 5);
|
assert_eq!(trays.len(), 5);
|
||||||
assert_eq!(trays[0].name, "Auto");
|
assert_eq!(trays[0].name, "Auto");
|
||||||
assert_eq!(trays[1].name, "Upper");
|
assert_eq!(trays[1].name, "Upper");
|
||||||
@@ -484,9 +484,14 @@ Duplex/2-Sided Printing: *None DuplexNoTumble DuplexTumble\n\
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_build_lp_args_raw() {
|
fn test_build_lp_args_raw() {
|
||||||
let args = build_lp_args("Epson-Stylus-SX420W", "/tmp/target.tif", None);
|
let args = build_lp_args("Epson-Stylus-SX420W", "/tmp/target.tif", None);
|
||||||
assert_eq!(args.len(), 5);
|
assert_eq!(args.len(), 7);
|
||||||
assert_eq!(args[0], "-d");
|
assert_eq!(args[0], "-d");
|
||||||
assert_eq!(args[4], "/tmp/target.tif");
|
assert_eq!(args[1], "Epson-Stylus-SX420W");
|
||||||
|
assert_eq!(args[2], "-t");
|
||||||
|
assert_eq!(args[3], "ICCery Target - target.tif");
|
||||||
|
assert_eq!(args[4], "-o");
|
||||||
|
assert_eq!(args[5], "raw");
|
||||||
|
assert_eq!(args[6], "/tmp/target.tif");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ use windows::Win32::Graphics::Printing::{
|
|||||||
use windows::Win32::UI::WindowsAndMessaging::GetForegroundWindow;
|
use windows::Win32::UI::WindowsAndMessaging::GetForegroundWindow;
|
||||||
|
|
||||||
use crate::print::{
|
use crate::print::{
|
||||||
PrintOptions, Printer, PrinterCapabilities, PrinterDevModeStore, PrinterPaperSize, PrinterTray,
|
PrintOptions, Printer, PrinterCapabilities, PrinterDevModeStore, PrinterMediaType,
|
||||||
|
PrinterPaperSize, PrinterTray,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
@@ -54,11 +55,14 @@ const DM_ICMMETHOD: u32 = 0x00800000;
|
|||||||
const DMICMMETHOD_NONE: u32 = 1;
|
const DMICMMETHOD_NONE: u32 = 1;
|
||||||
const DMORIENT_PORTRAIT: i16 = 1;
|
const DMORIENT_PORTRAIT: i16 = 1;
|
||||||
const DMORIENT_LANDSCAPE: i16 = 2;
|
const DMORIENT_LANDSCAPE: i16 = 2;
|
||||||
|
const DM_MEDIATYPE: u32 = 0x02000000;
|
||||||
|
|
||||||
const DC_PAPERS: u16 = 2;
|
const DC_PAPERS: u16 = 2;
|
||||||
const DC_BINS: u16 = 6;
|
const DC_BINS: u16 = 6;
|
||||||
const DC_BINNAMES: u16 = 12;
|
const DC_BINNAMES: u16 = 12;
|
||||||
const DC_PAPERNAMES: u16 = 16;
|
const DC_PAPERNAMES: u16 = 16;
|
||||||
|
const DC_MEDIATYPENAMES: u16 = 34;
|
||||||
|
const DC_MEDIATYPES: u16 = 35;
|
||||||
const IDOK: i32 = 1;
|
const IDOK: i32 = 1;
|
||||||
|
|
||||||
fn to_wide(s: &str) -> Vec<u16> {
|
fn to_wide(s: &str) -> Vec<u16> {
|
||||||
@@ -262,9 +266,58 @@ pub fn get_printer_capabilities(printer_name: &str) -> Result<PrinterCapabilitie
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Query media types
|
||||||
|
let num_media = DeviceCapabilitiesW(
|
||||||
|
PCWSTR(printer_wide.as_ptr()),
|
||||||
|
PCWSTR::null(),
|
||||||
|
DC_MEDIATYPES,
|
||||||
|
std::ptr::null_mut(),
|
||||||
|
std::ptr::null(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut media_types = Vec::new();
|
||||||
|
if num_media > 0 {
|
||||||
|
let mut media_ids = vec![0u32; num_media as usize];
|
||||||
|
let mut media_names_raw = vec![0u16; num_media as usize * 64];
|
||||||
|
|
||||||
|
let res_ids = DeviceCapabilitiesW(
|
||||||
|
PCWSTR(printer_wide.as_ptr()),
|
||||||
|
PCWSTR::null(),
|
||||||
|
DC_MEDIATYPES,
|
||||||
|
media_ids.as_mut_ptr() as *mut u16,
|
||||||
|
std::ptr::null(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let res_names = DeviceCapabilitiesW(
|
||||||
|
PCWSTR(printer_wide.as_ptr()),
|
||||||
|
PCWSTR::null(),
|
||||||
|
DC_MEDIATYPENAMES,
|
||||||
|
media_names_raw.as_mut_ptr(),
|
||||||
|
std::ptr::null(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if res_ids > 0 && res_names > 0 {
|
||||||
|
for i in 0..num_media as usize {
|
||||||
|
let id = media_ids[i];
|
||||||
|
let name_slice = &media_names_raw[i * 64..(i + 1) * 64];
|
||||||
|
let name = extract_null_terminated_string(name_slice);
|
||||||
|
let display_name = if name.is_empty() {
|
||||||
|
format!("Media Type {}", id)
|
||||||
|
} else {
|
||||||
|
name
|
||||||
|
};
|
||||||
|
media_types.push(PrinterMediaType {
|
||||||
|
id: id.to_string(),
|
||||||
|
name: display_name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(PrinterCapabilities {
|
Ok(PrinterCapabilities {
|
||||||
trays,
|
trays,
|
||||||
paper_sizes,
|
paper_sizes,
|
||||||
|
media_types,
|
||||||
supports_orientation: true,
|
supports_orientation: true,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -370,6 +423,13 @@ pub fn apply_print_options_to_devmode(
|
|||||||
(*p_devmode).Anonymous1.Anonymous1.dmOrientation = DMORIENT_PORTRAIT;
|
(*p_devmode).Anonymous1.Anonymous1.dmOrientation = DMORIENT_PORTRAIT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(ref media_type) = opts.media_type {
|
||||||
|
if let Ok(media_id) = media_type.parse::<u32>() {
|
||||||
|
(*p_devmode).dmFields |= DEVMODE_FIELD_FLAGS(DM_MEDIATYPE);
|
||||||
|
(*p_devmode).dmMediaType = media_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user