chiark / gitweb /
images in bundles: Support png
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 22 May 2021 12:32:06 +0000 (13:32 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sat, 22 May 2021 17:11:14 +0000 (18:11 +0100)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
nwtemplates/image-usvg.tera [new file with mode: 0644]
src/bundles.rs

diff --git a/nwtemplates/image-usvg.tera b/nwtemplates/image-usvg.tera
new file mode 100644 (file)
index 0000000..78fc6aa
--- /dev/null
@@ -0,0 +1,7 @@
+<svg xmlns="http://www.w3.org/2000/svg" 
+     width="{{width}}" height="{{height}}"
+     viewBox="0 0 {{width}} {{height}}"
+     enable-background="new 0 0 {{width}} {{height}}">
+  <image x="0" y="0" width="{{width}}" height="{{height}}"
+         href="data:{{ctype}};base64,@DATA@"/>
+</svg>
index 5de632a0e1cb97347d5d6661e3a87694d1617278..33c404d632d5b06978825c69b793f1cd4d8a0bd1 100644 (file)
@@ -699,7 +699,43 @@ fn process_bundle(ForProcess { mut za, mut newlibs }: ForProcess,
 // In preference order
 enum PictureFormat {
   Svg,
-//  Png,   xxx implement this
+  Png,
+}
+
+#[throws(LE)]
+fn image_usvg(zfname: &str, input: File, output: File,
+              format: image::ImageFormat, ctype: &'static str) {
+  #[derive(Serialize,Copy,Clone,Debug)]
+  struct Render {
+    width: u32,
+    height: u32,
+    ctype: &'static str,
+  }
+
+  let mut input = BufReader::new(input);
+  let mut output = BufWriter::new(output);
+
+  let image = image::io::Reader::with_format(&mut input, format);
+  let (width, height) = image.into_dimensions().map_err(
+    |e| LE::BadBundle(format!("{}: image examination failed: {}",
+                              zfname, e)))?;
+
+  let render = Render { width, height, ctype };
+  let rendered = nwtemplates::render("image-usvg.tera", &render)
+    .map_err(IE::from)?;
+  let (head, tail) = rendered.rsplit_once("@DATA@").ok_or_else(
+    || IE::from(anyhow!("image-usvg template did not produce @DATA@")))?;
+
+  input.rewind().context("rewind input").map_err(IE::from)?;
+  write!(output,"{}",head).context("write head to output").map_err(IE::from)?;
+  let charset = base64::CharacterSet::Standard;
+  let b64cfg = base64::Config::new(charset,true);
+  let mut output = base64::write::EncoderWriter::new(output, b64cfg);
+  io::copy(&mut input, &mut output).map_err(|e| LE::BadBundle(format!(
+    "{}: read and base64-encode image data: {}", zfname, e)))?;
+  let mut output = output.finish().context("finish b64").map_err(IE::from)?;
+  write!(output,"{}",tail).context("write tail to output").map_err(IE::from)?;
+  output.flush().context("flush output?").map_err(IE::from)?;
 }
 
 #[throws(LE)]
@@ -736,6 +772,7 @@ fn make_usvg(za: &mut IndexedZip, progress_count: &mut usize,
     .with_context(|| usvg_path.clone()).context("create").map_err(IE::from)?;
 
   use PictureFormat as PF;
+  use image::ImageFormat as IF;
   match format {
     PF::Svg => {
       let got = Command::new(&config().usvg_bin).args(&["-c","-"])
@@ -748,6 +785,7 @@ fn make_usvg(za: &mut IndexedZip, progress_count: &mut usize,
         )));
       }
     },
+    PF::Png => image_usvg(zf.name(),input,output, IF::Png, "image/png")?,
   }
 }