From 3942152cdaa715a78f783f0a24093bb62dac6b90 Mon Sep 17 00:00:00 2001 From: Stattek Date: Mon, 24 Nov 2025 22:30:06 -0600 Subject: [PATCH 1/6] Optimize setting a background on an image. - Create vectors with capacities to avoid as much memory allocation. --- .../converters/generic_converter.rs | 17 ++++---- src/conversion/render_char_to_png.rs | 39 +++++++------------ 2 files changed, 23 insertions(+), 33 deletions(-) diff --git a/src/conversion/converters/generic_converter.rs b/src/conversion/converters/generic_converter.rs index 826a923..5fdcb0a 100644 --- a/src/conversion/converters/generic_converter.rs +++ b/src/conversion/converters/generic_converter.rs @@ -30,22 +30,20 @@ pub fn render_ascii_generic( // contains lines of images // starting at 0 is the top, first line of the vector // inside an inner vec, 0 starts at the leftmost character of the line - let mut image_2d_vec = vec![]; + let mut image_2d_vec = Vec::with_capacity(ascii_text.lines().count()); // read every line in the file for line in ascii_text.lines() { - let mut char_images = vec![]; + let mut char_images = Vec::with_capacity(line.len()); // we need to find each character that we are going to write // we assume that there's only one character for each color - let control_char = '\u{1b}'; // represents the ansi escape character `\033` - let mut pattern_string = String::from(control_char); - let pattern = r"\[38;2;([0-9]+);([0-9]+);([0-9]+)m(.)"; - pattern_string += pattern; + // NOTE: \u{1b} represents the \033 character + let pattern_str = concat!('\u{1b}', r"\[38;2;([0-9]+);([0-9]+);([0-9]+)m(.)"); // TODO: if multiple threads are using this same regex object, maybe we could make it a // static global or compile it early so we can reuse it? Maybe as a "parser" object? - let re = Regex::new(&pattern_string)?; + let re = Regex::new(pattern_str)?; // create the image for this character for (_full_str, [r, g, b, the_str]) in re.captures_iter(line).map(|c| c.extract()) { @@ -59,10 +57,13 @@ pub fn render_ascii_generic( ParseIntError::new(String::from("blue"), String::from(the_str), err) })?; + // create this once since it will always be the same + let transparent_png = str_to_transparent_png(imgii_options); + let generated_png = { if the_str.trim().is_empty() { // create a transparent png for a space - str_to_transparent_png(imgii_options) + transparent_png.clone() } else { // render the actual text if it's not empty let colored = ColoredStr { diff --git a/src/conversion/render_char_to_png.rs b/src/conversion/render_char_to_png.rs index 93db035..8286029 100644 --- a/src/conversion/render_char_to_png.rs +++ b/src/conversion/render_char_to_png.rs @@ -1,7 +1,7 @@ use crate::{conversion::image_data::ImageData, options::ImgiiOptions}; use ab_glyph::{FontRef, PxScale}; use image::{DynamicImage, ImageBuffer, Rgba, RgbaImage}; -use imageproc::drawing::draw_text_mut; +use imageproc::{definitions::Image, drawing::draw_text_mut}; use rayon::prelude::*; /// Represents a colored string to write. @@ -22,17 +22,17 @@ pub fn str_to_png(data: ColoredStr, font: &FontRef<'_>, imgii_options: &ImgiiOpt let font_size = imgii_options.font_size(); let (char_width, char_height) = calculate_char_dimensions(font_size); // create our image to work with - let mut image = RgbaImage::new(char_width, char_height); + let mut image = if imgii_options.background() { + // create with background + ImageBuffer::from_pixel(char_width, char_height, BACKGROUND_PIXEL) + } else { + ImageBuffer::new(char_width, char_height) + }; let scale = PxScale { x: font_size as f32, y: font_size as f32, }; - // set background if user wants it - if imgii_options.background() { - set_background(&mut image); - } - draw_text_mut( &mut image, Rgba([data.red, data.green, data.blue, u8::MAX]), @@ -46,27 +46,16 @@ pub fn str_to_png(data: ColoredStr, font: &FontRef<'_>, imgii_options: &ImgiiOpt ImageData::new(image) } -// PERF: this is a costly operation and should probably be removed -fn set_background(image: &mut ImageBuffer, Vec>) { - image.par_enumerate_pixels_mut().for_each(|(_, _, pixel)| { - // set background - *pixel = BACKGROUND_PIXEL; - }); -} - /// Creates a transparent png in place of a character pub fn str_to_transparent_png(imgii_options: &ImgiiOptions) -> ImageData { let (char_width, char_height) = calculate_char_dimensions(imgii_options.font_size()); - let mut output = DynamicImage::new_rgba8(char_width, char_height).into(); - - // TODO: instead of doing a background like this, why don't we create a single image that is a - // solid color (or we could do more interesting backgrounds) and overlay the output image over - // top of that? - - // set background if user wants it - if imgii_options.background() { - set_background(&mut output); - } + let output = if imgii_options.background() { + // create image with background + ImageBuffer::from_pixel(char_width, char_height, BACKGROUND_PIXEL) + } else { + // empty image + ImageBuffer::new(char_width, char_height) + }; ImageData::new(output) } From b9f6b8dfc7d1a3efad5b42c7edee29830676fdb1 Mon Sep 17 00:00:00 2001 From: Stattek Date: Mon, 24 Nov 2025 22:33:29 -0600 Subject: [PATCH 2/6] Remove unused imports. --- src/conversion/render_char_to_png.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/conversion/render_char_to_png.rs b/src/conversion/render_char_to_png.rs index 8286029..05970a4 100644 --- a/src/conversion/render_char_to_png.rs +++ b/src/conversion/render_char_to_png.rs @@ -1,8 +1,7 @@ use crate::{conversion::image_data::ImageData, options::ImgiiOptions}; use ab_glyph::{FontRef, PxScale}; -use image::{DynamicImage, ImageBuffer, Rgba, RgbaImage}; -use imageproc::{definitions::Image, drawing::draw_text_mut}; -use rayon::prelude::*; +use image::{ImageBuffer, Rgba}; +use imageproc::drawing::draw_text_mut; /// Represents a colored string to write. /// All characters are contiguous and share the same color. From aa0529879a711ac27fe96c6da511cc72a8e67fa0 Mon Sep 17 00:00:00 2001 From: Stattek Date: Mon, 24 Nov 2025 22:33:55 -0600 Subject: [PATCH 3/6] . --- src/conversion/render_char_to_png.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conversion/render_char_to_png.rs b/src/conversion/render_char_to_png.rs index 05970a4..c2de0e1 100644 --- a/src/conversion/render_char_to_png.rs +++ b/src/conversion/render_char_to_png.rs @@ -15,7 +15,7 @@ pub struct ColoredStr { const BACKGROUND_PIXEL: Rgba = Rgba([0, 0, 0, u8::MAX]); -/// Converts string data into a png +/// Converts string data into a png. /// Uses `imageproc` to render text. pub fn str_to_png(data: ColoredStr, font: &FontRef<'_>, imgii_options: &ImgiiOptions) -> ImageData { let font_size = imgii_options.font_size(); From 282db1c6f862fad73e6d7a6427e210ed799cc87c Mon Sep 17 00:00:00 2001 From: Stattek Date: Wed, 26 Nov 2025 22:34:27 -0600 Subject: [PATCH 4/6] More optimization. - Preallocate memory for our 2d vec when we can. - Make the 2d vec of images a single vec instead of a Vec>. --- .../converters/generic_converter.rs | 70 ++++++++++++++----- src/conversion/converters/gif_converter.rs | 25 ++++--- src/conversion/converters/png_converter.rs | 8 +-- src/conversion/image_writer.rs | 36 ++++------ 4 files changed, 87 insertions(+), 52 deletions(-) diff --git a/src/conversion/converters/generic_converter.rs b/src/conversion/converters/generic_converter.rs index 5fdcb0a..c0e84b6 100644 --- a/src/conversion/converters/generic_converter.rs +++ b/src/conversion/converters/generic_converter.rs @@ -1,7 +1,7 @@ use crate::{ ImgiiOptions, conversion::{image_data::ImageData, render_char_to_png::str_to_png}, - error::{FontError, ImgiiError, ParseIntError}, + error::{FontError, ImgiiError, InternalError, ParseIntError}, }; use super::super::render_char_to_png::{ColoredStr, str_to_transparent_png}; @@ -14,28 +14,43 @@ use regex::Regex; const FONT_FILE: &str = "../../../fonts/UbuntuMono.ttf"; const FONT_BYTES: &[u8] = include_bytes!("../../../fonts/UbuntuMono.ttf"); +/// Simple struct for holding a 2d image with its width and height. +#[derive(Clone, Debug)] +pub(crate) struct Imgii2dImage { + pub image_2d: Vec, + pub width: usize, + pub height: usize, +} + /// Generic function for parsing and rendering ASCII into an image. /// /// * `imgii_options`: The imgii options for rendering ASCII. /// * `ascii_text`: The ASCII text to render. -pub fn render_ascii_generic( +/// +/// # Returns +/// `Ok` containing a 2d `Vec` if `ImageData`, holding each character image, otherwise an `Err`. +pub(crate) fn render_ascii_generic( imgii_options: &ImgiiOptions, ascii_text: String, -) -> Result>, ImgiiError> { +) -> Result { // set up font for rendering let font = FontRef::try_from_slice(FONT_BYTES) // there's nothing useful in this error, convert it! .map_err(|_| FontError::new(String::from(FONT_FILE)))?; - // contains lines of images - // starting at 0 is the top, first line of the vector - // inside an inner vec, 0 starts at the leftmost character of the line - let mut image_2d_vec = Vec::with_capacity(ascii_text.lines().count()); + // 2d Vec of images for each character + let mut image_2d_vec = Vec::new(); - // read every line in the file - for line in ascii_text.lines() { - let mut char_images = Vec::with_capacity(line.len()); + // create this once since it will always be the same + let transparent_png = str_to_transparent_png(imgii_options); + + // width and height, in characters + // NOTE: we can know height beforehand but we have to wait until we have parsed a whole line of + // text to know the width + let (mut width, mut height) = (0, ascii_text.lines().count()); + // read every line in the file + for (i, line) in ascii_text.lines().enumerate() { // we need to find each character that we are going to write // we assume that there's only one character for each color // NOTE: \u{1b} represents the \033 character @@ -45,6 +60,9 @@ pub fn render_ascii_generic( // static global or compile it early so we can reuse it? Maybe as a "parser" object? let re = Regex::new(pattern_str)?; + // current line's width + let mut line_width = 0; + // create the image for this character for (_full_str, [r, g, b, the_str]) in re.captures_iter(line).map(|c| c.extract()) { let red = r.parse::().map_err(|err| { @@ -57,9 +75,6 @@ pub fn render_ascii_generic( ParseIntError::new(String::from("blue"), String::from(the_str), err) })?; - // create this once since it will always be the same - let transparent_png = str_to_transparent_png(imgii_options); - let generated_png = { if the_str.trim().is_empty() { // create a transparent png for a space @@ -77,11 +92,34 @@ pub fn render_ascii_generic( } }; - char_images.push(generated_png); + line_width += 1; + image_2d_vec.push(generated_png); } - image_2d_vec.push(char_images); + // check that this width is always the same now that we have the width + if i != 0 { + assert_eq!( + width, line_width, + "width {} is not equal to the current line width {}", + width, line_width + ); + } else { + width = line_width; + // now we can reserve the rest of the space for our vec + image_2d_vec.reserve(width * height); + } } - Ok(image_2d_vec) + assert!( + width * height == image_2d_vec.len(), + "expected length of the 2d vector was {} but got {}", + width * height, + image_2d_vec.len() + ); + + Ok(Imgii2dImage { + image_2d: image_2d_vec, + width: width, + height: height, + }) } diff --git a/src/conversion/converters/gif_converter.rs b/src/conversion/converters/gif_converter.rs index d4f2ee6..ee18043 100644 --- a/src/conversion/converters/gif_converter.rs +++ b/src/conversion/converters/gif_converter.rs @@ -1,7 +1,10 @@ use std::{fs::File, io::BufReader}; use crate::{ - conversion::{converters::generic_converter::render_ascii_generic, image_data::ImageData}, + conversion::{ + converters::generic_converter::{Imgii2dImage, render_ascii_generic}, + image_data::ImageData, + }, error::{BoxedDynErr, ImgiiError}, options::{ImgiiOptions, RasciiOptions}, }; @@ -12,7 +15,7 @@ use rayon::iter::{IntoParallelIterator, ParallelIterator}; /// Holds the metadata for a frame that has been deconstructed. #[derive(Debug, Clone)] -pub struct FrameMetadata { +pub(crate) struct FrameMetadata { /// The left value for this frame. left: u32, /// The top value for this frame. @@ -24,7 +27,7 @@ pub struct FrameMetadata { /// Holds the deconstructed frame data for a single frame, before it is converted to image data. /// Holds the raw ASCII string and frame metadata. #[derive(Debug, Clone)] -pub struct NonRenderedFramePart { +pub(crate) struct NonRenderedFramePart { /// The ASCII representation of the frame. image_ascii: String, /// The frame metadata for this frame. @@ -33,9 +36,9 @@ pub struct NonRenderedFramePart { /// Holds the deconstructed frame data for a single frame that has been rendered to a 2D vector. #[derive(Debug, Clone)] -pub struct RenderedFramePart { +pub(crate) struct RenderedFramePart { /// The image data with the rendered image data for this frame as a 2D vector. - image_data: Vec>, + image_data: Imgii2dImage, /// The frame metadata for this frame. frame_metadata: FrameMetadata, } @@ -77,7 +80,7 @@ impl RenderedFramePart { /// * `image_data`: The image data. /// * `frame_metadata`: The frame metadata. #[must_use] - pub fn new(image_data: Vec>, frame_metadata: FrameMetadata) -> Self { + pub fn new(image_data: Imgii2dImage, frame_metadata: FrameMetadata) -> Self { Self { image_data, frame_metadata, @@ -86,7 +89,7 @@ impl RenderedFramePart { /// Gets the image data for this frame. #[must_use] - pub fn image_data(&self) -> &Vec> { + pub fn image_data(&self) -> &Imgii2dImage { &self.image_data } @@ -99,7 +102,7 @@ impl RenderedFramePart { /// Moves out of this RenderedFramePart, returning a tuple containing the image data followed /// by metadata. #[must_use] - pub fn into_frame_data(self) -> (Vec>, FrameMetadata) { + pub fn into_frame_data(self) -> (Imgii2dImage, FrameMetadata) { (self.image_data, self.frame_metadata) } } @@ -129,7 +132,7 @@ impl NonRenderedFramePart { /// /// * `input_file_name`: The input file name. /// * `rascii_options`: The RASCII options for converting to ASCII. -pub fn read_gif_as_deconstructed_ascii( +pub(crate) fn read_gif_as_deconstructed_ascii( input_file_name: &str, rascii_options: &RasciiOptions, ) -> Result>, ImgiiError> { @@ -159,7 +162,7 @@ pub fn read_gif_as_deconstructed_ascii( /// /// * `input_file_name`: the input file name. /// * `imgii_options`: the imgii options for rendering ascii. -pub fn read_as_deconstructed_rendered_gif_vec( +pub(crate) fn read_as_deconstructed_rendered_gif_vec( input_file_name: &str, imgii_options: &ImgiiOptions, ) -> Result>, ImgiiError> { @@ -196,7 +199,7 @@ pub fn read_as_deconstructed_rendered_gif_vec( /// /// # Returns /// `Err()` upon error reading the GIF, `Ok()` otherwise. -pub fn read_deconstructed_gif( +pub(crate) fn read_deconstructed_gif( input_file_name: &str, ) -> Result, ImgiiError> { let file_in = BufReader::new(File::open(input_file_name)?); diff --git a/src/conversion/converters/png_converter.rs b/src/conversion/converters/png_converter.rs index a97869a..823642a 100644 --- a/src/conversion/converters/png_converter.rs +++ b/src/conversion/converters/png_converter.rs @@ -1,6 +1,6 @@ use super::generic_converter::render_ascii_generic; use crate::{ - conversion::image_data::ImageData, + conversion::{converters::generic_converter::Imgii2dImage, image_data::ImageData}, error::{BoxedDynErr, ImgiiError}, options::{ImgiiOptions, RasciiOptions}, }; @@ -17,10 +17,10 @@ use rascii_art_img::render_image_to; /// # Returns /// * `Vec>`: A 2d `Vec` of images, containing each rendered character from the /// image. -pub fn parse_ascii_to_2d_png_vec( +pub(crate) fn parse_ascii_to_2d_png_vec( input_file_name: &str, imgii_options: &ImgiiOptions, -) -> Result>, ImgiiError> { +) -> Result { let ascii_text = read_png_as_ascii(input_file_name, imgii_options.rascii_options())?; render_ascii_generic(imgii_options, ascii_text) } @@ -33,7 +33,7 @@ pub fn parse_ascii_to_2d_png_vec( /// /// # Returns /// * `String` containing the colored image data as ASCII, colored using terminal escape sequences. -pub fn read_png_as_ascii( +pub(crate) fn read_png_as_ascii( input_file_name: &str, rascii_options: &RasciiOptions, ) -> Result { diff --git a/src/conversion/image_writer.rs b/src/conversion/image_writer.rs index f179b2c..96b0b58 100644 --- a/src/conversion/image_writer.rs +++ b/src/conversion/image_writer.rs @@ -1,5 +1,6 @@ use crate::{ conversion::{ + converters::generic_converter::Imgii2dImage, image_data::{ImageData, InternalImage}, render_char_to_png::calculate_char_dimensions, }, @@ -35,38 +36,30 @@ impl AsciiImageWriter { /// # Returns /// - An `Option` containing `Some` `AsciiImageWriter` upon success, or a /// `None` upon failure. - pub fn from_2d_vec( - parts: Vec>, + pub(crate) fn from_2d_vec( + the_image: Imgii2dImage, pngii_options: &ImgiiOptions, ) -> Result { - if parts.is_empty() || parts[0].is_empty() { + if the_image.image_2d.is_empty() { // no image to build return Err(InvalidParameterError::new(String::from("parts")).into()); } - let font_size = pngii_options.font_size(); - - let (mut height, mut width) = (0, 0); // find out the new canvas size - for (cur_line, line) in parts.iter().enumerate() { - // assume that every image has the same height and width - if !line.is_empty() { - height += line[0].as_buffer().height(); - // calculate the width - width = line[0].as_buffer().width() * line.len() as u32; - } else { - return Err(ParseImageError::new(cur_line).into()); - } - } + // this should always exist + let char_width = the_image.image_2d[0].as_buffer().width(); + let char_height = the_image.image_2d[0].as_buffer().height(); + + // calculate image resolution in pixels based on this reference image + let height = char_height * the_image.height as u32; + let width = char_width * the_image.width as u32; // create the new canvas to write to let mut canvas: InternalImage = image::ImageBuffer::new(width, height); - // calculate character width and height - let (char_width, char_height) = calculate_char_dimensions(font_size); - + // copy over pixels to canvas canvas.par_enumerate_pixels_mut().for_each(|(x, y, pixel)| { - // the index into the row and column from the parts vec + // the index into the row and column from the image_2d vec let row = y / char_height; let column = x / char_width; @@ -74,7 +67,8 @@ impl AsciiImageWriter { let inner_x = x % char_width; let inner_y = y % char_height; - let new_pixel = parts[row as usize][column as usize] + let new_pixel = the_image.image_2d + [column as usize + row as usize * the_image.width as usize] .as_buffer() .get_pixel(inner_x, inner_y); // write the pixel we have chosen From bf78db1c124bbe33496382faf1dd00787dcf0ddc Mon Sep 17 00:00:00 2001 From: Stattek Date: Wed, 26 Nov 2025 22:35:00 -0600 Subject: [PATCH 5/6] Make the conversion module only public within the library. --- src/conversion.rs | 8 ++++---- src/conversion/converters.rs | 6 +++--- .../converters/generic_converter.rs | 6 +++--- src/conversion/converters/gif_converter.rs | 18 ++++++++--------- src/conversion/image_data.rs | 8 ++++---- src/conversion/image_writer.rs | 4 ++-- src/conversion/render_char_to_png.rs | 20 +++++++++++-------- src/lib.rs | 2 +- 8 files changed, 38 insertions(+), 34 deletions(-) diff --git a/src/conversion.rs b/src/conversion.rs index c17b537..76a0de9 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -1,7 +1,7 @@ //! Holds types and code necessary for converting images to ASCII and rendering as images. Can //! handle different image types. -pub mod converters; -pub mod image_data; -pub mod image_writer; -pub mod render_char_to_png; +pub(crate) mod converters; +pub(crate) mod image_data; +pub(crate) mod image_writer; +pub(crate) mod render_char_to_png; diff --git a/src/conversion/converters.rs b/src/conversion/converters.rs index 75af8a3..25d3ff1 100644 --- a/src/conversion/converters.rs +++ b/src/conversion/converters.rs @@ -1,5 +1,5 @@ //! Holds converters for different image types. -pub mod generic_converter; -pub mod gif_converter; -pub mod png_converter; +pub(crate) mod generic_converter; +pub(crate) mod gif_converter; +pub(crate) mod png_converter; diff --git a/src/conversion/converters/generic_converter.rs b/src/conversion/converters/generic_converter.rs index c0e84b6..80ef84c 100644 --- a/src/conversion/converters/generic_converter.rs +++ b/src/conversion/converters/generic_converter.rs @@ -17,9 +17,9 @@ const FONT_BYTES: &[u8] = include_bytes!("../../../fonts/UbuntuMono.ttf"); /// Simple struct for holding a 2d image with its width and height. #[derive(Clone, Debug)] pub(crate) struct Imgii2dImage { - pub image_2d: Vec, - pub width: usize, - pub height: usize, + pub(crate) image_2d: Vec, + pub(crate) width: usize, + pub(crate) height: usize, } /// Generic function for parsing and rendering ASCII into an image. diff --git a/src/conversion/converters/gif_converter.rs b/src/conversion/converters/gif_converter.rs index ee18043..21ba093 100644 --- a/src/conversion/converters/gif_converter.rs +++ b/src/conversion/converters/gif_converter.rs @@ -50,25 +50,25 @@ pub(crate) struct RenderedFramePart { impl FrameMetadata { /// Creates a new [`FrameMetadata`]. #[must_use] - pub fn new(left: u32, top: u32, delay: Delay) -> Self { + pub(crate) fn new(left: u32, top: u32, delay: Delay) -> Self { Self { left, top, delay } } /// Gets the x offset for this frame. #[must_use] - pub fn left(&self) -> u32 { + pub(crate) fn left(&self) -> u32 { self.left } /// Gets the y offset for this frame. #[must_use] - pub fn top(&self) -> u32 { + pub(crate) fn top(&self) -> u32 { self.top } /// Gets the delay of this frame. #[must_use] - pub fn delay(&self) -> Delay { + pub(crate) fn delay(&self) -> Delay { self.delay } } @@ -80,7 +80,7 @@ impl RenderedFramePart { /// * `image_data`: The image data. /// * `frame_metadata`: The frame metadata. #[must_use] - pub fn new(image_data: Imgii2dImage, frame_metadata: FrameMetadata) -> Self { + pub(crate) fn new(image_data: Imgii2dImage, frame_metadata: FrameMetadata) -> Self { Self { image_data, frame_metadata, @@ -89,20 +89,20 @@ impl RenderedFramePart { /// Gets the image data for this frame. #[must_use] - pub fn image_data(&self) -> &Imgii2dImage { + pub(crate) fn image_data(&self) -> &Imgii2dImage { &self.image_data } /// Gets the metadata for this frame. #[must_use] - pub fn frame_metadata(&self) -> &FrameMetadata { + pub(crate) fn frame_metadata(&self) -> &FrameMetadata { &self.frame_metadata } /// Moves out of this RenderedFramePart, returning a tuple containing the image data followed /// by metadata. #[must_use] - pub fn into_frame_data(self) -> (Imgii2dImage, FrameMetadata) { + pub(crate) fn into_frame_data(self) -> (Imgii2dImage, FrameMetadata) { (self.image_data, self.frame_metadata) } } @@ -114,7 +114,7 @@ impl NonRenderedFramePart { /// * `image_ascii`: The ASCII string representation of an image. /// * `frame_metadata`: The frame metadata. #[must_use] - pub fn new(image_ascii: String, frame_metadata: FrameMetadata) -> Self { + pub(crate) fn new(image_ascii: String, frame_metadata: FrameMetadata) -> Self { Self { image_ascii, frame_metadata, diff --git a/src/conversion/image_data.rs b/src/conversion/image_data.rs index 6c77408..50ef605 100644 --- a/src/conversion/image_data.rs +++ b/src/conversion/image_data.rs @@ -1,21 +1,21 @@ use image::ImageBuffer; // easier to read -pub type InternalImage = ImageBuffer, Vec>; +pub(crate) type InternalImage = ImageBuffer, Vec>; /// Represents the image data to work with. /// Holds an `ImageBuffer` with the image data. #[derive(Debug, Clone)] -pub struct ImageData(InternalImage); +pub(crate) struct ImageData(InternalImage); impl ImageData { /// Create a new ImageData struct as this image buffer. - pub fn new(image_buffer: InternalImage) -> Self { + pub(crate) fn new(image_buffer: InternalImage) -> Self { Self(image_buffer) } /// Gets a reference to the internal buffer for this image data. - pub fn as_buffer(&self) -> &InternalImage { + pub(crate) fn as_buffer(&self) -> &InternalImage { &self.0 } } diff --git a/src/conversion/image_writer.rs b/src/conversion/image_writer.rs index 96b0b58..b2d07a0 100644 --- a/src/conversion/image_writer.rs +++ b/src/conversion/image_writer.rs @@ -11,8 +11,8 @@ use rayon::prelude::*; /// An image writer which holds a rendered ASCII image. #[derive(Debug, Clone)] -pub struct AsciiImageWriter { - pub imagebuf: ImageData, +pub(crate) struct AsciiImageWriter { + pub(crate) imagebuf: ImageData, } impl From for AsciiImageWriter { diff --git a/src/conversion/render_char_to_png.rs b/src/conversion/render_char_to_png.rs index c2de0e1..5d85533 100644 --- a/src/conversion/render_char_to_png.rs +++ b/src/conversion/render_char_to_png.rs @@ -6,18 +6,22 @@ use imageproc::drawing::draw_text_mut; /// Represents a colored string to write. /// All characters are contiguous and share the same color. #[derive(Debug, Clone)] -pub struct ColoredStr { - pub red: u8, - pub blue: u8, - pub green: u8, - pub string: String, +pub(crate) struct ColoredStr { + pub(crate) red: u8, + pub(crate) blue: u8, + pub(crate) green: u8, + pub(crate) string: String, } const BACKGROUND_PIXEL: Rgba = Rgba([0, 0, 0, u8::MAX]); /// Converts string data into a png. /// Uses `imageproc` to render text. -pub fn str_to_png(data: ColoredStr, font: &FontRef<'_>, imgii_options: &ImgiiOptions) -> ImageData { +pub(crate) fn str_to_png( + data: ColoredStr, + font: &FontRef<'_>, + imgii_options: &ImgiiOptions, +) -> ImageData { let font_size = imgii_options.font_size(); let (char_width, char_height) = calculate_char_dimensions(font_size); // create our image to work with @@ -46,7 +50,7 @@ pub fn str_to_png(data: ColoredStr, font: &FontRef<'_>, imgii_options: &ImgiiOpt } /// Creates a transparent png in place of a character -pub fn str_to_transparent_png(imgii_options: &ImgiiOptions) -> ImageData { +pub(crate) fn str_to_transparent_png(imgii_options: &ImgiiOptions) -> ImageData { let (char_width, char_height) = calculate_char_dimensions(imgii_options.font_size()); let output = if imgii_options.background() { // create image with background @@ -63,6 +67,6 @@ pub fn str_to_transparent_png(imgii_options: &ImgiiOptions) -> ImageData { /// /// # Returns /// (width, height) in a tuple -pub fn calculate_char_dimensions(font_size: u32) -> (u32, u32) { +pub(crate) fn calculate_char_dimensions(font_size: u32) -> (u32, u32) { (font_size / 2, font_size) } diff --git a/src/lib.rs b/src/lib.rs index f41a72e..8e7634c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ //! Imgii is a library for converting images to ASCII and rendering as different image types. For //! example, it can take a PNG input and convert it into ASCII, render it, and save it. -pub mod conversion; +pub(crate) mod conversion; pub mod error; pub mod image_types; pub mod options; From c4449b8d344e5a26faf8607ea2810369bef29ea2 Mon Sep 17 00:00:00 2001 From: Stattek Date: Wed, 26 Nov 2025 22:46:40 -0600 Subject: [PATCH 6/6] Cargo clippy warnings. --- src/conversion/converters/generic_converter.rs | 8 ++++---- src/conversion/converters/gif_converter.rs | 9 +++++---- src/conversion/converters/png_converter.rs | 2 +- src/conversion/image_writer.rs | 12 +++--------- src/conversion/render_char_to_png.rs | 1 + src/lib.rs | 7 ++----- 6 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/conversion/converters/generic_converter.rs b/src/conversion/converters/generic_converter.rs index 80ef84c..f1a73ab 100644 --- a/src/conversion/converters/generic_converter.rs +++ b/src/conversion/converters/generic_converter.rs @@ -1,7 +1,7 @@ use crate::{ ImgiiOptions, conversion::{image_data::ImageData, render_char_to_png::str_to_png}, - error::{FontError, ImgiiError, InternalError, ParseIntError}, + error::{FontError, ImgiiError, ParseIntError}, }; use super::super::render_char_to_png::{ColoredStr, str_to_transparent_png}; @@ -47,7 +47,7 @@ pub(crate) fn render_ascii_generic( // width and height, in characters // NOTE: we can know height beforehand but we have to wait until we have parsed a whole line of // text to know the width - let (mut width, mut height) = (0, ascii_text.lines().count()); + let (mut width, height) = (0, ascii_text.lines().count()); // read every line in the file for (i, line) in ascii_text.lines().enumerate() { @@ -119,7 +119,7 @@ pub(crate) fn render_ascii_generic( Ok(Imgii2dImage { image_2d: image_2d_vec, - width: width, - height: height, + width, + height, }) } diff --git a/src/conversion/converters/gif_converter.rs b/src/conversion/converters/gif_converter.rs index 21ba093..ff0356a 100644 --- a/src/conversion/converters/gif_converter.rs +++ b/src/conversion/converters/gif_converter.rs @@ -1,10 +1,7 @@ use std::{fs::File, io::BufReader}; use crate::{ - conversion::{ - converters::generic_converter::{Imgii2dImage, render_ascii_generic}, - image_data::ImageData, - }, + conversion::converters::generic_converter::{Imgii2dImage, render_ascii_generic}, error::{BoxedDynErr, ImgiiError}, options::{ImgiiOptions, RasciiOptions}, }; @@ -80,6 +77,7 @@ impl RenderedFramePart { /// * `image_data`: The image data. /// * `frame_metadata`: The frame metadata. #[must_use] + #[allow(dead_code)] pub(crate) fn new(image_data: Imgii2dImage, frame_metadata: FrameMetadata) -> Self { Self { image_data, @@ -89,12 +87,14 @@ impl RenderedFramePart { /// Gets the image data for this frame. #[must_use] + #[allow(dead_code)] pub(crate) fn image_data(&self) -> &Imgii2dImage { &self.image_data } /// Gets the metadata for this frame. #[must_use] + #[allow(dead_code)] pub(crate) fn frame_metadata(&self) -> &FrameMetadata { &self.frame_metadata } @@ -102,6 +102,7 @@ impl RenderedFramePart { /// Moves out of this RenderedFramePart, returning a tuple containing the image data followed /// by metadata. #[must_use] + #[allow(dead_code)] pub(crate) fn into_frame_data(self) -> (Imgii2dImage, FrameMetadata) { (self.image_data, self.frame_metadata) } diff --git a/src/conversion/converters/png_converter.rs b/src/conversion/converters/png_converter.rs index 823642a..7144589 100644 --- a/src/conversion/converters/png_converter.rs +++ b/src/conversion/converters/png_converter.rs @@ -1,6 +1,6 @@ use super::generic_converter::render_ascii_generic; use crate::{ - conversion::{converters::generic_converter::Imgii2dImage, image_data::ImageData}, + conversion::converters::generic_converter::Imgii2dImage, error::{BoxedDynErr, ImgiiError}, options::{ImgiiOptions, RasciiOptions}, }; diff --git a/src/conversion/image_writer.rs b/src/conversion/image_writer.rs index b2d07a0..13c5ef5 100644 --- a/src/conversion/image_writer.rs +++ b/src/conversion/image_writer.rs @@ -2,10 +2,8 @@ use crate::{ conversion::{ converters::generic_converter::Imgii2dImage, image_data::{ImageData, InternalImage}, - render_char_to_png::calculate_char_dimensions, }, - error::{ImgiiError, InvalidParameterError, ParseImageError}, - options::ImgiiOptions, + error::{ImgiiError, InvalidParameterError}, }; use rayon::prelude::*; @@ -36,10 +34,7 @@ impl AsciiImageWriter { /// # Returns /// - An `Option` containing `Some` `AsciiImageWriter` upon success, or a /// `None` upon failure. - pub(crate) fn from_2d_vec( - the_image: Imgii2dImage, - pngii_options: &ImgiiOptions, - ) -> Result { + pub(crate) fn from_2d_vec(the_image: Imgii2dImage) -> Result { if the_image.image_2d.is_empty() { // no image to build return Err(InvalidParameterError::new(String::from("parts")).into()); @@ -67,8 +62,7 @@ impl AsciiImageWriter { let inner_x = x % char_width; let inner_y = y % char_height; - let new_pixel = the_image.image_2d - [column as usize + row as usize * the_image.width as usize] + let new_pixel = the_image.image_2d[column as usize + row as usize * the_image.width] .as_buffer() .get_pixel(inner_x, inner_y); // write the pixel we have chosen diff --git a/src/conversion/render_char_to_png.rs b/src/conversion/render_char_to_png.rs index 5d85533..ff493df 100644 --- a/src/conversion/render_char_to_png.rs +++ b/src/conversion/render_char_to_png.rs @@ -67,6 +67,7 @@ pub(crate) fn str_to_transparent_png(imgii_options: &ImgiiOptions) -> ImageData /// /// # Returns /// (width, height) in a tuple +#[inline] pub(crate) fn calculate_char_dimensions(font_size: u32) -> (u32, u32) { (font_size / 2, font_size) } diff --git a/src/lib.rs b/src/lib.rs index 8e7634c..c577759 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,7 +78,7 @@ pub fn convert_to_ascii_png( imgii_options: &ImgiiOptions, ) -> Result<(), ImgiiError> { let lines = parse_ascii_to_2d_png_vec(input_file_name, imgii_options)?; - let final_image_writer = AsciiImageWriter::from_2d_vec(lines, imgii_options)?; + let final_image_writer = AsciiImageWriter::from_2d_vec(lines)?; // write the image final_image_writer @@ -152,10 +152,7 @@ pub fn convert_to_ascii_gif( .filter_map(|frame_part| frame_part) .map(|frame_part| { let (image_data, frame_metadata) = frame_part.into_frame_data(); - ( - AsciiImageWriter::from_2d_vec(image_data, imgii_options), - frame_metadata, - ) + (AsciiImageWriter::from_2d_vec(image_data), frame_metadata) }) .collect::>();