#[derive(Debug, Clone)] pub struct ImageInfo { pub r#type: u32, pub subtype: u32, pub width: u32, pub height: u32, pub xhot: u32, pub yhot: u32, pub delay: u32, pub data: Vec, } pub struct XCursorEncoder { pub images: Vec, } const MAGIC: [u8; 4] = [0x58, 0x63, 0x75, 0x72]; const IMAGE_HEADER: [u8; 4] = [0x02, 0x00, 0xfd, 0xff]; impl XCursorEncoder { pub fn new(images: Vec) -> Self { XCursorEncoder { images } } fn image_pos(&self, position: usize) -> usize { let mut val = 12 * self.images.len() + 16; for n in 0..position { val += 36 + ((self.images[n].width as usize) * (self.images[n].height as usize) * 4) } val } pub fn pack(&mut self) -> Vec { fn insert_bytes(data: &mut Vec, new_data: impl IntoIterator) { for int in new_data { data.push(int); } } fn insert_int(data: &mut Vec, int: u32) { data.push((int & 0xff) as u8); data.push(((int >> 8) & 0xff) as u8); data.push(((int >> 16) & 0xff) as u8); data.push(((int >> 24) & 0xff) as u8); } let mut data: Vec = Vec::new(); // File Header { // MAGIC string ("Xcur") insert_bytes(&mut data, MAGIC); // CARD32 bytes in this header insert_int(&mut data, 16); // CARD32 file version insert_int(&mut data, 1); // CARD32 number of toc entries insert_int(&mut data, self.images.len().try_into().unwrap()); } // ntoc entries { let mut img_idx: usize = 0; for img in self.images.clone().into_iter() { // Some header insert_bytes(&mut data, IMAGE_HEADER); // CARD32 type-specific label - size for images insert_int(&mut data, img.r#type); // CARD32 absolute byte position of table in file insert_int(&mut data, self.image_pos(img_idx).try_into().unwrap()); img_idx += 1; } } // images { for img in self.images.clone().into_iter() { // Header Size (36) insert_int(&mut data, 36); // Image Type insert_bytes(&mut data, IMAGE_HEADER); // Subtype, for nominal size insert_int(&mut data, img.subtype); // Version insert_int(&mut data, 1); // Image dimensions insert_int(&mut data, img.width); insert_int(&mut data, img.height); // Cursor positioning insert_int(&mut data, img.xhot); insert_int(&mut data, img.yhot); // Milliseconds till next frame insert_int(&mut data, img.delay); // Raw image data insert_bytes(&mut data, img.data); } } data } }