#[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> { 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 { 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/")] 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(()) }