diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..44ea687 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 Alex Butler + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..33e1a3f --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# ab-glyph +Glyph stuff. + +## [ab_glyph_rasterizer](rasterizer) [![](https://img.shields.io/crates/v/ab_glyph_rasterizer.svg)](https://crates.io/crates/ab_glyph_rasterizer) [![](https://docs.rs/ab_glyph_rasterizer/badge.svg)](https://docs.rs/ab_glyph_rasterizer) +Zero dependency coverage rasterization for lines, quadratic & cubic beziers. + +## Minimum supported rust compiler +All crates maintained with [latest stable rust](https://gist.github.com/alexheretic/d1e98d8433b602e57f5d0a9637927e0c). diff --git a/dev/benches/draw.rs b/dev/benches/draw.rs index d34fd21..1bff936 100644 --- a/dev/benches/draw.rs +++ b/dev/benches/draw.rs @@ -21,8 +21,11 @@ macro_rules! bench_draw { }); }); // ensure the byte array has changed (and not discarded by optimization?). - assert_ne!(&target as &[u8], &[0u8; $const_dimensions.0 * $const_dimensions.1] as &[u8]); - }} + assert_ne!( + &target as &[u8], + &[0u8; $const_dimensions.0 * $const_dimensions.1] as &[u8] + ); + }}; } /// Calls draw_* outline functions without timing the `for_each_pixel` (accumulation). @@ -45,8 +48,11 @@ macro_rules! bench_draw_outline { // draw into the byte array rasterizer.for_each_pixel(|idx, alpha| target[idx] = (alpha * 255.0) as u8); // ensure the byte array has changed (and not discarded by optimization?). - assert_ne!(&target as &[u8], &[0u8; $const_dimensions.0 * $const_dimensions.1] as &[u8]); - }} + assert_ne!( + &target as &[u8], + &[0u8; $const_dimensions.0 * $const_dimensions.1] as &[u8] + ); + }}; } /// Calls `for_each_pixel` on a pre-outlined rasterizer. @@ -68,8 +74,11 @@ macro_rules! bench_accumulate { }); }); // ensure the byte array has changed (and not discarded by optimization?). - assert_ne!(&target as &[u8], &[0u8; $const_dimensions.0 * $const_dimensions.1] as &[u8]); - }} + assert_ne!( + &target as &[u8], + &[0u8; $const_dimensions.0 * $const_dimensions.1] as &[u8] + ); + }}; } fn draw_ttf_w(c: &mut Criterion) { @@ -85,23 +94,48 @@ fn accumulate_ttf_w(c: &mut Criterion) { } fn draw_ttf_tailed_e(c: &mut Criterion) { - bench_draw!(c, "draw_ttf_tailed_e", dev::rasterize_ttf_tailed_e, (98, 158)); + bench_draw!( + c, + "draw_ttf_tailed_e", + dev::rasterize_ttf_tailed_e, + (98, 158) + ); } fn draw_otf_tailed_e(c: &mut Criterion) { - bench_draw!(c, "draw_otf_tailed_e", dev::rasterize_otf_tailed_e, (106, 183)); + bench_draw!( + c, + "draw_otf_tailed_e", + dev::rasterize_otf_tailed_e, + (106, 183) + ); } fn draw_ttf_biohazard(c: &mut Criterion) { - bench_draw!(c, "draw_ttf_biohazard", dev::rasterize_ttf_biohazard, (294, 269)); + bench_draw!( + c, + "draw_ttf_biohazard", + dev::rasterize_ttf_biohazard, + (294, 269) + ); } fn draw_outline_ttf_biohazard(c: &mut Criterion) { - bench_draw_outline!(c, "draw_outline_ttf_biohazard", dev::rasterize_ttf_biohazard, (294, 269)); + bench_draw_outline!( + c, + "draw_outline_ttf_biohazard", + dev::rasterize_ttf_biohazard, + (294, 269) + ); } fn accumulate_ttf_biohazard(c: &mut Criterion) { - bench_accumulate!(c, "accumulate_ttf_biohazard", dev::rasterize_ttf_biohazard, (294, 269)); + bench_accumulate!( + c, + "accumulate_ttf_biohazard", + dev::rasterize_ttf_biohazard, + (294, 269) + ); } criterion_group!( diff --git a/dev/tests/reference_otf_tailed_e.png b/dev/tests/reference_otf_tailed_e.png index 274ad1c..a517498 100644 Binary files a/dev/tests/reference_otf_tailed_e.png and b/dev/tests/reference_otf_tailed_e.png differ diff --git a/dev/tests/reference_ttf_biohazard.png b/dev/tests/reference_ttf_biohazard.png index e9262ab..0094252 100644 Binary files a/dev/tests/reference_ttf_biohazard.png and b/dev/tests/reference_ttf_biohazard.png differ diff --git a/dev/tests/reference_ttf_iota.png b/dev/tests/reference_ttf_iota.png index 5f46ab6..a7b8f7b 100644 Binary files a/dev/tests/reference_ttf_iota.png and b/dev/tests/reference_ttf_iota.png differ diff --git a/dev/tests/reference_ttf_tailed_e.png b/dev/tests/reference_ttf_tailed_e.png index 40ee2d4..7ca8079 100644 Binary files a/dev/tests/reference_ttf_tailed_e.png and b/dev/tests/reference_ttf_tailed_e.png differ diff --git a/dev/tests/reference_ttf_w.png b/dev/tests/reference_ttf_w.png index c194b42..b960380 100644 Binary files a/dev/tests/reference_ttf_w.png and b/dev/tests/reference_ttf_w.png differ diff --git a/rasterizer/Cargo.toml b/rasterizer/Cargo.toml index b029096..4711ce7 100644 --- a/rasterizer/Cargo.toml +++ b/rasterizer/Cargo.toml @@ -3,6 +3,11 @@ name = "ab_glyph_rasterizer" version = "0.1.0" authors = ["Alex Butler "] edition = "2018" +description = "Coverage rasterization for lines, quadratic & cubic beziers" +repository = "https://github.com/alexheretic/gfx-glyph" +keywords = ["text", "ttf", "otf", "font"] +license = "Apache-2.0" +readme="README.md" [dependencies] # no_std float stuff diff --git a/rasterizer/README.md b/rasterizer/README.md new file mode 100644 index 0000000..72337e6 --- /dev/null +++ b/rasterizer/README.md @@ -0,0 +1,51 @@ +ab_glyph_rasterizer +[![crates.io](https://img.shields.io/crates/v/ab_glyph_rasterizer.svg)](https://crates.io/crates/ab_glyph_rasterizer) +[![Documentation](https://docs.rs/ab_glyph_rasterizer/badge.svg)](https://docs.rs/ab_glyph_rasterizer) +=================== +Coverage rasterization for lines, quadratic & cubic beziers. +Useful for drawing .otf font glyphs. + +Inspired by [font-rs](https://github.com/raphlinus/font-rs) & +[stb_truetype](https://github.com/nothings/stb/blob/master/stb_truetype.h). + +## Example + +```rust +let mut rasterizer = ab_glyph_rasterizer::Rasterizer::new(106, 183); + +// draw a 300px 'ę' character +rasterizer.draw_cubic(point(103.0, 163.5), point(86.25, 169.25), point(77.0, 165.0), point(82.25, 151.5)); +rasterizer.draw_cubic(point(82.25, 151.5), point(86.75, 139.75), point(94.0, 130.75), point(102.0, 122.0)); +rasterizer.draw_line(point(102.0, 122.0), point(100.25, 111.25)); +rasterizer.draw_cubic(point(100.25, 111.25), point(89.0, 112.75), point(72.75, 114.25), point(58.5, 114.25)); +rasterizer.draw_cubic(point(58.5, 114.25), point(30.75, 114.25), point(18.5, 105.25), point(16.75, 72.25)); +rasterizer.draw_line(point(16.75, 72.25), point(77.0, 72.25)); +rasterizer.draw_cubic(point(77.0, 72.25), point(97.0, 72.25), point(105.25, 60.25), point(104.75, 38.5)); +rasterizer.draw_cubic(point(104.75, 38.5), point(104.5, 13.5), point(89.0, 0.75), point(54.25, 0.75)); +rasterizer.draw_cubic(point(54.25, 0.75), point(16.0, 0.75), point(0.0, 16.75), point(0.0, 64.0)); +rasterizer.draw_cubic(point(0.0, 64.0), point(0.0, 110.5), point(16.0, 128.0), point(56.5, 128.0)); +rasterizer.draw_cubic(point(56.5, 128.0), point(66.0, 128.0), point(79.5, 127.0), point(90.0, 125.0)); +rasterizer.draw_cubic(point(90.0, 125.0), point(78.75, 135.25), point(73.25, 144.5), point(70.75, 152.0)); +rasterizer.draw_cubic(point(70.75, 152.0), point(64.5, 169.0), point(75.5, 183.0), point(105.0, 170.5)); +rasterizer.draw_line(point(105.0, 170.5), point(103.0, 163.5)); +rasterizer.draw_cubic(point(55.0, 14.5), point(78.5, 14.5), point(88.5, 21.75), point(88.75, 38.75)); +rasterizer.draw_cubic(point(88.75, 38.75), point(89.0, 50.75), point(85.75, 59.75), point(73.5, 59.75)); +rasterizer.draw_line(point(73.5, 59.75), point(16.5, 59.75)); +rasterizer.draw_cubic(point(16.5, 59.75), point(17.25, 25.5), point(27.0, 14.5), point(55.0, 14.5)); +rasterizer.draw_line(point(55.0, 14.5), point(55.0, 14.5)); + +// iterate over the resultant pixel alphas, e.g. save pixel to a buffer +rasterizer.for_each_pixel(|index, alpha| { + // ... +}); +``` + +Rendering the resultant pixel alphas as 8-bit grey produces: + +![reference_otf_tailed_e](https://user-images.githubusercontent.com/2331607/78987793-ee95f480-7b26-11ea-91fb-e9f359d766f8.png) + +## no_std +no_std environments are supported using `alloc` & [`libm`](https://github.com/rust-lang/libm). +```toml +ab_glyph_rasterizer = { default-features = false, features = ["libm"] } +``` diff --git a/rasterizer/src/geometry.rs b/rasterizer/src/geometry.rs index ea8b36a..50bd7e9 100644 --- a/rasterizer/src/geometry.rs +++ b/rasterizer/src/geometry.rs @@ -1,14 +1,22 @@ +/// An (x, y) coordinate. #[derive(Clone, Copy, Debug, Default)] pub struct Point { pub x: f32, pub y: f32, } +/// [`Point`](struct.Point.html) constructor. +/// +/// ``` +/// use ab_glyph_rasterizer::{point, Point}; +/// let control: Point = point(0.1, 23.2); +/// ``` #[inline] pub fn point(x: f32, y: f32) -> Point { Point { x, y } } +/// Linear interpolation between points. #[inline] pub(crate) fn lerp(t: f32, p0: Point, p1: Point) -> Point { point(p0.x + t * (p1.x - p0.x), p0.y + t * (p1.y - p0.y)) diff --git a/rasterizer/src/lib.rs b/rasterizer/src/lib.rs index 88c57d2..e6870f4 100644 --- a/rasterizer/src/lib.rs +++ b/rasterizer/src/lib.rs @@ -1,3 +1,23 @@ +//! Coverage rasterization for lines, quadratic & cubic beziers. +//! Useful for drawing .otf font glyphs. +//! +//! ``` +//! use ab_glyph_rasterizer::Rasterizer; +//! # let (width, height) = (1, 1); +//! let mut rasterizer = Rasterizer::new(width, height); +//! +//! // draw outlines +//! # let [l0, l1, q0, q1, q2, c0, c1, c2, c3] = [ab_glyph_rasterizer::point(0.0, 0.0); 9]; +//! rasterizer.draw_line(l0, l1); +//! rasterizer.draw_quad(q0, q1, q2); +//! rasterizer.draw_cubic(c0, c1, c2, c3); +//! +//! // iterate over the resultant pixel alphas, e.g. save pixel to a buffer +//! rasterizer.for_each_pixel(|index, alpha| { +//! // ... +//! }); +//! ``` + #![cfg_attr(not(feature = "std"), no_std)] #[cfg(not(feature = "std"))] #[macro_use] @@ -9,5 +29,5 @@ mod nostd_float; mod geometry; mod raster; -pub use geometry::{Point, point}; +pub use geometry::{point, Point}; pub use raster::Rasterizer; diff --git a/rasterizer/src/nostd_float.rs b/rasterizer/src/nostd_float.rs index 1a650f0..8da4739 100644 --- a/rasterizer/src/nostd_float.rs +++ b/rasterizer/src/nostd_float.rs @@ -1,3 +1,4 @@ +/// Basic required float operations. pub(crate) trait FloatExt { fn floor(self) -> Self; fn ceil(self) -> Self; diff --git a/rasterizer/src/raster.rs b/rasterizer/src/raster.rs index 83bbde5..ab9dd3b 100644 --- a/rasterizer/src/raster.rs +++ b/rasterizer/src/raster.rs @@ -15,6 +15,12 @@ pub struct Rasterizer { } impl Rasterizer { + /// Allocates a new rasterizer that can draw onto a `width` x `height` alpha grid. + /// + /// ``` + /// use ab_glyph_rasterizer::Rasterizer; + /// let mut rasterizer = Rasterizer::new(14, 38); + /// ``` pub fn new(width: usize, height: usize) -> Self { Self { width, @@ -23,10 +29,24 @@ impl Rasterizer { } } + /// Returns the dimensions the rasterizer was built to draw to. + /// + /// ``` + /// # use ab_glyph_rasterizer::*; + /// let rasterizer = Rasterizer::new(9, 8); + /// assert_eq!((9, 8), rasterizer.dimensions()); + /// ``` pub fn dimensions(&self) -> (usize, usize) { (self.width, self.height) } + /// Adds a straight line from `p0` to `p1` to the outline. + /// + /// ``` + /// # use ab_glyph_rasterizer::*; + /// # let mut rasterizer = Rasterizer::new(9, 8); + /// rasterizer.draw_line(point(0.0, 0.48), point(1.22, 0.48)); + /// ``` pub fn draw_line(&mut self, p0: Point, p1: Point) { if (p0.y - p1.y).abs() < core::f32::EPSILON { return; @@ -80,6 +100,13 @@ impl Rasterizer { } } + /// Adds a quadratic Bézier curve from `p0` to `p2` to the outline using `p1` as the control. + /// + /// ``` + /// # use ab_glyph_rasterizer::*; + /// # let mut rasterizer = Rasterizer::new(14, 38); + /// rasterizer.draw_quad(point(6.2, 34.5), point(7.2, 34.5), point(9.2, 34.0)); + /// ``` pub fn draw_quad(&mut self, p0: Point, p1: Point, p2: Point) { let devx = p0.x - 2.0 * p1.x + p2.x; let devy = p0.y - 2.0 * p1.y + p2.y; @@ -102,6 +129,19 @@ impl Rasterizer { self.draw_line(p, p2); } + /// Adds a cubic Bézier curve from `p0` to `p3` to the outline using `p1` as the control + /// at the beginning of the curve and `p2` at the end of the curve. + /// + /// ``` + /// # use ab_glyph_rasterizer::*; + /// # let mut rasterizer = Rasterizer::new(12, 20); + /// rasterizer.draw_cubic( + /// point(10.3, 16.4), + /// point(8.6, 16.9), + /// point(7.7, 16.5), + /// point(8.2, 15.2), + /// ); + /// ``` pub fn draw_cubic(&mut self, p0: Point, p1: Point, p2: Point, p3: Point) { self.tesselate_cubic(p0, p1, p2, p3, 0); } @@ -144,6 +184,17 @@ impl Rasterizer { } } + /// Run a callback for each pixel index & alpha, with indices in `0..width * height`. + /// + /// ``` + /// # use ab_glyph_rasterizer::*; + /// # let (width, height) = (1, 1); + /// # let mut rasterizer = Rasterizer::new(width, height); + /// let mut pixels = vec![0u8; width * height]; + /// rasterizer.for_each_pixel(|index, alpha| { + /// pixels[index] = (alpha * 255.0).round() as u8; + /// }); + /// ``` pub fn for_each_pixel(&self, mut px_fn: O) { let mut acc = 0.0; self.a[..self.width * self.height] @@ -155,12 +206,31 @@ impl Rasterizer { }); } + /// Run a callback for each pixel x position, y position & alpha. + /// + /// Convenience wrapper for `for_each_pixel`. + /// + /// ``` + /// # use ab_glyph_rasterizer::*; + /// # let (width, height) = (1, 1); + /// # let mut rasterizer = Rasterizer::new(width, height); + /// # struct Img; + /// # impl Img { fn set_pixel(&self, x: u32, y: u32, a: u8) {} } + /// # let image = Img; + /// rasterizer.for_each_pixel_2d(|x, y, alpha| { + /// image.set_pixel(x, y, (alpha * 255.0).round() as u8); + /// }); + /// ``` pub fn for_each_pixel_2d(&self, mut px_fn: O) { let width32 = self.width as u32; self.for_each_pixel(|idx, alpha| px_fn(idx as u32 % width32, idx as u32 / width32, alpha)); } } +/// ``` +/// let rasterizer = ab_glyph_rasterizer::Rasterizer::new(3, 4); +/// assert_eq!(&format!("{:?}", rasterizer), "Rasterizer { width: 3, height: 4 }"); +/// ``` impl core::fmt::Debug for Rasterizer { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("Rasterizer") diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..7d2cf54 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +merge_imports = true