Take DPR into account for image inversion (#88309)
This commit is contained in:
parent
a562b3cb3d
commit
c91a298249
@ -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
|
since they test that trace data is written to the timeline by connecting to
|
||||||
the observatory.
|
the observatory.
|
||||||
|
|
||||||
These tests will fail if run without this flag.
|
These tests will fail if run without this flag.
|
||||||
|
@ -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.
|
||||||
}
|
}
|
||||||
|
@ -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,11 +82,10 @@ 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,
|
||||||
'height': imageSize.height,
|
'height': imageSize.height,
|
||||||
|
@ -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 '
|
||||||
|
@ -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;
|
||||||
});
|
});
|
||||||
|
@ -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),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user