diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart index 4fb8203945cc6..8976f5e2dc017 100644 --- a/lib/ui/painting.dart +++ b/lib/ui/painting.dart @@ -2129,8 +2129,9 @@ Future _decodeImageFromListAsync(Uint8List list, /// Convert an array of pixel values into an [Image] object. /// -/// The `pixels` parameter is the pixel data in the encoding described by -/// `format`. +/// The `pixels` parameter is the pixel data. They are packed in bytes in the +/// order described by `format`, then grouped in rows, from left to right, +/// then top to bottom. /// /// The `rowBytes` parameter is the number of bytes consumed by each row of /// pixels in the data buffer. If unspecified, it defaults to `width` multiplied @@ -5637,8 +5638,9 @@ class ImageDescriptor extends NativeFieldWrapperClass1 { /// Creates an image descriptor from raw image pixels. /// - /// The `pixels` parameter is the pixel data in the encoding described by - /// `format`. + /// The `pixels` parameter is the pixel data. They are packed in bytes in the + /// order described by `pixelFormat`, then grouped in rows, from left to right, + /// then top to bottom. /// /// The `rowBytes` parameter is the number of bytes consumed by each row of /// pixels in the data buffer. If unspecified, it defaults to `width` multiplied diff --git a/lib/web_ui/test/html/image_test.dart b/lib/web_ui/test/html/image_test.dart index 6b6ec48bd312c..318ed62d3a6d7 100644 --- a/lib/web_ui/test/html/image_test.dart +++ b/lib/web_ui/test/html/image_test.dart @@ -72,6 +72,32 @@ Future _encodeToHtmlThenDecode( return (await (await descriptor.instantiateCodec()).getNextFrame()).image; } +// This utility function detects how the current Web engine decodes pixel data. +// +// The HTML renderer uses the BMP format to display pixel data, but it used to +// use a wrong implementation. The bug has been fixed, but the fix breaks apps +// that had to provide incorrect data to work around this issue. This function +// is used in the migration guide to assist libraries that would like to run on +// both pre- and post-patch engines by testing the current behavior on a single +// pixel, making use the fact that the patch fixes the pixel order. +// +// The `format` argument is used for testing. In the actual code it should be +// replaced by `PixelFormat.rgba8888`. +// +// See also: +// +// * Patch: https://github.com/flutter/engine/pull/29448 +// * Migration guide: https://docs.flutter.dev/release/breaking-changes/raw-images-on-web-uses-correct-origin-and-colors +Future rawImageUsesCorrectBehavior(PixelFormat format) async { + final ImageDescriptor descriptor = ImageDescriptor.raw( + await ImmutableBuffer.fromUint8List(Uint8List.fromList([0xED, 0, 0, 0xFF])), + width: 1, height: 1, pixelFormat: format); + final Image image = (await (await descriptor.instantiateCodec()).getNextFrame()).image; + final Uint8List resultPixels = Uint8List.sublistView( + (await image.toByteData(format: ImageByteFormat.rawStraightRgba))!); + return resultPixels[0] == 0xED; +} + Future testMain() async { test('Correctly encodes an opaque image', () async { // A 2x2 testing image without transparency. @@ -145,4 +171,9 @@ Future testMain() async { ); expect(actualPixels, listEqual(benchmarkPixels, tolerance: 1)); }); + + test('The behavior detector works correctly', () async { + expect(await rawImageUsesCorrectBehavior(PixelFormat.rgba8888), true); + expect(await rawImageUsesCorrectBehavior(PixelFormat.bgra8888), false); + }); }