Support raw straight RGBA format in Image.toByteData() (flutter/engine#28293)

This commit is contained in:
ColdPaleLight 2021-08-28 01:11:01 +08:00 committed by GitHub
parent 391934cf47
commit d90a23b4ae
5 changed files with 103 additions and 6 deletions

View File

@ -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

View File

@ -31,6 +31,7 @@ namespace {
// This must be kept in sync with the enum in painting.dart
enum ImageByteFormat {
kRawRGBA,
kRawStraightRGBA,
kRawUnmodified,
kPNG,
};
@ -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;
@ -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.";
@ -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;
}

View File

@ -425,6 +425,7 @@ class ImageFilter {
enum ImageByteFormat {
rawRgba,
rawStraightRgba,
rawUnmodified,
png,
}

View File

@ -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))!;
@ -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();

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 B