| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:async'; |
| import 'dart:typed_data'; |
| import 'dart:ui' as ui; |
| |
| import 'package:flutter/painting.dart'; |
| import 'package:flutter_test/flutter_test.dart'; |
| |
| import '../image_data.dart'; |
| import '../rendering/rendering_tester.dart'; |
| |
| void main() { |
| TestRenderingFlutterBinding.ensureInitialized(); |
| |
| tearDown(() { |
| PaintingBinding.instance.imageCache.clear(); |
| PaintingBinding.instance.imageCache.clearLiveImages(); |
| }); |
| |
| group('ResizeImage', () { |
| group('resizing', () { |
| test('upscales to the correct dimensions', () async { |
| final Uint8List bytes = Uint8List.fromList(kTransparentImage); |
| final MemoryImage imageProvider = MemoryImage(bytes); |
| final Size rawImageSize = await _resolveAndGetSize(imageProvider); |
| expect(rawImageSize, const Size(1, 1)); |
| |
| const Size resizeDims = Size(14, 7); |
| final ResizeImage resizedImage = ResizeImage(MemoryImage(bytes), width: resizeDims.width.round(), height: resizeDims.height.round(), allowUpscaling: true); |
| const ImageConfiguration resizeConfig = ImageConfiguration(size: resizeDims); |
| final Size resizedImageSize = await _resolveAndGetSize(resizedImage, configuration: resizeConfig); |
| expect(resizedImageSize, resizeDims); |
| }); |
| |
| |
| test('downscales to the correct dimensions', () async { |
| final Uint8List bytes = Uint8List.fromList(kBlueSquarePng); |
| final MemoryImage imageProvider = MemoryImage(bytes); |
| final Size rawImageSize = await _resolveAndGetSize(imageProvider); |
| expect(rawImageSize, const Size(50, 50)); |
| |
| const Size resizeDims = Size(25, 25); |
| final ResizeImage resizedImage = ResizeImage(MemoryImage(bytes), width: resizeDims.width.round(), height: resizeDims.height.round(), allowUpscaling: true); |
| const ImageConfiguration resizeConfig = ImageConfiguration(size: resizeDims); |
| final Size resizedImageSize = await _resolveAndGetSize(resizedImage, configuration: resizeConfig); |
| expect(resizedImageSize, resizeDims); |
| }); |
| |
| test('refuses upscaling when allowUpscaling=false', () async { |
| final Uint8List bytes = Uint8List.fromList(kTransparentImage); |
| final MemoryImage imageProvider = MemoryImage(bytes); |
| final Size rawImageSize = await _resolveAndGetSize(imageProvider); |
| expect(rawImageSize, const Size(1, 1)); |
| |
| const Size resizeDims = Size(50, 50); |
| final ResizeImage resizedImage = ResizeImage(MemoryImage(bytes), width: resizeDims.width.round(), height: resizeDims.height.round()); |
| const ImageConfiguration resizeConfig = ImageConfiguration(size: resizeDims); |
| final Size resizedImageSize = await _resolveAndGetSize(resizedImage, configuration: resizeConfig); |
| expect(resizedImageSize, const Size(1, 1)); |
| }); |
| |
| group('with policy=fit and allowResize=false', () { |
| test('constrains square image to bounded portrait rect', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueSquarePng)); |
| await _expectImageSize(rawImage, const Size(50, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 25, height: 50, policy: ResizeImagePolicy.fit); |
| await _expectImageSize(resizedImage, const Size(25, 25)); |
| }); |
| |
| test('constrains square image to bounded landscape rect', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueSquarePng)); |
| await _expectImageSize(rawImage, const Size(50, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 50, height: 25, policy: ResizeImagePolicy.fit); |
| await _expectImageSize(resizedImage, const Size(25, 25)); |
| }); |
| |
| test('constrains square image to bounded square', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueSquarePng)); |
| await _expectImageSize(rawImage, const Size(50, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 25, height: 25, policy: ResizeImagePolicy.fit); |
| await _expectImageSize(resizedImage, const Size(25, 25)); |
| }); |
| |
| test('constrains square image to bounded width', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueSquarePng)); |
| await _expectImageSize(rawImage, const Size(50, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 25, policy: ResizeImagePolicy.fit); |
| await _expectImageSize(resizedImage, const Size(25, 25)); |
| }); |
| |
| test('constrains square image to bounded height', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueSquarePng)); |
| await _expectImageSize(rawImage, const Size(50, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, height: 25, policy: ResizeImagePolicy.fit); |
| await _expectImageSize(resizedImage, const Size(25, 25)); |
| }); |
| |
| test('constrains portrait image to bounded portrait rect', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBluePortraitPng)); |
| await _expectImageSize(rawImage, const Size(50, 100)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 25, height: 60, policy: ResizeImagePolicy.fit); |
| await _expectImageSize(resizedImage, const Size(25, 50)); |
| }); |
| |
| test('constrains portrait image to bounded landscape rect', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBluePortraitPng)); |
| await _expectImageSize(rawImage, const Size(50, 100)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 60, height: 25, policy: ResizeImagePolicy.fit); |
| await _expectImageSize(resizedImage, const Size(12, 25)); |
| }); |
| |
| test('constrains portrait image to bounded square', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBluePortraitPng)); |
| await _expectImageSize(rawImage, const Size(50, 100)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 25, height: 25, policy: ResizeImagePolicy.fit); |
| await _expectImageSize(resizedImage, const Size(12, 25)); |
| }); |
| |
| test('constrains portrait image to bounded width', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBluePortraitPng)); |
| await _expectImageSize(rawImage, const Size(50, 100)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 25, policy: ResizeImagePolicy.fit); |
| await _expectImageSize(resizedImage, const Size(25, 50)); |
| }); |
| |
| test('constrains portrait image to bounded height', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBluePortraitPng)); |
| await _expectImageSize(rawImage, const Size(50, 100)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, height: 25, policy: ResizeImagePolicy.fit); |
| await _expectImageSize(resizedImage, const Size(12, 25)); |
| }); |
| |
| test('constrains landscape image to bounded portrait rect', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueLandscapePng)); |
| await _expectImageSize(rawImage, const Size(100, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 25, height: 60, policy: ResizeImagePolicy.fit); |
| await _expectImageSize(resizedImage, const Size(25, 12)); |
| }); |
| |
| test('constrains landscape image to bounded landscape rect', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueLandscapePng)); |
| await _expectImageSize(rawImage, const Size(100, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 60, height: 25, policy: ResizeImagePolicy.fit); |
| await _expectImageSize(resizedImage, const Size(50, 25)); |
| }); |
| |
| test('constrains landscape image to bounded square', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueLandscapePng)); |
| await _expectImageSize(rawImage, const Size(100, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 25, height: 25, policy: ResizeImagePolicy.fit); |
| await _expectImageSize(resizedImage, const Size(25, 12)); |
| }); |
| |
| test('constrains landscape image to bounded width', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueLandscapePng)); |
| await _expectImageSize(rawImage, const Size(100, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 25, policy: ResizeImagePolicy.fit); |
| await _expectImageSize(resizedImage, const Size(25, 12)); |
| }); |
| |
| test('constrains landscape image to bounded height', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueLandscapePng)); |
| await _expectImageSize(rawImage, const Size(100, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, height: 25, policy: ResizeImagePolicy.fit); |
| await _expectImageSize(resizedImage, const Size(50, 25)); |
| }); |
| |
| test('leaves image as-is if constraints are bigger than image', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueSquarePng)); |
| await _expectImageSize(rawImage, const Size(50, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 120, height: 100, policy: ResizeImagePolicy.fit); |
| await _expectImageSize(resizedImage, const Size(50, 50)); |
| }); |
| }); |
| |
| group('with policy=fit and allowResize=true', () { |
| test('constrains square image to bounded portrait rect', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueSquarePng)); |
| await _expectImageSize(rawImage, const Size(50, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 100, height: 200, policy: ResizeImagePolicy.fit, allowUpscaling: true); |
| await _expectImageSize(resizedImage, const Size(100, 100)); |
| }); |
| |
| test('constrains square image to bounded landscape rect', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueSquarePng)); |
| await _expectImageSize(rawImage, const Size(50, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 200, height: 100, policy: ResizeImagePolicy.fit, allowUpscaling: true); |
| await _expectImageSize(resizedImage, const Size(100, 100)); |
| }); |
| |
| test('constrains square image to bounded square', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueSquarePng)); |
| await _expectImageSize(rawImage, const Size(50, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 100, height: 100, policy: ResizeImagePolicy.fit, allowUpscaling: true); |
| await _expectImageSize(resizedImage, const Size(100, 100)); |
| }); |
| |
| test('constrains square image to bounded width', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueSquarePng)); |
| await _expectImageSize(rawImage, const Size(50, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 100, policy: ResizeImagePolicy.fit, allowUpscaling: true); |
| await _expectImageSize(resizedImage, const Size(100, 100)); |
| }); |
| |
| test('constrains square image to bounded height', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueSquarePng)); |
| await _expectImageSize(rawImage, const Size(50, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, height: 100, policy: ResizeImagePolicy.fit, allowUpscaling: true); |
| await _expectImageSize(resizedImage, const Size(100, 100)); |
| }); |
| |
| test('constrains portrait image to bounded portrait rect', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBluePortraitPng)); |
| await _expectImageSize(rawImage, const Size(50, 100)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 100, height: 250, policy: ResizeImagePolicy.fit, allowUpscaling: true); |
| await _expectImageSize(resizedImage, const Size(100, 200)); |
| }); |
| |
| test('constrains portrait image to bounded landscape rect', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBluePortraitPng)); |
| await _expectImageSize(rawImage, const Size(50, 100)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 400, height: 200, policy: ResizeImagePolicy.fit, allowUpscaling: true); |
| await _expectImageSize(resizedImage, const Size(100, 200)); |
| }); |
| |
| test('constrains portrait image to bounded square', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBluePortraitPng)); |
| await _expectImageSize(rawImage, const Size(50, 100)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 200, height: 200, policy: ResizeImagePolicy.fit, allowUpscaling: true); |
| await _expectImageSize(resizedImage, const Size(100, 200)); |
| }); |
| |
| test('constrains portrait image to bounded width', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBluePortraitPng)); |
| await _expectImageSize(rawImage, const Size(50, 100)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 100, policy: ResizeImagePolicy.fit, allowUpscaling: true); |
| await _expectImageSize(resizedImage, const Size(100, 200)); |
| }); |
| |
| test('constrains portrait image to bounded height', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBluePortraitPng)); |
| await _expectImageSize(rawImage, const Size(50, 100)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, height: 200, policy: ResizeImagePolicy.fit, allowUpscaling: true); |
| await _expectImageSize(resizedImage, const Size(100, 200)); |
| }); |
| |
| test('constrains landscape image to bounded portrait rect', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueLandscapePng)); |
| await _expectImageSize(rawImage, const Size(100, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 200, height: 400, policy: ResizeImagePolicy.fit, allowUpscaling: true); |
| await _expectImageSize(resizedImage, const Size(200, 100)); |
| }); |
| |
| test('constrains landscape image to bounded landscape rect', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueLandscapePng)); |
| await _expectImageSize(rawImage, const Size(100, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 250, height: 100, policy: ResizeImagePolicy.fit, allowUpscaling: true); |
| await _expectImageSize(resizedImage, const Size(200, 100)); |
| }); |
| |
| test('constrains landscape image to bounded square', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueLandscapePng)); |
| await _expectImageSize(rawImage, const Size(100, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 200, height: 200, policy: ResizeImagePolicy.fit, allowUpscaling: true); |
| await _expectImageSize(resizedImage, const Size(200, 100)); |
| }); |
| |
| test('constrains landscape image to bounded width', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueLandscapePng)); |
| await _expectImageSize(rawImage, const Size(100, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 200, policy: ResizeImagePolicy.fit, allowUpscaling: true); |
| await _expectImageSize(resizedImage, const Size(200, 100)); |
| }); |
| |
| test('constrains landscape image to bounded height', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueLandscapePng)); |
| await _expectImageSize(rawImage, const Size(100, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, height: 100, policy: ResizeImagePolicy.fit, allowUpscaling: true); |
| await _expectImageSize(resizedImage, const Size(200, 100)); |
| }); |
| |
| test('shrinks image if constraints are smaller than image', () async { |
| final MemoryImage rawImage = MemoryImage(Uint8List.fromList(kBlueSquarePng)); |
| await _expectImageSize(rawImage, const Size(50, 50)); |
| final ResizeImage resizedImage = ResizeImage(rawImage, width: 25, height: 30, policy: ResizeImagePolicy.fit, allowUpscaling: true); |
| await _expectImageSize(resizedImage, const Size(25, 25)); |
| }); |
| }); |
| }, skip: isBrowser); // https://github.com/flutter/flutter/issues/73120); |
| |
| test('does not resize when no size is passed', () async { |
| final Uint8List bytes = Uint8List.fromList(kTransparentImage); |
| final MemoryImage imageProvider = MemoryImage(bytes); |
| final Size rawImageSize = await _resolveAndGetSize(imageProvider); |
| expect(rawImageSize, const Size(1, 1)); |
| |
| final ImageProvider<Object> resizedImage = ResizeImage.resizeIfNeeded(null, null, imageProvider); |
| final Size resizedImageSize = await _resolveAndGetSize(resizedImage); |
| expect(resizedImageSize, const Size(1, 1)); |
| }); |
| |
| test('stores values', () async { |
| final Uint8List bytes = Uint8List.fromList(kTransparentImage); |
| final MemoryImage memoryImage = MemoryImage(bytes); |
| memoryImage.resolve(ImageConfiguration.empty); |
| final ResizeImage resizeImage = ResizeImage(memoryImage, width: 10, height: 20); |
| expect(resizeImage.width, 10); |
| expect(resizeImage.height, 20); |
| expect(resizeImage.imageProvider, memoryImage); |
| expect(memoryImage.resolve(ImageConfiguration.empty) != resizeImage.resolve(ImageConfiguration.empty), true); |
| }); |
| |
| test('takes one dim', () async { |
| final Uint8List bytes = Uint8List.fromList(kTransparentImage); |
| final MemoryImage memoryImage = MemoryImage(bytes); |
| final ResizeImage resizeImage = ResizeImage(memoryImage, width: 10); |
| expect(resizeImage.width, 10); |
| expect(resizeImage.height, null); |
| expect(resizeImage.imageProvider, memoryImage); |
| expect(memoryImage.resolve(ImageConfiguration.empty) != resizeImage.resolve(ImageConfiguration.empty), true); |
| }); |
| |
| test('forms closure', () async { |
| final Uint8List bytes = Uint8List.fromList(kTransparentImage); |
| final MemoryImage memoryImage = MemoryImage(bytes); |
| final ResizeImage resizeImage = ResizeImage(memoryImage, width: 123, height: 321, allowUpscaling: true); |
| |
| Future<ui.Codec> decode(ui.ImmutableBuffer buffer, {ui.TargetImageSizeCallback? getTargetSize}) { |
| return PaintingBinding.instance.instantiateImageCodecWithSize(buffer, getTargetSize: (int intrinsicWidth, int intrinsicHeight) { |
| expect(getTargetSize, isNotNull); |
| final ui.TargetImageSize targetSize = getTargetSize!(intrinsicWidth, intrinsicHeight); |
| expect(targetSize.width, 123); |
| expect(targetSize.height, 321); |
| return targetSize; |
| }); |
| } |
| |
| resizeImage.loadImage(await resizeImage.obtainKey(ImageConfiguration.empty), decode); |
| }); |
| |
| test('handles sync obtainKey', () async { |
| final Uint8List bytes = Uint8List.fromList(kTransparentImage); |
| final MemoryImage memoryImage = MemoryImage(bytes); |
| final ResizeImage resizeImage = ResizeImage(memoryImage, width: 123, height: 321); |
| |
| bool isAsync = false; |
| bool keyObtained = false; |
| resizeImage.obtainKey(ImageConfiguration.empty).then((Object key) { |
| keyObtained = true; |
| expect(isAsync, false); |
| }); |
| isAsync = true; |
| expect(isAsync, true); |
| expect(keyObtained, true); |
| }); |
| |
| test('handles async obtainKey', () async { |
| final Uint8List bytes = Uint8List.fromList(kTransparentImage); |
| final _AsyncKeyMemoryImage memoryImage = _AsyncKeyMemoryImage(bytes); |
| final ResizeImage resizeImage = ResizeImage(memoryImage, width: 123, height: 321); |
| |
| bool isAsync = false; |
| final Completer<void> completer = Completer<void>(); |
| resizeImage.obtainKey(ImageConfiguration.empty).then((Object key) { |
| try { |
| expect(isAsync, true); |
| } finally { |
| completer.complete(); |
| } |
| }); |
| isAsync = true; |
| await completer.future; |
| expect(isAsync, true); |
| }); |
| }); |
| } |
| |
| Future<void> _expectImageSize(ImageProvider<Object> imageProvider, Size size) async { |
| final Size actualSize = await _resolveAndGetSize(imageProvider); |
| expect(actualSize, size); |
| } |
| |
| Future<Size> _resolveAndGetSize( |
| ImageProvider imageProvider, { |
| ImageConfiguration configuration = ImageConfiguration.empty, |
| }) async { |
| final ImageStream stream = imageProvider.resolve(configuration); |
| final Completer<Size> completer = Completer<Size>(); |
| final ImageStreamListener listener = |
| ImageStreamListener((ImageInfo image, bool synchronousCall) { |
| final int height = image.image.height; |
| final int width = image.image.width; |
| completer.complete(Size(width.toDouble(), height.toDouble())); |
| } |
| ); |
| stream.addListener(listener); |
| return completer.future; |
| } |
| |
| // This version of MemoryImage guarantees obtainKey returns a future that has not been |
| // completed synchronously. |
| class _AsyncKeyMemoryImage extends MemoryImage { |
| const _AsyncKeyMemoryImage(super.bytes); |
| |
| @override |
| Future<MemoryImage> obtainKey(ImageConfiguration configuration) { |
| return Future<MemoryImage>(() => this); |
| } |
| } |