TIL: Base64 Encoding an ImageBuffer as PNG(in Rust)

Recently, I had to base64-encode an image::ImageBuffer to send it as a data URL like

data:image/png;base64,iVBORw0KGgoAAAANSUhEU... 

Initially, I tried this:

// Cargo.toml
image = "0.24.7"
base64 = "0.21.5"
use base64::{engine::general_purpose, Engine as _};
use image::ImageBuffer;

// WRONG: doesn't base64-encode image as PNG
let image: ImageBuffer<Rgba<u8>, Vec<u8>> = ...;
let b64 = general_purpose::STANDARD.encode(bytes);
println!("b64: {:?}", b64);

But the ImageBuffer doesn’t store its pixels in PNG format, so the base64 string it returns won’t work inside a data URL.

Instead, we first need to create a separate buffer to write the image pixels as PNG, and then encode those bytes as base64:

use std::Cursor;

let image: ImageBuffer<Rgba<u8>, Vec<u8>> = ...;

let mut bytes: Vec<u8> = Vec::new();
image
    .write_to(&mut Cursor::new(&mut bytes), image::ImageOutputFormat::Png)
    .expect("Couldn't write image to bytes.");

let b64 = general_purpose::STANDARD.encode(bytes);
println!("b64: {:?}", b64);