use crate::enums::ColorDepth;
use crate::prelude::*;
use crate::utils::FlString;
use fltk_sys::image::*;
use std::{ffi::CString, mem, sync::Arc};
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum RgbScaling {
Nearest = 0,
Bilinear,
}
#[derive(Debug)]
pub struct Image {
inner: Arc<*mut Fl_Image>,
}
crate::macros::image::impl_image_ext!(Image, Fl_Image);
impl Image {
pub fn set_scaling_algorithm(algorithm: RgbScaling) {
unsafe { Fl_Image_set_scaling_algorithm(algorithm as i32) }
}
pub fn scaling_algorithm() -> RgbScaling {
unsafe { mem::transmute(Fl_Image_scaling_algorithm()) }
}
}
#[derive(Debug)]
pub struct SharedImage {
inner: Arc<*mut Fl_Shared_Image>,
}
crate::macros::image::impl_image_ext!(SharedImage, Fl_Shared_Image);
impl SharedImage {
pub fn load<P: AsRef<std::path::Path>>(path: P) -> Result<SharedImage, FltkError> {
Self::load_(path.as_ref())
}
fn load_(path: &std::path::Path) -> Result<SharedImage, FltkError> {
if !path.exists() {
return Err(FltkError::Internal(FltkErrorKind::ResourceNotFound));
}
unsafe {
let temp = path.to_str().ok_or_else(|| {
FltkError::Unknown(String::from("Failed to convert path to string"))
})?;
let temp = CString::new(temp)?;
let x = Fl_Shared_Image_get(temp.as_ptr(), 0, 0);
if x.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_Shared_Image_fail(x) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(SharedImage {
inner: Arc::from(x),
})
}
}
}
pub fn from_image<I: ImageExt>(image: I) -> Result<SharedImage, FltkError> {
unsafe {
assert!(!image.was_deleted());
let x = Fl_Shared_Image_from_rgb(image.as_image_ptr() as *mut Fl_RGB_Image, 1);
if x.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_Shared_Image_fail(x) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(SharedImage {
inner: Arc::from(x),
})
}
}
}
}
#[derive(Debug)]
pub struct JpegImage {
inner: Arc<*mut Fl_JPEG_Image>,
}
crate::macros::image::impl_image_ext!(JpegImage, Fl_JPEG_Image);
impl JpegImage {
pub fn load<P: AsRef<std::path::Path>>(path: P) -> Result<JpegImage, FltkError> {
Self::load_(path.as_ref())
}
fn load_(path: &std::path::Path) -> Result<JpegImage, FltkError> {
if !path.exists() {
return Err(FltkError::Internal(FltkErrorKind::ResourceNotFound));
}
unsafe {
let temp = path.to_str().ok_or_else(|| {
FltkError::Unknown(String::from("Failed to convert path to string"))
})?;
let temp = CString::new(temp)?;
let image_ptr = Fl_JPEG_Image_new(temp.as_ptr());
if image_ptr.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_JPEG_Image_fail(image_ptr) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(JpegImage {
inner: Arc::from(image_ptr),
})
}
}
}
pub fn from_data(data: &[u8]) -> Result<JpegImage, FltkError> {
unsafe {
if data.is_empty() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
let x = Fl_JPEG_Image_from(data.as_ptr());
if x.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_JPEG_Image_fail(x) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(JpegImage {
inner: Arc::from(x),
})
}
}
}
}
}
#[derive(Debug)]
pub struct PngImage {
inner: Arc<*mut Fl_PNG_Image>,
}
crate::macros::image::impl_image_ext!(PngImage, Fl_PNG_Image);
impl PngImage {
pub fn load<P: AsRef<std::path::Path>>(path: P) -> Result<PngImage, FltkError> {
Self::load_(path.as_ref())
}
fn load_(path: &std::path::Path) -> Result<PngImage, FltkError> {
if !path.exists() {
return Err(FltkError::Internal(FltkErrorKind::ResourceNotFound));
}
unsafe {
let temp = path.to_str().ok_or_else(|| {
FltkError::Unknown(String::from("Failed to convert path to string"))
})?;
let temp = CString::new(temp)?;
let image_ptr = Fl_PNG_Image_new(temp.as_ptr());
if image_ptr.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_PNG_Image_fail(image_ptr) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(PngImage {
inner: Arc::from(image_ptr),
})
}
}
}
pub fn from_data(data: &[u8]) -> Result<PngImage, FltkError> {
unsafe {
if data.is_empty() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
let x = Fl_PNG_Image_from(data.as_ptr(), data.len() as i32);
if x.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_PNG_Image_fail(x) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(PngImage {
inner: Arc::from(x),
})
}
}
}
}
}
#[derive(Debug)]
pub struct SvgImage {
inner: Arc<*mut Fl_SVG_Image>,
}
crate::macros::image::impl_image_ext!(SvgImage, Fl_SVG_Image);
impl SvgImage {
pub fn load<P: AsRef<std::path::Path>>(path: P) -> Result<SvgImage, FltkError> {
Self::load_(path.as_ref())
}
fn load_(path: &std::path::Path) -> Result<SvgImage, FltkError> {
if !path.exists() {
return Err(FltkError::Internal(FltkErrorKind::ResourceNotFound));
}
unsafe {
let temp = path.to_str().ok_or_else(|| {
FltkError::Unknown(String::from("Failed to convert path to string"))
})?;
let temp = CString::new(temp)?;
let image_ptr = Fl_SVG_Image_new(temp.as_ptr());
if image_ptr.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_SVG_Image_fail(image_ptr) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(SvgImage {
inner: Arc::from(image_ptr),
})
}
}
}
pub fn from_data(data: &str) -> Result<SvgImage, FltkError> {
if data.is_empty() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
let data = CString::safe_new(data);
unsafe {
let x = Fl_SVG_Image_from(data.as_ptr());
if x.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_SVG_Image_fail(x) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(SvgImage {
inner: Arc::from(x),
})
}
}
}
}
pub fn normalize(&mut self) {
assert!(!self.was_deleted());
unsafe { Fl_SVG_Image_normalize(*self.inner) }
}
}
#[derive(Debug)]
pub struct BmpImage {
inner: Arc<*mut Fl_BMP_Image>,
}
crate::macros::image::impl_image_ext!(BmpImage, Fl_BMP_Image);
impl BmpImage {
pub fn load<P: AsRef<std::path::Path>>(path: P) -> Result<BmpImage, FltkError> {
Self::load_(path.as_ref())
}
fn load_(path: &std::path::Path) -> Result<BmpImage, FltkError> {
if !path.exists() {
return Err(FltkError::Internal(FltkErrorKind::ResourceNotFound));
}
unsafe {
let temp = path.to_str().ok_or_else(|| {
FltkError::Unknown(String::from("Failed to convert path to string"))
})?;
let temp = CString::new(temp)?;
let image_ptr = Fl_BMP_Image_new(temp.as_ptr());
if image_ptr.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_BMP_Image_fail(image_ptr) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(BmpImage {
inner: Arc::from(image_ptr),
})
}
}
}
pub fn from_data(data: &[u8]) -> Result<BmpImage, FltkError> {
unsafe {
if data.is_empty() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
let x = Fl_BMP_Image_from(data.as_ptr(), data.len() as _);
if x.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_BMP_Image_fail(x) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(BmpImage {
inner: Arc::from(x),
})
}
}
}
}
}
#[derive(Debug)]
pub struct GifImage {
inner: Arc<*mut Fl_GIF_Image>,
}
crate::macros::image::impl_image_ext!(GifImage, Fl_GIF_Image);
impl GifImage {
pub fn load<P: AsRef<std::path::Path>>(path: P) -> Result<GifImage, FltkError> {
Self::load_(path.as_ref())
}
fn load_(path: &std::path::Path) -> Result<GifImage, FltkError> {
if !path.exists() {
return Err(FltkError::Internal(FltkErrorKind::ResourceNotFound));
}
unsafe {
let temp = path.to_str().ok_or_else(|| {
FltkError::Unknown(String::from("Failed to convert path to string"))
})?;
let temp = CString::new(temp)?;
let image_ptr = Fl_GIF_Image_new(temp.as_ptr());
if image_ptr.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_GIF_Image_fail(image_ptr) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(GifImage {
inner: Arc::from(image_ptr),
})
}
}
}
pub fn from_data(data: &[u8]) -> Result<GifImage, FltkError> {
unsafe {
if data.is_empty() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
let x = Fl_GIF_Image_from(data.as_ptr(), data.len() as _);
if x.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_GIF_Image_fail(x) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(GifImage {
inner: Arc::from(x),
})
}
}
}
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AnimGifImageFlags: u16 {
const None = 0;
const DONT_START = 1;
const DONT_RESIZE_CANVAS = 2;
const DONT_SET_AS_IMAGE = 4;
const OPTIMIZE_MEMORY = 8;
const LOG_FLAG = 64;
const DEBUG_FLAG = 128;
}
}
#[derive(Debug)]
pub struct AnimGifImage {
inner: Arc<*mut Fl_Anim_GIF_Image>,
}
crate::macros::image::impl_image_ext!(AnimGifImage, Fl_Anim_GIF_Image);
impl AnimGifImage {
pub fn load<P: AsRef<std::path::Path>, W: WidgetExt>(
path: P,
w: &mut W,
flags: AnimGifImageFlags,
) -> Result<AnimGifImage, FltkError> {
Self::load_(path.as_ref(), w, flags)
}
fn load_<W: WidgetExt>(
path: &std::path::Path,
w: &mut W,
flags: AnimGifImageFlags,
) -> Result<AnimGifImage, FltkError> {
if !path.exists() {
return Err(FltkError::Internal(FltkErrorKind::ResourceNotFound));
}
unsafe {
let temp = path.to_str().ok_or_else(|| {
FltkError::Unknown(String::from("Failed to convert path to string"))
})?;
let temp = CString::new(temp)?;
let image_ptr =
Fl_Anim_GIF_Image_new(temp.as_ptr(), w.as_widget_ptr() as _, flags.bits());
if image_ptr.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_Anim_GIF_Image_fail(image_ptr) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(AnimGifImage {
inner: Arc::from(image_ptr),
})
}
}
}
pub fn from_data<W: WidgetExt>(
data: &[u8],
w: &mut W,
flags: AnimGifImageFlags,
) -> Result<AnimGifImage, FltkError> {
unsafe {
if data.is_empty() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
let x = Fl_Anim_GIF_Image_from(
std::ptr::null(),
data.as_ptr(),
data.len() as _,
w.as_widget_ptr() as _,
flags.bits(),
);
if x.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_Anim_GIF_Image_fail(x) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(AnimGifImage {
inner: Arc::from(x),
})
}
}
}
}
pub fn delay(&self, frame: i32) -> f64 {
unsafe { Fl_Anim_GIF_Image_delay(*self.inner, frame) }
}
pub fn set_delay(&mut self, frame: i32, delay: f64) {
unsafe { Fl_Anim_GIF_Image_set_delay(*self.inner, frame, delay) }
}
pub fn is_animated(&self) -> bool {
unsafe { Fl_Anim_GIF_Image_is_animated(*self.inner) != 0 }
}
pub fn set_speed(&mut self, speed: f64) {
unsafe { Fl_Anim_GIF_Image_set_speed(*self.inner, speed) }
}
pub fn speed(&mut self) -> f64 {
unsafe { Fl_Anim_GIF_Image_speed(*self.inner) }
}
pub fn start(&mut self) -> bool {
unsafe { Fl_Anim_GIF_Image_start(*self.inner) != 0 }
}
pub fn stop(&mut self) -> bool {
unsafe { Fl_Anim_GIF_Image_stop(*self.inner) != 0 }
}
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Result<(), FltkError> {
unsafe {
if Fl_Anim_GIF_Image_next(*self.inner) != 0 {
Ok(())
} else {
Err(FltkError::Internal(FltkErrorKind::FailedOperation))
}
}
}
pub fn playing(&self) -> bool {
unsafe { Fl_Anim_GIF_Image_playing(*self.inner) != 0 }
}
}
#[derive(Debug)]
pub struct XpmImage {
inner: Arc<*mut Fl_XPM_Image>,
}
crate::macros::image::impl_image_ext!(XpmImage, Fl_XPM_Image);
impl XpmImage {
pub fn load<P: AsRef<std::path::Path>>(path: P) -> Result<XpmImage, FltkError> {
Self::load_(path.as_ref())
}
fn load_(path: &std::path::Path) -> Result<XpmImage, FltkError> {
if !path.exists() {
return Err(FltkError::Internal(FltkErrorKind::ResourceNotFound));
}
unsafe {
let temp = path.to_str().ok_or_else(|| {
FltkError::Unknown(String::from("Failed to convert path to string"))
})?;
let temp = CString::new(temp)?;
let image_ptr = Fl_XPM_Image_new(temp.as_ptr());
if image_ptr.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_XPM_Image_fail(image_ptr) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(XpmImage {
inner: Arc::from(image_ptr),
})
}
}
}
}
#[derive(Debug)]
pub struct XbmImage {
inner: Arc<*mut Fl_XBM_Image>,
}
crate::macros::image::impl_image_ext!(XbmImage, Fl_XBM_Image);
impl XbmImage {
pub fn load<P: AsRef<std::path::Path>>(path: P) -> Result<XbmImage, FltkError> {
Self::load_(path.as_ref())
}
fn load_(path: &std::path::Path) -> Result<XbmImage, FltkError> {
if !path.exists() {
return Err(FltkError::Internal(FltkErrorKind::ResourceNotFound));
}
unsafe {
let temp = path.to_str().ok_or_else(|| {
FltkError::Unknown(String::from("Failed to convert path to string"))
})?;
let temp = CString::new(temp)?;
let image_ptr = Fl_XBM_Image_new(temp.as_ptr());
if image_ptr.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_XBM_Image_fail(image_ptr) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(XbmImage {
inner: Arc::from(image_ptr),
})
}
}
}
}
#[derive(Debug)]
pub struct PnmImage {
inner: Arc<*mut Fl_PNM_Image>,
}
crate::macros::image::impl_image_ext!(PnmImage, Fl_PNM_Image);
impl PnmImage {
pub fn load<P: AsRef<std::path::Path>>(path: P) -> Result<PnmImage, FltkError> {
Self::load_(path.as_ref())
}
fn load_(path: &std::path::Path) -> Result<PnmImage, FltkError> {
if !path.exists() {
return Err(FltkError::Internal(FltkErrorKind::ResourceNotFound));
}
unsafe {
let temp = path.to_str().ok_or_else(|| {
FltkError::Unknown(String::from("Failed to convert path to string"))
})?;
let temp = CString::new(temp)?;
let image_ptr = Fl_PNM_Image_new(temp.as_ptr());
if image_ptr.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_PNM_Image_fail(image_ptr) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(PnmImage {
inner: Arc::from(image_ptr),
})
}
}
}
}
#[derive(Debug)]
pub struct TiledImage {
inner: Arc<*mut Fl_Tiled_Image>,
}
crate::macros::image::impl_image_ext!(TiledImage, Fl_Tiled_Image);
impl TiledImage {
pub fn new<Img: ImageExt>(img: Img, w: i32, h: i32) -> TiledImage {
unsafe {
assert!(!img.was_deleted());
let ptr = Fl_Tiled_Image_new(img.as_image_ptr(), w, h);
assert!(!ptr.is_null());
TiledImage {
inner: Arc::from(ptr),
}
}
}
}
#[derive(Debug)]
pub struct Pixmap {
inner: Arc<*mut Fl_Pixmap>,
}
crate::macros::image::impl_image_ext!(Pixmap, Fl_Pixmap);
impl Pixmap {
pub fn new(data: &[&str]) -> Result<Pixmap, FltkError> {
let mut temp_file = std::env::temp_dir();
temp_file.push("_internal_temp_fltk_file.xpm");
let mut temp = String::from("/* XPM */\nstatic char *_613589117910[] = {\n");
for elem in data {
temp.push('\"');
temp.push_str(elem);
temp.push_str("\",\n");
}
temp.push_str("};\n");
std::fs::write(&temp_file, temp)?;
unsafe {
let temp = CString::new(temp_file.to_string_lossy().as_bytes())?;
let image_ptr = Fl_XPM_Image_new(temp.as_ptr());
if image_ptr.is_null() {
std::fs::remove_file(temp_file)?;
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_XPM_Image_fail(image_ptr) < 0 {
std::fs::remove_file(temp_file)?;
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
std::fs::remove_file(temp_file)?;
Ok(Pixmap {
inner: Arc::from(image_ptr as *mut Fl_Pixmap),
})
}
}
}
}
#[derive(Debug)]
pub struct RgbImage {
pub(crate) inner: Arc<*mut Fl_RGB_Image>,
}
crate::macros::image::impl_image_ext!(RgbImage, Fl_RGB_Image);
impl RgbImage {
pub fn new(data: &[u8], w: i32, h: i32, depth: ColorDepth) -> Result<RgbImage, FltkError> {
let sz = w * h * depth as i32;
if sz > data.len() as i32 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
unsafe {
let img = Fl_RGB_Image_new(data.as_ptr(), w, h, depth as i32, 0);
if img.is_null() || Fl_RGB_Image_fail(img) < 0 {
Err(FltkError::Internal(FltkErrorKind::ImageFormatError))
} else {
Ok(RgbImage {
inner: Arc::from(img),
})
}
}
}
pub unsafe fn from_data(
data: &[u8],
w: i32,
h: i32,
depth: ColorDepth,
) -> Result<RgbImage, FltkError> {
let sz = w * h * depth as i32;
if sz > data.len() as i32 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
let img = Fl_RGB_Image_from_data(data.as_ptr(), w, h, depth as i32, 0);
if img.is_null() || Fl_RGB_Image_fail(img) < 0 {
Err(FltkError::Internal(FltkErrorKind::ImageFormatError))
} else {
Ok(RgbImage {
inner: Arc::from(img),
})
}
}
pub unsafe fn new2(
data: &[u8],
w: i32,
h: i32,
depth: i32,
line_data: i32,
) -> Result<RgbImage, FltkError> {
let img = Fl_RGB_Image_new(data.as_ptr(), w, h, depth, line_data);
if img.is_null() || Fl_RGB_Image_fail(img) < 0 {
Err(FltkError::Internal(FltkErrorKind::ImageFormatError))
} else {
Ok(RgbImage {
inner: Arc::from(img),
})
}
}
pub unsafe fn from_data2(
data: &[u8],
w: i32,
h: i32,
depth: i32,
line_data: i32,
) -> Result<RgbImage, FltkError> {
let img = Fl_RGB_Image_from_data(data.as_ptr(), w, h, depth, line_data);
if img.is_null() || Fl_RGB_Image_fail(img) < 0 {
Err(FltkError::Internal(FltkErrorKind::ImageFormatError))
} else {
Ok(RgbImage {
inner: Arc::from(img),
})
}
}
pub fn from_pixmap(image: &Pixmap) -> RgbImage {
unsafe { RgbImage::from_image_ptr(Fl_RGB_Image_from_pixmap(*image.inner as _) as _) }
}
pub unsafe fn into_parts(self) -> (Vec<u8>, i32, i32) {
let w = self.data_w();
let h = self.data_h();
(self.to_rgb_data(), w, h)
}
pub fn convert(&self, new_depth: ColorDepth) -> Result<RgbImage, FltkError> {
let depth = self.depth() as i32;
let new_depth = new_depth as i32;
if depth == new_depth {
Ok(self.copy())
} else {
let w = self.w();
let h = self.h();
let data = self.to_rgb_data();
let mut temp = Vec::new();
match depth {
1 => match new_depth {
2 => {
for i in data {
temp.push(i);
temp.push(255);
}
assert!(temp.len() as i32 == w * h * 2);
RgbImage::new(&temp, w, h, ColorDepth::La8)
}
3 => {
for i in data {
temp.push(i);
temp.push(i);
temp.push(i);
}
assert!(temp.len() as i32 == w * h * 3);
RgbImage::new(&temp, w, h, ColorDepth::Rgb8)
}
4 => {
for i in data {
temp.push(i);
temp.push(i);
temp.push(i);
temp.push(255);
}
assert!(temp.len() as i32 == w * h * 4);
RgbImage::new(&temp, w, h, ColorDepth::Rgba8)
}
_ => unreachable!(),
},
2 => match new_depth {
1 => {
for (i, item) in data.iter().enumerate() {
if i % 2 == 0 {
temp.push(*item);
} else {
}
}
assert!(temp.len() as i32 == w * h);
RgbImage::new(&temp, w, h, ColorDepth::L8)
}
3 => {
for (i, item) in data.iter().enumerate() {
if i % 2 == 0 {
temp.push(*item);
temp.push(*item);
temp.push(*item);
} else {
}
}
assert!(temp.len() as i32 == w * h * 3);
RgbImage::new(&temp, w, h, ColorDepth::Rgb8)
}
4 => {
for (i, item) in data.iter().enumerate() {
temp.push(*item);
if i % 2 == 0 {
temp.push(*item);
temp.push(*item);
}
}
assert!(temp.len() as i32 == w * h * 4);
RgbImage::new(&temp, w, h, ColorDepth::Rgba8)
}
_ => unreachable!(),
},
3 => match new_depth {
1 => {
for (_, pixel) in data.chunks_exact(3).enumerate() {
temp.push(
(pixel[0] as f32 * 0.299
+ pixel[1] as f32 * 0.587
+ pixel[2] as f32 * 0.114)
as u8,
);
}
assert!(temp.len() as i32 == w * h);
RgbImage::new(&temp, w, h, ColorDepth::L8)
}
2 => {
for (_, pixel) in data.chunks_exact(3).enumerate() {
temp.push(
(pixel[0] as f32 * 0.299
+ pixel[1] as f32 * 0.587
+ pixel[2] as f32 * 0.114)
as u8,
);
temp.push(255);
}
assert!(temp.len() as i32 == w * h * 2);
RgbImage::new(&temp, w, h, ColorDepth::La8)
}
4 => {
for (_, pixel) in data.chunks_exact(3).enumerate() {
temp.push(pixel[0]);
temp.push(pixel[1]);
temp.push(pixel[2]);
temp.push(255);
}
assert!(temp.len() as i32 == w * h * 4);
RgbImage::new(&temp, w, h, ColorDepth::Rgba8)
}
_ => unreachable!(),
},
4 => match new_depth {
1 => {
for (_, pixel) in data.chunks_exact(4).enumerate() {
temp.push(
(pixel[0] as f32 * 0.299
+ pixel[1] as f32 * 0.587
+ pixel[2] as f32 * 0.114)
as u8,
);
}
assert!(temp.len() as i32 == w * h);
RgbImage::new(&temp, w, h, ColorDepth::L8)
}
2 => {
for (_, pixel) in data.chunks_exact(4).enumerate() {
temp.push(
(pixel[0] as f32 * 0.299
+ pixel[1] as f32 * 0.587
+ pixel[2] as f32 * 0.114)
as u8,
);
temp.push(pixel[3]);
}
assert!(temp.len() as i32 == w * h * 2);
RgbImage::new(&temp, w, h, ColorDepth::La8)
}
3 => {
for (_, pixel) in data.chunks_exact(4).enumerate() {
temp.push(pixel[0]);
temp.push(pixel[1]);
temp.push(pixel[2]);
}
assert!(temp.len() as i32 == w * h * 3);
RgbImage::new(&temp, w, h, ColorDepth::Rgb8)
}
_ => unreachable!(),
},
_ => unreachable!(),
}
}
}
pub fn convert_transparent(&self) -> Result<RgbImage, FltkError> {
let depth = self.depth() as i32;
if depth == 2 || depth == 4 {
Ok(self.copy())
} else {
let w = self.w();
let h = self.h();
let data = self.to_rgb_data();
let mut temp = Vec::new();
match depth {
1 => {
for i in data {
temp.push(i);
if i == 0 {
temp.push(0);
} else {
temp.push(255);
}
}
assert!(temp.len() as i32 == w * h * 2);
RgbImage::new(&temp, w, h, ColorDepth::La8)
}
3 => {
for (_, pixel) in data.chunks_exact(3).enumerate() {
let r = pixel[0];
let g = pixel[1];
let b = pixel[2];
temp.push(r);
temp.push(g);
temp.push(b);
if r == 0 && g == 0 && b == 0 {
temp.push(0);
} else {
temp.push(255);
}
}
assert!(temp.len() as i32 == w * h * 4);
RgbImage::new(&temp, w, h, ColorDepth::Rgba8)
}
_ => unreachable!(),
}
}
}
pub fn blur(&self, radius: u32) -> Result<RgbImage, FltkError> {
assert!(self.depth() == ColorDepth::Rgba8);
let radius = radius as i32;
let mut src = self.to_rgb_data().clone();
let width = self.w();
let height = self.h();
let depth = self.depth();
let mut dst = vec![0u8; (width * height * depth as i32) as usize];
let mut kernel = [0u8; 17];
let size = kernel.len() as i32;
let half = size / 2;
let src_stride = width * depth as i32;
let dst_stride = src_stride;
let mut x: u32;
let mut y: u32;
let mut z: u32;
let mut w: u32;
let mut p: u32;
let mut a: u32 = 0;
for i in 0..size {
let f = i - half;
let f = f as f32;
kernel[i as usize] = ((-f * f / 30.0).exp() * 80.0) as u8;
a += kernel[i as usize] as u32;
}
for i in 0..height {
let s: &[u32] = unsafe { src[(i * src_stride) as usize..].align_to::<u32>().1 };
let d: &mut [u32] = unsafe { dst[(i * dst_stride) as usize..].align_to_mut::<u32>().1 };
for j in 0..width {
if radius < j && j < width - radius {
let j = j as usize;
d[j] = s[j];
continue;
}
x = 0;
y = 0;
z = 0;
w = 0;
for k in 0..size {
if j - half + k < 0 || j - half + k >= width {
continue;
}
p = s[(j - half + k) as usize];
let k = k as usize;
x += ((p >> 24) & 0xff) * kernel[k] as u32;
y += ((p >> 16) & 0xff) * kernel[k] as u32;
z += ((p >> 8) & 0xff) * kernel[k] as u32;
w += (p & 0xff) * kernel[k] as u32;
}
d[j as usize] = (x / a) << 24 | (y / a) << 16 | (z / a) << 8 | (w / a);
}
}
for i in 0..height {
let mut s: &mut [u32] =
unsafe { dst[(i * dst_stride) as usize..].align_to_mut::<u32>().1 };
let d: &mut [u32] = unsafe { src[(i * src_stride) as usize..].align_to_mut::<u32>().1 };
for j in 0..width {
if radius < i && i < height - radius {
let j = j as usize;
d[j] = s[j];
continue;
}
x = 0;
y = 0;
z = 0;
w = 0;
for k in 0..size {
if i - half + k < 0 || i - half + k >= height {
continue;
}
s = unsafe {
dst[((i - half + k) * dst_stride) as usize..]
.align_to_mut::<u32>()
.1
};
p = s[j as usize];
let k = k as usize;
x += ((p >> 24) & 0xff) * kernel[k] as u32;
y += ((p >> 16) & 0xff) * kernel[k] as u32;
z += ((p >> 8) & 0xff) * kernel[k] as u32;
w += (p & 0xff) * kernel[k] as u32;
}
d[j as usize] = (x / a) << 24 | (y / a) << 16 | (z / a) << 8 | (w / a);
}
}
RgbImage::new(&dst, width, height, depth)
}
pub fn to_srgb_image(&self) -> Result<RgbImage, FltkError> {
assert!(self.depth() as i32 >= 3);
let depth = self.depth() as i32;
let w = self.w();
let h = self.h();
fn correct_gamma(v: f32) -> f32 {
if v <= 0.0031308 {
v * 12.92
} else {
1.055 * v.powf(1.0 / 2.4) - 0.055
}
}
let mut temp = vec![];
let data = self.to_rgb_data();
match depth {
3 => {
for (_, pixel) in data.chunks_exact(3).enumerate() {
let r = (correct_gamma(pixel[0] as f32 / 255.0) * 255.0) as u8;
let g = (correct_gamma(pixel[1] as f32 / 255.0) * 255.0) as u8;
let b = (correct_gamma(pixel[2] as f32 / 255.0) * 255.0) as u8;
temp.push(r);
temp.push(g);
temp.push(b);
}
assert!(temp.len() as i32 == w * h * 3);
RgbImage::new(&temp, w, h, ColorDepth::Rgb8)
}
4 => {
for (_, pixel) in data.chunks_exact(4).enumerate() {
let r = (correct_gamma(pixel[0] as f32 / 255.0) * 255.0) as u8;
let g = (correct_gamma(pixel[1] as f32 / 255.0) * 255.0) as u8;
let b = (correct_gamma(pixel[2] as f32 / 255.0) * 255.0) as u8;
temp.push(r);
temp.push(g);
temp.push(b);
temp.push(pixel[3]);
}
assert!(temp.len() as i32 == w * h * 4);
RgbImage::new(&temp, w, h, ColorDepth::Rgba8)
}
_ => unreachable!(),
}
}
pub fn set_scaling_algorithm(algorithm: RgbScaling) {
unsafe { Fl_RGB_Image_set_scaling_algorithm(algorithm as i32) }
}
pub fn scaling_algorithm() -> RgbScaling {
unsafe { mem::transmute(Fl_RGB_Image_scaling_algorithm()) }
}
}
#[derive(Debug)]
pub struct IcoImage {
inner: Arc<*mut Fl_ICO_Image>,
}
crate::macros::image::impl_image_ext!(IcoImage, Fl_ICO_Image);
impl IcoImage {
pub fn load<P: AsRef<std::path::Path>>(path: P) -> Result<IcoImage, FltkError> {
Self::load_(path.as_ref())
}
fn load_(path: &std::path::Path) -> Result<IcoImage, FltkError> {
if !path.exists() {
return Err(FltkError::Internal(FltkErrorKind::ResourceNotFound));
}
unsafe {
let temp = path.to_str().ok_or_else(|| {
FltkError::Unknown(String::from("Failed to convert path to string"))
})?;
let temp = CString::new(temp)?;
let image_ptr = Fl_ICO_Image_new(temp.as_ptr(), -1);
if image_ptr.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_ICO_Image_fail(image_ptr) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(IcoImage {
inner: Arc::from(image_ptr),
})
}
}
}
pub fn from_data(data: &[u8]) -> Result<IcoImage, FltkError> {
unsafe {
if data.is_empty() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
let x = Fl_ICO_Image_from_data(data.as_ptr(), data.len() as _, -1);
if x.is_null() {
Err(FltkError::Internal(FltkErrorKind::ResourceNotFound))
} else {
if Fl_ICO_Image_fail(x) < 0 {
return Err(FltkError::Internal(FltkErrorKind::ImageFormatError));
}
Ok(IcoImage {
inner: Arc::from(x),
})
}
}
}
}
pub fn icon_dir_entry(&self) -> Vec<IconDirEntry> {
unsafe {
let mut size = 0;
let ret = Fl_ICO_Image_icondirentry(*self.inner, &mut size) as *mut IconDirEntry;
std::slice::from_raw_parts(ret, size as _).to_owned()
}
}
}
use std::os::raw::c_int;
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct IconDirEntry {
b_width: c_int,
b_height: c_int,
b_color_count: c_int,
b_reserve: c_int,
w_planes: c_int,
w_bit_count: c_int,
dw_bytes_in_res: c_int,
dw_image_offset: c_int,
}