@@ -272,6 +272,118 @@ impl Buffer<'_> {
272272 }
273273}
274274
275+ /// Pixel helper accessors.
276+ impl Buffer < ' _ > {
277+ /// Iterate over each row of pixels.
278+ ///
279+ /// Each slice returned from the iterator has a length of `buffer.width()`.
280+ ///
281+ /// # Examples
282+ ///
283+ /// Fill each row with alternating black and white.
284+ ///
285+ /// ```no_run
286+ /// # let buffer: softbuffer::Buffer<'_> = unimplemented!();
287+ /// for (y, row) in buffer.pixel_rows().enumerate() {
288+ /// if y % 2 == 0 {
289+ /// row.fill(0x00ffffff);
290+ /// } else {
291+ /// row.fill(0x00000000);
292+ /// }
293+ /// }
294+ /// ```
295+ ///
296+ /// Fill a red rectangle while skipping over regions that don't need to be modified.
297+ ///
298+ /// ```no_run
299+ /// # let buffer: softbuffer::Buffer<'_> = unimplemented!();
300+ /// let x = 100;
301+ /// let y = 200;
302+ /// let width = 10;
303+ /// let height = 20;
304+ ///
305+ /// for row in buffer.pixel_rows().skip(y).take(height) {
306+ /// for pixel in row.iter_mut().skip(x).take(width) {
307+ /// *pixel = 0x00ff0000;
308+ /// }
309+ /// }
310+ /// ```
311+ ///
312+ /// Iterate over each pixel (similar to what the [`pixels_iter`] method does).
313+ ///
314+ /// [`pixels_iter`]: Self::pixels_iter
315+ ///
316+ /// ```no_run
317+ /// # let buffer: softbuffer::Buffer<'_> = unimplemented!();
318+ /// # let pixel_value = |x, y| 0x00000000;
319+ /// for (y, row) in buffer.pixel_rows().enumerate() {
320+ /// for (x, pixel) in row.iter_mut().enumerate() {
321+ /// *pixel = pixel_value(x, y);
322+ /// }
323+ /// }
324+ /// ```
325+ #[ inline]
326+ pub fn pixel_rows (
327+ & mut self ,
328+ ) -> impl DoubleEndedIterator < Item = & mut [ u32 ] > + ExactSizeIterator {
329+ let width = self . width ( ) . get ( ) as usize ;
330+ let pixels = self . buffer_impl . pixels_mut ( ) ;
331+ assert_eq ! ( pixels. len( ) % width, 0 , "buffer must be multiple of width" ) ;
332+ // NOTE: This won't panic because `width` is `NonZeroU32`
333+ pixels. chunks_mut ( width)
334+ }
335+
336+ /// Iterate over each pixel in the data.
337+ ///
338+ /// The returned iterator contains the `x` and `y` coordinates and a mutable reference to the
339+ /// pixel at that position.
340+ ///
341+ /// # Examples
342+ ///
343+ /// Draw a red rectangle with a margin of 10 pixels, and fill the background with blue.
344+ ///
345+ /// ```no_run
346+ /// # let buffer: softbuffer::Buffer<'_> = unimplemented!();
347+ /// let width = buffer.width().get();
348+ /// let height = buffer.height().get();
349+ /// let left = 10;
350+ /// let top = 10;
351+ /// let right = width.saturating_sub(10);
352+ /// let bottom = height.saturating_sub(10);
353+ ///
354+ /// for (x, y, pixel) in buffer.pixels_iter() {
355+ /// if (left..=right).contains(&x) && (top..=bottom).contains(&y) {
356+ /// // Inside rectangle.
357+ /// *pixel = 0x00ff0000;
358+ /// } else {
359+ /// // Outside rectangle.
360+ /// *pixel = 0x000000ff;
361+ /// };
362+ /// }
363+ /// ```
364+ ///
365+ /// Iterate over the pixel data in reverse, and draw a red rectangle in the top-left corner.
366+ ///
367+ /// ```no_run
368+ /// # let buffer: softbuffer::Buffer<'_> = unimplemented!();
369+ /// // Only reverses iteration order, x and y are still relative to the top-left corner.
370+ /// for (x, y, pixel) in buffer.pixels_iter().rev() {
371+ /// if x <= 100 && y <= 100 {
372+ /// *pixel = 0x00ff0000;
373+ /// }
374+ /// }
375+ /// ```
376+ #[ inline]
377+ pub fn pixels_iter ( & mut self ) -> impl DoubleEndedIterator < Item = ( u32 , u32 , & mut u32 ) > {
378+ self . pixel_rows ( ) . enumerate ( ) . flat_map ( |( y, pixels) | {
379+ pixels
380+ . iter_mut ( )
381+ . enumerate ( )
382+ . map ( move |( x, pixel) | ( x as u32 , y as u32 , pixel) )
383+ } )
384+ }
385+ }
386+
275387impl ops:: Deref for Buffer < ' _ > {
276388 type Target = [ u32 ] ;
277389
0 commit comments