use base64::{engine::general_purpose::STANDARD, Engine as _};
use image::Luma;
use minijinja::{value::Kwargs, Error, ErrorKind, State};
use qrcode::{render::svg, QrCode};
use std::io::Cursor;
pub fn generate(_state: &State, content: String, options: Kwargs) -> Result<String, Error> {
let format = options
.get::<Option<String>>("format")?
.unwrap_or("png".to_string());
let width: Option<usize> = options.get("width")?;
let height: Option<usize> = options.get("height")?;
let code = QrCode::new(content.as_bytes()).unwrap();
if &format == "png" {
let image = if let (Some(w), Some(h)) = (width, height) {
code.render::<Luma<u8>>()
.max_dimensions(w as u32, h as u32)
.build()
} else {
code.render::<Luma<u8>>().build()
};
let mut w: Vec<u8> = Vec::new();
image
.write_to(&mut Cursor::new(&mut w), image::ImageFormat::Png)
.unwrap();
let image_data = STANDARD.encode(w);
Ok(format!("data:image/png;base64,{}", image_data))
} else if &format == "svg" || &format == "svg:raw" {
let image = if let (Some(w), Some(h)) = (width, height) {
code.render()
.max_dimensions(w as u32, h as u32)
.dark_color(svg::Color("#000000"))
.light_color(svg::Color("#ffffff"))
.build()
} else {
code.render()
.dark_color(svg::Color("#000000"))
.light_color(svg::Color("#ffffff"))
.build()
};
if &format == "svg" {
let image_data = STANDARD.encode(image);
Ok(format!("data:image/svg+xml;base64,{}", image_data))
} else {
Ok(String::from_utf8(image.into()).unwrap())
}
} else {
Err(Error::new(
ErrorKind::UndefinedError,
format!("unknown format: {}", format),
))
}
}