From 13dcff7b84c80be79b105152094fb695fcf25e23 Mon Sep 17 00:00:00 2001 From: winlogon Date: Tue, 23 Dec 2025 10:33:06 +0100 Subject: [PATCH 1/3] chore: initial implementation of Kitty graphics protocol --- Cargo.lock | 85 +++++++++++++++++++++------------------- Cargo.toml | 12 ++++-- src/main.rs | 27 +++++++++---- src/qr_generator.rs | 95 +++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 165 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 334530e..441eadd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,22 +49,22 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.10" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -121,6 +121,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "bit_field" version = "0.10.3" @@ -168,6 +174,7 @@ name = "ciphercanvas" version = "0.2.1" dependencies = [ "anyhow", + "base64 0.22.1", "clap", "image 0.24.9", "log", @@ -183,9 +190,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.51" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" dependencies = [ "clap_builder", "clap_derive", @@ -193,9 +200,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.51" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" dependencies = [ "anstream", "anstyle", @@ -315,9 +322,9 @@ dependencies = [ [[package]] name = "exr" -version = "1.73.0" +version = "1.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83197f59927b46c04a183a619b7c29df34e63e63c7869320862268c0ef687e0" +checksum = "4300e043a56aa2cb633c01af81ca8f699a321879a7854d3896a0ba89056363be" dependencies = [ "bit_field", "half", @@ -471,9 +478,9 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "7ee5b5339afb4c41626dde77b7a611bd4f2c202b897852b4bcf5d03eddc61010" [[package]] name = "jpeg-decoder" @@ -511,9 +518,9 @@ checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" [[package]] name = "libc" -version = "0.2.177" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "linux-raw-sys" @@ -523,9 +530,9 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "memchr" @@ -713,9 +720,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.41" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -807,9 +814,9 @@ checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" [[package]] name = "rustix" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ "bitflags 2.10.0", "errno", @@ -865,9 +872,9 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" [[package]] name = "simple_logger" @@ -898,9 +905,9 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "slotmap" -version = "1.0.7" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" dependencies = [ "version_check", ] @@ -937,9 +944,9 @@ dependencies = [ [[package]] name = "supports-hyperlinks" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804f44ed3c63152de6a9f90acbea1a110441de43006ea51bcce8f436196a288b" +checksum = "e396b6523b11ccb83120b115a0b7366de372751aa6edf19844dfb13a6af97e91" [[package]] name = "supports-unicode" @@ -959,9 +966,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.109" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f17c7e013e88258aa9543dcbe81aca68a667a9ac37cd69c9fbc07858bfe0e2f" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -1137,9 +1144,9 @@ checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" [[package]] name = "unicode-script" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" +checksum = "383ad40bb927465ec0ce7720e033cb4ca06912855fc35db31b5755d0de75b1ee" [[package]] name = "unicode-vo" @@ -1165,7 +1172,7 @@ version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c04150a94f0bfc3b2c15d4e151524d14cd06765fc6641d8b1c59a248360d4474" dependencies = [ - "base64", + "base64 0.21.7", "data-url", "flate2", "fontdb", @@ -1200,9 +1207,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "weezl" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a751b3277700db47d3e574514de2eced5e54dc8a5436a3bf7a0b248b2cee16f3" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" [[package]] name = "windows-link" @@ -1383,18 +1390,18 @@ checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" [[package]] name = "zerocopy" -version = "0.8.27" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.27" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index cd50df9..10d744e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ license = "GPL-3.0" categories = ["command-line-utilities"] keywords = ["command-line", "cli", "qrcode"] readme = "README.md" -repository = "https://github.com/walker84837/ciphercanvas-rs" +repository = "https://github.com/walker84837/ciphercanvas" [profile.dev] debug = false @@ -24,11 +24,15 @@ image = "0.24.9" log = "0.4.21" miette = { version = "7.5.0", features = ["fancy"] } thiserror = "1.0" - qrcode = "0.12" rpassword = "7.4.0" -resvg = "0.40.0" simple_logger = "5.0.0" +resvg = "0.40.0" tiny-skia = "0.11.4" - usvg = "0.40.0" + +base64 = { version = "0.22.1", optional = true } + +[features] +default = [] +kitty_graphics = ["dep:base64"] diff --git a/src/main.rs b/src/main.rs index 0380e78..f2ad953 100644 --- a/src/main.rs +++ b/src/main.rs @@ -124,8 +124,7 @@ fn main() -> Result<(), error::Error> { background, overwrite, }) => { - let password = - get_password(password_file).map_err(error::Error::Anyhow)?; + let password = get_password(password_file).map_err(error::Error::Anyhow)?; let options = QrCodeOptions { ssid, @@ -138,13 +137,25 @@ fn main() -> Result<(), error::Error> { format: format.clone(), overwrite, }; - qr_generator::generate_qr_code(options)?; - if let Some(path) = output { - println!( - "QR code successfully generated and saved to \"{}\"", - path.display() - ); + if options.output_path.is_none() { + #[cfg(feature = "kitty_graphics")] + { + qr_generator::print_qr_code_kitty(&options)?; + } + #[cfg(not(feature = "kitty_graphics"))] + { + qr_generator::generate_qr_code(&options)?; + } + } else { + qr_generator::generate_qr_code(&options)?; + + if let Some(path) = options.output_path { + println!( + "QR code successfully generated and saved to \"{}\"", + path.display() + ); + } } } None => {} diff --git a/src/qr_generator.rs b/src/qr_generator.rs index fea0f66..7711473 100644 --- a/src/qr_generator.rs +++ b/src/qr_generator.rs @@ -2,7 +2,15 @@ use crate::{error::Error, image_ops::save_image}; use log::{info, warn}; use miette::Result; use qrcode::{EcLevel, QrCode, render::svg}; +use resvg::render; use std::path::PathBuf; +use tiny_skia::{Pixmap, Transform}; +use usvg::{Options, Tree, fontdb}; + +#[cfg(feature = "kitty_graphics")] +use base64::{engine::general_purpose, prelude::*}; +#[cfg(feature = "kitty_graphics")] +use std::io::Write; pub struct QrCodeOptions { pub ssid: String, @@ -16,7 +24,88 @@ pub struct QrCodeOptions { pub overwrite: bool, } -pub fn generate_qr_code(options: QrCodeOptions) -> Result<(), Error> { +#[cfg(feature = "kitty_graphics")] +fn load_svg_for_kitty(contents: &[u8], size: u32) -> Result { + info!("Loading SVG content with size {size}x{size}"); + + let options = Options::default(); + let fontdb = fontdb::Database::new(); + let tree: Tree = Tree::from_data(contents, &options, &fontdb).map_err(|e| { + Error::Image(format!( + "Failed to create SVG tree from data of size {size}x{size}: {e}" + )) + })?; + + let mut pixmap: Pixmap = + Pixmap::new(size, size).ok_or(Error::Image("Failed to create a new Pixmap".to_string()))?; + + render(&tree, Transform::default(), &mut pixmap.as_mut()); + info!("Rendered SVG to Pixmap"); + + Ok(pixmap) +} + +#[cfg(feature = "kitty_graphics")] +pub fn print_qr_code_kitty(options: &QrCodeOptions) -> Result<(), Error> { + let contents_to_encode = format!( + "WIFI:S:{};T:{};P:{};;", + options.ssid, + options.encryption.to_uppercase(), + options.password + ); + + let qrcode = QrCode::with_error_correction_level(contents_to_encode.as_bytes(), EcLevel::H) + .map_err(|e| Error::QrCode(format!("Failed to generate the QR code: {e}")))?; + info!("QR code generated successfully."); + + let image_svg = qrcode + .render() + .min_dimensions(options.size, options.size) + .dark_color(svg::Color(&options.dark_color)) + .light_color(svg::Color(&options.light_color)) + .build(); + info!("QR code rendered to SVG."); + + let pixmap = load_svg_for_kitty(image_svg.as_bytes(), options.size)?; + let png_data = pixmap + .encode_png() + .map_err(|e| Error::Image(format!("Failed to encode PNG: {e}")))?; + info!("Encoded QR code to PNG."); + + let encoded_data = general_purpose::STANDARD.encode(&png_data); + let chunks: Vec<&[u8]> = encoded_data.as_bytes().chunks(4096).collect(); + let num_chunks = chunks.len(); + + let mut stdout = std::io::stdout().lock(); + + for (i, chunk) in chunks.iter().enumerate() { + if i == 0 { + // First chunk + write!(stdout, "\x1b_Gf=100,a=T,")?; + } else { + // Subsequent chunks + write!(stdout, "\x1b_G")?; + } + + if i == num_chunks - 1 { + // Last chunk + write!(stdout, "m=0;")?; + } else { + // Not the last chunk + write!(stdout, "m=1;")?; + } + + stdout.write_all(chunk)?; + write!(stdout, "\x1b\\")?; + } + stdout.flush()?; + println!(); + info!("Printed QR code to terminal using Kitty graphics protocol."); + + Ok(()) +} + +pub fn generate_qr_code(options: &QrCodeOptions) -> Result<(), Error> { if options.size < 256 { warn!("Image size is lower than 256. The resulting QR code may appear cropped."); } @@ -41,9 +130,9 @@ pub fn generate_qr_code(options: QrCodeOptions) -> Result<(), Error> { info!("QR code rendered to image."); - if let Some(path) = options.output_path { + if let Some(path) = &options.output_path { save_image( - &path, + path, &options.format, &image, options.size, From 668d7e0becbe8880fab3993e0f62e0efbc2bbc7c Mon Sep 17 00:00:00 2001 From: winlogon Date: Wed, 4 Feb 2026 01:38:14 +0100 Subject: [PATCH 2/3] chore: use kitty_image crate instead of manual implementation --- Cargo.lock | 19 ++++++++++------- Cargo.toml | 4 ++-- src/qr_generator.rs | 51 +++++++++++++++++++-------------------------- 3 files changed, 35 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 441eadd..2c32ae2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,12 +121,6 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - [[package]] name = "bit_field" version = "0.10.3" @@ -174,9 +168,9 @@ name = "ciphercanvas" version = "0.2.1" dependencies = [ "anyhow", - "base64 0.22.1", "clap", "image 0.24.9", + "kitty_image", "log", "miette", "qrcode", @@ -491,6 +485,15 @@ dependencies = [ "rayon", ] +[[package]] +name = "kitty_image" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59bed8e1e801b75e8a97ecef1d8a3528ec8b38ceafd354691ddde887aac35736" +dependencies = [ + "base64", +] + [[package]] name = "kurbo" version = "0.9.5" @@ -1172,7 +1175,7 @@ version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c04150a94f0bfc3b2c15d4e151524d14cd06765fc6641d8b1c59a248360d4474" dependencies = [ - "base64 0.21.7", + "base64", "data-url", "flate2", "fontdb", diff --git a/Cargo.toml b/Cargo.toml index 10d744e..9e901d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,8 +31,8 @@ resvg = "0.40.0" tiny-skia = "0.11.4" usvg = "0.40.0" -base64 = { version = "0.22.1", optional = true } +kitty_image = "0.1.0" [features] default = [] -kitty_graphics = ["dep:base64"] +kitty_graphics = [] diff --git a/src/qr_generator.rs b/src/qr_generator.rs index 7711473..48783d2 100644 --- a/src/qr_generator.rs +++ b/src/qr_generator.rs @@ -2,13 +2,10 @@ use crate::{error::Error, image_ops::save_image}; use log::{info, warn}; use miette::Result; use qrcode::{EcLevel, QrCode, render::svg}; -use resvg::render; use std::path::PathBuf; -use tiny_skia::{Pixmap, Transform}; -use usvg::{Options, Tree, fontdb}; #[cfg(feature = "kitty_graphics")] -use base64::{engine::general_purpose, prelude::*}; +use kitty_image::{Action, ActionPut, ActionTransmission, Command, Format, Medium, WrappedCommand}; #[cfg(feature = "kitty_graphics")] use std::io::Write; @@ -72,34 +69,30 @@ pub fn print_qr_code_kitty(options: &QrCodeOptions) -> Result<(), Error> { .map_err(|e| Error::Image(format!("Failed to encode PNG: {e}")))?; info!("Encoded QR code to PNG."); - let encoded_data = general_purpose::STANDARD.encode(&png_data); - let chunks: Vec<&[u8]> = encoded_data.as_bytes().chunks(4096).collect(); - let num_chunks = chunks.len(); + let action = Action::TransmitAndDisplay( + ActionTransmission { + format: Format::Png, + medium: Medium::Direct, + width: options.size, + height: options.size, + ..Default::default() + }, + ActionPut { + move_cursor: true, + ..Default::default() + }, + ); - let mut stdout = std::io::stdout().lock(); + let mut command = Command::new(action); + command.payload = std::borrow::Cow::Borrowed(&png_data); - for (i, chunk) in chunks.iter().enumerate() { - if i == 0 { - // First chunk - write!(stdout, "\x1b_Gf=100,a=T,")?; - } else { - // Subsequent chunks - write!(stdout, "\x1b_G")?; - } - - if i == num_chunks - 1 { - // Last chunk - write!(stdout, "m=0;")?; - } else { - // Not the last chunk - write!(stdout, "m=1;")?; - } - - stdout.write_all(chunk)?; - write!(stdout, "\x1b\\")?; - } + let wrapped = WrappedCommand::new(command); + let mut stdout = std::io::stdout().lock(); + wrapped + .send_chunked(&mut stdout) + .map_err(|e| Error::Image(format!("Failed to send to kitty: {}", e)))?; stdout.flush()?; - println!(); + info!("Printed QR code to terminal using Kitty graphics protocol."); Ok(()) From a720c90951cab1275ec5c3703b3361a47c47de81 Mon Sep 17 00:00:00 2001 From: winlogon Date: Mon, 9 Feb 2026 04:00:20 +0100 Subject: [PATCH 3/3] refactor: small code improvements --- Cargo.toml | 5 +++-- src/image_ops.rs | 4 ++-- src/qr_generator.rs | 26 ++++---------------------- 3 files changed, 9 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9e901d0..f045346 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,8 +31,9 @@ resvg = "0.40.0" tiny-skia = "0.11.4" usvg = "0.40.0" -kitty_image = "0.1.0" +kitty_image = { version = "0.1.0", optional = true } [features] default = [] -kitty_graphics = [] +# Enables support for the Kitty graphics protocol to display QR codes directly in the terminal. +kitty_graphics = ["dep:kitty_image"] diff --git a/src/image_ops.rs b/src/image_ops.rs index eb4dda3..82e37f6 100644 --- a/src/image_ops.rs +++ b/src/image_ops.rs @@ -12,7 +12,7 @@ use usvg::{Options, Tree, fontdb}; const SUPPORTED_FORMATS: &[&str] = &["svg", "png"]; /// Load and render SVG content into a Pixmap of the specified size. -fn load_svg(contents: &[u8], size: u32) -> Result { +pub(crate) fn load_svg(contents: &[u8], size: u32) -> Result { info!("Loading SVG content with size {size}x{size}"); let options = Options::default(); @@ -23,7 +23,7 @@ fn load_svg(contents: &[u8], size: u32) -> Result { )) })?; - let mut pixmap: Pixmap = + let mut pixmap = Pixmap::new(size, size).ok_or(Error::Image("Failed to create a new Pixmap".to_string()))?; render(&tree, Transform::default(), &mut pixmap.as_mut()); diff --git a/src/qr_generator.rs b/src/qr_generator.rs index 48783d2..bd4bb26 100644 --- a/src/qr_generator.rs +++ b/src/qr_generator.rs @@ -4,6 +4,8 @@ use miette::Result; use qrcode::{EcLevel, QrCode, render::svg}; use std::path::PathBuf; +#[cfg(feature = "kitty_graphics")] +use crate::image_ops::load_svg; #[cfg(feature = "kitty_graphics")] use kitty_image::{Action, ActionPut, ActionTransmission, Command, Format, Medium, WrappedCommand}; #[cfg(feature = "kitty_graphics")] @@ -21,27 +23,6 @@ pub struct QrCodeOptions { pub overwrite: bool, } -#[cfg(feature = "kitty_graphics")] -fn load_svg_for_kitty(contents: &[u8], size: u32) -> Result { - info!("Loading SVG content with size {size}x{size}"); - - let options = Options::default(); - let fontdb = fontdb::Database::new(); - let tree: Tree = Tree::from_data(contents, &options, &fontdb).map_err(|e| { - Error::Image(format!( - "Failed to create SVG tree from data of size {size}x{size}: {e}" - )) - })?; - - let mut pixmap: Pixmap = - Pixmap::new(size, size).ok_or(Error::Image("Failed to create a new Pixmap".to_string()))?; - - render(&tree, Transform::default(), &mut pixmap.as_mut()); - info!("Rendered SVG to Pixmap"); - - Ok(pixmap) -} - #[cfg(feature = "kitty_graphics")] pub fn print_qr_code_kitty(options: &QrCodeOptions) -> Result<(), Error> { let contents_to_encode = format!( @@ -63,7 +44,7 @@ pub fn print_qr_code_kitty(options: &QrCodeOptions) -> Result<(), Error> { .build(); info!("QR code rendered to SVG."); - let pixmap = load_svg_for_kitty(image_svg.as_bytes(), options.size)?; + let pixmap = load_svg(image_svg.as_bytes(), options.size)?; let png_data = pixmap .encode_png() .map_err(|e| Error::Image(format!("Failed to encode PNG: {e}")))?; @@ -92,6 +73,7 @@ pub fn print_qr_code_kitty(options: &QrCodeOptions) -> Result<(), Error> { .send_chunked(&mut stdout) .map_err(|e| Error::Image(format!("Failed to send to kitty: {}", e)))?; stdout.flush()?; + println!(); info!("Printed QR code to terminal using Kitty graphics protocol.");