@@ -770,23 +770,7 @@ impl Image {
770770 SharedImageBuffer :: RGBA8Premultiplied ( buffer) => SharedPixelBuffer :: < Rgba8Pixel > {
771771 width : buffer. width ,
772772 height : buffer. height ,
773- data : buffer
774- . data
775- . into_iter ( )
776- . map ( |rgba_premul| {
777- if rgba_premul. a == 0 {
778- Rgba8Pixel :: new ( 0 , 0 , 0 , 0 )
779- } else {
780- let af = rgba_premul. a as f32 / 255.0 ;
781- Rgba8Pixel {
782- r : ( rgba_premul. r as f32 * 255. / af) as u8 ,
783- g : ( rgba_premul. g as f32 * 255. / af) as u8 ,
784- b : ( rgba_premul. b as f32 * 255. / af) as u8 ,
785- a : rgba_premul. a ,
786- }
787- }
788- } )
789- . collect ( ) ,
773+ data : buffer. data . into_iter ( ) . map ( Image :: premultiplied_rgba_to_rgba) . collect ( ) ,
790774 } ,
791775 } )
792776 }
@@ -804,28 +788,43 @@ impl Image {
804788 SharedImageBuffer :: RGBA8 ( buffer) => SharedPixelBuffer :: < Rgba8Pixel > {
805789 width : buffer. width ,
806790 height : buffer. height ,
807- data : buffer
808- . data
809- . into_iter ( )
810- . map ( |rgba| {
811- if rgba. a == 255 {
812- rgba
813- } else {
814- let af = rgba. a as f32 / 255.0 ;
815- Rgba8Pixel {
816- r : ( rgba. r as f32 * af / 255. ) as u8 ,
817- g : ( rgba. g as f32 * af / 255. ) as u8 ,
818- b : ( rgba. b as f32 * af / 255. ) as u8 ,
819- a : rgba. a ,
820- }
821- }
822- } )
823- . collect ( ) ,
791+ data : buffer. data . into_iter ( ) . map ( Image :: rgba_to_premultiplied_rgba) . collect ( ) ,
824792 } ,
825793 SharedImageBuffer :: RGBA8Premultiplied ( buffer) => buffer,
826794 } )
827795 }
828796
797+ /// Returns the pixel converted from premultiplied RGBA to RGBA.
798+ fn premultiplied_rgba_to_rgba ( pixel : Rgba8Pixel ) -> Rgba8Pixel {
799+ if pixel. a == 0 {
800+ Rgba8Pixel :: new ( 0 , 0 , 0 , 0 )
801+ } else {
802+ let af = pixel. a as u32 ;
803+ let round = ( af / 2 ) as u32 ;
804+ Rgba8Pixel {
805+ r : ( ( pixel. r as u32 * 255 + round) / af) . min ( 255 ) as u8 ,
806+ g : ( ( pixel. g as u32 * 255 + round) / af) . min ( 255 ) as u8 ,
807+ b : ( ( pixel. b as u32 * 255 + round) / af) . min ( 255 ) as u8 ,
808+ a : pixel. a ,
809+ }
810+ }
811+ }
812+
813+ /// Returns the pixel converted from RGBA to premultiplied RGBA.
814+ fn rgba_to_premultiplied_rgba ( pixel : Rgba8Pixel ) -> Rgba8Pixel {
815+ if pixel. a == 255 {
816+ pixel
817+ } else {
818+ let af = pixel. a as u32 ;
819+ Rgba8Pixel {
820+ r : ( ( ( pixel. r as u32 * af + 128 ) * 257 ) >> 16 ) as u8 ,
821+ g : ( ( ( pixel. g as u32 * af + 128 ) * 257 ) >> 16 ) as u8 ,
822+ b : ( ( ( pixel. b as u32 * af + 128 ) * 257 ) >> 16 ) as u8 ,
823+ a : pixel. a ,
824+ }
825+ }
826+ }
827+
829828 /// Returns the [WGPU](http://wgpu.rs) 26.x texture that this image wraps; returns None if the image does not
830829 /// hold such a previously wrapped texture.
831830 ///
@@ -1472,3 +1471,52 @@ pub struct BorrowedOpenGLTexture {
14721471 /// Origin of the texture when rendering.
14731472 pub origin : BorrowedOpenGLTextureOrigin ,
14741473}
1474+
1475+ #[ cfg( test) ]
1476+ mod tests {
1477+ use crate :: graphics:: Rgba8Pixel ;
1478+
1479+ use super :: Image ;
1480+
1481+ #[ test]
1482+ fn test_premultiplied_to_rgb_zero_alpha ( ) {
1483+ let pixel = Rgba8Pixel :: new ( 5 , 10 , 15 , 0 ) ;
1484+ let converted = Image :: premultiplied_rgba_to_rgba ( pixel) ;
1485+ assert_eq ! ( converted, Rgba8Pixel :: new( 0 , 0 , 0 , 0 ) ) ;
1486+ }
1487+
1488+ #[ test]
1489+ fn test_premultiplied_to_rgb_full_alpha ( ) {
1490+ let pixel = Rgba8Pixel :: new ( 5 , 10 , 15 , 255 ) ;
1491+ let converted = Image :: premultiplied_rgba_to_rgba ( pixel) ;
1492+ assert_eq ! ( converted, Rgba8Pixel :: new( 5 , 10 , 15 , 255 ) ) ;
1493+ }
1494+
1495+ #[ test]
1496+ fn test_premultiplied_to_rgb ( ) {
1497+ let pixel = Rgba8Pixel :: new ( 5 , 10 , 15 , 128 ) ;
1498+ let converted = Image :: premultiplied_rgba_to_rgba ( pixel) ;
1499+ assert_eq ! ( converted, Rgba8Pixel :: new( 10 , 20 , 30 , 128 ) ) ;
1500+ }
1501+
1502+ #[ test]
1503+ fn test_rgb_to_premultiplied_zero_alpha ( ) {
1504+ let pixel = Rgba8Pixel :: new ( 10 , 20 , 30 , 0 ) ;
1505+ let converted = Image :: rgba_to_premultiplied_rgba ( pixel) ;
1506+ assert_eq ! ( converted, Rgba8Pixel :: new( 0 , 0 , 0 , 0 ) ) ;
1507+ }
1508+
1509+ #[ test]
1510+ fn test_rgb_to_premultiplied_full_alpha ( ) {
1511+ let pixel = Rgba8Pixel :: new ( 10 , 20 , 30 , 255 ) ;
1512+ let converted = Image :: rgba_to_premultiplied_rgba ( pixel) ;
1513+ assert_eq ! ( converted, Rgba8Pixel :: new( 10 , 20 , 30 , 255 ) ) ;
1514+ }
1515+
1516+ #[ test]
1517+ fn test_rgb_to_premultiplied ( ) {
1518+ let pixel = Rgba8Pixel :: new ( 10 , 20 , 30 , 128 ) ;
1519+ let converted = Image :: rgba_to_premultiplied_rgba ( pixel) ;
1520+ assert_eq ! ( converted, Rgba8Pixel :: new( 5 , 10 , 15 , 128 ) ) ;
1521+ }
1522+ }
0 commit comments