Skip to main content

escpos_rs/printer/
printer_profile.rs

1use std::collections::HashMap;
2use crate::{
3    Error,
4    command::{Font, ImageMode}
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, when using certain image mode
42    pub (crate) width_per_image_mode: HashMap<ImageMode, 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_per_image_mode: HashMap<ImageMode, u16>) -> PrinterProfile {
50        PrinterProfile {
51            printer_connection_data,
52            columns_per_font,
53            width_per_image_mode
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_per_image_mode: HashMap<ImageMode, 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 for the `ImageMode::EightDotSingleDensity` image mode 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_per_image_mode: vec![(ImageMode::EightDotSingleDensity, 384)].into_iter().collect()
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_per_image_mode: vec![(ImageMode::EightDotSingleDensity, 384)].into_iter().collect()
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_image_mode_width(mut self, image_mode: ImageMode, width: u16) -> PrinterProfileBuilder {
165        self.width_per_image_mode.insert(image_mode, 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    ///
173    /// ```rust
174    /// use escpos_rs::{PrinterProfileBuilder, command::Font};
175    /// let printer_profile = PrinterProfileBuilder::new_usb(0x0001, 0x0001)
176    ///     .with_font_width(Font::FontA, 32)
177    ///     .build();
178    /// ```
179    pub fn with_font_width(mut self, font: Font, width: u8) -> PrinterProfileBuilder {
180        self.columns_per_font.insert(font, width);
181        self
182    }
183
184    /// Adds a bulk write timeout (usb only)
185    ///
186    /// 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.
187    /// ```rust
188    /// use escpos_rs::PrinterProfileBuilder;
189    /// let printer_profile = PrinterProfileBuilder::new_usb(0x0001, 0x0001)
190    ///     .with_timeout(std::time::Duration::from_secs(3)).unwrap()
191    ///     .build();
192    /// ```
193    pub fn with_timeout(mut self, timeout: std::time::Duration) -> Result<PrinterProfileBuilder, Error> {
194        match &mut self.printer_connection_data {
195            PrinterConnectionData::Usb{timeout: self_timeout, ..} => {
196                *self_timeout = timeout;
197                Ok(self)
198            },
199            _other => Err(Error::UnsupportedForPrinterConnection)
200        }
201    }
202
203    /// Build the `PrinterProfile` that lies beneath the builder
204    ///
205    /// ```rust
206    /// # use escpos_rs::PrinterProfileBuilder;
207    /// let printer_profile = PrinterProfileBuilder::new_usb(0x0001, 0x0001).build();
208    /// ```
209    pub fn build(self) -> PrinterProfile {
210        PrinterProfile {
211            printer_connection_data: self.printer_connection_data,
212            columns_per_font: self.columns_per_font,
213            width_per_image_mode: self.width_per_image_mode
214        }
215    }
216}