Skip to content

Commit c95fa32

Browse files
laurmaedjereknih
andcommitted
Simple command line interface
Co-Authored-By: Martin <[email protected]>
1 parent b850bbd commit c95fa32

2 files changed

Lines changed: 77 additions & 1 deletion

File tree

Cargo.toml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,20 @@ categories = ["encoding", "graphics", "multimedia"]
1111
keywords = ["svg", "pdf", "vector-graphics", "conversion"]
1212

1313
[features]
14-
default = ["png", "jpeg", "text"]
14+
default = ["png", "jpeg"]
1515
png = ["image/png"]
1616
jpeg = ["image/jpeg"]
17+
cli = ["clap", "termcolor", "usvg/text", "fontdb"]
1718

1819
[dependencies]
1920
miniz_oxide = "0.4"
2021
pdf-writer = "0.4.1"
2122
usvg = { version = "0.20", default-features = false }
23+
clap = { version = "3", features = ["derive"], optional = true }
24+
fontdb = { version = "0.7", optional = true }
2225
image = { version = "0.23", default-features = false, optional = true }
26+
termcolor = { version = "1", optional = true }
27+
28+
[[bin]]
29+
name = "svg2pdf"
30+
required-features = ["cli"]

src/main.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
use std::io::{self, Write};
2+
use std::path::{Path, PathBuf};
3+
use std::process;
4+
5+
use clap::Parser;
6+
use termcolor::{ColorChoice, ColorSpec, StandardStream, WriteColor};
7+
8+
#[derive(Debug, Parser)]
9+
#[clap(about, version)]
10+
struct Args {
11+
/// Path to read SVG file from.
12+
input: PathBuf,
13+
/// Path to write PDF file to.
14+
output: Option<PathBuf>,
15+
/// The number of SVG pixels per PDF points.
16+
#[clap(long, default_value = "72.0")]
17+
dpi: f64,
18+
}
19+
20+
fn main() {
21+
if let Err(msg) = run() {
22+
print_error(&msg).unwrap();
23+
process::exit(1);
24+
}
25+
}
26+
27+
fn run() -> Result<(), String> {
28+
let args = Args::parse();
29+
30+
// Determine output path.
31+
let name =
32+
Path::new(args.input.file_name().ok_or("Input path does not point to a file")?);
33+
let output = args.output.unwrap_or_else(|| name.with_extension("pdf"));
34+
35+
// Load source file.
36+
let svg =
37+
std::fs::read_to_string(&args.input).map_err(|_| "Failed to load SVG file")?;
38+
39+
// Convert string to SVG.
40+
let mut options = usvg::Options::default();
41+
options.fontdb = fontdb::Database::new();
42+
options.fontdb.load_system_fonts();
43+
let tree =
44+
usvg::Tree::from_str(&svg, &options.to_ref()).map_err(|err| err.to_string())?;
45+
46+
// Convert SVG to PDF.
47+
let mut options = svg2pdf::Options::default();
48+
options.dpi = args.dpi;
49+
let pdf = svg2pdf::convert_tree(&tree, options);
50+
51+
// Write output file.
52+
std::fs::write(output, pdf).map_err(|_| "Failed to write PDF file")?;
53+
54+
Ok(())
55+
}
56+
57+
fn print_error(msg: &str) -> io::Result<()> {
58+
let mut w = StandardStream::stderr(ColorChoice::Always);
59+
60+
let mut color = ColorSpec::new();
61+
color.set_fg(Some(termcolor::Color::Red));
62+
color.set_bold(true);
63+
w.set_color(&color)?;
64+
write!(w, "error")?;
65+
66+
w.reset()?;
67+
writeln!(w, ": {msg}.")
68+
}

0 commit comments

Comments
 (0)