Skip to content

Commit

Permalink
improve scaling and resizing
Browse files Browse the repository at this point in the history
  • Loading branch information
atomofiron committed Jul 26, 2023
1 parent 682538d commit eabd650
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 18 deletions.
14 changes: 12 additions & 2 deletions src/core/bitmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ pub struct Bitmap {
pub width: u8,
pub height: u8,
pub bytes: Vec<u8>,
pub dx: i32,
pub dy: i32,
}

impl Bitmap {

pub fn new(width: u8, height: u8) -> Bitmap {
Bitmap { width, height, bytes: vec![0x00] }
pub fn new(width: u8, height: u8, dx: i32, dy: i32) -> Bitmap {
Bitmap { width, height, bytes: vec![0x00], dx, dy }
}

pub fn set(&mut self, x: u32, y: u32) {
Expand All @@ -36,6 +38,14 @@ impl Bitmap {
.unwrap_or(false);
}

pub fn get_src_x(&self, dst_x: u32) -> i32 {
dst_x as i32 + self.dx
}

pub fn get_src_y(&self, dst_y: u32) -> i32 {
dst_y as i32 + self.dy
}

fn get_indexes(&self, x: u32, y: u32) -> (usize, usize) {
let offset = (self.width as u32 * y + x) as usize;
((offset / 8 + 1), (7 - offset % 8))
Expand Down
48 changes: 32 additions & 16 deletions src/core/img2bm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ use image::{DynamicImage, GrayImage, RgbaImage};
use image::imageops::FilterType;
use crate::core::params::background::Background;
use crate::core::bitmap::Bitmap;
use crate::core::params::alignment::Alignment;
use crate::core::params::params::Params;
use crate::core::params::scale_type::ScaleType;
use crate::core::params::threshold::Threshold;
use crate::ext::range_ext::for_each;
use crate::ext::image_ext::Resizing;


const MAX_RADIUS: f32 = 4.0;

pub fn img2bm(image: &RgbaImage, params: &Params) -> Bitmap {
let resized = resize(image, params);
let output_height = resized.height() as i32;
let mut bitmap = Bitmap::new(params.width, output_height as u8);
let resized = resize(image, params).to_luma8();
let mut bitmap = create_bitmap(&resized, params);
if params.threshold.dark > 0.0 {
process_dark(params, &resized, &mut bitmap);
}
Expand All @@ -35,6 +36,24 @@ pub fn img2bm(image: &RgbaImage, params: &Params) -> Bitmap {
return bitmap;
}

fn create_bitmap(image: &GrayImage, params: &Params) -> Bitmap {
let mut dx = 0;
if params.alignment != Alignment::Left {
dx = image.width() as i32 - params.width as i32;
}
if params.alignment != Alignment::Right {
dx = dx / 2 + dx % 2;
}
let mut dy = 0;
if params.alignment != Alignment::Top {
dy = image.height() as i32 - params.height as i32;
}
if params.alignment != Alignment::Bottom {
dy = dy / 2 + dy % 2;
}
return Bitmap::new(params.width, params.height, dx, dy);
}

fn process_dark(params: &Params, resized: &GrayImage, bitmap: &mut Bitmap) {
for_each_luminance(resized, bitmap, |bitmap, x, y, outside, luminance| {
if !outside && luminance < params.threshold.dark {
Expand Down Expand Up @@ -86,32 +105,29 @@ fn for_each_luminance<F>(
image: &GrayImage,
bitmap: &mut Bitmap,
mut action: F,
) where F: FnMut(&mut Bitmap, u32, u32, bool/*is outside*/, f32) {
) where F: FnMut(&mut Bitmap, u32, u32, /*outside:*/bool, /*luminance:*/f32) {
let width = bitmap.width;
let height = bitmap.height;
for_each(0..height as u32, 0..width as u32, |x,y| {
if bitmap.get(x, y) { return; }
let bitmap_width = bitmap.width as u32;
let dif = bitmap_width - image.width();
let left = dif / 2;
let right = bitmap_width - left - dif % 2;
if x < left || x >= right {
let src_x = bitmap.get_src_x(x);
let src_y = bitmap.get_src_y(y);
if src_x < 0 || src_x >= image.width() as i32 || src_y < 0 || src_y >= image.height() as i32 {
action(bitmap, x, y, true, 0.0);
return;
}
let luminance = image.get_pixel(x - left, y).0[0] as f32 / 255.0;
let luminance = image.get_pixel(src_x as u32, src_y as u32).0[0] as f32 / 255.0;
action(bitmap, x, y, false, luminance);
});
}

fn resize(image: &RgbaImage, params: &Params) -> GrayImage {
fn resize(image: &RgbaImage, params: &Params) -> DynamicImage {
let dynamic = DynamicImage::from(image.clone());
let size = (params.width as u32, params.height as u32);
let resized = match params.scale_type {
ScaleType::Fit => dynamic.resize(size.0, size.1, FilterType::Nearest),
ScaleType::Fill => dynamic.resize_to_fill(size.0, size.1, FilterType::Nearest),
let fill = match params.scale_type {
ScaleType::Fill => true,
ScaleType::Fit => false,
};
return resized.to_luma8();
return Resizing::resize(&dynamic, params.width as u32, params.height as u32, fill, FilterType::Nearest);
}

pub fn find_in_radius(bitmap: &Bitmap, luminance: f32, x: i32, y: i32) -> bool {
Expand Down
1 change: 1 addition & 0 deletions src/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ pub mod iter_ext;
pub mod path_ext;
pub mod string_ext;
pub mod range_ext;
pub mod image_ext;
44 changes: 44 additions & 0 deletions src/ext/image_ext.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use image::DynamicImage;
use image::imageops::FilterType;

pub trait Resizing {
fn resize(&self, nwidth: u32, nheight: u32, fill: bool, filter: FilterType) -> Self;
}

impl Resizing for DynamicImage {
fn resize(&self, to_width: u32, to_height: u32, fill: bool, filter: FilterType) -> Self {
let (width, height) = resize_dimensions(self.width(), self.height(), to_width, to_height, fill);
return self.resize_exact(width, height, filter);
}
}

// image::math::utils::resize_dimensions()
fn resize_dimensions(
width: u32,
height: u32,
nwidth: u32,
nheight: u32,
fill: bool,
) -> (u32, u32) {
let wratio = nwidth as f64 / width as f64;
let hratio = nheight as f64 / height as f64;

let ratio = if fill {
f64::max(wratio, hratio)
} else {
f64::min(wratio, hratio)
};

let nw = 1.max((width as f64 * ratio).round() as u64);
let nh = 1.max((height as f64 * ratio).round() as u64);

if nw > u64::from(u32::MAX) {
let ratio = u32::MAX as f64 / width as f64;
(u32::MAX, 1.max((height as f64 * ratio).round() as u32))
} else if nh > u64::from(u32::MAX) {
let ratio = u32::MAX as f64 / height as f64;
(1.max((width as f64 * ratio).round() as u32), u32::MAX)
} else {
(nw as u32, nh as u32)
}
}

0 comments on commit eabd650

Please sign in to comment.