use std::marker::PhantomData;
use cairo::prelude::SurfaceExt;
use cairo::{Context, Format, ImageSurface};
use piet::{ErrorKind, ImageFormat};
pub use piet_cairo::*;
pub type Piet<'a> = CairoRenderContext<'a>;
pub struct Device;
pub struct BitmapTarget<'a> {
surface: ImageSurface,
cr: Context,
phantom: PhantomData<&'a ()>,
}
impl Device {
pub fn new() -> Result<Device, piet::Error> {
Ok(Device)
}
pub fn bitmap_target(
&self,
width: usize,
height: usize,
pix_scale: f64,
) -> Result<BitmapTarget, piet::Error> {
let surface = ImageSurface::create(Format::ARgb32, width as i32, height as i32).unwrap();
let cr = Context::new(&surface);
cr.scale(pix_scale, pix_scale);
let phantom = Default::default();
Ok(BitmapTarget {
surface,
cr,
phantom,
})
}
}
impl<'a> BitmapTarget<'a> {
pub fn render_context<'b>(&'b mut self) -> CairoRenderContext<'b> {
CairoRenderContext::new(&mut self.cr)
}
pub fn into_raw_pixels(mut self, fmt: ImageFormat) -> Result<Vec<u8>, piet::Error> {
if fmt != ImageFormat::RgbaPremul {
return Err(piet::new_error(ErrorKind::NotSupported));
}
std::mem::drop(self.cr);
self.surface.flush();
let stride = self.surface.get_stride() as usize;
let width = self.surface.get_width() as usize;
let height = self.surface.get_height() as usize;
let mut raw_data = vec![0; width * height * 4];
let buf = self
.surface
.get_data()
.map_err(|e| Into::<Box<dyn std::error::Error>>::into(e))?;
for y in 0..height {
let src_off = y * stride;
let dst_off = y * width * 4;
for x in 0..width {
raw_data[dst_off + x * 4 + 0] = buf[src_off + x * 4 + 2];
raw_data[dst_off + x * 4 + 1] = buf[src_off + x * 4 + 1];
raw_data[dst_off + x * 4 + 2] = buf[src_off + x * 4 + 0];
raw_data[dst_off + x * 4 + 3] = buf[src_off + x * 4 + 3];
}
}
Ok(raw_data)
}
}