Added a filterQuality parameter to images. (#23329) * Added a filterQuality parameter to images. * Removed this break by accident. * Modified the test case to check the filterQuality * Update packages/flutter/lib/src/rendering/image.dart Co-Authored-By: namanix <namanix@gmail.com> * Update packages/flutter/lib/src/rendering/image.dart Co-Authored-By: namanix <namanix@gmail.com> * Update packages/flutter/lib/src/rendering/image.dart Co-Authored-By: namanix <namanix@gmail.com> * Update packages/flutter/lib/src/widgets/image.dart Co-Authored-By: namanix <namanix@gmail.com> * Update packages/flutter/lib/src/widgets/image.dart Co-Authored-By: namanix <namanix@gmail.com> * Update packages/flutter/lib/src/rendering/image.dart Co-Authored-By: namanix <namanix@gmail.com> * Update packages/flutter/lib/src/rendering/image.dart Co-Authored-By: namanix <namanix@gmail.com> * Added documentation for the new parameter and corrected some space issue's
diff --git a/packages/flutter/lib/src/painting/decoration_image.dart b/packages/flutter/lib/src/painting/decoration_image.dart index fa0a4c8..18462ea 100644 --- a/packages/flutter/lib/src/painting/decoration_image.dart +++ b/packages/flutter/lib/src/painting/decoration_image.dart
@@ -261,6 +261,7 @@ centerSlice: _details.centerSlice, repeat: _details.repeat, flipHorizontally: flipHorizontally, + filterQuality: FilterQuality.low ); if (clipPath != null) @@ -347,7 +348,12 @@ /// invert will be applied after it. This is primarily used for implementing /// smart invert on iOS. /// -/// The `canvas`, `rect`, `image`, `scale`, `alignment`, `repeat`, and `flipHorizontally` +/// * `filterQuality`: Use this to change the quality when scaling an image. +/// Use the [FilterQuality.low] quality setting to scale the image, which corresponds to +/// bilinear interpolation, rather than the default [FilterQuality.none] which corresponds +/// to nearest-neighbor. +/// +/// The `canvas`, `rect`, `image`, `scale`, `alignment`, `repeat`, `flipHorizontally` and `filterQuality` /// arguments must not be null. /// /// See also: @@ -367,6 +373,7 @@ ImageRepeat repeat = ImageRepeat.noRepeat, bool flipHorizontally = false, bool invertColors = false, + FilterQuality filterQuality = FilterQuality.low }) { assert(canvas != null); assert(image != null); @@ -407,10 +414,7 @@ if (colorFilter != null) paint.colorFilter = colorFilter; if (sourceSize != destinationSize) { - // Use the "low" quality setting to scale the image, which corresponds to - // bilinear interpolation, rather than the default "none" which corresponds - // to nearest-neighbor. - paint.filterQuality = FilterQuality.low; + paint.filterQuality = filterQuality; } paint.invertColors = invertColors; final double halfWidthDelta = (outputSize.width - destinationSize.width) / 2.0;
diff --git a/packages/flutter/lib/src/rendering/image.dart b/packages/flutter/lib/src/rendering/image.dart index 6844002..6f12dfa 100644 --- a/packages/flutter/lib/src/rendering/image.dart +++ b/packages/flutter/lib/src/rendering/image.dart
@@ -21,7 +21,7 @@ class RenderImage extends RenderBox { /// Creates a render box that displays an image. /// - /// The [scale], [alignment], [repeat], and [matchTextDirection] arguments + /// The [scale], [alignment], [repeat], [matchTextDirection] and [filterQuality] arguments /// must not be null. The [textDirection] argument must not be null if /// [alignment] will need resolving or if [matchTextDirection] is true. RenderImage({ @@ -37,10 +37,12 @@ Rect centerSlice, bool matchTextDirection = false, TextDirection textDirection, - bool invertColors = false + bool invertColors = false, + FilterQuality filterQuality = FilterQuality.low }) : assert(scale != null), assert(repeat != null), assert(alignment != null), + assert(filterQuality != null), assert(matchTextDirection != null), _image = image, _width = width, @@ -54,7 +56,8 @@ _centerSlice = centerSlice, _matchTextDirection = matchTextDirection, _invertColors = invertColors, - _textDirection = textDirection { + _textDirection = textDirection, + _filterQuality = filterQuality { _updateColorFilter(); } @@ -145,6 +148,21 @@ markNeedsPaint(); } + /// Used to set the filterQuality of the image + /// Use the [FilterQuality.low] quality setting to scale the image, which corresponds to + /// bilinear interpolation, rather than the default [FilterQuality.none] which corresponds + /// to nearest-neighbor. + FilterQuality get filterQuality => _filterQuality; + FilterQuality _filterQuality; + set filterQuality(FilterQuality value) { + assert(value != null); + if(value == _filterQuality) + return; + _filterQuality = value; + markNeedsPaint(); + } + + /// Used to combine [color] with this image. /// /// The default is [BlendMode.srcIn]. In terms of the blend mode, [color] is @@ -348,6 +366,7 @@ repeat: _repeat, flipHorizontally: _flipHorizontally, invertColors: invertColors, + filterQuality: _filterQuality ); } @@ -367,5 +386,6 @@ properties.add(FlagProperty('matchTextDirection', value: matchTextDirection, ifTrue: 'match text direction')); properties.add(EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null)); properties.add(DiagnosticsProperty<bool>('invertColors', invertColors)); + properties.add(EnumProperty<FilterQuality>('filterQuality', filterQuality)); } }
diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart index f08f66f..12410f3 100644 --- a/packages/flutter/lib/src/widgets/basic.dart +++ b/packages/flutter/lib/src/widgets/basic.dart
@@ -4498,7 +4498,7 @@ class RawImage extends LeafRenderObjectWidget { /// Creates a widget that displays an image. /// - /// The [scale], [alignment], [repeat], and [matchTextDirection] arguments must + /// The [scale], [alignment], [repeat], [matchTextDirection] and [filterQuality] arguments must /// not be null. const RawImage({ Key key, @@ -4514,6 +4514,7 @@ this.centerSlice, this.matchTextDirection = false, this.invertColors = false, + this.filterQuality = FilterQuality.low, }) : assert(scale != null), assert(alignment != null), assert(repeat != null), @@ -4543,6 +4544,12 @@ /// If non-null, this color is blended with each image pixel using [colorBlendMode]. final Color color; + /// Used to set the filterQuality of the image + /// Use the "low" quality setting to scale the image, which corresponds to + /// bilinear interpolation, rather than the default "none" which corresponds + /// to nearest-neighbor. + final FilterQuality filterQuality; + /// Used to combine [color] with this image. /// /// The default is [BlendMode.srcIn]. In terms of the blend mode, [color] is @@ -4643,6 +4650,7 @@ matchTextDirection: matchTextDirection, textDirection: matchTextDirection || alignment is! Alignment ? Directionality.of(context) : null, invertColors: invertColors, + filterQuality: filterQuality, ); } @@ -4661,7 +4669,8 @@ ..centerSlice = centerSlice ..matchTextDirection = matchTextDirection ..textDirection = matchTextDirection || alignment is! Alignment ? Directionality.of(context) : null - ..invertColors = invertColors; + ..invertColors = invertColors + ..filterQuality = filterQuality; } @override @@ -4679,6 +4688,7 @@ properties.add(DiagnosticsProperty<Rect>('centerSlice', centerSlice, defaultValue: null)); properties.add(FlagProperty('matchTextDirection', value: matchTextDirection, ifTrue: 'match text direction')); properties.add(DiagnosticsProperty<bool>('invertColors', invertColors)); + properties.add(EnumProperty<FilterQuality>('filterQuality', filterQuality)); } }
diff --git a/packages/flutter/lib/src/widgets/image.dart b/packages/flutter/lib/src/widgets/image.dart index 6901b7e..b6c2a9a 100644 --- a/packages/flutter/lib/src/widgets/image.dart +++ b/packages/flutter/lib/src/widgets/image.dart
@@ -21,6 +21,7 @@ AssetImage, ExactAssetImage, FileImage, + FilterQuality, ImageConfiguration, ImageInfo, ImageStream, @@ -143,6 +144,11 @@ /// Otherwise, the image dimensions will change as the image is loaded, which /// will result in ugly layout changes. /// + /// Use [filterQuality] to change the quality when scaling an image. + /// Use the [FilterQuality.low] quality setting to scale the image, + /// which corresponds to bilinear interpolation, rather than the default + /// [FilterQuality.none] which corresponds to nearest-neighbor. + /// /// If [excludeFromSemantics] is true, then [semanticLabel] will be ignored. const Image({ Key key, @@ -159,9 +165,11 @@ this.centerSlice, this.matchTextDirection = false, this.gaplessPlayback = false, + this.filterQuality = FilterQuality.low, }) : assert(image != null), assert(alignment != null), assert(repeat != null), + assert(filterQuality != null), assert(matchTextDirection != null), super(key: key); @@ -179,6 +187,11 @@ /// An optional [headers] argument can be used to send custom HTTP headers /// with the image request. /// + /// Use [filterQuality] to change the quality when scaling an image. + /// Use the [FilterQuality.low] quality setting to scale the image, + /// which corresponds to bilinear interpolation, rather than the default + /// [FilterQuality.none] which corresponds to nearest-neighbor. + /// /// If [excludeFromSemantics] is true, then [semanticLabel] will be ignored. Image.network(String src, { Key key, @@ -195,6 +208,7 @@ this.centerSlice, this.matchTextDirection = false, this.gaplessPlayback = false, + this.filterQuality = FilterQuality.low, Map<String, String> headers, }) : image = NetworkImage(src, scale: scale, headers: headers), assert(alignment != null), @@ -214,6 +228,11 @@ /// On Android, this may require the /// `android.permission.READ_EXTERNAL_STORAGE` permission. /// + /// Use [filterQuality] to change the quality when scaling an image. + /// Use the [FilterQuality.low] quality setting to scale the image, + /// which corresponds to bilinear interpolation, rather than the default + /// [FilterQuality.none] which corresponds to nearest-neighbor. + /// /// If [excludeFromSemantics] is true, then [semanticLabel] will be ignored. Image.file(File file, { Key key, @@ -230,9 +249,11 @@ this.centerSlice, this.matchTextDirection = false, this.gaplessPlayback = false, + this.filterQuality = FilterQuality.low, }) : image = FileImage(file, scale: scale), assert(alignment != null), assert(repeat != null), + assert(filterQuality != null), assert(matchTextDirection != null), super(key: key); @@ -272,6 +293,11 @@ /// Otherwise, the image dimensions will change as the image is loaded, which /// will result in ugly layout changes. /// + /// Use [filterQuality] to change the quality when scaling an image. + /// Use the [FilterQuality.low] quality setting to scale the image, + /// which corresponds to bilinear interpolation, rather than the default + /// [FilterQuality.none] which corresponds to nearest-neighbor. + /// /// ## Sample code /// /// Suppose that the project's `pubspec.yaml` file contains the following: @@ -370,6 +396,7 @@ this.matchTextDirection = false, this.gaplessPlayback = false, String package, + this.filterQuality = FilterQuality.low, }) : image = scale != null ? ExactAssetImage(name, bundle: bundle, scale: scale, package: package) : AssetImage(name, bundle: bundle, package: package), @@ -387,6 +414,11 @@ /// Otherwise, the image dimensions will change as the image is loaded, which /// will result in ugly layout changes. /// + /// Use [filterQuality] to change the quality when scaling an image. + /// Use the [FilterQuality.low] quality setting to scale the image, + /// which corresponds to bilinear interpolation, rather than the default + /// [FilterQuality.none] which corresponds to nearest-neighbor. + /// /// If [excludeFromSemantics] is true, then [semanticLabel] will be ignored. Image.memory(Uint8List bytes, { Key key, @@ -403,6 +435,7 @@ this.centerSlice, this.matchTextDirection = false, this.gaplessPlayback = false, + this.filterQuality = FilterQuality.low, }) : image = MemoryImage(bytes, scale: scale), assert(alignment != null), assert(repeat != null), @@ -439,6 +472,12 @@ /// If non-null, this color is blended with each image pixel using [colorBlendMode]. final Color color; + /// Used to set the filterQuality of the image + /// Use the "low" quality setting to scale the image, which corresponds to + /// bilinear interpolation, rather than the default "none" which corresponds + /// to nearest-neighbor. + final FilterQuality filterQuality; + /// Used to combine [color] with this image. /// /// The default is [BlendMode.srcIn]. In terms of the blend mode, [color] is @@ -545,6 +584,7 @@ properties.add(FlagProperty('matchTextDirection', value: matchTextDirection, ifTrue: 'match text direction')); properties.add(StringProperty('semanticLabel', semanticLabel, defaultValue: null)); properties.add(DiagnosticsProperty<bool>('this.excludeFromSemantics', excludeFromSemantics)); + properties.add(EnumProperty<FilterQuality>('filterQuality', filterQuality)); } } @@ -651,6 +691,7 @@ centerSlice: widget.centerSlice, matchTextDirection: widget.matchTextDirection, invertColors: _invertColors, + filterQuality: widget.filterQuality, ); if (widget.excludeFromSemantics) return image;
diff --git a/packages/flutter/test/rendering/image_test.dart b/packages/flutter/test/rendering/image_test.dart index 1426262..fef1f8d 100644 --- a/packages/flutter/test/rendering/image_test.dart +++ b/packages/flutter/test/rendering/image_test.dart
@@ -93,6 +93,7 @@ ' image: [10×10]\n' ' alignment: center\n' ' invertColors: false\n' + ' filterQuality: low\n' ), );