### NativeImage::as_png Source: https://docs.rs/pigment64/latest/pigment64/image/native_image/struct.NativeImage.html?search=std%3A%3Avec Decodes the image into RGBA8 and writes it as PNG to the given writer. Exception is CI4 and CI8, which get written as an indexed PNG. ```APIDOC ## NativeImage::as_png ### Description Decodes the image into RGBA8 and writes it as PNG to the given writer. Exception is CI4 and CI8, which get written as an indexed PNG. ### Method `pub fn as_png(&self, writer: &mut W, tlut_color_table: Option<&[u8]>) -> Result<(), Error>` ### Parameters - `writer` (&mut W) - Required - The writer to which the PNG data is written. - `tlut_color_table` (Option<&[u8]>) - Optional - An optional color lookup table for decoding. ### Returns - `Result<(), Error>` - Ok if successful, or an error. ``` -------------------------------- ### Return Ok Source: https://docs.rs/pigment64/latest/src/pigment64/image/png_image.rs.html?search=std%3A%3Avec Returns Ok for successful conversion. ```rust Ok(()) } ``` -------------------------------- ### get_tlut_color_at_index: Read RGBA color from buffer Source: https://docs.rs/pigment64/latest/src/pigment64/image/native_image.rs.html?search= Reads an RGBA color from a buffer starting at the given index. The index is multiplied by 4 to get the byte offset. Returns Error::TlutIndexOutOfBounds if the end of the color exceeds the buffer length. ```rust /// Reads an rgba color from a buffer starting at the given offset fn get_tlut_color_at_index(tlut_color_table: &[u8], index: u8) -> Result<[u8; 4], Error> { let start = (index * 4) as usize; let end = start + 4; if end > tlut_color_table.len() { return Err(Error::TlutIndexOutOfBounds); } let r = tlut_color_table[start]; let g = tlut_color_table[start + 1]; let b = tlut_color_table[start + 2]; let a = tlut_color_table[start + 3]; Ok([r, g, b, a]) } ``` -------------------------------- ### pub fn as_png(&self, writer: &mut W, tlut_color_table: Option<&[u8]>) -> Result<(), Error> Source: https://docs.rs/pigment64/latest/pigment64/image/native_image/struct.NativeImage.html Decodes the image and writes it as a PNG to the given writer, handling palette-based formats appropriately. ```APIDOC ## pub fn as_png(&self, writer: &mut W, tlut_color_table: Option<&[u8]>) -> Result<(), Error> ### Description Decodes the image into RGBA8 and writes it as PNG to the given writer. For CI4 and CI8 formats, it is written as an indexed PNG. ### Method Rust function ### Parameters - **writer**: `&mut W` - Required - The writer to write the PNG data to. - **tlut_color_table**: `Option<&[u8]>` - Optional - A color lookup table for palette-based formats. ### Returns `Result<(), Error>` - `Ok(())` on success or an error. ``` -------------------------------- ### pub fn decode(&self, writer: &mut W, tlut_color_table: Option<&[u8]>) -> Result<(), Error> Source: https://docs.rs/pigment64/latest/pigment64/image/native_image/struct.NativeImage.html Decodes the image into RGBA8 format and writes it to the given writer. ```APIDOC ## pub fn decode(&self, writer: &mut W, tlut_color_table: Option<&[u8]>) -> Result<(), Error> ### Description Decodes the image into RGBA8 format and writes the image bytes to the given writer. ### Method Rust function ### Parameters - **writer**: `&mut W` - Required - The writer to write the decoded RGBA8 bytes to. - **tlut_color_table**: `Option<&[u8]>` - Optional - A color lookup table for palette-based formats. ### Returns `Result<(), Error>` - `Ok(())` on success or an error. ``` -------------------------------- ### pigment64 lib.rs module root with Error, ImageSize, ImageFormat, ImageType Source: https://docs.rs/pigment64/latest/src/pigment64/lib.rs.html Rust module root for the pigment64 library. Declares public modules `color` and `image`, re-exports `NativeImage`, `PNGImage`, and `create_palette_from_png`, and defines the `Error`, `ImageSize`, `ImageFormat`, and `ImageType` enums along with their associated methods. The `ImageType::from_name` function supports parsing string names like "rgba32" or "ci8", and `get_size` returns the corresponding `ImageSize` variant. ```rust pub mod color; pub mod image; pub use crate::image::native_image::NativeImage; pub use crate::image::png_image::{PNGImage, create_palette_from_png}; use num_enum::TryFromPrimitive; use strum_macros::{EnumCount, EnumIter}; use thiserror::Error; #[derive(Debug, Error)] #[non_exhaustive] pub enum Error { #[error("Invalid image size for TLUT: {0:?}")] InvalidSizeForTlut(ImageSize), #[error("A TLUT color table is required for this image format")] MissingTlut, #[error("The specified TLUT mode is not supported: {0:?}")] UnsupportedTlutMode(TextureLUT), #[error("TLUT index is out of bounds")] TlutIndexOutOfBounds, #[error("I/O error: {0}")] Io(#[from] std::io::Error), #[error("PNG encoding error: {0}")] PngEncoding(#[from] png::EncodingError), #[error("PNG decoding error: {0}")] PngDecoding(#[from] png::DecodingError), #[error("PNG is missing a palette, which is required for this operation")] MissingPngPalette, #[error( "Unsupported PNG format for conversion to {target_format:?}: color={color:?}, depth={depth:?}" )] UnsupportedPngConversion { color: png::ColorType, depth: png::BitDepth, target_format: ImageType, }, #[error("Palette format cannot be converted to a native image format")] PaletteConversionError, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TryFromPrimitive)] #[repr(u8)] pub enum ImageSize { Bits1 = 4, Bits4 = 0, Bits8 = 1, Bits16 = 2, Bits32 = 3, DD = 5, } impl ImageSize { /// Returns the size of the TLUT (Table Look-Up Table) based on the image size. /// /// # Returns /// /// An `Option` containing the size of the TLUT as a `usize` value, or `None` /// if the image size is not valid for a TLUT. pub fn get_tlut_size(&self) -> Option { match self { ImageSize::Bits1 => Some(0b10), ImageSize::Bits4 => Some(0x10), ImageSize::Bits8 => Some(0x100), ImageSize::Bits16 => Some(0x1000), ImageSize::Bits32 => Some(0x10000), _ => None, } } /// Returns the bits per pixel. pub fn get_bpp(&self) -> u32 { match self { ImageSize::Bits1 => 1, ImageSize::Bits4 => 4, ImageSize::Bits8 => 8, ImageSize::Bits16 => 16, ImageSize::Bits32 => 32, ImageSize::DD => 0, } } } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TryFromPrimitive)] #[repr(u8)] pub enum ImageFormat { Rgba = 0, Yuv = 1, Ci = 2, Ia = 3, I = 4, } /// Represents the type of image. /// /// This enum is used to specify the type of image, which determines the size and format of the /// image data. /// Each variant corresponds to a specific image type, such as indexed color (Ci), grayscale (I), /// grayscale with alpha (Ia), or red-green-blue-alpha (RGBA). /// #[derive(Copy, Clone, Debug, PartialEq, EnumCount, EnumIter, Eq, Hash, TryFromPrimitive)] #[repr(u8)] pub enum ImageType { I1, I4, I8, Ia4, Ia8, Ia16, Ci4, Ci8, Rgba16, Rgba32, } impl ImageType { /// Creates an `ImageType` from its string name. /// /// This is useful for converting string-based input (e.g., from Python) /// into the corresponding enum variant. pub fn from_name(name: &str) -> Option { match name { "rgba32" => Some(ImageType::Rgba32), "rgba16" => Some(ImageType::Rgba16), "ia16" => Some(ImageType::Ia16), "ia8" => Some(ImageType::Ia8), "ia4" => Some(ImageType::Ia4), "i8" => Some(ImageType::I8), "i4" => Some(ImageType::I4), "i1" => Some(ImageType::I1), "ci8" => Some(ImageType::Ci8), "ci4" => Some(ImageType::Ci4), _ => None, } } /// Returns the size of the image type. /// /// This function returns the size of the image type, which represents the number of bits used /// to store each pixel. The size is determined based on the image type variant. /// /// # Returns /// /// - `ImageSize` - The size of the image type. pub fn get_size(&self) -> ImageSize { match self { ImageType::Ci4 => ImageSize::Bits4, ImageType::Ci8 => ImageSize::Bits8, ImageType::I1 => ImageSize::Bits1, ``` -------------------------------- ### Write image as PNG (Rust) Source: https://docs.rs/pigment64/latest/src/pigment64/image/native_image.rs.html?search=std%3A%3Avec Encodes the image to PNG. For CI4 and CI8, writes an indexed PNG using the provided TLUT color table; otherwise writes RGBA8. Requires a TLUT for CI4/CI8, else returns Error::MissingTlut. ```rust let mut data: Vec = vec![]; let mut encoder = png::Encoder::new(writer, self.width, self.height); match self.format { ImageType::I1 | ImageType::I4 | ImageType::I8 | ImageType::Ia4 | ImageType::Ia8 | ImageType::Ia16 => { self.decode(&mut data, None)?; } ImageType::Ci4 => { let tlut = tlut_color_table.ok_or(Error::MissingTlut)?; let mut cursor = Cursor::new(&self.data); let mut data: Vec = vec![]; for _y in 0..self.height { for _x in (0..self.width).step_by(2) { let byte = cursor.read_u8()?; data.push(byte); } } encoder.set_color(png::ColorType::Indexed); encoder.set_depth(png::BitDepth::Four); let (palette_data, trans_data) = split_color_table_for_png(tlut); encoder.set_palette(palette_data); encoder.set_trns(trans_data); let mut writer = encoder.write_header()?; writer.write_image_data(&data)?; return Ok(()); } ImageType::Ci8 => { let tlut = tlut_color_table.ok_or(Error::MissingTlut)?; let mut cursor = Cursor::new(&self.data); let mut data: Vec = vec![]; for _y in 0..self.height { for _x in 0..self.width { let index = cursor.read_u8()?; data.push(index); } } encoder.set_color(png::ColorType::Indexed); encoder.set_depth(png::BitDepth::Eight); let (palette_data, trans_data) = split_color_table_for_png(tlut); encoder.set_palette(palette_data); encoder.set_trns(trans_data); let mut writer = encoder.write_header()?; writer.write_image_data(&data)?; return Ok(()); } ImageType::Rgba16 => { self.decode(&mut data, None)?; } ImageType::Rgba32 => { self.decode(&mut data, None)?; } } encoder.set_color(png::ColorType::Rgba); encoder.set_depth(png::BitDepth::Eight); let mut writer = encoder.write_header()?; writer.write_image_data(&data)?; Ok(()) ``` -------------------------------- ### as_i8: Convert PNG to 8-bit grayscale Source: https://docs.rs/pigment64/latest/src/pigment64/image/png_image.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Converts the PNG image to 8-bit grayscale. Handles Grayscale with BitDepth::Eight (direct write), Grayscale with BitDepth::Four (expands each nibble to a byte), and RGBA/RGB with BitDepth::Eight (converts each pixel to intensity). Returns UnsupportedPngConversion error for other formats. ```rust pub fn as_i8(&self, writer: &mut W) -> Result<(), Error> { match (self.color_type, self.bit_depth) { (ColorType::Grayscale, BitDepth::Eight) => writer.write_all(&self.data)?, (ColorType::Grayscale, BitDepth::Four) => { for chunk in self.data.chunks_exact(2) { writer.write_u8(chunk[0] << 4 | chunk[1])?; } } (ColorType::Rgba, BitDepth::Eight) => { for chunk in self.data.chunks_exact(4) { let c = Color::RGBA(chunk[0], chunk[1], chunk[2], chunk[3]); writer.write_u8(c.rgb_to_intensity())?; } } (ColorType::Rgb, BitDepth::Eight) => { for chunk in self.data.chunks_exact(3) { let c = Color::RGB(chunk[0], chunk[1], chunk[2]); writer.write_u8(c.rgb_to_intensity())?; } } _ => { return Err(Error::UnsupportedPngConversion { color: self.color_type, depth: self.bit_depth, target_format: ImageType::I8, }); } } Ok(()) } ``` -------------------------------- ### PNGImage struct with read, flip, as_png, and native conversion methods Source: https://docs.rs/pigment64/latest/src/pigment64/image/png_image.rs.html?search=u32+-%3E+bool Defines the PNGImage struct and its core methods for reading, flipping, and converting PNG images. The read method decodes a PNG from a reader, flip mirrors the image horizontally/vertically, as_png encodes to PNG, and as_native dispatches to format-specific converters. Conversion methods like as_ci8 and as_ci4 enforce color type and bit depth constraints, returning Error::UnsupportedPngConversion on mismatch. ```rust use crate::color::Color; use crate::{Error, ImageType}; use byteorder::{BigEndian, WriteBytesExt}; use png::{BitDepth, ColorType}; use std::io::{Read, Write}; #[derive(Debug, Clone)] pub struct PNGImage { /// Raw image data in row-major order. data: Vec, /// The color type of the image. color_type: ColorType, /// The bit depth of each color channel. bit_depth: BitDepth, /// The width of the image in pixels. width: u32, /// The height of the image in pixels. height: u32, } #[inline] fn u8_to_u4(x: u8) -> u8 { x >> 4 } impl PNGImage { pub fn read(r: R) -> Result { let decoder = png::Decoder::new(r); let mut reader = decoder.read_info()?; let mut buf = vec![0; reader.output_buffer_size()]; let info = reader.next_frame(&mut buf)?; let input_bytes = &buf[..info.buffer_size()]; Ok(PNGImage { data: input_bytes.to_vec(), color_type: info.color_type, bit_depth: info.bit_depth, width: info.width, height: info.height, }) } pub fn width(&self) -> u32 { self.width } pub fn height(&self) -> u32 { self.height } pub fn flip(&self, flip_x: bool, flip_y: bool) -> PNGImage { let mut flipped_bytes = vec![0; self.data.len()]; let samples = self.color_type.samples(); for y in 0..self.height { for x in 0..self.width { let old_x = if flip_x { self.width - 1 - x } else { x }; let old_y = if flip_y { self.height - 1 - y } else { y }; let old_index = (old_y * self.width + old_x) as usize * samples; let new_index = (y * self.width + x) as usize * samples; flipped_bytes[new_index..new_index + samples] .copy_from_slice(&self.data[old_index..old_index + samples]); } } PNGImage { data: flipped_bytes, color_type: self.color_type, bit_depth: self.bit_depth, width: self.width, height: self.height, } } /// Writes the image as a PNG to the given writer. pub fn as_png(&self, writer: &mut W) -> Result<(), Error> { let mut encoder = png::Encoder::new(writer, self.width, self.height); encoder.set_color(self.color_type); encoder.set_depth(self.bit_depth); let mut writer = encoder.write_header()?; writer.write_image_data(&self.data)?; Ok(()) } pub fn as_native(&self, writer: &mut W, image_type: ImageType) -> Result<(), Error> { match image_type { ImageType::I1 => self.as_i1(writer), ImageType::I4 => self.as_i4(writer), ImageType::I8 => self.as_i8(writer), ImageType::Ia4 => self.as_ia4(writer), ImageType::Ia8 => self.as_ia8(writer), ImageType::Ia16 => self.as_ia16(writer), ImageType::Ci4 => self.as_ci4(writer), ImageType::Ci8 => self.as_ci8(writer), ImageType::Rgba32 => self.as_rgba32(writer), ImageType::Rgba16 => self.as_rgba16(writer), } } pub fn as_ci8(&self, writer: &mut W) -> Result<(), Error> { if self.bit_depth != BitDepth::Eight || self.color_type != ColorType::Indexed { return Err(Error::UnsupportedPngConversion { color: self.color_type, depth: self.bit_depth, target_format: ImageType::Ci8, }); } writer.write_all(&self.data)?; Ok(()) } pub fn as_ci4(&self, writer: &mut W) -> Result<(), Error> { if self.color_type != ColorType::Indexed { return Err(Error::UnsupportedPngConversion { color: self.color_type, depth: self.bit_depth, target_format: ImageType::Ci4, }); } match self.bit_depth { BitDepth::Four => writer.write_all(&self.data)?, BitDepth::Eight => { for chunk in self.data.chunks_exact(2) { writer.write_u8(chunk[0] << 4 | chunk[1])?; } } _ => { return Err(Error::UnsupportedPngConversion { color: self.color_type, depth: self.bit_depth, target_format: ImageType::Ci4, }); } } ``` -------------------------------- ### PNGImage::as_png method Source: https://docs.rs/pigment64/latest/src/pigment64/image/png_image.rs.html Encodes the image data as a PNG and writes it to the provided writer. ```rust /// Writes the image as a PNG to the given writer. pub fn as_png(&self, writer: &mut W) -> Result<(), Error> { let mut encoder = png::Encoder::new(writer, self.width, self.height); encoder.set_color(self.color_type); encoder.set_depth(self.bit_depth); let mut writer = encoder.write_header()?; writer.write_image_data(&self.data)?; Ok(()) } ``` -------------------------------- ### as_i4: Convert PNG to 4-bit grayscale Source: https://docs.rs/pigment64/latest/src/pigment64/image/png_image.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Converts the PNG image to 4-bit grayscale. Handles Grayscale with BitDepth::Four (direct write), Grayscale with BitDepth::Eight (packs two pixels per byte), and RGBA/RGB with BitDepth::Eight (converts each pixel to intensity and packs two per byte). Returns UnsupportedPngConversion error for other formats. ```rust pub fn as_i4(&self, writer: &mut W) -> Result<(), Error> { match (self.color_type, self.bit_depth) { (ColorType::Grayscale, BitDepth::Four) => writer.write_all(&self.data)?, (ColorType::Grayscale, BitDepth::Eight) => { for chunk in self.data.chunks_exact(2) { writer.write_u8(chunk[0] << 4 | u8_to_u4(chunk[1]))?; } } (ColorType::Rgba, BitDepth::Eight) => { for chunk in self.data.chunks_exact(8) { let c1 = Color::RGBA(chunk[0], chunk[1], chunk[2], chunk[3]); let i1 = c1.rgb_to_intensity(); let c2 = Color::RGBA(chunk[4], chunk[5], chunk[6], chunk[7]); let i2 = c2.rgb_to_intensity(); writer.write_u8(u8_to_u4(i1) << 4 | u8_to_u4(i2))?; } } (ColorType::Rgb, BitDepth::Eight) => { for chunk in self.data.chunks_exact(6) { let c1 = Color::RGB(chunk[0], chunk[1], chunk[2]); let i1 = c1.rgb_to_intensity(); let c2 = Color::RGB(chunk[3], chunk[4], chunk[5]); let i2 = c2.rgb_to_intensity(); writer.write_u8(u8_to_u4(i1) << 4 | u8_to_u4(i2))?; } } _ => { return Err(Error::UnsupportedPngConversion { color: self.color_type, depth: self.bit_depth, target_format: ImageType::I4, }); } } Ok(()) } ``` -------------------------------- ### RGBA Color struct with 8-bit components and 16/32-bit conversions Source: https://docs.rs/pigment64/latest/src/pigment64/color.rs.html This is the complete color.rs source. It defines the 8-bit RGBA Color struct with constants TRANSPARENT, BLACK, and WHITE. The methods cover constructors (RGBA, RGB, from_u32, from_u16) and conversions (to_u16, rgba16, rgb_to_intensity). The from_u16 method expands 5-bit channels to 8-bit; to_u16 and rgba16 convert back to 16-bit formats; rgb_to_intensity uses ITU-R BT.601 coefficients for grayscale. ```rust 1/// RGBA color type where values are 8-bit integers (0-255). 2/// 3/// This is not to be used as a generic color type, only for specific pigment interfaces. 4#[repr(C)] 5#[derive(Copy, Clone, Debug, PartialEq)] 6pub struct Color { 7 pub r: u8, 8 pub g: u8, 9 pub b: u8, 10 pub a: u8, 11} 12 13impl Color { 14 #[rustfmt::skip] 15 pub const TRANSPARENT: Color = Color { r: 0, g: 0, b: 0, a: 0 }; 16 #[rustfmt::skip] 17 pub const BLACK: Color = Color { r: 0, g: 0, b: 0, a: 255 }; 18 #[rustfmt::skip] 19 pub const WHITE: Color = Color { r: 255, g: 255, b: 255, a: 255 }; 20 21 /// Creates a new color with the given RGBA values. 22 #[inline] 23 #[allow(non_snake_case)] 24 pub const fn RGBA(r: u8, g: u8, b: u8, a: u8) -> Color { 25 Color { r, g, b, a } 26 } 27 28 /// Creates a new color with the given RGB values and an alpha value of 255. 29 #[inline] 30 #[allow(non_snake_case)] 31 pub const fn RGB(r: u8, g: u8, b: u8) -> Color { 32 Color { r, g, b, a: 0xFF } 33 } 34 35 /// Creates a new color from a 32-bit RGBA pixel. 36 #[inline] 37 pub fn from_u32(pixel: u32) -> Color { 38 let r = ((pixel >> 24) & 0xFF) as u8; 39 let g = ((pixel >> 16) & 0xFF) as u8; 40 let b = ((pixel >> 8) & 0xFF) as u8; 41 let a = (pixel & 0xFF) as u8; 42 43 Color { r, g, b, a } 44 } 45 46 /// Converts a 16-bit RGBA pixel to a 32-bit RGBA color. 47 #[inline] 48 pub fn from_u16(pixel: u16) -> Color { 49 let r = ((pixel >> 11) & 0x1F) as u8; 50 let g = ((pixel >> 6) & 0x1F) as u8; 51 let b = ((pixel >> 1) & 0x1F) as u8; 52 let a = (pixel & 0x01) as u8; 53 54 let r = (r << 3) | (r >> 2); 55 let g = (g << 3) | (g >> 2); 56 let b = (b << 3) | (b >> 2); 57 let a = 255 * a; 58 59 Color { r, g, b, a } 60 } 61 62 /// Converts a 32-bit RGBA color to a 16-bit RGBA pixel. 63 #[inline] 64 pub fn to_u16(&self) -> u16 { 65 let r = (self.r / 8) as u16; 66 let g = (self.g / 8) as u16; 67 let b = (self.b / 8) as u16; 68 let a = (self.a / 255) as u16; 69 70 (r << 11) | (g << 6) | (b << 1) | a 71 } 72 73 /// Converts a 32-bit RGBA color to a 16-bit RGBA pixel and 74 /// returns the two 8-bit components. 75 #[inline] 76 pub fn rgba16(self) -> [u8; 2] { 77 let pixel = self.to_u16(); 78 [(pixel >> 8) as u8, (pixel & 0xFF) as u8] 79 } 80 81 /// Converts the rgb components to a single intensity value. 82 /// This is used for grayscale images. 83 #[inline] 84 pub fn rgb_to_intensity(&self) -> u8 { 85 (self.r as f32 * 0.2126 + self.g as f32 * 0.7152 + 0.0722 * self.b as f32).round() as u8 86 } 87} ``` -------------------------------- ### pub fn read(reader: R, format: ImageType, width: u32, height: u32) -> Result Source: https://docs.rs/pigment64/latest/pigment64/image/native_image/struct.NativeImage.html Reads an image from a reader with the specified format and dimensions, returning a `NativeImage` on success. ```APIDOC ## pub fn read(reader: R, format: ImageType, width: u32, height: u32) -> Result ### Description Reads an image from a reader with the specified format and dimensions. ### Method Rust function ### Parameters - **reader**: `R` - Required - The reader to read image data from. - **format**: `ImageType` - Required - The image format. - **width**: `u32` - Required - The width of the image. - **height**: `u32` - Required - The height of the image. ### Returns `Result` - The resulting `NativeImage` or an error. ``` -------------------------------- ### as_i1: Convert PNG to 1-bit grayscale Source: https://docs.rs/pigment64/latest/src/pigment64/image/png_image.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Converts the PNG image to 1-bit grayscale. If the image is already Grayscale with BitDepth::One, writes data directly. Otherwise, converts to i8 first and then packs each 8 pixels into a single byte, setting a bit if the intensity is over half of u8::MAX. ```rust pub fn as_i1(&self, writer: &mut W) -> Result<(), Error> { if let (ColorType::Grayscale, BitDepth::One) = (self.color_type, self.bit_depth) { writer.write_all(&self.data)?; } else { // Convert to i8 and then convert to i1 let mut i8_data = Vec::new(); self.as_i8(&mut i8_data)?; for pixels in i8_data.chunks_exact(8) { // Combine the 8 pixels into a single byte let mut byte = 0; for (i, pixel) in pixels.iter().copied().enumerate() { // If its intensity is over half, set the bit if pixel > u8::MAX / 2 { byte |= 1 << (7 - i); } } writer.write_u8(byte)?; } } Ok(()) } ``` -------------------------------- ### take(n: usize) -> Take Source: https://docs.rs/pigment64/latest/pigment64/struct.ImageTypeIter.html?search=std%3A%3Avec Creates an iterator that yields the first `n` elements, or fewer if the underlying iterator ends sooner. ```APIDOC ## take(n: usize) -> Take ### Description Creates an iterator that yields the first `n` elements, or fewer if the underlying iterator ends sooner. ### Parameters - `n` (usize) - Required - The number of elements to yield. ### Returns `Take` - The new iterator that yields the first n elements. ``` -------------------------------- ### pigment64 lib.rs module with error and image enums Source: https://docs.rs/pigment64/latest/src/pigment64/lib.rs.html?search= Defines the crate's public modules, re-exports, error enum, and image size/format/type enums with methods for TLUT size, bits per pixel, and name conversion. ```rust pub mod color; pub mod image; pub use crate::image::native_image::NativeImage; pub use crate::image::png_image::{PNGImage, create_palette_from_png}; use num_enum::TryFromPrimitive; use strum_macros::{EnumCount, EnumIter}; use thiserror::Error; #[derive(Debug, Error)] #[non_exhaustive] pub enum Error { #[error("Invalid image size for TLUT: {0:?}")] InvalidSizeForTlut(ImageSize), #[error("A TLUT color table is required for this image format")] MissingTlut, #[error("The specified TLUT mode is not supported: {0:?}")] UnsupportedTlutMode(TextureLUT), #[error("TLUT index is out of bounds")] TlutIndexOutOfBounds, #[error("I/O error: {0}")] Io(#[from] std::io::Error), #[error("PNG encoding error: {0}")] PngEncoding(#[from] png::EncodingError), #[error("PNG decoding error: {0}")] PngDecoding(#[from] png::DecodingError), #[error("PNG is missing a palette, which is required for this operation")] MissingPngPalette, #[error( "Unsupported PNG format for conversion to {target_format:?}: color={color:?}, depth={depth:?}" )] UnsupportedPngConversion { color: png::ColorType, depth: png::BitDepth, target_format: ImageType, }, #[error("Palette format cannot be converted to a native image format")] PaletteConversionError, } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TryFromPrimitive)] #[repr(u8)] pub enum ImageSize { Bits1 = 4, Bits4 = 0, Bits8 = 1, Bits16 = 2, Bits32 = 3, DD = 5, } impl ImageSize { /// Returns the size of the TLUT (Table Look-Up Table) based on the image size. /// /// # Returns /// /// An `Option` containing the size of the TLUT as a `usize` value, or `None` /// if the image size is not valid for a TLUT. pub fn get_tlut_size(&self) -> Option { match self { ImageSize::Bits1 => Some(0b10), ImageSize::Bits4 => Some(0x10), ImageSize::Bits8 => Some(0x100), ImageSize::Bits16 => Some(0x1000), ImageSize::Bits32 => Some(0x10000), _ => None, } } /// Returns the bits per pixel. pub fn get_bpp(&self) -> u32 { match self { ImageSize::Bits1 => 1, ImageSize::Bits4 => 4, ImageSize::Bits8 => 8, ImageSize::Bits16 => 16, ImageSize::Bits32 => 32, ImageSize::DD => 0, } } } #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TryFromPrimitive)] #[repr(u8)] pub enum ImageFormat { Rgba = 0, Yuv = 1, Ci = 2, Ia = 3, I = 4, } /// Represents the type of image. /// /// This enum is used to specify the type of image, which determines the size and format of the /// image data. /// Each variant corresponds to a specific image type, such as indexed color (Ci), grayscale (I), /// grayscale with alpha (Ia), or red-green-blue-alpha (RGBA). /// #[derive(Copy, Clone, Debug, PartialEq, EnumCount, EnumIter, Eq, Hash, TryFromPrimitive)] #[repr(u8)] pub enum ImageType { I1, I4, I8, Ia4, Ia8, Ia16, Ci4, Ci8, Rgba16, Rgba32, } impl ImageType { /// Creates an `ImageType` from its string name. /// /// This is useful for converting string-based input (e.g., from Python) /// into the corresponding enum variant. pub fn from_name(name: &str) -> Option { match name { "rgba32" => Some(ImageType::Rgba32), "rgba16" => Some(ImageType::Rgba16), "ia16" => Some(ImageType::Ia16), "ia8" => Some(ImageType::Ia8), "ia4" => Some(ImageType::Ia4), "i8" => Some(ImageType::I8), "i4" => Some(ImageType::I4), "i1" => Some(ImageType::I1), "ci8" => Some(ImageType::Ci8), "ci4" => Some(ImageType::Ci4), _ => None, } } /// Returns the size of the image type. /// /// This function returns the size of the image type, which represents the number of bits used /// to store each pixel. The size is determined based on the image type variant. /// /// # Returns /// /// - `ImageSize` - The size of the image type. pub fn get_size(&self) -> ImageSize { match self { ImageType::Ci4 => ImageSize::Bits4, ImageType::Ci8 => ImageSize::Bits8, ImageType::I1 => ImageSize::Bits1, ImageType::I4 => ImageSize::Bits4, } } } ``` -------------------------------- ### fn partition(self, f: F) -> (B, B) Source: https://docs.rs/pigment64/latest/pigment64/struct.ImageTypeIter.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Consumes an iterator, creating two collections from it based on a predicate. Elements for which the predicate returns true go into the first collection, and the rest go into the second. ```APIDOC ## fn partition(self, f: F) -> (B, B) ### Description Consumes an iterator, creating two collections from it. Elements for which the predicate returns `true` go into the first collection, and the rest go into the second. ### Method `partition` ### Signature ```rust fn partition(self, f: F) -> (B, B) where Self: Sized, B: Default + Extend, F: FnMut(&Self::Item) -> bool, ``` ### Parameters - `f` (F) - Required - A predicate function that determines which collection each element goes into. ### Return Value Returns a tuple of two collections: the first contains elements for which `f` returned `true`, the second contains the rest. ``` -------------------------------- ### fn rposition

(&mut self, predicate: P) -> Option Source: https://docs.rs/pigment64/latest/pigment64/struct.ImageTypeIter.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Searches for an element in an iterator from the right, returning its index. This is a stable API. ```APIDOC ## fn rposition

(&mut self, predicate: P) -> Option ### Description Searches for an element in an iterator from the right, returning its index. ### Method `rposition` ### Signature ```rust fn rposition

(&mut self, predicate: P) -> Option where P: FnMut(Self::Item) -> bool, Self: Sized + ExactSizeIterator + DoubleEndedIterator, ``` ### Parameters - `predicate` (P) - Required - A predicate function. ### Return Value Returns the index of the first element from the right that satisfies the predicate, or `None` if none found. ``` -------------------------------- ### product Source: https://docs.rs/pigment64/latest/pigment64/struct.ImageTypeIter.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Iterates over the entire iterator, multiplying all the elements. ```APIDOC ## product ### Description Iterates over the entire iterator, multiplying all the elements. ### Signature ```rust fn product

(self) -> P where Self: Sized, P: Product, ``` ### Return Value - `P` - The product of all elements in the iterator. ### Notes - Available since Rust 1.11.0 (const: unstable). ``` -------------------------------- ### PNGImage::as_ci8 method Source: https://docs.rs/pigment64/latest/src/pigment64/image/png_image.rs.html Writes indexed color data as 8-bit. Returns an error if the image is not 8-bit indexed. ```rust pub fn as_ci8(&self, writer: &mut W) -> Result<(), Error> { if self.bit_depth != BitDepth::Eight || self.color_type != ColorType::Indexed { return Err(Error::UnsupportedPngConversion { color: self.color_type, depth: self.bit_depth, target_format: ImageType::Ci8, }); } writer.write_all(&self.data)?; Ok(()) } ``` -------------------------------- ### fn fold(self, init: B, f: F) -> B Source: https://docs.rs/pigment64/latest/pigment64/struct.ImageTypeIter.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Folds every element into an accumulator by applying an operation, returning the final result. This is a stable API. ```APIDOC ## fn fold(self, init: B, f: F) -> B ### Description Folds every element into an accumulator by applying an operation, returning the final result. ### Method `fold` ### Signature ```rust fn fold(self, init: B, f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, ``` ### Parameters - `init` (B) - Required - The initial accumulator value. - `f` (F) - Required - A function that takes the accumulator and an element, returning a new accumulator. ### Return Value Returns the final accumulator value. ``` -------------------------------- ### pigment64 lib.rs module declarations and re-exports Source: https://docs.rs/pigment64/latest/src/pigment64/lib.rs.html?search=Option%3CT%3E%2C+%28T+-%3E+U%29+-%3E+Option%3CU%3E Declares public modules color and image, re-exports NativeImage, PNGImage, and create_palette_from_png, and imports dependencies for error handling and enum utilities. ```rust pub mod color; pub mod image; pub use crate::image::native_image::NativeImage; pub use crate::image::png_image::{PNGImage, create_palette_from_png}; use num_enum::TryFromPrimitive; use strum_macros::{EnumCount, EnumIter}; use thiserror::Error; ``` -------------------------------- ### PNGImage width and height accessors Source: https://docs.rs/pigment64/latest/src/pigment64/image/png_image.rs.html Getter methods that return the width and height of the image. ```rust pub fn width(&self) -> u32 { self.width } pub fn height(&self) -> u32 { self.height } ``` -------------------------------- ### split_color_table_for_png: Split color table into palette and transparency Source: https://docs.rs/pigment64/latest/src/pigment64/image/native_image.rs.html?search= Splits a color table into a palette and a transparency table for PNG encoding. The palette data is built from the first three bytes of each 4-byte chunk, and the transparency data is the fourth byte of each chunk. ```rust /// Splits a color table into a palette and a transparency table for png encoding fn split_color_table_for_png(table: &[u8]) -> (Vec, Vec) { let palette_data: Vec = table .chunks(4) .flat_map(|chunk| chunk[..3].to_vec()) .collect(); let trans_data: Vec = table.chunks(4).map(|chunk| chunk[3]).collect(); (palette_data, trans_data) } ``` -------------------------------- ### Handle unsupported IA4 conversion Source: https://docs.rs/pigment64/latest/src/pigment64/image/png_image.rs.html?search=std%3A%3Avec Handles unsupported formats for IA4 conversion. ```rust _ => { return Err(Error::UnsupportedPngConversion { color: self.color_type, depth: self.bit_depth, target_format: ImageType::Ia4, }); } ``` -------------------------------- ### PNGImage::as_ci4 method Source: https://docs.rs/pigment64/latest/src/pigment64/image/png_image.rs.html Writes indexed color data as 4-bit. If the image is 8-bit indexed, it packs two 4-bit values per byte. Returns an error for unsupported bit depths. ```rust pub fn as_ci4(&self, writer: &mut W) -> Result<(), Error> { if self.color_type != ColorType::Indexed { return Err(Error::UnsupportedPngConversion { color: self.color_type, depth: self.bit_depth, target_format: ImageType::Ci4, }); } match self.bit_depth { BitDepth::Four => writer.write_all(&self.data)?, BitDepth::Eight => { for chunk in self.data.chunks_exact(2) { writer.write_u8(chunk[0] << 4 | chunk[1])?; } } _ => { return Err(Error::UnsupportedPngConversion { color: self.color_type, depth: self.bit_depth, target_format: ImageType::Ci4, }); } } Ok(()) } ``` -------------------------------- ### PNGImage::as_native method Source: https://docs.rs/pigment64/latest/src/pigment64/image/png_image.rs.html Dispatches to the appropriate conversion method based on the target ImageType. ```rust pub fn as_native(&self, writer: &mut W, image_type: ImageType) -> Result<(), Error> { match image_type { ImageType::I1 => self.as_i1(writer), ImageType::I4 => self.as_i4(writer), ImageType::I8 => self.as_i8(writer), ImageType::Ia4 => self.as_ia4(writer), ImageType::Ia8 => self.as_ia8(writer), ImageType::Ia16 => self.as_ia16(writer), ImageType::Ci4 => self.as_ci4(writer), ImageType::Ci8 => self.as_ci8(writer), ImageType::Rgba32 => self.as_rgba32(writer), ImageType::Rgba16 => self.as_rgba16(writer), } } ```