#![allow(clippy::identity_op)]
use std::marker::PhantomData;
use std::path::Path;
#[cfg(feature = "png")]
use std::{fs::File, io::BufWriter};
use core_graphics::{color_space::CGColorSpace, context::CGContext, image::CGImage};
#[cfg(feature = "png")]
use png::{ColorType, Encoder};
use piet::{Error, ImageFormat};
#[doc(hidden)]
pub use piet_coregraphics::*;
pub type Piet<'a> = CoreGraphicsContext<'a>;
pub type Brush = piet_coregraphics::Brush;
pub type PietText<'a> = CoreGraphicsText<'a>;
pub type PietFont = CoreGraphicsFont;
pub type PietFontBuilder<'a> = CoreGraphicsFontBuilder;
pub type PietTextLayout = CoreGraphicsTextLayout;
pub type PietTextLayoutBuilder<'a> = CoreGraphicsTextLayout;
pub type Image = CGImage;
pub struct Device;
pub struct BitmapTarget<'a> {
ctx: CGContext,
height: f64,
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 ctx = CGContext::create_bitmap_context(
None,
width,
height,
8,
0,
&CGColorSpace::create_device_rgb(),
core_graphics::base::kCGImageAlphaPremultipliedLast,
);
ctx.scale(pix_scale, pix_scale);
let height = height as f64 * pix_scale.recip();
Ok(BitmapTarget {
ctx,
height,
phantom: PhantomData,
})
}
}
impl<'a> BitmapTarget<'a> {
pub fn render_context(&mut self) -> CoreGraphicsContext {
CoreGraphicsContext::new_y_up(&mut self.ctx, self.height)
}
pub fn into_raw_pixels(mut self, fmt: ImageFormat) -> Result<Vec<u8>, piet::Error> {
if fmt != ImageFormat::RgbaPremul {
return Err(Error::NotSupported);
}
let data = self.ctx.data();
Ok(data.to_owned())
}
#[cfg(feature = "png")]
pub fn save_to_file<P: AsRef<Path>>(self, path: P) -> Result<(), piet::Error> {
let width = self.ctx.width() as usize;
let height = self.ctx.height() as usize;
let mut data = self.into_raw_pixels(ImageFormat::RgbaPremul)?;
piet_coregraphics::unpremultiply_rgba(&mut data);
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.set_depth(png::BitDepth::Eight);
encoder
.write_header()
.map_err(|e| Into::<Box<_>>::into(e))?
.write_image_data(&data)
.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(Error::MissingFeature)
}
}