#![allow(clippy::identity_op)]
use cairo::{Context, Format, ImageSurface};
#[cfg(feature = "png")]
use png::{ColorType, Encoder};
#[cfg(feature = "png")]
use std::fs::File;
#[cfg(feature = "png")]
use std::io::BufWriter;
use std::marker::PhantomData;
use std::path::Path;
use piet::{ErrorKind, ImageFormat};
#[doc(hidden)]
pub use piet_cairo::*;
pub type Piet<'a> = CairoRenderContext<'a>;
pub type Brush = piet_cairo::Brush;
pub type PietText<'a> = CairoText<'a>;
pub type PietFont = CairoFont;
pub type PietFontBuilder<'a> = CairoFontBuilder;
pub type PietTextLayout = CairoTextLayout;
pub type PietTextLayoutBuilder<'a> = CairoTextLayoutBuilder;
pub type Image = ImageSurface;
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(
&mut 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(&mut self) -> CairoRenderContext {
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(Into::<Box<dyn std::error::Error>>::into)?;
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)
}
#[cfg(feature = "png")]
pub fn save_to_file<P: AsRef<Path>>(self, path: P) -> Result<(), piet::Error> {
let height = self.surface.get_height();
let width = self.surface.get_width();
let image = self.into_raw_pixels(ImageFormat::RgbaPremul)?;
let file = BufWriter::new(File::create(path).map_err(|e| Into::<Box<_>>::into(e))?);
let mut encoder = Encoder::new(file, width as u32, height as u32);
encoder.set_color(ColorType::RGBA);
encoder
.write_header()
.map_err(|e| Into::<Box<_>>::into(e))?
.write_image_data(&image)
.map_err(|e| Into::<Box<_>>::into(e))?;
Ok(())
}
#[cfg(not(feature = "png"))]
pub fn save_to_file<P: AsRef<Path>>(self, _path: P) -> Result<(), piet::Error> {
Err(piet::new_error(ErrorKind::MissingFeature))
}
}