Skip to main content

ipp_printer_app/
raster.rs

1//! [`RasterDriver`] trait + page-header DTO for raster print jobs.
2
3/// Failure of a print job, carrying IPP-visible printer reasons + a message.
4#[derive(Debug, Clone)]
5pub struct JobFailure {
6    /// Reasons OR'd into the printer's `printer-state-reasons` IPP attribute
7    /// when this job aborts.
8    pub printer_reasons: crate::flags::PrinterReason,
9    /// Human-readable message surfaced as `job-state-message`.
10    pub message: String,
11}
12
13impl JobFailure {
14    /// Build a failure with explicit `printer-state-reasons`.
15    pub fn new(
16        printer_reasons: crate::flags::PrinterReason,
17        message: impl Into<String>,
18    ) -> Self {
19        Self {
20            printer_reasons,
21            message: message.into(),
22        }
23    }
24
25    /// Shorthand for a generic failure (`PrinterReason::OTHER`).
26    pub fn other(message: impl Into<String>) -> Self {
27        Self::new(crate::flags::PrinterReason::OTHER, message)
28    }
29}
30
31impl std::fmt::Display for JobFailure {
32    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33        write!(f, "{}", self.message)
34    }
35}
36
37impl std::error::Error for JobFailure {}
38
39/// Page geometry parsed from a CUPS/PWG raster page header.
40#[derive(Debug, Clone)]
41pub struct JobOptions {
42    /// Page width in pixels.
43    pub width: u32,
44    /// Page height in pixels.
45    pub height: u32,
46    /// Bits per pixel (typically 1 for monochrome, 8 for grayscale, 24 for RGB).
47    pub bits_per_pixel: u32,
48    /// Bytes per scanline (already pre-padded by the raster source).
49    pub bytes_per_line: u32,
50    /// Number of copies requested. Always ≥ 1.
51    pub copies: u32,
52}
53
54impl JobOptions {
55    /// Construct from a CUPS raster v1 page header. `num_copies < 1` is
56    /// clamped to 1 per IPP convention.
57    pub fn from_cups_v1(
58        width: u32,
59        height: u32,
60        bits_per_pixel: u32,
61        bytes_per_line: u32,
62        num_copies: u32,
63    ) -> Self {
64        Self {
65            width,
66            height,
67            bits_per_pixel,
68            bytes_per_line,
69            copies: num_copies.max(1),
70        }
71    }
72}
73
74/// Driver that turns a stream of raster scanlines into device bytes.
75///
76/// Implementations are *per-job stateful* — `start_job` returns a fresh
77/// value that owns the page buffer, `write_line` accumulates scanlines,
78/// `end_page` transfers the page to the device, `end_job` releases
79/// resources. The framework's IPP `Print-Job` handler drives this trait;
80/// you only need to provide a type that knows how to talk to your device.
81pub trait RasterDriver: Sized + Send + 'static {
82    /// The driver's opaque device handle (e.g. an open HID descriptor).
83    type Device: Send;
84
85    /// Allocate per-job state. Called once at the top of each job.
86    fn start_job(
87        printer: &crate::printer::PrinterHandle<'_>,
88        options: &JobOptions,
89        device: &Self::Device,
90    ) -> Result<Self, JobFailure>;
91
92    /// Called once per page before any `write_line`. Default: no-op.
93    fn start_page(
94        &mut self,
95        _options: &JobOptions,
96        _page: u32,
97        _device: &Self::Device,
98    ) -> Result<(), JobFailure> {
99        Ok(())
100    }
101
102    /// Append one scanline to the page buffer.
103    fn write_line(
104        &mut self,
105        options: &JobOptions,
106        y: u32,
107        line: &[u8],
108    ) -> Result<(), JobFailure>;
109
110    /// Transfer the completed page to the device (and repeat for copies).
111    fn end_page(
112        &mut self,
113        options: &JobOptions,
114        page: u32,
115        device: &Self::Device,
116    ) -> Result<(), JobFailure>;
117
118    /// Release per-job state. Called once at the end of the job.
119    fn end_job(self, device: &Self::Device);
120}