aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
blob: 235023a1dcc4de5f2b9f2083d38e33943ec3f128 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#[macro_use]
extern crate rocket;

use quick_xml::events::BytesText;
use quick_xml::Writer;
use rocket::http::{ContentType, Status};
use std::io;
use std::io::{Cursor, Write};
use std::process::{Command, Stdio};

fn to_input_svg(text: &str) -> anyhow::Result<Vec<u8>> {
    let mut writer = Writer::new(Cursor::new(vec![]));
    writer
        .create_element("svg")
        .with_attribute(("xmlns", "http://www.w3.org/2000/svg"))
        .write_inner_content(|writer| {
            writer
                .create_element("style")
                .write_text_content(BytesText::new("text { font-family: 'linja pona'; }"))?;
            writer
                .create_element("text")
                .write_text_content(BytesText::new(text))?;
            Ok(())
        })?;
    Ok(writer.into_inner().into_inner())
}

fn to_final_svg(text: &str) -> anyhow::Result<String> {
    let input_svg = to_input_svg(text)?;
    let mut inkscape_command = Command::new("inkscape")
        .args([
            "--pipe",
            "--export-type=svg",
            "--export-area-drawing",
            "--export-plain-svg",
            "--export-text-to-path",
        ])
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()?;

    inkscape_command
        .stdin
        .take()
        .unwrap()
        .write_all(&input_svg)?;

    let mut svgo_command = Command::new("svgo")
        .args(["--config", "./svgo.config.js", "-"])
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()?;

    io::copy(
        &mut inkscape_command.stdout.take().unwrap(),
        &mut svgo_command.stdin.take().unwrap(),
    )?;

    let inkscape_result = inkscape_command.wait()?;
    assert!(inkscape_result.success());
    let svgo_result = svgo_command.wait_with_output()?;
    assert!(svgo_result.status.success());
    let result = String::from_utf8(svgo_result.stdout)?;
    Ok(result)
}

#[get("/")]
fn index() -> &'static str {
    "Hello, world!"
}

#[get("/render/<text>")]
fn render(text: &str) -> Result<(ContentType, String), (Status, String)> {
    match to_final_svg(text) {
        Ok(svg) => Ok((ContentType::SVG, svg)),
        Err(e) => Err((Status::InternalServerError, e.to_string())),
    }
}

#[rocket::main]
async fn main() -> Result<(), rocket::Error> {
    let _rocket = rocket::build()
        .mount("/", routes![index, render])
        .launch()
        .await?;

    Ok(())
}