This commit is contained in:
Conrad Ludgate 2022-12-04 11:48:27 +00:00 committed by GitHub
commit ebc1a1c659
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 339 additions and 330 deletions

265
Cargo.lock generated
View File

@ -2,12 +2,6 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "ab_glyph_rasterizer"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "330223a1aecc308757b9926e9391c9b47f8ef2dbd8aea9df88312aea18c5e8d6"
[[package]]
name = "adler"
version = "1.0.2"
@ -29,15 +23,6 @@ version = "1.0.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602"
[[package]]
name = "approx"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6"
dependencies = [
"num-traits",
]
[[package]]
name = "atty"
version = "0.2.14"
@ -509,17 +494,6 @@ dependencies = [
"pkg-config",
]
[[package]]
name = "getrandom"
version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
"cfg-if",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
]
[[package]]
name = "getrandom"
version = "0.2.7"
@ -528,7 +502,7 @@ checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
dependencies = [
"cfg-if",
"libc",
"wasi 0.11.0+wasi-snapshot-preview1",
"wasi",
]
[[package]]
@ -590,24 +564,6 @@ dependencies = [
"png",
]
[[package]]
name = "imageproc"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aee993351d466301a29655d628bfc6f5a35a0d062b6160ca0808f425805fd7"
dependencies = [
"approx",
"conv",
"image",
"itertools",
"nalgebra",
"num",
"rand",
"rand_distr",
"rayon",
"rusttype",
]
[[package]]
name = "indexmap"
version = "1.9.1"
@ -627,15 +583,6 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.4"
@ -706,15 +653,6 @@ dependencies = [
"libc",
]
[[package]]
name = "matrixmultiply"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "add85d4dd35074e6fedc608f8c8f513a3548619a9024b751949ef0e8e45a4d84"
dependencies = [
"rawpointer",
]
[[package]]
name = "memoffset"
version = "0.6.5"
@ -733,55 +671,6 @@ dependencies = [
"adler",
]
[[package]]
name = "nalgebra"
version = "0.30.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fb2d0de08694bed883320212c18ee3008576bfe8c306f4c3c4a58b4876998be"
dependencies = [
"approx",
"matrixmultiply",
"num-complex",
"num-rational",
"num-traits",
"simba",
"typenum",
]
[[package]]
name = "num"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19"
dependencies = [
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.45"
@ -792,17 +681,6 @@ dependencies = [
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.1"
@ -810,7 +688,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
dependencies = [
"autocfg",
"num-bigint",
"num-integer",
"num-traits",
]
@ -911,21 +788,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "owned_ttf_parser"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f923fb806c46266c02ab4a5b239735c144bdeda724a50ed058e5226f594cde3"
dependencies = [
"ttf-parser",
]
[[package]]
name = "paste"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1"
[[package]]
name = "pasteboard"
version = "0.1.3"
@ -998,12 +860,6 @@ dependencies = [
"miniz_oxide",
]
[[package]]
name = "ppv-lite86"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
@ -1046,62 +902,6 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
"getrandom 0.1.16",
"libc",
"rand_chacha",
"rand_core",
"rand_hc",
]
[[package]]
name = "rand_chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
"getrandom 0.1.16",
]
[[package]]
name = "rand_distr"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96977acbdd3a6576fb1d27391900035bf3863d4a16422973a409b488cf29ffb2"
dependencies = [
"rand",
]
[[package]]
name = "rand_hc"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
dependencies = [
"rand_core",
]
[[package]]
name = "rawpointer"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
[[package]]
name = "rayon"
version = "1.5.3"
@ -1141,7 +941,7 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
dependencies = [
"getrandom 0.2.7",
"getrandom",
"redox_syscall",
"thiserror",
]
@ -1170,31 +970,12 @@ dependencies = [
"semver",
]
[[package]]
name = "rusttype"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc7c727aded0be18c5b80c1640eae0ac8e396abf6fa8477d96cb37d18ee5ec59"
dependencies = [
"ab_glyph_rasterizer",
"owned_ttf_parser",
]
[[package]]
name = "ryu"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
[[package]]
name = "safe_arch"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "794821e4ccb0d9f979512f9c1973480123f9bd62a90d74ab0f9426fcf8f4a529"
dependencies = [
"bytemuck",
]
[[package]]
name = "safemem"
version = "0.3.3"
@ -1284,7 +1065,6 @@ dependencies = [
"font-kit",
"harfbuzz-sys",
"image",
"imageproc",
"lazy_static",
"log",
"pasteboard",
@ -1296,19 +1076,6 @@ dependencies = [
"tempfile",
]
[[package]]
name = "simba"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c48e45e5961033db030b56ad67aef22e9c908c493a6e8348c0a0f6b93433cd77"
dependencies = [
"approx",
"num-complex",
"num-traits",
"paste",
"wide",
]
[[package]]
name = "str-buf"
version = "1.0.6"
@ -1453,18 +1220,6 @@ dependencies = [
"num_threads",
]
[[package]]
name = "ttf-parser"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc"
[[package]]
name = "typenum"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
[[package]]
name = "ucd-trie"
version = "0.1.5"
@ -1512,28 +1267,12 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "wasi"
version = "0.9.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wide"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae41ecad2489a1655c8ef8489444b0b113c0a0c795944a3572a0931cf7d2525c"
dependencies = [
"bytemuck",
"safe_arch",
]
[[package]]
name = "winapi"
version = "0.3.9"

View File

@ -18,7 +18,6 @@ harfbuzz = ["harfbuzz-sys", "font-kit/loader-freetype-default", "font-kit/source
[dependencies]
dirs = "4.0"
imageproc = "0.23.0"
clipboard = "0.5.0"
tempfile = "3.1.0"
conv = "0.3.3"

View File

@ -14,6 +14,7 @@
use crate::error::FontError;
#[cfg(feature = "harfbuzz")]
use crate::hb_wrapper::{feature_from_tag, HBBuffer, HBFont};
use crate::imageproc::{weighted_sum, Clamp};
use anyhow::Result;
use conv::ValueInto;
use font_kit::canvas::{Canvas, Format, RasterizationOptions};
@ -22,8 +23,6 @@ use font_kit::hinting::HintingOptions;
use font_kit::properties::{Properties, Style, Weight};
use font_kit::source::SystemSource;
use image::{GenericImage, Pixel};
use imageproc::definitions::Clamp;
use imageproc::pixelops::weighted_sum;
use pathfinder_geometry::transform2d::Transform2F;
use std::collections::HashMap;
use std::sync::Arc;
@ -348,7 +347,7 @@ impl FontCollection {
) -> u32
where
I: GenericImage,
<I::Pixel as Pixel>::Subpixel: ValueInto<f32> + Clamp<f32>,
<I::Pixel as Pixel>::Subpixel: ValueInto<f32> + Clamp,
{
let metrics = self.0[0].get_regular().metrics();
let offset =

327
src/imageproc.rs Normal file
View File

@ -0,0 +1,327 @@
//! Manual implementations of some things from imageproc - without all the unnecessary faff
//!
//! The MIT License (MIT)
//!
//! Copyright (c) 2015 PistonDevelopers
//!
//! Permission is hereby granted, free of charge, to any person obtaining a copy
//! of this software and associated documentation files (the "Software"), to deal
//! in the Software without restriction, including without limitation the rights
//! to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//! copies of the Software, and to permit persons to whom the Software is
//! furnished to do so, subject to the following conditions:
//!
//! The above copyright notice and this permission notice shall be included in all
//! copies or substantial portions of the Software.
//!
//! THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//! IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//! FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//! AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//! LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//! OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//! SOFTWARE.
use conv::ValueInto;
use image::{GenericImage, Pixel, Rgba, RgbaImage};
/// Draw as much of a circle, including its contents, as lies inside the image bounds.
pub(crate) fn draw_filled_circle_mut<I>(
image: &mut I,
center: (i32, i32),
radius: i32,
color: I::Pixel,
) where
I: GenericImage,
I::Pixel: 'static,
{
let mut x = 0i32;
let mut y = radius;
let mut p = 1 - radius;
let x0 = center.0;
let y0 = center.1;
while x <= y {
draw_line_segment_mut(
image,
((x0 - x) as f32, (y0 + y) as f32),
((x0 + x) as f32, (y0 + y) as f32),
color,
);
draw_line_segment_mut(
image,
((x0 - y) as f32, (y0 + x) as f32),
((x0 + y) as f32, (y0 + x) as f32),
color,
);
draw_line_segment_mut(
image,
((x0 - x) as f32, (y0 - y) as f32),
((x0 + x) as f32, (y0 - y) as f32),
color,
);
draw_line_segment_mut(
image,
((x0 - y) as f32, (y0 - x) as f32),
((x0 + y) as f32, (y0 - x) as f32),
color,
);
x += 1;
if p < 0 {
p += 2 * x + 1;
} else {
y -= 1;
p += 2 * (x - y) + 1;
}
}
}
/// Draws a line segment on an image in place.
///
/// Draws as much of the line segment between start and end as lies inside the image bounds.
///
/// Uses [Bresenham's line drawing algorithm](https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm).
pub(crate) fn draw_line_segment_mut<I>(
canvas: &mut I,
start: (f32, f32),
end: (f32, f32),
color: I::Pixel,
) where
I: GenericImage,
I::Pixel: 'static,
{
let (width, height) = canvas.dimensions();
let in_bounds = |x, y| x >= 0 && x < width as i32 && y >= 0 && y < height as i32;
let line_iterator = BresenhamLineIter::new(start, end);
for point in line_iterator {
let x = point.0;
let y = point.1;
if in_bounds(x, y) {
canvas.put_pixel(x as u32, y as u32, color);
}
}
}
/// Iterates over the coordinates in a line segment using
/// [Bresenham's line drawing algorithm](https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm).
struct BresenhamLineIter {
dx: f32,
dy: f32,
x: i32,
y: i32,
error: f32,
end_x: i32,
is_steep: bool,
y_step: i32,
}
impl BresenhamLineIter {
/// Creates a [`BresenhamLineIter`](struct.BresenhamLineIter.html) which will iterate over the integer coordinates
/// between `start` and `end`.
fn new(start: (f32, f32), end: (f32, f32)) -> BresenhamLineIter {
let (mut x0, mut y0) = (start.0, start.1);
let (mut x1, mut y1) = (end.0, end.1);
let is_steep = (y1 - y0).abs() > (x1 - x0).abs();
if is_steep {
std::mem::swap(&mut x0, &mut y0);
std::mem::swap(&mut x1, &mut y1);
}
if x0 > x1 {
std::mem::swap(&mut x0, &mut x1);
std::mem::swap(&mut y0, &mut y1);
}
let dx = x1 - x0;
BresenhamLineIter {
dx,
dy: (y1 - y0).abs(),
x: x0 as i32,
y: y0 as i32,
error: dx / 2f32,
end_x: x1 as i32,
is_steep,
y_step: if y0 < y1 { 1 } else { -1 },
}
}
}
impl Iterator for BresenhamLineIter {
type Item = (i32, i32);
fn next(&mut self) -> Option<(i32, i32)> {
if self.x > self.end_x {
None
} else {
let ret = if self.is_steep {
(self.y, self.x)
} else {
(self.x, self.y)
};
self.x += 1;
self.error -= self.dy;
if self.error < 0f32 {
self.y += self.y_step;
self.error += self.dx;
}
Some(ret)
}
}
}
/// Draws a rectangle and its contents on an image in place.
///
/// Draws as much of the rectangle and its contents as lies inside the image bounds.
pub(crate) fn draw_filled_rect_mut(canvas: &mut RgbaImage, rect: Rect, color: Rgba<u8>) {
let canvas_bounds = Rect {
left: 0,
top: 0,
width: canvas.width(),
height: canvas.height(),
};
if let Some(intersection) = canvas_bounds.intersect(rect) {
for dy in 0..intersection.height {
for dx in 0..intersection.width {
let x = intersection.left as u32 + dx;
let y = intersection.top as u32 + dy;
canvas.put_pixel(x, y, color);
}
}
}
}
/// A rectangular region of non-zero width and height.
/// # Examples
/// ```
/// use imageproc::rect::Rect;
/// use imageproc::rect::Region;
///
/// // Construct a rectangle with top-left corner at (4, 5), width 6 and height 7.
/// let rect = Rect::at(4, 5).of_size(6, 7);
///
/// // Contains top-left point:
/// assert_eq!(rect.left(), 4);
/// assert_eq!(rect.top(), 5);
/// assert!(rect.contains(rect.left(), rect.top()));
///
/// // Contains bottom-right point, at (left + width - 1, top + height - 1):
/// assert_eq!(rect.right(), 9);
/// assert_eq!(rect.bottom(), 11);
/// assert!(rect.contains(rect.right(), rect.bottom()));
/// ```
pub(crate) struct Rect {
pub(crate) left: i32,
pub(crate) top: i32,
pub(crate) width: u32,
pub(crate) height: u32,
}
impl Rect {
/// Greatest y-coordinate reached by rect.
fn bottom(&self) -> i32 {
self.top + (self.height as i32) - 1
}
/// Greatest x-coordinate reached by rect.
fn right(&self) -> i32 {
self.left + (self.width as i32) - 1
}
/// Returns the intersection of self and other, or none if they are are disjoint.
fn intersect(&self, other: Rect) -> Option<Rect> {
let left = std::cmp::max(self.left, other.left);
let top = std::cmp::max(self.top, other.top);
let right = std::cmp::min(self.right(), other.right());
let bottom = std::cmp::min(self.bottom(), other.bottom());
if right < left || bottom < top {
return None;
}
Some(Rect {
left,
top,
width: (right - left) as u32 + 1,
height: (bottom - top) as u32 + 1,
})
}
}
/// Adds pixels with the given weights. Results are clamped to prevent arithmetical overflows.
///
/// # Examples
/// ```
/// # extern crate image;
/// # extern crate imageproc;
/// # fn main() {
/// use image::Rgb;
/// use imageproc::pixelops::weighted_sum;
///
/// let left = Rgb([10u8, 20u8, 30u8]);
/// let right = Rgb([100u8, 80u8, 60u8]);
///
/// let sum = weighted_sum(left, right, 0.7, 0.3);
/// assert_eq!(sum, Rgb([37, 38, 39]));
/// # }
/// ```
pub(crate) fn weighted_sum<P: Pixel>(left: P, right: P, left_weight: f32, right_weight: f32) -> P
where
P::Subpixel: ValueInto<f32> + Clamp,
{
left.map2(&right, |p, q| {
Clamp::clamp(cast(p) * left_weight + cast(q) * right_weight)
})
}
fn cast<T, U>(x: T) -> U
where
T: ValueInto<U>,
{
match x.value_into() {
Ok(y) => y,
Err(_) => panic!("Failed to convert"),
}
}
/// A type to which we can clamp a value of type f32.
/// Implementations are not required to handle `NaN`s gracefully.
pub trait Clamp {
/// Clamp `x` to a valid value for this type.
fn clamp(x: f32) -> Self;
}
/// Creates an implementation of Clamp for type To.
macro_rules! implement_clamp {
($to:ty) => {
impl Clamp for $to {
fn clamp(x: f32) -> $to {
if x < <$to>::MAX as f32 {
if x > <$to>::MIN as f32 {
x as $to
} else {
<$to>::MIN
}
} else {
<$to>::MAX
}
}
}
};
}
impl Clamp for f32 {
fn clamp(x: f32) -> f32 {
x
}
}
implement_clamp!(u8);
implement_clamp!(u16);

View File

@ -46,3 +46,4 @@ pub mod formatter;
#[cfg(feature = "harfbuzz")]
pub mod hb_wrapper;
pub mod utils;
mod imageproc;

View File

@ -1,9 +1,8 @@
use crate::error::ParseColorError;
use crate::imageproc::{draw_filled_circle_mut, draw_filled_rect_mut, Rect};
use image::imageops::{crop_imm, resize, FilterType};
use image::Pixel;
use image::{DynamicImage, GenericImage, GenericImageView, Rgba, RgbaImage};
use imageproc::drawing::{draw_filled_rect_mut, draw_line_segment_mut};
use imageproc::rect::Rect;
pub trait ToRgba {
type Target;
@ -212,11 +211,12 @@ impl ShadowAdder {
// create the shadow
let mut shadow = self.background.to_image(width, height);
if self.blur_radius > 0.0 {
let rect = Rect::at(
self.pad_horiz as i32 + self.offset_x,
self.pad_vert as i32 + self.offset_y,
)
.of_size(image.width(), image.height());
let rect = Rect {
left: self.pad_horiz as i32 + self.offset_x,
top: self.pad_vert as i32 + self.offset_y,
width: image.width(),
height: image.height(),
};
draw_filled_rect_mut(&mut shadow, rect, self.shadow_color);
@ -300,62 +300,6 @@ pub(crate) fn round_corner(image: &mut DynamicImage, radius: u32) {
.unwrap();
}
// `draw_filled_circle_mut` doesn't work well with small radius in imageproc v0.18.0
// it has been fixed but still have to wait for releasing
// issue: https://github.com/image-rs/imageproc/issues/328
// PR: https://github.com/image-rs/imageproc/pull/330
/// Draw as much of a circle, including its contents, as lies inside the image bounds.
pub(crate) fn draw_filled_circle_mut<I>(
image: &mut I,
center: (i32, i32),
radius: i32,
color: I::Pixel,
) where
I: GenericImage,
I::Pixel: 'static,
{
let mut x = 0i32;
let mut y = radius;
let mut p = 1 - radius;
let x0 = center.0;
let y0 = center.1;
while x <= y {
draw_line_segment_mut(
image,
((x0 - x) as f32, (y0 + y) as f32),
((x0 + x) as f32, (y0 + y) as f32),
color,
);
draw_line_segment_mut(
image,
((x0 - y) as f32, (y0 + x) as f32),
((x0 + y) as f32, (y0 + x) as f32),
color,
);
draw_line_segment_mut(
image,
((x0 - x) as f32, (y0 - y) as f32),
((x0 + x) as f32, (y0 - y) as f32),
color,
);
draw_line_segment_mut(
image,
((x0 - y) as f32, (y0 - x) as f32),
((x0 + y) as f32, (y0 - x) as f32),
color,
);
x += 1;
if p < 0 {
p += 2 * x + 1;
} else {
y -= 1;
p += 2 * (x - y) + 1;
}
}
}
#[cfg(test)]
mod tests {
use crate::utils::ToRgba;