use image::{GenericImage, GenericImageView};
use crate::{
graphics::{rgba_u8_to_u32, u32_to_rgba_u8},
prelude::Buffer,
};
#[must_use]
pub const fn u32_to_image_rgba(color: u32) -> image::Rgba<u8> {
let (r, g, b, a) = u32_to_rgba_u8(color);
image::Rgba([r, g, b, 255 - a])
}
#[must_use]
pub const fn image_rgba_to_u32(rgba: image::Rgba<u8>) -> u32 {
let [r, g, b, a] = rgba.0;
rgba_u8_to_u32(r, g, b, a)
}
#[must_use]
pub const fn rgb_to_image_rgba(r: u8, g: u8, b: u8) -> image::Rgba<u8> {
image::Rgba([r, g, b, 255])
}
#[must_use]
pub fn create_empty_image(width: u32, height: u32) -> image::DynamicImage {
image::DynamicImage::new_rgba8(width, height)
}
#[allow(clippy::cast_precision_loss)]
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_sign_loss)]
pub fn draw_texture_into_image(
image: &mut image::DynamicImage,
texture_width: u16,
texture_height: u16,
texture_x: u16,
texture_y: u16,
texture: &image::DynamicImage,
) {
if core::intrinsics::unlikely(texture.width() == 0 || texture.height() == 0)
{
return;
}
let scaling_x = (texture_width as f32) / (texture.width() as f32);
let scaling_y = (texture_height as f32) / (texture.height() as f32);
for x in texture_x..texture_x + texture_width {
let texture_uv_x = ((x - texture_x) as f32 / scaling_x) as u32;
for y in texture_y..texture_y + texture_height {
let texture_uv_y = ((y - texture_y) as f32 / scaling_y) as u32;
if texture_uv_x < texture.width() && texture_uv_y < texture.height()
{
let pixel = texture.get_pixel(texture_uv_x, texture_uv_y);
image.put_pixel(x as u32, y as u32, pixel);
}
}
}
}
#[must_use]
#[allow(clippy::cast_precision_loss)]
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_sign_loss)]
pub fn set_image_size(
image: &image::DynamicImage,
width: u32,
height: u32,
) -> image::DynamicImage {
let mut img = create_empty_image(width, height);
draw_texture_into_image(
&mut img,
image.width() as u16,
image.height() as u16,
0,
0,
image,
);
img
}
#[must_use]
#[allow(clippy::unwrap_used, clippy::missing_panics_doc)]
#[cfg(feature = "svg")]
pub fn pixmap_to_dynamic_image(
ras: &resvg::tiny_skia::Pixmap,
) -> Option<image::DynamicImage> {
let mut img = image::DynamicImage::new(
ras.width(),
ras.height(),
image::ColorType::Rgba8,
);
for x in 0..ras.width() {
for y in 0..ras.height() {
use crate::extensions::*;
let color = unsafe { ras.pixel(x, y).unwrap_unchecked() }; let (r, g, b) = crate::graphics::shift_hue_rgb(
color.red(),
color.green(),
color.blue(),
50.0,
)
.try_tuple_into()?;
let pixel = image::Rgba([r, g, b, color.alpha()]);
img.put_pixel(x, y, pixel);
}
}
Some(img)
}
#[allow(clippy::cast_precision_loss)]
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_sign_loss)]
#[must_use]
pub fn dynamic_image_to_buffer(image: &image::DynamicImage) -> Buffer {
let width = image.width() as usize;
let height = image.height() as usize;
let mut img = Buffer::new_empty((width, height));
for y in 0..height {
for x in 0..width {
let color = image.get_pixel(x as u32, y as u32);
img.data[y * img.width + x] = image_rgba_to_u32(color);
}
}
img
}
#[must_use]
#[allow(clippy::cast_precision_loss)]
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_sign_loss)]
pub fn buffer_to_dynamic_image(buffer: &Buffer) -> image::DynamicImage {
let mut img = create_empty_image(buffer.width as u32, buffer.height as u32);
for y in 0..buffer.height {
for x in 0..buffer.width {
let color = buffer.data[y * buffer.width + x];
img.put_pixel(x as u32, y as u32, u32_to_image_rgba(color));
}
}
img
}
impl From<Buffer> for image::DynamicImage {
fn from(bush: Buffer) -> Self {
buffer_to_dynamic_image(&bush)
}
}
impl From<image::DynamicImage> for Buffer {
fn from(bush: image::DynamicImage) -> Self {
dynamic_image_to_buffer(&bush)
}
}
use crate::graphics::pixel::Pixel;
impl From<Pixel> for image::Rgba<u8> {
fn from(p: Pixel) -> Self {
rgb_to_image_rgba(p.r, p.g, p.b)
}
}