We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
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
In my project I've introduced an enum to give me a more readable representation of the PDF operations:
enum PdfOperation { OpenPath { x: PdfNumber, y: PdfNumber }, Line { x: PdfNumber, y: PdfNumber }, ClosePath {}, Stroke {}, ClosePathAndStroke {}, SetStrokeGrayLevel { gray: Percentage }, SetStrokeRGBColor { r: Percentage, g: Percentage, b: Percentage }, SetLineWidth { width: NonNegativePdfNumber }, BeginText {}, EndText {}, NextLine {}, MoveTextCursor { x: PdfNumber, y: PdfNumber }, SetTextFont { font: String, size: PdfNumber }, SetTextLeading { leading: PdfNumber }, ShowText { text: PdfString }, NextLineAndShowText { text: PdfString }, } impl Into<lopdf::content::Operation> for PdfOperation { fn into(self) -> lopdf::content::Operation { use lopdf::content::Operation; macro_rules! operation { ($operator:expr $(,)?) => { Operation::new($operator, vec![]) }; ($operator:expr, $($operants:expr),+ $(,)?) => { Operation::new($operator, vec![$($operants.into()),+]) }; } match self { Self::OpenPath { x, y } => operation!("m", x, y), Self::ClosePath {} => operation!("h"), Self::Line { x, y } => operation!("l", x, y), Self::Stroke {} => operation!("S"), Self::ClosePathAndStroke {} => operation!("s"), Self::SetStrokeGrayLevel { gray } => operation!("G", gray), Self::SetStrokeRGBColor { r, g, b } => operation!("RG", r, g, b), Self::SetLineWidth { width } => operation!("w", width), Self::BeginText {} => operation!("BT"), Self::EndText {} => operation!("ET"), Self::NextLine {} => operation!("T*"), Self::MoveTextCursor { x, y } => operation!("Td", x, y), Self::SetTextFont { font, size } => operation!("Tf", font, size), Self::SetTextLeading { leading } => operation!("TL", leading), Self::ShowText { text } => operation!("Tj", text), Self::NextLineAndShowText { text } => operation!("'", text), } } }
The PdfNumber and PdfString types are subsets of Object:
PdfNumber
PdfString
Object
#[derive(Debug, Clone, Copy)] enum PdfNumber { Integer(i64), Real(f64), } impl Into<lopdf::Object> for PdfNumber { fn into(self) -> lopdf::Object { use lopdf::Object; match self { Self::Integer(i) => Object::Integer(i), Self::Real(r) => Object::Real(r), } } } impl From<i64> for PdfNumber { fn from(i: i64) -> Self { Self::Integer(i) } } impl From<f64> for PdfNumber { fn from(r: f64) -> Self { Self::Real(r) } } #[derive(Debug, Clone)] enum PdfString { Literal(Vec<u8>), Hexadecimal(Vec<u8>), } impl Into<lopdf::Object> for PdfString { fn into(self) -> lopdf::Object { use lopdf::{Object, StringFormat}; match self { Self::Literal(s) => Object::String(s, StringFormat::Literal), Self::Hexadecimal(s) => Object::String(s, StringFormat::Hexadecimal), } } } impl From<String> for PdfString { fn from(s: String) -> Self { Self::from(s.as_str()) } } impl<'a> From<&'a str> for PdfString { fn from(s: &'a str) -> Self { // probably specific to my usecase use encoding::Encoding as _; Self::Literal(encoding::all::ISO_8859_1.encode(s, encoding::EncoderTrap::Strict) .unwrap_or_else(|e| panic!("Encoding failire: {}", e))) } }
Percentage and NonNegativePdfNumber are wrappers like std::num::NonZero*, to ensure valid ranges:
Percentage
NonNegativePdfNumber
std::num::NonZero*
#[derive(Debug, Clone, Copy)] // strictly in range [0..1] struct Percentage(f64); impl Percentage { pub fn new(r: f64) -> Self { assert!(r >= 0.); assert!(r <= 1.); Self(r) } } impl Into<lopdf::Object> for Percentage { fn into(self) -> lopdf::Object { lopdf::Object::Real(self.0) } } #[derive(Debug, Clone, Copy)] enum NonNegativePdfNumber { Integer(i64), Real(f64), } impl NonNegativePdfNumber { pub fn new_integer(i: i64) -> Self { assert!(i >= 0); Self::Integer(i) } pub fn new_real(r: f64) -> Self { assert!(r >= 0.); Self::Real(r) } } impl Into<lopdf::Object> for NonNegativePdfNumber { fn into(self) -> lopdf::Object { use lopdf::Object; match self { Self::Integer(i) => Object::Integer(i), Self::Real(r) => Object::Real(r), } } }
Obviously this is only the subset that I require. Maybe extending it and integrating it into lopdf would be desirable though. Here's an example usage:
macro_rules! operations_vec { ($($operation:expr),* $(,)?) => { vec![$($operation.into()),*] }; } let content = lopdf::content::Content { operations: operations_vec![ PdfOperation::BeginText {}, PdfOperation::SetTextFont { font: "F1".into(), size: 48.into() }, PdfOperation::MoveTextCursor { x: 100.into(), y: 600.into() }, PdfOperation::ShowText { text: "Hello World!".into() }, PdfOperation::EndText {}, ], };
The text was updated successfully, but these errors were encountered:
I also wonder why this project intensively uses strings instead of enums? Is there any reason?
Sorry, something went wrong.
Just because defining so many enums is very laborious.
Would you be open to a potential PR that implements operations as enum instead of strings?
No branches or pull requests
In my project I've introduced an enum to give me a more readable representation of the PDF operations:
The
PdfNumber
andPdfString
types are subsets ofObject
:Percentage
andNonNegativePdfNumber
are wrappers likestd::num::NonZero*
, to ensure valid ranges:Obviously this is only the subset that I require. Maybe extending it and integrating it into lopdf would be desirable though.
Here's an example usage:
The text was updated successfully, but these errors were encountered: