escpos_rust/printer/
printer_profile.rs

1use std::collections::HashMap;
2use crate::{
3    Error,
4    command::Font
5};
6
7/// Available connections with the printer
8///
9/// Determines the kind of connection that will be sustained with the printer. At the moment, only Usb and Terminal are implemented. Try not to use this enum directly, use the builder pattern instead (using the [usb_builder](PrinterProfile::usb_builder) or [usb_builder](PrinterProfile::terminal_builder) methods. `network_builder` soon to be available).
10#[derive(Clone, Debug)]
11pub enum PrinterConnectionData {
12    /// Usb connection
13    Usb {
14        /// Vendor id for the printer
15        vendor_id: u16,
16        /// product id for the printer
17        product_id: u16,
18        /// Endpoint where the usb data is meant to be written to
19        endpoint: Option<u8>,
20        /// Timeout for bulk write operations
21        timeout: std::time::Duration
22    },
23    /// Network connection (not implemented yet)
24    Network {
25        _host: String,
26        _port: u16
27    },
28    /// Terminal printer, used for really simple previews.
29    Terminal
30}
31
32/// Details required to connect and print
33///
34/// In order to use the full functionality of the library, some information should be provided regarding the printer. The bare minimum information needed is the product id and the vendor id.
35#[derive(Clone, Debug)]
36pub struct PrinterProfile {
37    /// Existing connection to the printer
38    pub (crate) printer_connection_data: PrinterConnectionData,
39    /// Paper width, in characters, for the printer
40    pub (crate) columns_per_font: HashMap<Font, u8>,
41    /// Total printer width in pixels, for image printing
42    pub (crate) width: u16
43}
44
45impl PrinterProfile {
46    /// Create custom printing details
47    ///
48    /// Not recommended to use, as it contains a lot of arguments. See one of the builders instead (at the moment, only [usb_builder](PrinterProfile::usb_builder) and [terminal_builder](PrinterProfile::terminal_builder) available).
49    pub fn new(printer_connection_data: PrinterConnectionData, columns_per_font: HashMap<Font, u8>, width: u16) -> PrinterProfile {
50        PrinterProfile {
51            printer_connection_data,
52            columns_per_font,
53            width
54        }
55    }
56
57    /// Creates a [PrinterProfileBuilder](crate::PrinterProfileBuilder) set for usb printing.
58    ///
59    /// Equivalent to a call to [PrinterProfileBuilder](crate::PrinterProfileBuilder)'s [new_usb](crate::PrinterProfileBuilder::new_usb) function.
60    /// ```rust
61    /// use escpos_rs::PrinterProfile;
62    /// // Creates a minimum data structure to connect to a printer
63    /// let printer_profile = PrinterProfile::usb_builder(0x0001, 0x0001).build();
64    /// ```
65    pub fn usb_builder(vendor_id: u16, product_id: u16) -> PrinterProfileBuilder {
66        PrinterProfileBuilder::new_usb(vendor_id, product_id)
67    }
68
69    /// Creates a [PrinterProfileBuilder](crate::PrinterProfileBuilder) set for terminal printing
70    ///
71    /// Equivalent to a call to [PrinterProfileBuilder](crate::PrinterProfileBuilder)'s [new_terminal](crate::PrinterProfileBuilder::new_terminal) function.
72    /// ```rust
73    /// use escpos_rs::PrinterProfile;
74    /// // Creates a minimum data structure to connect to a printer
75    /// let printer_profile = PrinterProfile::terminal_builder().build();
76    /// ```
77    pub fn terminal_builder() -> PrinterProfileBuilder {
78        PrinterProfileBuilder::new_terminal()
79    }
80}
81
82/// Helper structure to create a [PrinterProfile](crate::PrinterProfile)
83///
84/// Builder pattern for the [PrinterProfile](crate::PrinterProfile) structure.
85pub struct PrinterProfileBuilder {
86    /// The connection to the printer
87    printer_connection_data: PrinterConnectionData,
88    /// Columns that each font spans at maximum
89    columns_per_font: HashMap<Font, u8>,
90    /// Widtth, in dots, of the printer
91    width: u16
92}
93
94impl PrinterProfileBuilder {
95    /// Creates a new [PrinterProfileBuilder](crate::PrinterProfileBuilder) set for usb printing
96    ///
97    /// ```rust
98    /// use escpos_rs::PrinterProfileBuilder;
99    /// // Creates a minimum data structure to connect to a printer
100    /// let printer_profile_builder = PrinterProfileBuilder::new_usb(0x0001, 0x0001);
101    /// ```
102    ///
103    /// The data structure will be properly built just with the vendor id and the product id. The [Printer](crate::Printer)'s [new](crate::Printer::new) method will try to locate a bulk write endpoint, but it might fail to do so. See [with_endpoint](PrinterProfileBuilder::with_endpoint) for manual setup.
104    ///
105    /// By default, a width of 384 dots and the `FontA` with 32 columns of width will be loaded with the profile.
106    pub fn new_usb(vendor_id: u16, product_id: u16) -> PrinterProfileBuilder {
107        PrinterProfileBuilder {
108            printer_connection_data: PrinterConnectionData::Usb {
109                vendor_id,
110                product_id,
111                endpoint: None,
112                timeout: std::time::Duration::from_secs(2)
113            },
114            columns_per_font: vec![(Font::FontA, 32)].into_iter().collect(),
115            width: 384
116        }
117    }
118
119    /// Creates a new [PrinterProfileBuilder](crate::PrinterProfileBuilder) set for terminal printing
120    ///
121    /// ```rust
122    /// use escpos_rs::PrinterProfileBuilder;
123    /// // Creates a minimum (probably non-working) data structure to connect to a printer
124    /// let printer_profile_builder = PrinterProfileBuilder::new_terminal();
125    /// ```
126    ///
127    /// The printer will have a 32-char width for printing text, and a default with of 384 (but it cannot be used, as pictures can't be printed to the terminal).
128    pub fn new_terminal() -> PrinterProfileBuilder {
129        PrinterProfileBuilder {
130            printer_connection_data: PrinterConnectionData::Terminal,
131            columns_per_font: vec![(Font::FontA, 32)].into_iter().collect(),
132            width: 384
133        }
134    }
135
136    /// Sets the usb endpoint to which the data will be written.
137    ///
138    /// ```rust
139    /// use escpos_rs::PrinterProfileBuilder;
140    /// // Creates the printer details with the endpoint 0x02
141    /// let printer_profile = PrinterProfileBuilder::new_usb(0x0001, 0x0001)
142    ///     .with_endpoint(0x02).unwrap()
143    ///     .build();
144    /// ```
145    pub fn with_endpoint(mut self, endpoint: u8) -> Result<PrinterProfileBuilder, Error> {
146        match &mut self.printer_connection_data {
147            PrinterConnectionData::Usb{endpoint: self_endpoint, ..} => {
148                *self_endpoint = Some(endpoint);
149                Ok(self)
150            },
151            _other => Err(Error::UnsupportedForPrinterConnection)
152        }
153    }
154
155    /// Adds a specific pixel width for the printer (required for printing images)
156    ///
157    /// Defaults to 384, usually for 58mm printers.
158    /// ```rust
159    /// use escpos_rs::PrinterProfileBuilder;
160    /// let printer_profile = PrinterProfileBuilder::new_usb(0x0001, 0x0001)
161    ///     .with_width(384)
162    ///     .build();
163    /// ```
164    pub fn with_width(mut self, width: u16) -> PrinterProfileBuilder {
165        self.width = width;
166        self
167    }
168
169    /// Adds a specific width per font
170    ///
171    /// This allows the justification, and proper word splitting to work. If you feel insecure about what value to use, the default font (FontA) usually has 32 characters of width for 58mm paper printers, and 48 for 80mm paper. You can also look for the specsheet, or do trial and error.
172    /// ```rust
173    /// use escpos_rs::{PrinterProfileBuilder, command::Font};
174    /// let printer_profile = PrinterProfileBuilder::new_usb(0x0001, 0x0001)
175    ///     .with_font_width(Font::FontA, 32)
176    ///     .build();
177    /// ```
178    pub fn with_font_width(mut self, font: Font, width: u8) -> PrinterProfileBuilder {
179        self.columns_per_font.insert(font, width);
180        self
181    }
182
183    /// Adds a bulk write timeout (usb only)
184    ///
185    /// USB devices might fail to write to the bulk endpoint. In such a case, a timeout must be provided to know when to stop waiting for the buffer to flush to the printer. The default value is 2 seconds.
186    /// ```rust
187    /// use escpos_rs::PrinterProfileBuilder;
188    /// let printer_profile = PrinterProfileBuilder::new_usb(0x0001, 0x0001)
189    ///     .with_timeout(std::time::Duration::from_secs(3)).unwrap()
190    ///     .build();
191    /// ```
192    pub fn with_timeout(mut self, timeout: std::time::Duration) -> Result<PrinterProfileBuilder, Error> {
193        match &mut self.printer_connection_data {
194            PrinterConnectionData::Usb{timeout: self_timeout, ..} => {
195                *self_timeout = timeout;
196                Ok(self)
197            },
198            _other => Err(Error::UnsupportedForPrinterConnection)
199        }
200    }
201
202    /// Build the `PrinterProfile` that lies beneath the builder
203    ///
204    /// ```rust
205    /// # use escpos_rs::PrinterProfileBuilder;
206    /// let printer_profile = PrinterProfileBuilder::new_usb(0x0001, 0x0001).build();
207    /// ```
208    pub fn build(self) -> PrinterProfile {
209        PrinterProfile {
210            printer_connection_data: self.printer_connection_data,
211            columns_per_font: self.columns_per_font,
212            width: self.width
213        }
214    }
215}