1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//! SVG rendering support.
//!
//! # Example
//!
//! ```
//! use qrcode::QrCode;
//! use qrcode::render::svg;
//!
//! let code = QrCode::new(b"Hello").unwrap();
//! let svg_xml = code.render::<svg::Color>().build();
//! println!("{}", svg_xml);

#![cfg(feature="svg")]

use std::fmt::Write;
use std::marker::PhantomData;

use crate::render::{Canvas as RenderCanvas, Pixel};
use crate::types::Color as ModuleColor;

/// An SVG color.
#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Color<'a>(pub &'a str);

impl<'a> Pixel for Color<'a> {
    type Canvas = Canvas<'a>;
    type Image = String;

    fn default_color(color: ModuleColor) -> Self {
        Color(color.select("#000", "#fff"))
    }
}

#[doc(hidden)]
pub struct Canvas<'a> {
    svg: String,
    marker: PhantomData<Color<'a>>,
}

impl<'a> RenderCanvas for Canvas<'a> {
    type Pixel = Color<'a>;
    type Image = String;

    fn new(width: u32, height: u32, dark_pixel: Color<'a>, light_pixel: Color<'a>) -> Self {
        Canvas {
            svg: format!(
                concat!(
                    r#"<?xml version="1.0" standalone="yes"?>"#,
                    r#"<svg xmlns="http://www.w3.org/2000/svg""#,
                    r#" version="1.1" width="{w}" height="{h}""#,
                    r#" viewBox="0 0 {w} {h}" shape-rendering="crispEdges">"#,
                    r#"<rect x="0" y="0" width="{w}" height="{h}" fill="{bg}"/>"#,
                    r#"<path fill="{fg}" d=""#,
                ),
                w = width,
                h = height,
                fg = dark_pixel.0,
                bg = light_pixel.0
            ),
            marker: PhantomData,
        }
    }

    fn draw_dark_pixel(&mut self, x: u32, y: u32) {
        self.draw_dark_rect(x, y, 1, 1)
    }

    fn draw_dark_rect(&mut self, left: u32, top: u32, width: u32, height: u32) {
        write!(self.svg, "M{l} {t}h{w}v{h}H{l}V{t}", l = left, t = top, w = width, h = height).unwrap();
    }

    fn into_image(mut self) -> String {
        self.svg.push_str(r#""/></svg>"#);
        self.svg
    }
}