Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to center all text, and display encryption time by default #89

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@
test-output.json
/visual-snapshots
*.profraw
.idea/
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a small thing but editor specific files should be ignored in a global gitignore file and not per-repo.

https://docs.github.com/en/get-started/getting-started-with-git/ignoring-files#configuring-ignored-files-for-all-repositories-on-your-computer

90 changes: 88 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ printpdf = { version = "0.5.3", features = ["svg"] }
qrcode = "0.12.0"
log = "0.4"
env_logger = "0.10"
chrono = "0.4.28"

[dev-dependencies]
assert_cmd = "2.0"
Expand Down
101 changes: 70 additions & 31 deletions src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! PaperAge
use std::io::{BufReader, Cursor};
use chrono::Local;

use printpdf::{
Color, IndirectFontRef, Line, LineDashPattern, Mm, PdfDocument, PdfDocumentReference,
Expand All @@ -13,6 +14,9 @@ pub mod svg;
/// PaperAge version
pub const VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION");

/// Font width / height = 3 / 5
pub const FONT_RATIO: f64 = 3.0 / 5.0;

/// Container for all the data required to insert elements into the PDF
pub struct Document {
/// A reference to the printpdf PDF document
Expand Down Expand Up @@ -69,17 +73,25 @@ impl Document {
self.doc.get_page(self.page).get_layer(self.layer)
}

/// Calculate the left margin when text is centered
fn calc_center_margin(&self, font_size: f64, text_length: usize) -> Mm {
let text_width = font_size * FONT_RATIO * text_length as f64;
(self.page_size.dimensions().width - Mm::from(Pt(text_width))) / 2.0
}

/// Insert the given title at the top of the PDF
pub fn insert_title_text(&self, title: String) {
pub fn insert_title_text(&self, title: String, center: bool) {
debug!("Inserting title: {}", title.as_str());

let current_layer = self.get_current_layer();

let font_size = 14.0;

// Align the title with the QR code if the title is narrower than the QR code
let margin = {
if title.len() <= 37 {
let left_margin = {
if center {
self.calc_center_margin(font_size, title.len())
} else if title.len() <= 37 {
self.page_size.qrcode_left_edge()
} else {
self.page_size.dimensions().margin
Expand All @@ -89,7 +101,7 @@ impl Document {
current_layer.use_text(
title,
font_size,
margin,
left_margin,
self.page_size.dimensions().height
- self.page_size.dimensions().margin
- Mm::from(Pt(font_size)),
Expand All @@ -98,7 +110,7 @@ impl Document {
}

/// Insert the given PEM ciphertext in the bottom half of the page
pub fn insert_pem_text(&self, pem: String) {
pub fn insert_pem_text(&self, pem: String, center: bool) {
debug!("Inserting PEM encoded ciphertext");

let current_layer = self.get_current_layer();
Expand All @@ -123,8 +135,14 @@ impl Document {

current_layer.begin_text_section();

let left_margin = if center {
self.calc_center_margin(font_size, 64)
} else {
self.page_size.dimensions().margin
};

current_layer.set_text_cursor(
self.page_size.dimensions().margin,
left_margin,
(self.page_size.dimensions().height / 2.0)
- Mm::from(Pt(font_size))
- self.page_size.dimensions().margin,
Expand Down Expand Up @@ -238,49 +256,70 @@ impl Document {
current_layer.add_shape(divider);
}

/// Insert the passphrase label and placeholder in the PDF
pub fn insert_passphrase(&self) {
/// Insert the time or passphrase field in the PDF
pub fn insert_time_or_passphrase(&self, passphrase_field: bool, center: bool) {
debug!("Inserting passphrase placeholder");

let current_layer = self.get_current_layer();

let baseline =
self.page_size.dimensions().height / 2.0 + self.page_size.dimensions().margin;
let font_size = 13.0;
let baseline = self.page_size.dimensions().height / 2.0 + self.page_size.dimensions().margin;
let text = if passphrase_field { "Passphrase: ".to_string() } else {
Local::now()
.format("Encrypted at %Y-%m-%d %H:%M:%S")
.to_string()
};

let left_margin = if center && !passphrase_field {
self.calc_center_margin(font_size, text.len())
} else {
self.page_size.qrcode_left_edge()
};

current_layer.use_text(
"Passphrase: ",
13.0,
self.page_size.qrcode_left_edge(),
text,
font_size,
left_margin,
baseline,
&self.title_font,
);

self.draw_line(
vec![
Point::new(
self.page_size.qrcode_left_edge() + Mm(30.0),
baseline - Mm(1.0),
),
Point::new(
self.page_size.qrcode_left_edge() + self.page_size.qrcode_size(),
baseline - Mm(1.0),
),
],
1.0,
LineDashPattern::default(),
)
if passphrase_field {
self.draw_line(
vec![
Point::new(
self.page_size.qrcode_left_edge() + Mm(30.0),
baseline - Mm(1.0),
),
Point::new(
self.page_size.qrcode_left_edge() + self.page_size.qrcode_size(),
baseline - Mm(1.0),
),
],
1.0,
LineDashPattern::default(),
)
}
}

/// Add the footer at the bottom of the page
pub fn insert_footer(&self) {
pub fn insert_footer(&self, center: bool) {
debug!("Inserting footer");

let current_layer = self.get_current_layer();
let text = "Scan QR code and decrypt using Age <https://age-encryption.org>";
let font_size = 13.0;

let left_margin = if center {
self.calc_center_margin(font_size, text.len())
} else {
self.page_size.dimensions().margin
};

current_layer.use_text(
"Scan QR code and decrypt using Age <https://age-encryption.org>",
13.0,
self.page_size.dimensions().margin,
text,
font_size,
left_margin,
self.page_size.dimensions().margin,
&self.title_font,
);
Expand Down
8 changes: 8 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ pub struct Args {
#[arg(short = 's', long, default_value_t = PageSize::A4)]
pub page_size: PageSize,

/// Center all text
#[arg(short, long, default_value_t = false)]
pub center: bool,

/// Display passphrase field instead of time
#[arg(short = 'P', long, default_value_t = false)]
pub passphrase_field: bool,

/// Overwrite the output file if it already exists
#[arg(short, long, default_value_t = false)]
pub force: bool,
Expand Down
8 changes: 4 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
pdf.draw_grid();
}

pdf.insert_title_text(args.title);
pdf.insert_title_text(args.title, args.center);

match pdf.insert_qr_code(encrypted.clone()) {
Ok(()) => (),
Expand All @@ -109,7 +109,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
}

pdf.insert_passphrase();
pdf.insert_time_or_passphrase(args.passphrase_field, args.center);

pdf.draw_line(
vec![
Expand All @@ -123,9 +123,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
},
);

pdf.insert_pem_text(encrypted);
pdf.insert_pem_text(encrypted, args.center);

pdf.insert_footer();
pdf.insert_footer(args.center);

if output == PathBuf::from("-") {
debug!("Writing to STDOUT");
Expand Down