From 325cdfc9d464e756210886eb99d8cf90c15b3432 Mon Sep 17 00:00:00 2001 From: Dietrich Date: Sun, 7 Feb 2021 17:49:13 +0100 Subject: [PATCH] Add PNG download of QR-Code --- Cargo.lock | 224 +++++++++++++++++++++++++++++++++++++-- Cargo.toml | 3 +- src/main.rs | 4 + src/views.rs | 49 +++++++-- templates/view_link.html | 9 +- 5 files changed, 270 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ad2446c..ea97442 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -304,6 +304,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + [[package]] name = "aead" version = "0.3.2" @@ -475,7 +481,7 @@ dependencies = [ "addr2line", "cfg-if 1.0.0", "libc", - "miniz_oxide", + "miniz_oxide 0.4.3", "object", "rustc-demangle", ] @@ -606,6 +612,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" +[[package]] +name = "bytemuck" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a4bad0c5981acc24bc09e532f35160f952e35422603f0563cd7a73c2c2e65a0" + [[package]] name = "byteorder" version = "1.4.2" @@ -663,6 +675,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "checked_int_cast" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17cc5e6b5ab06331c33589842070416baa137e8b0eb912b008cfd4a78ada7919" + [[package]] name = "chrono" version = "0.4.19" @@ -731,6 +749,12 @@ dependencies = [ "bitflags", ] +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + [[package]] name = "const_fn" version = "0.4.5" @@ -781,6 +805,41 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d" +dependencies = [ + "cfg-if 1.0.0", + "const_fn", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard 1.1.0", +] + [[package]] name = "crossbeam-utils" version = "0.8.1" @@ -811,6 +870,16 @@ dependencies = [ "cipher", ] +[[package]] +name = "deflate" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" +dependencies = [ + "adler32", + "byteorder", +] + [[package]] name = "derive-error-chain" version = "0.10.1" @@ -1029,7 +1098,7 @@ dependencies = [ "cfg-if 1.0.0", "crc32fast", "libc", - "miniz_oxide", + "miniz_oxide 0.4.3", ] [[package]] @@ -1229,6 +1298,16 @@ dependencies = [ "polyval", ] +[[package]] +name = "gif" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02efba560f227847cb41463a7395c514d127d4f74fff12ef0137fff1b84b96c4" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "gimli" version = "0.23.0" @@ -1417,6 +1496,25 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "image" +version = "0.23.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "293f07a1875fa7e9c5897b51aa68b2d8ed8271b87e1a44cb64b9c3d98aabbc0d" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "gif", + "jpeg-decoder", + "num-iter", + "num-rational", + "num-traits", + "png", + "scoped_threadpool", + "tiff", +] + [[package]] name = "indexmap" version = "1.6.1" @@ -1472,6 +1570,15 @@ dependencies = [ "libc", ] +[[package]] +name = "jpeg-decoder" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" +dependencies = [ + "rayon", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -1577,6 +1684,15 @@ version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +[[package]] +name = "memoffset" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87" +dependencies = [ + "autocfg 1.0.1", +] + [[package]] name = "mime" version = "0.3.16" @@ -1593,6 +1709,15 @@ dependencies = [ "unicase", ] +[[package]] +name = "miniz_oxide" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" +dependencies = [ + "adler32", +] + [[package]] name = "miniz_oxide" version = "0.4.3" @@ -1676,6 +1801,28 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +dependencies = [ + "autocfg 1.0.1", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg 1.0.1", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.14" @@ -1878,6 +2025,18 @@ version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +[[package]] +name = "png" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" +dependencies = [ + "bitflags", + "crc32fast", + "deflate", + "miniz_oxide 0.3.7", +] + [[package]] name = "polyval" version = "0.4.5" @@ -1926,10 +2085,14 @@ dependencies = [ ] [[package]] -name = "qrcodegen" -version = "1.6.0" +name = "qrcode" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24ea38b2345f15533e6668104bec0136883404287e095f15f9ea2522e2b4b6c" +checksum = "16d2f1455f3630c6e5107b4f2b94e74d76dea80736de0981fd27644216cff57f" +dependencies = [ + "checked_int_cast", + "image", +] [[package]] name = "quick-error" @@ -2161,6 +2324,31 @@ dependencies = [ "rand_core 0.3.1", ] +[[package]] +name = "rayon" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" +dependencies = [ + "autocfg 1.0.1", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + [[package]] name = "rdrand" version = "0.4.0" @@ -2265,6 +2453,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scoped_threadpool" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" + [[package]] name = "scopeguard" version = "0.3.3" @@ -2407,8 +2601,9 @@ dependencies = [ "diesel_codegen", "dotenv", "env_logger 0.8.2", + "image", "log", - "qrcodegen", + "qrcode", "serde", "tera", ] @@ -2649,6 +2844,17 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "tiff" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437" +dependencies = [ + "jpeg-decoder", + "miniz_oxide 0.4.3", + "weezl", +] + [[package]] name = "time" version = "0.1.43" @@ -3071,6 +3277,12 @@ version = "0.2.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd4945e4943ae02d15c13962b38a5b1e81eadd4b71214eee75af64a4d6a4fd64" +[[package]] +name = "weezl" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a32b378380f4e9869b22f0b5177c68a5519f03b3454fde0b291455ddbae266c" + [[package]] name = "which" version = "2.0.1" diff --git a/Cargo.toml b/Cargo.toml index f37c9bb..5599a07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,8 @@ chrono = { version = "0.4", features = ["serde"] } argonautica = "0.2" env_logger = "0.8" log = "0.4" -qrcodegen = "1.6" +qrcode = "0.12" +image = "0.23" [build-dependencies] actix-web-static-files = "3" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 92f2c47..3ac7b4d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -126,6 +126,10 @@ async fn main() -> std::io::Result<()> { web::scope("/view") .route("/{redirect_id}", web::get().to(views::view_link)), ) + .service( + web::scope("/download") + .route("/png/{redirect_id}", web::get().to(views::download_png)), + ) // login to the admin area .route("/login/", web::get().to(views::login)) .route("/login/", web::post().to(views::process_login)), diff --git a/src/views.rs b/src/views.rs index ce68f05..212e45a 100644 --- a/src/views.rs +++ b/src/views.rs @@ -2,22 +2,23 @@ use std::time::SystemTime; use actix_identity::Identity; +use crate::ServerError; use actix_web::{ - http::header::{CacheControl, CacheDirective, Expires}, + http::header::{CacheControl, CacheDirective, ContentType, Expires}, web, HttpResponse, }; -use qrcodegen::{QrCode, QrCodeEcc}; - -use crate::ServerError; - -use super::forms::LinkForm; -use super::models::{Link, LoginUser, NewLink, NewUser, User}; use argonautica::Verifier; use diesel::sqlite::SqliteConnection; use diesel::{prelude::*, result::Error::NotFound}; use dotenv::dotenv; +use image::{DynamicImage, ImageOutputFormat, Luma}; +use qrcode::render::svg; +use qrcode::QrCode; use tera::{Context, Tera}; +use super::forms::LinkForm; +use super::models::{Link, LoginUser, NewLink, NewUser, User}; + fn establish_connection() -> Result { dotenv().ok(); @@ -82,9 +83,13 @@ pub(crate) async fn view_link( .filter(code.eq(&link_id.0)) .first::(&connection)?; - let qr = - QrCode::encode_text(&format!("http://fhs.li/{}", &link_id.0), QrCodeEcc::Low).unwrap(); - let svg = qr.to_svg_string(4); + let qr = QrCode::new(&format!("http://fhs.li/{}", &link_id.0)).unwrap(); + let svg = qr + .render() + .min_dimensions(200, 200) + .dark_color(svg::Color("#000000")) + .light_color(svg::Color("#ffffff")) + .build(); let mut data = Context::new(); data.insert("name", &id); @@ -102,6 +107,30 @@ pub(crate) async fn view_link( } } +pub(crate) async fn download_png( + id: Identity, + link_id: web::Path, +) -> Result { + if let Some(_id) = id.identity() { + use super::schema::links::dsl::{code, links}; + let connection = establish_connection()?; + if let Ok(_link) = links.filter(code.eq(&link_id.0)).first::(&connection) { + let qr = QrCode::new(&format!("http://fhs.li/{}", &link_id)).unwrap(); + let png = qr.render::>().quiet_zone(false).build(); + let mut temporary_data = std::io::Cursor::new(Vec::new()); + DynamicImage::ImageLuma8(png) + .write_to(&mut temporary_data, ImageOutputFormat::Png) + .unwrap(); + let image_data = temporary_data.into_inner(); + Ok(HttpResponse::Ok().set(ContentType::png()).body(image_data)) + } else { + Ok(redirect_builder("/admin/index/")) + } + } else { + Ok(redirect_builder("/admin/login/")) + } +} + pub(crate) async fn signup( tera: web::Data, id: Identity, diff --git a/templates/view_link.html b/templates/view_link.html index 6e14b93..fbefa5a 100644 --- a/templates/view_link.html +++ b/templates/view_link.html @@ -1,7 +1,7 @@ {% extends "admin.html" %} {% block admin %} -

The Link {{ link.code }}

+

{{ link.title }}

@@ -21,7 +21,12 @@ - +
Beschreibung:
QR-Code{{ qr | safe }} + {{ qr | trim_start_matches(pat= + '.*?>') + | safe }} + +