Skip to content

Commit

Permalink
Support raw straight RGBA format in Image.toByteData() (flutter#28293)
Browse files Browse the repository at this point in the history
  • Loading branch information
ColdPaleLight authored Aug 27, 2021
1 parent f843dd6 commit 7cf0c31
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 6 deletions.
7 changes: 6 additions & 1 deletion lib/ui/painting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1577,9 +1577,14 @@ class Paint {
enum ImageByteFormat {
/// Raw RGBA format.
///
/// Unencoded bytes, in RGBA row-primary form, 8 bits per channel.
/// Unencoded bytes, in RGBA row-primary form with premultiplied alpha, 8 bits per channel.
rawRgba,

/// Raw straight RGBA format.
///
/// Unencoded bytes, in RGBA row-primary form with straight alpha, 8 bits per channel.
rawStraightRgba,

/// Raw unmodified format.
///
/// Unencoded bytes, in the image's existing format. For example, a grayscale
Expand Down
18 changes: 13 additions & 5 deletions lib/ui/painting/image_encoding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ namespace {
// This must be kept in sync with the enum in painting.dart
enum ImageByteFormat {
kRawRGBA,
kRawStraightRGBA,
kRawUnmodified,
kPNG,
};
Expand Down Expand Up @@ -151,7 +152,8 @@ void ConvertImageToRaster(sk_sp<SkImage> image,
}

sk_sp<SkData> CopyImageByteData(sk_sp<SkImage> raster_image,
SkColorType color_type) {
SkColorType color_type,
SkAlphaType alpha_type) {
FML_DCHECK(raster_image);

SkPixmap pixmap;
Expand All @@ -162,14 +164,14 @@ sk_sp<SkData> CopyImageByteData(sk_sp<SkImage> raster_image,
}

// The color types already match. No need to swizzle. Return early.
if (pixmap.colorType() == color_type) {
if (pixmap.colorType() == color_type && pixmap.alphaType() == alpha_type) {
return SkData::MakeWithCopy(pixmap.addr(), pixmap.computeByteSize());
}

// Perform swizzle if the type doesnt match the specification.
auto surface = SkSurface::MakeRaster(
SkImageInfo::Make(raster_image->width(), raster_image->height(),
color_type, kPremul_SkAlphaType, nullptr));
color_type, alpha_type, nullptr));

if (!surface) {
FML_LOG(ERROR) << "Could not set up the surface for swizzle.";
Expand Down Expand Up @@ -205,10 +207,16 @@ sk_sp<SkData> EncodeImage(sk_sp<SkImage> raster_image, ImageByteFormat format) {
return png_image;
} break;
case kRawRGBA: {
return CopyImageByteData(raster_image, kRGBA_8888_SkColorType);
return CopyImageByteData(raster_image, kRGBA_8888_SkColorType,
kPremul_SkAlphaType);
} break;
case kRawStraightRGBA: {
return CopyImageByteData(raster_image, kRGBA_8888_SkColorType,
kUnpremul_SkAlphaType);
} break;
case kRawUnmodified: {
return CopyImageByteData(raster_image, raster_image->colorType());
return CopyImageByteData(raster_image, raster_image->colorType(),
raster_image->alphaType());
} break;
}

Expand Down
1 change: 1 addition & 0 deletions lib/web_ui/lib/src/ui/painting.dart
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ class ImageFilter {

enum ImageByteFormat {
rawRgba,
rawStraightRgba,
rawUnmodified,
png,
}
Expand Down
83 changes: 83 additions & 0 deletions testing/dart/encoding_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,22 @@ void main() {
expect(bytes, GrayscaleImage.bytesAsRgba);
});

test('Image.toByteData RGBA format works with transparent image', () async {
final Image image = await TransparentImage.load();
final ByteData data = (await image.toByteData())!;
final Uint8List bytes = data.buffer.asUint8List();
expect(bytes, hasLength(64));
expect(bytes, TransparentImage.bytesAsPremultipliedRgba);
});

test('Image.toByteData Straight RGBA format works with transparent image', () async {
final Image image = await TransparentImage.load();
final ByteData data = (await image.toByteData(format: ImageByteFormat.rawStraightRgba))!;
final Uint8List bytes = data.buffer.asUint8List();
expect(bytes, hasLength(64));
expect(bytes, TransparentImage.bytesAsStraightRgba);
});

test('Image.toByteData Unmodified format works with simple image', () async {
final Image image = await Square4x4Image.image;
final ByteData data = (await image.toByteData(format: ImageByteFormat.rawUnmodified))!;
Expand Down Expand Up @@ -124,6 +140,73 @@ class GrayscaleImage {
static List<int> get bytesUnmodified => <int>[255, 127, 127, 0];
}

class TransparentImage {
TransparentImage._();

static Future<Image> load() async {
final Uint8List bytes = await readFile('transparent_image.png');
final Completer<Image> completer = Completer<Image>();
decodeImageFromList(bytes, (Image image) => completer.complete(image));
return completer.future;
}

static List<int> get bytesAsPremultipliedRgba {
return <int>[
//First raw, solid colors
255, 0, 0, 255, // red
0, 255, 0, 255, // green
0, 0, 255, 255, // blue
136, 136, 136, 255, // grey

//Second raw, 50% transparent
127, 0, 0, 127, // red
0, 127, 0, 127, // green
0, 0, 127, 127, // blue
67, 67, 67, 127, // grey

//Third raw, 25% transparent
63, 0, 0, 63, // red
0, 63, 0, 63, // green
0, 0, 63, 63, // blue
33, 33, 33, 63, // grey

//Fourth raw, transparent
0, 0, 0, 0, // red
0, 0, 0, 0, // green
0, 0, 0, 0, // blue
0, 0, 0, 0, // grey
];
}

static List<int> get bytesAsStraightRgba {
return <int>[
//First raw, solid colors
255, 0, 0, 255, // red
0, 255, 0, 255, // green
0, 0, 255, 255, // blue
136, 136, 136, 255, // grey

//Second raw, 50% transparent
255, 0, 0, 127, // red
0, 255, 0, 127, // green
0, 0, 255, 127, // blue
135, 135, 135, 127, // grey

//Third raw, 25% transparent
255, 0, 0, 63, // red
0, 255, 0, 63, // green
0, 0, 255, 63, // blue
134, 134, 134, 63, // grey

//Fourth raw, transparent
0, 0, 0, 0, // red
0, 0, 0, 0, // green
0, 0, 0, 0, // blue
0, 0, 0, 0, // grey
];
}
}

Future<Uint8List> readFile(String fileName) async {
final File file = File(path.join('flutter', 'testing', 'resources', fileName));
return file.readAsBytes();
Expand Down
Binary file added testing/resources/transparent_image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 7cf0c31

Please sign in to comment.