Support SVG rendering.

Fixes #8.
This commit is contained in:
kennytm 2017-05-23 05:49:51 +08:00
parent 0b3b8f2637
commit cd5223640c
6 changed files with 100 additions and 1 deletions

View file

@ -19,8 +19,9 @@ travis-ci = { repository = "kennytm/qrcode-rust" }
image = { version = "0.13", optional = true } image = { version = "0.13", optional = true }
[features] [features]
default = ["image"] default = ["image", "svg"]
bench = [] bench = []
svg = []
[[bin]] [[bin]]
name = "qrencode" name = "qrencode"

View file

@ -328,3 +328,29 @@ mod image_tests {
} }
} }
#[cfg(all(test, feature="svg"))]
mod svg_tests {
use render::svg::Color as SvgColor;
use {QrCode, Version, EcLevel};
#[test]
fn test_annex_i_qr_as_svg() {
let code = QrCode::new(b"01234567").unwrap();
let image = code.render::<SvgColor>().build();
let expected = include_str!("test_annex_i_qr_as_svg.svg");
assert_eq!(&image, expected);
}
#[test]
fn test_annex_i_micro_qr_as_svg() {
let code = QrCode::with_version(b"01234567", Version::Micro(2), EcLevel::L).unwrap();
let image = code.render()
.min_dimensions(200, 200)
.dark_color(SvgColor("#800000"))
.light_color(SvgColor("#ffff80"))
.build();
let expected = include_str!("test_annex_i_micro_qr_as_svg.svg");
assert_eq!(&image, expected);
}
}

View file

@ -5,6 +5,7 @@ use types::Color;
pub mod image; pub mod image;
pub mod string; pub mod string;
pub mod svg;
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
//{{{ Pixel trait //{{{ Pixel trait

69
src/render/svg.rs Normal file
View file

@ -0,0 +1,69 @@
//! SVG rendering support.
//!
//! # Example
//!
//! ```
//! extern crate qrcode;
//!
//! use qrcode::QrCode;
//! use qrcode::render::svg;
//!
//! fn main() {
//! 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 render::{Pixel, Canvas as RenderCanvas};
use 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!(
r#"<?xml version="1.0" standalone="yes"?><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="{w}" height="{h}" shape-rendering="crispEdges"><rect x="0" y="0" width="{w}" height="{h}" fill="{bg}"/><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(self) -> String {
self.svg + r#""/></svg>"#
}
}

View file

@ -0,0 +1 @@
<?xml version="1.0" standalone="yes"?><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="204" height="204" shape-rendering="crispEdges"><rect x="0" y="0" width="204" height="204" fill="#ffff80"/><path fill="#800000" d="M24 24h12v12H24V24M36 24h12v12H36V24M48 24h12v12H48V24M60 24h12v12H60V24M72 24h12v12H72V24M84 24h12v12H84V24M96 24h12v12H96V24M120 24h12v12H120V24M144 24h12v12H144V24M168 24h12v12H168V24M24 36h12v12H24V36M96 36h12v12H96V36M120 36h12v12H120V36M132 36h12v12H132V36M144 36h12v12H144V36M168 36h12v12H168V36M24 48h12v12H24V48M48 48h12v12H48V48M60 48h12v12H60V48M72 48h12v12H72V48M96 48h12v12H96V48M132 48h12v12H132V48M144 48h12v12H144V48M168 48h12v12H168V48M24 60h12v12H24V60M48 60h12v12H48V60M60 60h12v12H60V60M72 60h12v12H72V60M96 60h12v12H96V60M132 60h12v12H132V60M144 60h12v12H144V60M156 60h12v12H156V60M168 60h12v12H168V60M24 72h12v12H24V72M48 72h12v12H48V72M60 72h12v12H60V72M72 72h12v12H72V72M96 72h12v12H96V72M120 72h12v12H120V72M132 72h12v12H132V72M144 72h12v12H144V72M24 84h12v12H24V84M96 84h12v12H96V84M120 84h12v12H120V84M168 84h12v12H168V84M24 96h12v12H24V96M36 96h12v12H36V96M48 96h12v12H48V96M60 96h12v12H60V96M72 96h12v12H72V96M84 96h12v12H84V96M96 96h12v12H96V96M132 96h12v12H132V96M144 96h12v12H144V96M156 96h12v12H156V96M168 96h12v12H168V96M132 108h12v12H132V108M144 108h12v12H144V108M24 120h12v12H24V120M36 120h12v12H36V120M60 120h12v12H60V120M120 120h12v12H120V120M168 120h12v12H168V120M36 132h12v12H36V132M48 132h12v12H48V132M72 132h12v12H72V132M96 132h12v12H96V132M120 132h12v12H120V132M144 132h12v12H144V132M168 132h12v12H168V132M24 144h12v12H24V144M36 144h12v12H36V144M48 144h12v12H48V144M84 144h12v12H84V144M96 144h12v12H96V144M108 144h12v12H108V144M120 144h12v12H120V144M132 144h12v12H132V144M144 144h12v12H144V144M156 144h12v12H156V144M60 156h12v12H60V156M84 156h12v12H84V156M144 156h12v12H144V156M156 156h12v12H156V156M24 168h12v12H24V168M36 168h12v12H36V168M48 168h12v12H48V168M72 168h12v12H72V168M108 168h12v12H108V168M120 168h12v12H120V168M144 168h12v12H144V168M156 168h12v12H156V168M168 168h12v12H168V168"/></svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -0,0 +1 @@
<?xml version="1.0" standalone="yes"?><svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="232" height="232" shape-rendering="crispEdges"><rect x="0" y="0" width="232" height="232" fill="#fff"/><path fill="#000" d="M32 32h8v8H32V32M40 32h8v8H40V32M48 32h8v8H48V32M56 32h8v8H56V32M64 32h8v8H64V32M72 32h8v8H72V32M80 32h8v8H80V32M104 32h8v8H104V32M120 32h8v8H120V32M128 32h8v8H128V32M144 32h8v8H144V32M152 32h8v8H152V32M160 32h8v8H160V32M168 32h8v8H168V32M176 32h8v8H176V32M184 32h8v8H184V32M192 32h8v8H192V32M32 40h8v8H32V40M80 40h8v8H80V40M104 40h8v8H104V40M112 40h8v8H112V40M120 40h8v8H120V40M128 40h8v8H128V40M144 40h8v8H144V40M192 40h8v8H192V40M32 48h8v8H32V48M48 48h8v8H48V48M56 48h8v8H56V48M64 48h8v8H64V48M80 48h8v8H80V48M96 48h8v8H96V48M144 48h8v8H144V48M160 48h8v8H160V48M168 48h8v8H168V48M176 48h8v8H176V48M192 48h8v8H192V48M32 56h8v8H32V56M48 56h8v8H48V56M56 56h8v8H56V56M64 56h8v8H64V56M80 56h8v8H80V56M96 56h8v8H96V56M104 56h8v8H104V56M144 56h8v8H144V56M160 56h8v8H160V56M168 56h8v8H168V56M176 56h8v8H176V56M192 56h8v8H192V56M32 64h8v8H32V64M48 64h8v8H48V64M56 64h8v8H56V64M64 64h8v8H64V64M80 64h8v8H80V64M96 64h8v8H96V64M112 64h8v8H112V64M120 64h8v8H120V64M128 64h8v8H128V64M144 64h8v8H144V64M160 64h8v8H160V64M168 64h8v8H168V64M176 64h8v8H176V64M192 64h8v8H192V64M32 72h8v8H32V72M80 72h8v8H80V72M96 72h8v8H96V72M128 72h8v8H128V72M144 72h8v8H144V72M192 72h8v8H192V72M32 80h8v8H32V80M40 80h8v8H40V80M48 80h8v8H48V80M56 80h8v8H56V80M64 80h8v8H64V80M72 80h8v8H72V80M80 80h8v8H80V80M96 80h8v8H96V80M112 80h8v8H112V80M128 80h8v8H128V80M144 80h8v8H144V80M152 80h8v8H152V80M160 80h8v8H160V80M168 80h8v8H168V80M176 80h8v8H176V80M184 80h8v8H184V80M192 80h8v8H192V80M96 88h8v8H96V88M120 88h8v8H120V88M128 88h8v8H128V88M32 96h8v8H32V96M48 96h8v8H48V96M56 96h8v8H56V96M64 96h8v8H64V96M72 96h8v8H72V96M80 96h8v8H80V96M104 96h8v8H104V96M128 96h8v8H128V96M144 96h8v8H144V96M152 96h8v8H152V96M160 96h8v8H160V96M168 96h8v8H168V96M176 96h8v8H176V96M56 104h8v8H56V104M72 104h8v8H72V104M88 104h8v8H88V104M96 104h8v8H96V104M112 104h8v8H112V104M128 104h8v8H128V104M152 104h8v8H152V104M168 104h8v8H168V104M176 104h8v8H176V104M48 112h8v8H48V112M80 112h8v8H80V112M88 112h8v8H88V112M104 112h8v8H104V112M120 112h8v8H120V112M136 112h8v8H136V112M160 112h8v8H160V112M168 112h8v8H168V112M176 112h8v8H176V112M184 112h8v8H184V112M192 112h8v8H192V112M64 120h8v8H64V120M104 120h8v8H104V120M152 120h8v8H152V120M160 120h8v8H160V120M168 120h8v8H168V120M176 120h8v8H176V120M56 128h8v8H56V128M64 128h8v8H64V128M72 128h8v8H72V128M80 128h8v8H80V128M88 128h8v8H88V128M96 128h8v8H96V128M120 128h8v8H120V128M136 128h8v8H136V128M160 128h8v8H160V128M96 136h8v8H96V136M112 136h8v8H112V136M120 136h8v8H120V136M128 136h8v8H128V136M136 136h8v8H136V136M144 136h8v8H144V136M168 136h8v8H168V136M176 136h8v8H176V136M32 144h8v8H32V144M40 144h8v8H40V144M48 144h8v8H48V144M56 144h8v8H56V144M64 144h8v8H64V144M72 144h8v8H72V144M80 144h8v8H80V144M104 144h8v8H104V144M112 144h8v8H112V144M128 144h8v8H128V144M144 144h8v8H144V144M152 144h8v8H152V144M32 152h8v8H32V152M80 152h8v8H80V152M96 152h8v8H96V152M112 152h8v8H112V152M120 152h8v8H120V152M128 152h8v8H128V152M136 152h8v8H136V152M144 152h8v8H144V152M176 152h8v8H176V152M192 152h8v8H192V152M32 160h8v8H32V160M48 160h8v8H48V160M56 160h8v8H56V160M64 160h8v8H64V160M80 160h8v8H80V160M96 160h8v8H96V160M128 160h8v8H128V160M152 160h8v8H152V160M168 160h8v8H168V160M176 160h8v8H176V160M32 168h8v8H32V168M48 168h8v8H48V168M56 168h8v8H56V168M64 168h8v8H64V168M80 168h8v8H80V168M96 168h8v8H96V168M104 168h8v8H104V168M128 168h8v8H128V168M152 168h8v8H152V168M32 176h8v8H32V176M48 176h8v8H48V176M56 176h8v8H56V176M64 176h8v8H64V176M80 176h8v8H80V176M96 176h8v8H96V176M112 176h8v8H112V176M120 176h8v8H120V176M136 176h8v8H136V176M160 176h8v8H160V176M176 176h8v8H176V176M32 184h8v8H32V184M80 184h8v8H80V184M152 184h8v8H152V184M160 184h8v8H160V184M176 184h8v8H176V184M184 184h8v8H184V184M32 192h8v8H32V192M40 192h8v8H40V192M48 192h8v8H48V192M56 192h8v8H56V192M64 192h8v8H64V192M72 192h8v8H72V192M80 192h8v8H80V192M96 192h8v8H96V192M104 192h8v8H104V192M112 192h8v8H112V192M120 192h8v8H120V192M136 192h8v8H136V192M160 192h8v8H160V192M176 192h8v8H176V192"/></svg>

After

Width:  |  Height:  |  Size: 4.1 KiB