esc_pos_lib/
image.rs

1use super::constants;
2use image::imageops;
3use image::GrayImage;
4use image::DynamicImage;
5
6pub struct Image {
7    width: u32,
8    height: u32,
9    pixels: Vec<bool>,
10}
11
12fn resize_image(img: &DynamicImage) -> DynamicImage {
13    img.resize(constants::MAX_X_WIDTH/2 + constants::MAX_X_WIDTH/16, std::u32::MAX, imageops::FilterType::Nearest)
14}
15
16fn get_image(path: &str) ->
17    Result<DynamicImage, String> {
18    return match image::open(path) {
19        Ok(img) => Ok(img),
20        Err(_) => Err(String::from("Could not open image")),
21    }
22}
23
24fn buffer_to_bool_vec(buffer: &GrayImage) -> Vec<bool> {
25    let mut vec: Vec<bool> = Vec::new();
26    for pixel in buffer.pixels() {
27        vec.push(pixel[0] == 0);
28    }
29    return vec;
30}
31
32/// Create a new Image object from a DynamicImage in the image crate
33pub fn image_from_dynamic(buffer: &image::DynamicImage) -> Result<Image, String> {
34
35    let mut buffer = resize_image(buffer).into_luma8();
36    imageops::dither(&mut buffer, &image::imageops::colorops::BiLevel);
37
38    let vec = buffer_to_bool_vec(&buffer);
39
40    return match Image::new(buffer.width(), buffer.height(), vec) {
41        Ok(img) => Ok(img),
42        Err(_) => Err("Could not create image from buffer".to_string()),
43    }
44}
45
46///Give a path to an image and get an Image object back
47///It's based on the crate image in rust. 
48///Filetype is checked by parsing the file extension
49///If they mismatch then an error will be thrown so be aware
50pub fn image_from_path(path: &str) -> Result<Image, String> {
51    
52    let img = match get_image(path) {
53        Ok(img) => img,
54        Err(err) => return Err(err),
55    };
56
57    match image_from_dynamic(&img) {
58        Ok(e) => return Ok(e),
59        Err(err) => return Err(err),
60    }
61}
62
63impl Image {
64
65    ///Requires the width and height of the image in terms of pixels
66    ///The height has no max while the width is limited to constant:MAX_X_WIDTH which is 1024
67    ///The vector contains pixels from top left to bottom right in a left to right fashion
68    pub fn new(width : u32, height: u32, image: Vec<bool>) -> Result<Image, String> {
69        if width > constants::MAX_X_WIDTH {
70            return Err(format!("Width {} exceeds maximum width of 1024",
71                               width));
72        }
73        if image.len() != (width * height) as usize {
74            return Err(format!("Image size {} does not match width {} and height {} area {}",
75                               image.len(),
76                               width,
77                               height,
78                               width * height));
79        }
80        Ok(
81        Image {
82            width: width/8,
83            height,
84            pixels: image,
85        }
86        )
87    }
88
89    ///Returns a vector of bytes which can be sent to the printer add function.
90    pub fn export(&self ) -> Vec<u8> {
91        let mut to_return = Vec::new();
92        to_return.push(constants::GS); //GS
93        to_return.push(0x76); // v
94        to_return.push(0x30); // O
95        to_return.push(0); // m
96        to_return.push((self.width % 256) as u8);   // xL
97        to_return.push((self.width / 256) as u8);   // xH
98        to_return.push((self.height % 256) as u8);  // yL
99        to_return.push((self.height / 256) as u8);  // yH
100
101        let mut curr: u8 = 0;
102        let mut count = 0;
103        for i in 0..self.pixels.len() {
104            if self.pixels[i] {
105                curr |= 1 << (7 - count);
106            } 
107            count += 1;
108            if count == 8 {
109                to_return.push(curr);
110                curr = 0;
111                count = 0;
112            }
113        }
114        to_return
115    }
116}