aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--Cargo.lock68
-rw-r--r--Cargo.toml2
-rw-r--r--src/consts.rs4
-rw-r--r--src/listing.rs41
-rw-r--r--src/main.rs52
-rw-r--r--src/renderer.rs40
6 files changed, 138 insertions, 69 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 174d5bc..62c1ff0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -475,6 +475,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
[[package]]
+name = "bytemuck"
+version = "1.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f5715e491b5a1598fc2bef5a606847b5dc1d48ea625bd3c02c00de8285591da"
+
+[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -523,6 +529,12 @@ 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.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -627,6 +639,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e769b5c8c8283982a987c6e948e540254f1058d5a74b8794914d4ef5fc2a24"
[[package]]
+name = "color_quant"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
+
+[[package]]
name = "comrak"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1072,7 +1090,7 @@ dependencies = [
"indexmap",
"lasso",
"num-bigint",
- "num-rational",
+ "num-rational 0.4.1",
"num-traits",
"once_cell",
"phf 0.9.0",
@@ -1268,6 +1286,20 @@ dependencies = [
]
[[package]]
+name = "image"
+version = "0.23.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1"
+dependencies = [
+ "bytemuck",
+ "byteorder",
+ "color_quant",
+ "num-iter",
+ "num-rational 0.3.2",
+ "num-traits",
+]
+
+[[package]]
name = "indexmap"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1546,7 +1578,7 @@ dependencies = [
"port_check",
"predicates",
"pretty_assertions",
- "qrcodegen",
+ "qrcode",
"regex",
"reqwest",
"rstest",
@@ -1630,6 +1662,28 @@ dependencies = [
]
[[package]]
+name = "num-iter"
+version = "0.1.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
+dependencies = [
+ "autocfg",
+ "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",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
name = "num-rational"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2024,10 +2078,14 @@ dependencies = [
]
[[package]]
-name = "qrcodegen"
-version = "1.8.0"
+name = "qrcode"
+version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4339fc7a1021c9c1621d87f5e3505f2805c8c105420ba2f2a4df86814590c142"
+checksum = "16d2f1455f3630c6e5107b4f2b94e74d76dea80736de0981fd27644216cff57f"
+dependencies = [
+ "checked_int_cast",
+ "image",
+]
[[package]]
name = "quote"
diff --git a/Cargo.toml b/Cargo.toml
index de73987..9094883 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -44,7 +44,7 @@ mime = "0.3"
nanoid = "0.4"
percent-encoding = "2"
port_check = "0.1"
-qrcodegen = "1"
+qrcode = "0.12.0"
rustls = { version = "0.20", optional = true }
rustls-pemfile = { version = "1.0", optional = true }
serde = { version = "1", features = ["derive"] }
diff --git a/src/consts.rs b/src/consts.rs
new file mode 100644
index 0000000..07f47b0
--- /dev/null
+++ b/src/consts.rs
@@ -0,0 +1,4 @@
+use qrcode::EcLevel;
+
+/// The error correction level to use for all QR code generation.
+pub const QR_EC_LEVEL: EcLevel = EcLevel::M;
diff --git a/src/listing.rs b/src/listing.rs
index 82b4cdb..f90c40c 100644
--- a/src/listing.rs
+++ b/src/listing.rs
@@ -9,14 +9,14 @@ use actix_web::{HttpMessage, HttpRequest, HttpResponse};
use bytesize::ByteSize;
use comrak::{markdown_to_html, ComrakOptions};
use percent_encoding::{percent_decode_str, utf8_percent_encode};
-use qrcodegen::{QrCode, QrCodeEcc};
+use qrcode::QrCode;
use serde::Deserialize;
use strum_macros::{Display, EnumString};
use crate::archive::ArchiveMethod;
use crate::auth::CurrentUser;
use crate::errors::{self, ContextualError};
-use crate::renderer;
+use crate::{consts, renderer};
use self::percent_encode_sets::PATH_SEGMENT;
@@ -220,10 +220,10 @@ pub fn directory_listing(
// If the `qrcode` parameter is included in the url, then should respond to the QR code
if let Some(url) = query_params.qrcode {
- let res = match QrCode::encode_text(&url, QrCodeEcc::Medium) {
+ let res = match QrCode::with_error_correction_level(url, consts::QR_EC_LEVEL) {
Ok(qr) => HttpResponse::Ok()
- .append_header(("Content-Type", "image/svg+xml"))
- .body(qr_to_svg_string(&qr, 2)),
+ .content_type("text/html; charset=utf-8")
+ .body(renderer::qr_code_page(&qr).into_string()),
Err(err) => {
log::error!("URL is invalid (too long?): {:?}", err);
HttpResponse::UriTooLong().finish()
@@ -407,34 +407,3 @@ pub fn extract_query_parameters(req: &HttpRequest) -> QueryParameters {
}
}
}
-
-// Returns a string of SVG code for an image depicting
-// the given QR Code, with the given number of border modules.
-// The string always uses Unix newlines (\n), regardless of the platform.
-fn qr_to_svg_string(qr: &QrCode, border: i32) -> String {
- assert!(border >= 0, "Border must be non-negative");
- let mut result = String::new();
- result += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
- result += "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n";
- let dimension = qr
- .size()
- .checked_add(border.checked_mul(2).unwrap())
- .unwrap();
- result += &format!(
- "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 {0} {0}\" stroke=\"none\">\n", dimension);
- result += "\t<rect width=\"100%\" height=\"100%\" fill=\"#FFFFFF\"/>\n";
- result += "\t<path d=\"";
- for y in 0..qr.size() {
- for x in 0..qr.size() {
- if qr.get_module(x, y) {
- if x != 0 || y != 0 {
- result += " ";
- }
- result += &format!("M{},{}h1v1h-1z", x + border, y + border);
- }
- }
- }
- result += "\" fill=\"#000000\"/>\n";
- result += "</svg>\n";
- result
-}
diff --git a/src/main.rs b/src/main.rs
index b46262d..558dabb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -13,13 +13,14 @@ use anyhow::Result;
use clap::{crate_version, IntoApp, Parser};
use clap_complete::generate;
use log::{error, warn};
-use qrcodegen::{QrCode, QrCodeEcc};
+use qrcode::QrCode;
use yansi::{Color, Paint};
mod archive;
mod args;
mod auth;
mod config;
+mod consts;
mod errors;
mod file_upload;
mod listing;
@@ -239,7 +240,7 @@ async fn run(miniserve_config: MiniserveConfig) -> Result<(), ContextualError> {
.iter()
.filter(|url| !url.contains("//127.0.0.1:") && !url.contains("//[::1]:"))
{
- match QrCode::encode_text(url, QrCodeEcc::Low) {
+ match QrCode::with_error_correction_level(url, consts::QR_EC_LEVEL) {
Ok(qr) => {
println!("QR code for {}:", Color::Green.paint(url).bold());
print_qr(&qr);
@@ -352,30 +353,27 @@ async fn css() -> impl Responder {
.body(css)
}
-// Prints to the console two inverted QrCodes side by side.
+// Prints to the console a normal and an inverted QrCode side by side.
fn print_qr(qr: &QrCode) {
- let border = 4;
- let size = qr.size() + 2 * border;
-
- for y in (0..size).step_by(2) {
- for x in 0..2 * size {
- let inverted = x >= size;
- let (x, y) = (x % size - border, y - border);
-
- //each char represents two vertical modules
- let (mod1, mod2) = match inverted {
- false => (qr.get_module(x, y), qr.get_module(x, y + 1)),
- true => (!qr.get_module(x, y), !qr.get_module(x, y + 1)),
- };
- let c = match (mod1, mod2) {
- (false, false) => ' ',
- (true, false) => '▀',
- (false, true) => '▄',
- (true, true) => '█',
- };
- print!("{0}", c);
- }
- println!();
- }
- println!();
+ use qrcode::render::unicode::Dense1x2;
+
+ let normal = qr
+ .render()
+ .quiet_zone(true)
+ .dark_color(Dense1x2::Dark)
+ .light_color(Dense1x2::Light)
+ .build();
+ let inverted = qr
+ .render()
+ .quiet_zone(true)
+ .dark_color(Dense1x2::Light)
+ .light_color(Dense1x2::Dark)
+ .build();
+ let codes = normal
+ .lines()
+ .zip(inverted.lines())
+ .map(|(l, r)| format!("{} {}", l, r))
+ .collect::<Vec<_>>()
+ .join("\n");
+ println!("{}", codes);
}
diff --git a/src/renderer.rs b/src/renderer.rs
index 7ec48b0..48b74b6 100644
--- a/src/renderer.rs
+++ b/src/renderer.rs
@@ -3,6 +3,7 @@ use chrono::{DateTime, Utc};
use chrono_humanize::Humanize;
use clap::{crate_name, crate_version};
use maud::{html, Markup, PreEscaped, DOCTYPE};
+use qrcode::QrCode;
use std::time::SystemTime;
use strum::IntoEnumIterator;
@@ -224,6 +225,45 @@ pub fn raw(entries: Vec<Entry>, is_root: bool) -> Markup {
}
}
+/// Renders the QR code page
+pub fn qr_code_page(qr: &QrCode) -> Markup {
+ use qrcode::render::svg;
+
+ html! {
+ (DOCTYPE)
+ html {
+ body {
+ // make QR code expand and fill page
+ style {
+ (PreEscaped("\
+ html {\
+ width: 100vw;\
+ height: 100vh;\
+ }\
+ body {\
+ width: 100%;\
+ height: 100%;\
+ margin: 0;\
+ display: grid;\
+ align-items: center;\
+ justify-items: center;\
+ }\
+ svg {\
+ width: 80%;\
+ height: 80%;\
+ }\
+ "))
+ }
+ (PreEscaped(qr.render()
+ .quiet_zone(false)
+ .dark_color(svg::Color("#000000"))
+ .light_color(svg::Color("#ffffff"))
+ .build()))
+ }
+ }
+ }
+}
+
// Partial: version footer
fn version_footer() -> Markup {
html! {