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

@ -72,7 +72,7 @@ void main() {
expect(event.extensionKind, 'Flutter.ImageSizesForFrame'); expect(event.extensionKind, 'Flutter.ImageSizesForFrame');
expect( expect(
jsonEncode(event.extensionData!.data), 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. }, skip: isBrowser); // [intended] uses dart:isolate and io.
@ -104,7 +104,7 @@ void main() {
expect(event.extensionKind, 'Flutter.ImageSizesForFrame'); expect(event.extensionKind, 'Flutter.ImageSizesForFrame');
expect( expect(
jsonEncode(event.extensionData!.data), 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. }, 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 /// 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 /// to report to `dart:developer`'s [postEvent], as well as to the
/// [debugOnPaintImage] callback if it is set. /// [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 /// A unique identifier for this image, for example its asset path or network
/// URL. /// URL.
final String? source; final String? source;
/// The size of the area the image will be rendered in. /// 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. /// The size the image has been decoded to.
final Size imageSize; final Size imageSize;
/// The number of bytes needed to render the image without scaling it. /// 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. /// The number of bytes used by the image in memory.
int get decodedSizeInBytes => _sizeToBytes(imageSize); int get decodedSizeInBytes => _sizeToBytes(imageSize);
@ -82,10 +82,9 @@ class ImageSizeInfo {
Map<String, Object?> toJson() { Map<String, Object?> toJson() {
return <String, Object?>{ return <String, Object?>{
'source': source, 'source': source,
if (displaySize != null)
'displaySize': <String, Object?>{ 'displaySize': <String, Object?>{
'width': displaySize!.width, 'width': displaySize.width,
'height': displaySize!.height, 'height': displaySize.height,
}, },
'imageSize': <String, Object?>{ 'imageSize': <String, Object?>{
'width': imageSize.width, 'width': imageSize.width,

View File

@ -11,6 +11,7 @@ import 'package:flutter/scheduler.dart';
import 'alignment.dart'; import 'alignment.dart';
import 'basic_types.dart'; import 'basic_types.dart';
import 'binding.dart';
import 'borders.dart'; import 'borders.dart';
import 'box_fit.dart'; import 'box_fit.dart';
import 'debug.dart'; import 'debug.dart';
@ -494,14 +495,16 @@ void paintImage({
// Some ImageProvider implementations may not have given this. // Some ImageProvider implementations may not have given this.
source: debugImageLabel ?? '<Unknown Image(${image.width}×${image.height})>', source: debugImageLabel ?? '<Unknown Image(${image.width}×${image.height})>',
imageSize: Size(image.width.toDouble(), image.height.toDouble()), 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(() { assert(() {
if (debugInvertOversizedImages && if (debugInvertOversizedImages &&
sizeInfo.decodedSizeInBytes > sizeInfo.displaySizeInBytes + debugImageOverheadAllowance) { sizeInfo.decodedSizeInBytes > sizeInfo.displaySizeInBytes + debugImageOverheadAllowance) {
final int overheadInKilobytes = (sizeInfo.decodedSizeInBytes - sizeInfo.displaySizeInBytes) ~/ 1024; final int overheadInKilobytes = (sizeInfo.decodedSizeInBytes - sizeInfo.displaySizeInBytes) ~/ 1024;
final int outputWidth = outputSize.width.toInt(); final int outputWidth = sizeInfo.displaySize.width.toInt();
final int outputHeight = outputSize.height.toInt(); final int outputHeight = sizeInfo.displaySize.height.toInt();
FlutterError.reportError(FlutterErrorDetails( FlutterError.reportError(FlutterErrorDetails(
exception: 'Image $debugImageLabel has a display size of ' exception: 'Image $debugImageLabel has a display size of '
'$outputWidth×$outputHeight but a decode size of ' '$outputWidth×$outputHeight but a decode size of '

View File

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

View File

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