Take DPR into account for image inversion (#88309)

This commit is contained in:
Dan Field 2021-08-16 15:35:10 -07:00 committed by GitHub
parent a562b3cb3d
commit c91a298249
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 28 additions and 24 deletions

View File

@ -4,4 +4,4 @@ The tests in this folder must be run with `flutter test --enable-vmservice`,
since they test that trace data is written to the timeline by connecting to
the observatory.
These tests will fail if run without this flag.
These tests will fail if run without this flag.

View File

@ -72,7 +72,7 @@ void main() {
expect(event.extensionKind, 'Flutter.ImageSizesForFrame');
expect(
jsonEncode(event.extensionData!.data),
'{"test.png":{"source":"test.png","displaySize":{"width":200.0,"height":100.0},"imageSize":{"width":300.0,"height":300.0},"displaySizeInBytes":106666,"decodedSizeInBytes":480000}}',
'{"test.png":{"source":"test.png","displaySize":{"width":600.0,"height":300.0},"imageSize":{"width":300.0,"height":300.0},"displaySizeInBytes":960000,"decodedSizeInBytes":480000}}',
);
}, skip: isBrowser); // [intended] uses dart:isolate and io.
@ -104,7 +104,7 @@ void main() {
expect(event.extensionKind, 'Flutter.ImageSizesForFrame');
expect(
jsonEncode(event.extensionData!.data),
'{"test.png":{"source":"test.png","displaySize":{"width":300.0,"height":300.0},"imageSize":{"width":300.0,"height":300.0},"displaySizeInBytes":480000,"decodedSizeInBytes":480000}}',
'{"test.png":{"source":"test.png","displaySize":{"width":900.0,"height":900.0},"imageSize":{"width":300.0,"height":300.0},"displaySizeInBytes":4320000,"decodedSizeInBytes":480000}}',
);
}, skip: isBrowser); // [intended] uses dart:isolate and io.
}

View File

@ -54,20 +54,20 @@ class ImageSizeInfo {
/// This class is used by the framework when it paints an image to a canvas
/// to report to `dart:developer`'s [postEvent], as well as to the
/// [debugOnPaintImage] callback if it is set.
const ImageSizeInfo({this.source, this.displaySize, required this.imageSize});
const ImageSizeInfo({this.source, required this.displaySize, required this.imageSize});
/// A unique identifier for this image, for example its asset path or network
/// URL.
final String? source;
/// The size of the area the image will be rendered in.
final Size? displaySize;
final Size displaySize;
/// The size the image has been decoded to.
final Size imageSize;
/// The number of bytes needed to render the image without scaling it.
int get displaySizeInBytes => _sizeToBytes(displaySize!);
int get displaySizeInBytes => _sizeToBytes(displaySize);
/// The number of bytes used by the image in memory.
int get decodedSizeInBytes => _sizeToBytes(imageSize);
@ -82,11 +82,10 @@ class ImageSizeInfo {
Map<String, Object?> toJson() {
return <String, Object?>{
'source': source,
if (displaySize != null)
'displaySize': <String, Object?>{
'width': displaySize!.width,
'height': displaySize!.height,
},
'displaySize': <String, Object?>{
'width': displaySize.width,
'height': displaySize.height,
},
'imageSize': <String, Object?>{
'width': imageSize.width,
'height': imageSize.height,

View File

@ -11,6 +11,7 @@ import 'package:flutter/scheduler.dart';
import 'alignment.dart';
import 'basic_types.dart';
import 'binding.dart';
import 'borders.dart';
import 'box_fit.dart';
import 'debug.dart';
@ -494,14 +495,16 @@ void paintImage({
// Some ImageProvider implementations may not have given this.
source: debugImageLabel ?? '<Unknown Image(${image.width}×${image.height})>',
imageSize: Size(image.width.toDouble(), image.height.toDouble()),
displaySize: outputSize,
// It's ok to use this instead of a MediaQuery because if this changes,
// whatever is aware of the MediaQuery will be repainting the image anyway.
displaySize: outputSize * PaintingBinding.instance!.window.devicePixelRatio,
);
assert(() {
if (debugInvertOversizedImages &&
sizeInfo.decodedSizeInBytes > sizeInfo.displaySizeInBytes + debugImageOverheadAllowance) {
final int overheadInKilobytes = (sizeInfo.decodedSizeInBytes - sizeInfo.displaySizeInBytes) ~/ 1024;
final int outputWidth = outputSize.width.toInt();
final int outputHeight = outputSize.height.toInt();
final int outputWidth = sizeInfo.displaySize.width.toInt();
final int outputHeight = sizeInfo.displaySize.height.toInt();
FlutterError.reportError(FlutterErrorDetails(
exception: 'Image $debugImageLabel has a display size of '
'$outputWidth×$outputHeight but a decode size of '

View File

@ -5,6 +5,7 @@
import 'dart:ui' as ui;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:flutter_test/flutter_test.dart';
@ -52,6 +53,7 @@ void main() {
test('debugInvertOversizedImages', () async {
debugInvertOversizedImages = true;
expect(PaintingBinding.instance!.window.devicePixelRatio != 1.0, true);
final FlutterExceptionHandler? oldFlutterError = FlutterError.onError;
final List<String> messages = <String>[];
@ -60,7 +62,7 @@ void main() {
};
final TestCanvas canvas = TestCanvas();
const Rect rect = Rect.fromLTWH(50.0, 50.0, 200.0, 100.0);
const Rect rect = Rect.fromLTWH(50.0, 50.0, 100.0, 50.0);
paintImage(
canvas: canvas,
@ -88,7 +90,7 @@ void main() {
);
expect(commands[1].memberName, #translate);
expect(commands[1].positionalArguments[0], 0.0);
expect(commands[1].positionalArguments[1], 100.0);
expect(commands[1].positionalArguments[1], 75.0);
expect(commands[2].memberName, #scale);
expect(commands[2].positionalArguments[0], 1.0);
@ -97,12 +99,12 @@ void main() {
expect(commands[3].memberName, #translate);
expect(commands[3].positionalArguments[0], 0.0);
expect(commands[3].positionalArguments[1], -100.0);
expect(commands[3].positionalArguments[1], -75.0);
expect(
messages.single,
'Image TestImage has a display size of 200×100 but a decode size of 300×300, which uses an additional 364KB.\n\n'
'Consider resizing the asset ahead of time, supplying a cacheWidth parameter of 200, a cacheHeight parameter of 100, or using a ResizeImage.',
'Image TestImage has a display size of 300×150 but a decode size of 300×300, which uses an additional 234KB.\n\n'
'Consider resizing the asset ahead of time, supplying a cacheWidth parameter of 300, a cacheHeight parameter of 150, or using a ResizeImage.',
);
debugInvertOversizedImages = false;
@ -179,7 +181,7 @@ void main() {
expect(imageSizeInfo, isNotNull);
expect(imageSizeInfo.source, 'test.png');
expect(imageSizeInfo.imageSize, const Size(300, 300));
expect(imageSizeInfo.displaySize, const Size(200, 100));
expect(imageSizeInfo.displaySize, const Size(200, 100) * PaintingBinding.instance!.window.devicePixelRatio);
// Make sure that we don't report an identical image size info if we
// redraw in the next frame.
@ -218,7 +220,7 @@ void main() {
expect(imageSizeInfo, isNotNull);
expect(imageSizeInfo.source, 'test.png');
expect(imageSizeInfo.imageSize, const Size(300, 300));
expect(imageSizeInfo.displaySize, const Size(200, 100));
expect(imageSizeInfo.displaySize, const Size(200, 100) * PaintingBinding.instance!.window.devicePixelRatio);
// Make sure that we don't report an identical image size info if we
// redraw in the next frame.
@ -236,7 +238,7 @@ void main() {
expect(imageSizeInfo, isNotNull);
expect(imageSizeInfo.source, 'test.png');
expect(imageSizeInfo.imageSize, const Size(300, 300));
expect(imageSizeInfo.displaySize, const Size(200, 150));
expect(imageSizeInfo.displaySize, const Size(200, 150) * PaintingBinding.instance!.window.devicePixelRatio);
debugOnPaintImage = null;
});
@ -260,7 +262,7 @@ void main() {
expect(imageSizeInfo, isNotNull);
expect(imageSizeInfo.source, '<Unknown Image(300×200)>');
expect(imageSizeInfo.imageSize, const Size(300, 200));
expect(imageSizeInfo.displaySize, const Size(200, 100));
expect(imageSizeInfo.displaySize, const Size(200, 100) * PaintingBinding.instance!.window.devicePixelRatio);
debugOnPaintImage = null;
});

View File

@ -1819,7 +1819,7 @@ void main() {
const ImageSizeInfo(
source: 'test.png',
imageSize: Size(100, 100),
displaySize: Size(50, 50),
displaySize: Size(150, 150),
),
);