This commit is contained in:
Michael Zhang 2020-06-29 14:22:39 -05:00
parent 5cf99dda34
commit 1b17246d8d
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
2 changed files with 42 additions and 50 deletions

View file

@ -1,22 +1,19 @@
//! XImage
//! ======
//!
//! Xlib provides some structures to perform operations on images. However, because there are
//! different in-memory representations, working with images is actually totally fucked. If you
//! want to maintain your sanity, do NOT pry into the raw data buffer of an Image. Instead, index
//! into the image using `PixBuffer::get_pixel` which already performs the conversion and returns a
//! tuple of RGB values.
//!
//! Peeking into the raw data buffer of an Image
//! --------------------------------------------
//!
//! Images consist of lines of longs in row-major form.
use x11::xlib; use x11::xlib;
use crate::errors::{Error, Result}; use crate::errors::{Error, Result};
/// A handle to an XImage. /// A handle to an XImage
///
/// Xlib provides some structures to perform operations on images. However, because there are
/// different in-memory representations, working with images is actually totally fucked. If you
/// want to maintain your sanity, do NOT pry into the raw data buffer of an Image. Instead, index
/// into the image using `PixBuffer::get_pixel` which already performs the conversion and returns a
/// tuple of RGB values.
///
/// Peeking into the raw data buffer of an Image
/// --------------------------------------------
///
/// Images consist of lines of longs in row-major form.
pub struct Image { pub struct Image {
pub(super) inner: *mut xlib::XImage, pub(super) inner: *mut xlib::XImage,
} }
@ -29,20 +26,6 @@ pub enum ImageByteOrder {
MSBFirst, MSBFirst,
} }
/// The buffer pointed to by an XImage.
pub struct PixBuffer<'a> {
/// The raw pointer to the buffer
pub buf: *mut u8,
/// The size of the buffer
pub size: usize,
/// Rgb masks
pub masks: (u64, u64, u64),
pub image: &'a Image,
}
impl Image { impl Image {
/// Get the size (in bytes) of the data buffer. /// Get the size (in bytes) of the data buffer.
pub fn get_size(&self) -> usize { pub fn get_size(&self) -> usize {
@ -64,7 +47,7 @@ impl Image {
unsafe { (*self.inner).depth as u32 } unsafe { (*self.inner).depth as u32 }
} }
/// Get byte order /// Get byte order (LSB or MSB)
pub fn get_byte_order(&self) -> Result<ImageByteOrder> { pub fn get_byte_order(&self) -> Result<ImageByteOrder> {
let byte_order = unsafe { (*self.inner).byte_order }; let byte_order = unsafe { (*self.inner).byte_order };
match byte_order { match byte_order {
@ -81,7 +64,7 @@ impl Image {
(red_mask, blue_mask, green_mask) (red_mask, blue_mask, green_mask)
} }
/// Produces a PixBuffer /// Produces a PixBuffer.
pub fn buffer(&self) -> PixBuffer { pub fn buffer(&self) -> PixBuffer {
let size = self.get_size(); let size = self.get_size();
let buf = unsafe { (*self.inner).data as *mut u8 }; let buf = unsafe { (*self.inner).data as *mut u8 };
@ -101,34 +84,43 @@ impl Drop for Image {
} }
} }
/// The buffer pointed to by an XImage.
pub struct PixBuffer<'a> {
/// The raw pointer to the buffer
pub buf: *mut u8,
/// The size of the buffer
pub size: usize,
/// Rgb masks
pub masks: (u64, u64, u64),
pub image: &'a Image,
}
impl<'a> PixBuffer<'a> { impl<'a> PixBuffer<'a> {
/// Gets the byte at the index of the data buffer. /// Retrieve a direct reference to the internal buffer.
pub fn get_byte(&self, index: usize) -> Option<u8> { pub fn get_buffer(&self) -> &[u8] {
if index > self.size { unsafe { std::slice::from_raw_parts(self.buf, self.size) }
return None;
}
Some(unsafe { *self.buf.offset(index as isize) as u8 })
} }
/// Gets the rgb value of a particular pixel /// Gets the rgb value of a particular pixel, after performing conversion
///
/// This uses XImage's get_pixel function to retrieve the pixel value, and then the various
/// red/green/blue masks to actually perform the conversions, and fails (returns `None`) if the
/// (x, y) coordinates given aren't actually in the image.
pub fn get_pixel(&self, x: u32, y: u32) -> Option<(u8, u8, u8)> { pub fn get_pixel(&self, x: u32, y: u32) -> Option<(u8, u8, u8)> {
// let bytes_per_line = unsafe{(*self.image.inner).bytes_per_line} as u32;
// let bits_per_pixel=unsafe{(*self.image.inner).bits_per_pixel} as u32;
// let pixel_ptr = (y * bytes_per_line + x * bits_per_pixel) / 8;
// let pixel = unsafe{*((*self.image.inner).data.offset(pixel_ptr as isize) as *mut c_ulong)};
let get_pixel = unsafe { (*self.image.inner).funcs.get_pixel }.unwrap(); let get_pixel = unsafe { (*self.image.inner).funcs.get_pixel }.unwrap();
let pixel = unsafe { get_pixel(self.image.inner, x as i32, y as i32) }; let pixel = unsafe { get_pixel(self.image.inner, x as i32, y as i32) };
// warn!("pixel: {:?} {:#b}", pixel, pixel);
let red_mask = unsafe { (*self.image.inner).red_mask }; let red_mask = unsafe { (*self.image.inner).red_mask };
let green_mask = unsafe { (*self.image.inner).green_mask }; let green_mask = unsafe { (*self.image.inner).green_mask };
let blue_mask = unsafe { (*self.image.inner).blue_mask }; let blue_mask = unsafe { (*self.image.inner).blue_mask };
// warn!("masks: {:b} {:b} {:b}", red_mask, green_mask, blue_mask);
let red = ((pixel & unsafe { (*self.image.inner).red_mask }) >> 16) as u8; let red = ((pixel & red_mask) >> 16) as u8;
let green = ((pixel & unsafe { (*self.image.inner).green_mask }) >> 8) as u8; let green = ((pixel & green_mask) >> 8) as u8;
let blue = ((pixel & unsafe { (*self.image.inner).blue_mask }) >> 0) as u8; let blue = ((pixel & blue_mask) >> 0) as u8;
// warn!("rgb: {:?}", (red, green, blue));
Some((red, green, blue)) Some((red, green, blue))
} }
} }

View file

@ -12,6 +12,6 @@ pub use self::cursor::Cursor;
pub use self::display::{Display, GetDisplay}; pub use self::display::{Display, GetDisplay};
pub use self::drawable::Drawable; pub use self::drawable::Drawable;
pub use self::event::{Event, EventKind}; pub use self::event::{Event, EventKind};
pub use self::image::{Image, ImageByteOrder}; pub use self::image::{Image, ImageByteOrder, PixBuffer};
pub use self::visual::Visual; pub use self::visual::Visual;
pub use self::window::{EventMask, Window}; pub use self::window::{EventMask, Window};