use alloc::vec;
use alloc::vec::Vec;
use image::{ImageBuffer, Rgba, GenericImageView, ImageFormat};
use core::convert::TryFrom;
use core::num::NonZeroUsize;
use std::println;
use ruisa_path::{IntSize, ScreenIntRect};
use crate::{Color, IntRect};
use crate::color::PremultipliedColorU8;
use image::{DynamicImage, ImageError};
pub const BYTES_PER_PIXEL: usize = 4;
#[derive(Clone, PartialEq)]
pub struct Canvas {
data: Vec<u8>,
size: IntSize,
}
impl Canvas {
pub fn new(width: u32, height: u32) -> Option<Self> {
let size = IntSize::from_wh(width, height)?;
let data_len = data_len_for_size(size)?;
Some(Canvas {
data: vec![0; data_len],
size,
})
}
pub fn dump(&self) {
println!("Canvas width:{}, height: {}, data_len: {}", self.width(), self.height(), self.data.len());
}
pub fn from(buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>) -> Self {
Canvas {
data: buffer.to_vec(),
size:IntSize::from_wh(buffer.width(), buffer.height()).unwrap(),
}
}
pub fn from_vec(data: Vec<u8>, size: IntSize) -> Option<Self> {
let data_len = data_len_for_size(size)?;
if data.len() != data_len {
return None;
}
Some(Canvas { data, size })
}
pub fn from_image(data: &[u8]) -> Result<Self, ImageError> {
let image: DynamicImage = image::load_from_memory(data).unwrap();
let buffer = ImageBuffer::from_fn(image.width(), image.height(), |x, y|{
image.get_pixel(x, y)
});
Ok(Canvas {
data: buffer.to_vec(),
size:IntSize::from_wh(image.width(), image.height()).unwrap(),
})
}
pub fn from_image_file<P: AsRef<std::path::Path>>(path: P) -> Result<Self, ImageError> {
let image = image::open(path).unwrap();
let buffer = ImageBuffer::from_fn(image.width(), image.height(), |x, y|{
image.get_pixel(x, y)
});
Ok(Canvas {
data: buffer.to_vec(),
size:IntSize::from_wh(image.width(), image.height()).unwrap(),
})
}
pub fn to_png(&self) -> Result<Vec<u8>, ImageError> {
self.as_ref().to_png()
}
pub fn save_png<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), ImageError> {
self.as_ref().save_png(path)
}
pub fn save_image<P: AsRef<std::path::Path>>(&self, path: P, format: ImageFormat) -> Result<(), ImageError> {
self.as_ref().save_image(path, format)
}
pub fn as_ref(&self) -> CanvasRef {
CanvasRef {
data: &self.data,
size: self.size,
}
}
pub fn as_mut(&mut self) -> CanvasMut {
CanvasMut {
data: &mut self.data,
size: self.size,
}
}
#[inline]
pub fn width(&self) -> u32 {
self.size.width()
}
#[inline]
pub fn height(&self) -> u32 {
self.size.height()
}
#[allow(dead_code)]
pub(crate) fn size(&self) -> IntSize {
self.size
}
pub fn fill(&mut self, color: Color) {
let c = color.premultiply().to_color_u8();
for p in self.as_mut().pixels_mut() {
*p = c;
}
}
pub fn data(&self) -> &[u8] {
self.data.as_slice()
}
pub fn data_mut(&mut self) -> &mut [u8] {
self.data.as_mut_slice()
}
pub fn pixel(&self, x: u32, y: u32) -> Option<PremultipliedColorU8> {
let idx = self.width().checked_mul(y)?.checked_add(x)?;
self.pixels().get(idx as usize).cloned()
}
pub fn pixels_mut(&mut self) -> &mut [PremultipliedColorU8] {
bytemuck::cast_slice_mut(self.data_mut())
}
pub fn pixels(&self) -> &[PremultipliedColorU8] {
let ans = bytemuck::cast_slice(self.data());
ans
}
pub fn take(self) -> Vec<u8> {
self.data
}
pub fn clone_rect(&self, rect: IntRect) -> Option<Canvas> {
self.as_ref().clone_rect(rect)
}
}
impl core::fmt::Debug for Canvas {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Canvas")
.field("data", &"...")
.field("width", &self.size.width())
.field("height", &self.size.height())
.finish()
}
}
#[derive(Clone, Copy, PartialEq)]
pub struct CanvasRef<'a> {
data: &'a [u8],
size: IntSize,
}
impl<'a> CanvasRef<'a> {
pub fn from_bytes(data: &'a [u8], width: u32, height: u32) -> Option<Self> {
let size = IntSize::from_wh(width, height)?;
let data_len = data_len_for_size(size)?;
if data.len() < data_len {
return None;
}
Some(CanvasRef { data, size })
}
pub fn to_owned(&self) -> Canvas {
Canvas {
data: self.data.to_vec(),
size: self.size,
}
}
#[inline]
pub fn width(&self) -> u32 {
self.size.width()
}
#[inline]
pub fn height(&self) -> u32 {
self.size.height()
}
pub(crate) fn size(&self) -> IntSize {
self.size
}
pub(crate) fn rect(&self) -> ScreenIntRect {
self.size.to_screen_int_rect(0, 0)
}
pub fn data(&self) -> &'a [u8] {
self.data
}
pub fn pixel(&self, x: u32, y: u32) -> Option<PremultipliedColorU8> {
let idx = self.width().checked_mul(y)?.checked_add(x)?;
self.pixels().get(idx as usize).cloned()
}
pub fn pixels(&self) -> &'a [PremultipliedColorU8] {
bytemuck::cast_slice(self.data())
}
pub fn clone_rect(&self, rect: IntRect) -> Option<Canvas> {
let rect = self.rect().to_int_rect().intersect(&rect)?;
let mut new = Canvas::new(rect.width(), rect.height())?;
{
let old_pixels = self.pixels();
let mut new_mut = new.as_mut();
let new_pixels = new_mut.pixels_mut();
for y in 0..rect.height() {
for x in 0..rect.width() {
let old_idx = (y + rect.y() as u32) * self.width() + (x + rect.x() as u32);
let new_idx = y * rect.width() + x;
new_pixels[new_idx as usize] = old_pixels[old_idx as usize];
}
}
}
Some(new)
}
pub fn to_png(&self) -> Result<Vec<u8>, ImageError> {
let image: DynamicImage = image::load_from_memory(&self.data).unwrap();
Ok(image.to_bytes())
}
pub fn save_png<P: AsRef<std::path::Path>>(&self, path: P) -> Result<(), ImageError> {
self.save_image(path, image::ImageFormat::Png)
}
pub fn save_image<P: AsRef<std::path::Path>>(&self, path: P, format: image::ImageFormat) -> Result<(), ImageError> {
let buffer = ImageBuffer::from_fn(self.width(), self.height(), |x,y|{
let color = self.pixel(x, y).unwrap();
color.to_rgba()
});
let image: DynamicImage = DynamicImage::ImageRgba8(buffer);
image.save_with_format(path, format)
}
}
impl core::fmt::Debug for CanvasRef<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("CanvasRef")
.field("data", &"...")
.field("width", &self.size.width())
.field("height", &self.size.height())
.finish()
}
}
#[derive(PartialEq)]
pub struct CanvasMut<'a> {
data: &'a mut [u8],
size: IntSize,
}
impl<'a> CanvasMut<'a> {
pub fn from_bytes(data: &'a mut [u8], width: u32, height: u32) -> Option<Self> {
let size = IntSize::from_wh(width, height)?;
let data_len = data_len_for_size(size)?;
if data.len() < data_len {
return None;
}
Some(CanvasMut { data, size })
}
pub fn to_owned(&self) -> Canvas {
Canvas {
data: self.data.to_vec(),
size: self.size,
}
}
pub fn as_ref(&self) -> CanvasRef {
CanvasRef {
data: self.data,
size: self.size,
}
}
#[inline]
pub fn width(&self) -> u32 {
self.size.width()
}
#[inline]
pub fn height(&self) -> u32 {
self.size.height()
}
pub(crate) fn size(&self) -> IntSize {
self.size
}
pub fn fill(&mut self, color: Color) {
let c = color.premultiply().to_color_u8();
for p in self.pixels_mut() {
*p = c;
}
}
pub fn data_mut(&mut self) -> &mut [u8] {
self.data
}
pub fn pixels_mut(&mut self) -> &mut [PremultipliedColorU8] {
bytemuck::cast_slice_mut(self.data_mut())
}
pub(crate) fn as_subcanvas(&mut self) -> SubCanvasMut {
SubCanvasMut {
size: self.size(),
real_width: self.width() as usize,
data: &mut self.data,
}
}
pub(crate) fn subcanvas(&mut self, rect: IntRect) -> Option<SubCanvasMut> {
let rect = self.size.to_int_rect(0, 0).intersect(&rect)?;
let row_bytes = self.width() as usize * BYTES_PER_PIXEL;
let offset = rect.top() as usize * row_bytes + rect.left() as usize * BYTES_PER_PIXEL;
Some(SubCanvasMut {
size: rect.size(),
real_width: self.width() as usize,
data: &mut self.data[offset..],
})
}
}
impl core::fmt::Debug for CanvasMut<'_> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("CanvasMut")
.field("data", &"...")
.field("width", &self.size.width())
.field("height", &self.size.height())
.finish()
}
}
pub struct SubCanvasMut<'a> {
pub data: &'a mut [u8],
pub size: IntSize,
pub real_width: usize,
}
impl<'a> SubCanvasMut<'a> {
pub fn pixels_mut(&mut self) -> &mut [PremultipliedColorU8] {
bytemuck::cast_slice_mut(self.data)
}
}
fn min_row_bytes(size: IntSize) -> Option<NonZeroUsize> {
let w = i32::try_from(size.width()).ok()?;
let w = w.checked_mul(BYTES_PER_PIXEL as i32)?;
NonZeroUsize::new(w as usize)
}
fn compute_data_len(size: IntSize, row_bytes: usize) -> Option<usize> {
let h = size.height().checked_sub(1)?;
let h = (h as usize).checked_mul(row_bytes)?;
let w = (size.width() as usize).checked_mul(BYTES_PER_PIXEL)?;
h.checked_add(w)
}
fn data_len_for_size(size: IntSize) -> Option<usize> {
let row_bytes = min_row_bytes(size)?;
compute_data_len(size, row_bytes.get())
}