@@ -10,7 +10,7 @@ use crate::color::{FromColor, FromPrimitive, Luma, LumaA, Rgb, Rgba};
1010use crate :: error:: {
1111 ImageResult , ParameterError , ParameterErrorKind , UnsupportedError , UnsupportedErrorKind ,
1212} ;
13- use crate :: flat:: { FlatSamples , SampleLayout } ;
13+ use crate :: flat:: { FlatSamples , SampleLayout , ViewOfPixel } ;
1414use crate :: math:: Rect ;
1515use crate :: metadata:: cicp:: { CicpApplicable , CicpPixelCast , CicpRgb , ColorComponentForCicp } ;
1616use crate :: traits:: { EncodableLayout , Pixel , PixelWithColorType } ;
@@ -1238,6 +1238,16 @@ where
12381238 * self . get_pixel ( x, y)
12391239 }
12401240
1241+ fn to_pixel_view ( & self ) -> Option < ViewOfPixel < ' _ , Self :: Pixel > > {
1242+ let samples = FlatSamples {
1243+ samples : & * self . data ,
1244+ layout : self . sample_layout ( ) ,
1245+ color_hint : None ,
1246+ } ;
1247+
1248+ samples. into_view ( ) . ok ( )
1249+ }
1250+
12411251 /// Returns the pixel located at (x, y), ignoring bounds checking.
12421252 #[ inline( always) ]
12431253 unsafe fn unsafe_get_pixel ( & self , x : u32 , y : u32 ) -> P {
@@ -1280,6 +1290,61 @@ where
12801290 self . get_pixel_mut ( x, y) . blend ( & p) ;
12811291 }
12821292
1293+ fn copy_from_samples (
1294+ & mut self ,
1295+ view : ViewOfPixel < ' _ , Self :: Pixel > ,
1296+ x : u32 ,
1297+ y : u32 ,
1298+ ) -> ImageResult < ( ) > {
1299+ let ( width, height) = view. dimensions ( ) ;
1300+ let pix_stride = usize:: from ( <Self :: Pixel as Pixel >:: CHANNEL_COUNT ) ;
1301+ Rect :: from_image_at ( & view, x, y) . test_in_bounds ( self ) ?;
1302+
1303+ if width == 0 || height == 0 || pix_stride == 0 {
1304+ return Ok ( ( ) ) ;
1305+ }
1306+
1307+ // Since this image is not empty, all its indices fit into `usize` as they address the
1308+ // memory resident buffer of `self`.
1309+ let row_len = width as usize * pix_stride;
1310+ let img_sh = self . width as usize ;
1311+
1312+ let ( sw, sh) = view. strides_wh ( ) ;
1313+ let view_samples: & [ _ ] = view. samples ( ) ;
1314+ let inner = self . inner_pixels_mut ( ) ;
1315+
1316+ let img_pixel_indices_unchecked =
1317+ |x : u32 , y : u32 | ( y as usize * img_sh + x as usize ) * pix_stride;
1318+
1319+ // Can we use row-by-row byte copy?
1320+ if sw == pix_stride {
1321+ for j in 0 ..height {
1322+ let start = img_pixel_indices_unchecked ( x, j + y) ;
1323+ let img_row = & mut inner[ start..] [ ..row_len] ;
1324+ let view_row = & view_samples[ j as usize * sh..] [ ..row_len] ;
1325+ img_row. copy_from_slice ( view_row) ;
1326+ }
1327+
1328+ return Ok ( ( ) ) ;
1329+ }
1330+
1331+ // Fallback behavior.
1332+ for j in 0 ..height {
1333+ let img_start = img_pixel_indices_unchecked ( x, j + y) ;
1334+ let img_row = & mut inner[ img_start..] [ ..row_len] ;
1335+ let pixels = img_row. chunks_exact_mut ( pix_stride) ;
1336+
1337+ let view_start = j as usize * sh;
1338+
1339+ for ( i, sp) in pixels. enumerate ( ) {
1340+ let view_pixel = & view_samples[ i * sw + view_start..] [ ..pix_stride] ;
1341+ sp. copy_from_slice ( view_pixel) ;
1342+ }
1343+ }
1344+
1345+ Ok ( ( ) )
1346+ }
1347+
12831348 fn copy_within ( & mut self , source : Rect , x : u32 , y : u32 ) -> bool {
12841349 let Rect {
12851350 x : sx,
@@ -1769,8 +1834,8 @@ mod test {
17691834 use crate :: math:: Rect ;
17701835 use crate :: metadata:: Cicp ;
17711836 use crate :: metadata:: CicpTransform ;
1772- use crate :: GenericImage as _;
17731837 use crate :: ImageFormat ;
1838+ use crate :: { GenericImage as _, GenericImageView as _} ;
17741839 use crate :: { Luma , LumaA , Pixel , Rgb , Rgba } ;
17751840 use num_traits:: Zero ;
17761841
@@ -2131,6 +2196,160 @@ mod test {
21312196 let result = target. copy_from_color_space ( & source, options) ;
21322197 assert ! ( matches!( result, Err ( crate :: ImageError :: Parameter ( _) ) ) ) ;
21332198 }
2199+
2200+ /// We specialize copy_from on types that provide `as_samples` so test that.
2201+ #[ test]
2202+ fn copy_from_subimage_to_middle ( ) {
2203+ let mut source = RgbImage :: new ( 16 , 16 ) ;
2204+ let mut target = RgbImage :: new ( 16 , 16 ) ;
2205+
2206+ source. put_pixel ( 8 , 8 , Rgb ( [ 255 , 8 , 8 ] ) ) ;
2207+ source. put_pixel ( 9 , 8 , Rgb ( [ 255 , 9 , 8 ] ) ) ;
2208+ source. put_pixel ( 9 , 9 , Rgb ( [ 255 , 9 , 9 ] ) ) ;
2209+
2210+ let view = source. view ( 8 , 8 , 2 , 2 ) ;
2211+ assert ! ( target. copy_from( & * view, 4 , 4 ) . is_ok( ) ) ;
2212+
2213+ // Check the pixel was copied.
2214+ assert_eq ! ( * target. get_pixel( 4 , 4 ) , Rgb ( [ 255 , 8 , 8 ] ) ) ;
2215+ assert_eq ! ( * target. get_pixel( 5 , 4 ) , Rgb ( [ 255 , 9 , 8 ] ) ) ;
2216+ assert_eq ! ( * target. get_pixel( 5 , 5 ) , Rgb ( [ 255 , 9 , 9 ] ) ) ;
2217+
2218+ // Check that were the only copied pixel.
2219+ assert_eq ! (
2220+ target. iter( ) . copied( ) . map( usize :: from) . sum:: <usize >( ) ,
2221+ 3 * ( 255 + 8 + 9 )
2222+ ) ;
2223+ }
2224+
2225+ #[ test]
2226+ fn copy_from_band ( ) {
2227+ let source = RgbImage :: from_fn ( 16 , 8 , |x, y| Rgb ( [ x as u8 , y as u8 , 0 ] ) ) ;
2228+ let mut target = RgbImage :: new ( 16 , 16 ) ;
2229+
2230+ assert ! ( target. copy_from( & source, 0 , 4 ) . is_ok( ) ) ;
2231+
2232+ let lhs = source. chunks_exact ( 48 ) ;
2233+ let rhs = target. chunks_exact ( 48 ) . skip ( 4 ) . take ( 8 ) ;
2234+
2235+ assert ! ( lhs. eq( rhs) ) ;
2236+ }
2237+
2238+ #[ test]
2239+ fn copy_from_pixel ( ) {
2240+ let bg = Rgb ( [ 255 , 0 , 128 ] ) ;
2241+ let samples = crate :: flat:: FlatSamples :: with_monocolor ( & bg, 4 , 4 ) ;
2242+ let source = samples. as_view ( ) . unwrap ( ) ;
2243+
2244+ let mut target = RgbImage :: new ( 16 , 16 ) ;
2245+ assert ! ( target. copy_from( & source, 4 , 4 ) . is_ok( ) ) ;
2246+
2247+ for i in 4 ..8 {
2248+ for j in 4 ..8 {
2249+ assert_eq ! ( * target. get_pixel( i, j) , bg) ;
2250+ }
2251+ }
2252+
2253+ assert_eq ! (
2254+ target. iter( ) . copied( ) . map( usize :: from) . sum:: <usize >( ) ,
2255+ 16 * ( 255 + 128 )
2256+ ) ;
2257+ }
2258+
2259+ #[ test]
2260+ fn copy_from_strided ( ) {
2261+ #[ rustfmt:: skip]
2262+ let sample_data = [
2263+ 1 , 0xff , 0 , 0 , 2 , 0xff ,
2264+ 3 , 0xff , 0 , 0 , 4 , 0xff
2265+ ] ;
2266+
2267+ let samples = crate :: flat:: FlatSamples {
2268+ samples : & sample_data,
2269+ layout : crate :: flat:: SampleLayout {
2270+ channels : 2 ,
2271+ channel_stride : 1 ,
2272+ width : 2 ,
2273+ width_stride : 4 ,
2274+ height : 2 ,
2275+ height_stride : 6 ,
2276+ } ,
2277+ color_hint : None ,
2278+ } ;
2279+
2280+ let source = samples. as_view :: < LumaA < u8 > > ( ) . unwrap ( ) ;
2281+ let mut target = crate :: GrayAlphaImage :: new ( 16 , 16 ) ;
2282+ assert ! ( target. copy_from( & source, 4 , 4 ) . is_ok( ) ) ;
2283+
2284+ assert_eq ! ( * target. get_pixel( 4 , 4 ) , LumaA ( [ 1 , 0xff ] ) ) ;
2285+ assert_eq ! ( * target. get_pixel( 5 , 4 ) , LumaA ( [ 2 , 0xff ] ) ) ;
2286+ assert_eq ! ( * target. get_pixel( 4 , 5 ) , LumaA ( [ 3 , 0xff ] ) ) ;
2287+ assert_eq ! ( * target. get_pixel( 5 , 5 ) , LumaA ( [ 4 , 0xff ] ) ) ;
2288+
2289+ assert_eq ! (
2290+ target. iter( ) . copied( ) . map( usize :: from) . sum:: <usize >( ) ,
2291+ sample_data. iter( ) . copied( ) . map( usize :: from) . sum:: <usize >( ) ,
2292+ ) ;
2293+ }
2294+
2295+ #[ test]
2296+ fn copy_from_strided_subimage ( ) {
2297+ #[ rustfmt:: skip]
2298+ let sample_data = [
2299+ 1 , 0xff , 0 , 0 , 2 , 0xff ,
2300+ 3 , 0xff , 0 , 0 , 4 , 0xff
2301+ ] ;
2302+
2303+ let samples = crate :: flat:: FlatSamples {
2304+ samples : & sample_data,
2305+ layout : crate :: flat:: SampleLayout {
2306+ channels : 2 ,
2307+ channel_stride : 1 ,
2308+ width : 2 ,
2309+ width_stride : 4 ,
2310+ height : 2 ,
2311+ height_stride : 6 ,
2312+ } ,
2313+ color_hint : None ,
2314+ } ;
2315+
2316+ let view = samples. as_view :: < LumaA < u8 > > ( ) . unwrap ( ) ;
2317+ let source = view. view ( 1 , 0 , 1 , 2 ) ;
2318+
2319+ let mut target = crate :: GrayAlphaImage :: new ( 16 , 16 ) ;
2320+ assert ! ( target. copy_from( & * source, 4 , 4 ) . is_ok( ) ) ;
2321+
2322+ assert_eq ! ( * target. get_pixel( 4 , 4 ) , LumaA ( [ 2 , 0xff ] ) ) ;
2323+ assert_eq ! ( * target. get_pixel( 4 , 5 ) , LumaA ( [ 4 , 0xff ] ) ) ;
2324+
2325+ assert_eq ! (
2326+ target. iter( ) . copied( ) . map( usize :: from) . sum:: <usize >( ) ,
2327+ 2usize + 0xff + 4 + 0xff
2328+ ) ;
2329+ }
2330+
2331+ #[ test]
2332+ fn copy_from_subimage_subimage ( ) {
2333+ let mut source = RgbImage :: new ( 16 , 16 ) ;
2334+ let mut target = RgbImage :: new ( 16 , 16 ) ;
2335+
2336+ source. put_pixel ( 8 , 8 , Rgb ( [ 255 , 8 , 8 ] ) ) ;
2337+ source. put_pixel ( 9 , 8 , Rgb ( [ 255 , 9 , 8 ] ) ) ;
2338+ source. put_pixel ( 9 , 9 , Rgb ( [ 255 , 9 , 9 ] ) ) ;
2339+
2340+ let view = source. view ( 8 , 8 , 2 , 2 ) ;
2341+ let view = view. view ( 1 , 0 , 1 , 1 ) ;
2342+ assert ! ( target. copy_from( & * view, 4 , 4 ) . is_ok( ) ) ;
2343+
2344+ // Check the pixel was copied.
2345+ assert_eq ! ( * target. get_pixel( 4 , 4 ) , Rgb ( [ 255 , 9 , 8 ] ) ) ;
2346+
2347+ // Check that was the only copied pixel.
2348+ assert_eq ! (
2349+ target. iter( ) . copied( ) . map( usize :: from) . sum:: <usize >( ) ,
2350+ 255 + 9 + 8
2351+ ) ;
2352+ }
21342353}
21352354
21362355#[ cfg( test) ]
0 commit comments