-
Notifications
You must be signed in to change notification settings - Fork 26.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ImageFilter.blur creates shadow around image #39623
Comments
flutter doctor -v
|
A blur effect will extend the edges of the object being blurred as the pixels near the edge are blurred into the surrounding area. If you want to clip the edges of the blur off then you will need to use one of the various Clip* widgets (likely ClipRect in this case). |
Also note that we now have the ImageFiltered widget which can achieve the blur effect more directly, as in:
The ImageFiltered would also expand the bounds of the image due to the blur operation, so you would also need to use a ClipRect with this solution if you don't want the blurry edges to expand beyond the original image bounds. |
Hi @flar,tthansk for solution
using
Code Sample
flutter doctor -v
|
I'm not seeing that effect in this dartpad: https://dartpad.dev/1019ddb4e9c8d8a42370071b79f98426 I wonder if it is an effect that comes into play when the image is laid out in a container causing stretching of its edges? |
I can also confirm this issue. |
PreviewInside SliverAppBarScaffold Bodycode sampleimport 'dart:ui';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
theme: ThemeData.dark(),
home: Home(),
);
}
}
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
// body: CustomScrollView(
// slivers: [
// SliverAppBar(
// pinned: true,
// backgroundColor: Colors.red,
// collapsedHeight: 250,
// flexibleSpace: Stack(
// children: [
// Positioned.fill(
// child: ImageFiltered(
// imageFilter: ImageFilter.blur(
// sigmaX: 10,
// sigmaY: 10,
// ),
// child: Image.network(
// 'https://i.imgur.com/9OrBvmZ.jpg',
// fit: BoxFit.cover,
// ),
// ),
// ),
// ],
// ),
// ),
// SliverFillRemaining()
// ],
// ),
body: Container(
color: Colors.red,
child: Stack(
children: [
Positioned.fill(
child: ImageFiltered(
imageFilter: ImageFilter.blur(
sigmaX: 10,
sigmaY: 10,
),
child: Image.network(
'https://i.imgur.com/9OrBvmZ.jpg',
fit: BoxFit.cover,
),
),
),
],
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {},
),
);
}
} flutter doctor -v[✓] Flutter (Channel master, 1.24.0-8.0.pre.408, on macOS 11.0.1 20B29
darwin-x64, locale en-GB)
• Flutter version 1.24.0-8.0.pre.408 at
/Users/tahatesser/Code/flutter_master
• Framework revision 25986102c1 (2 hours ago), 2020-12-02 20:36:44 +0800
• Engine revision 20caf54969
• Dart version 2.12.0 (build 2.12.0-76.0.dev)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
• Android SDK at /Users/tahatesser/Code/sdk
• Platform android-30, build-tools 30.0.2
• ANDROID_HOME = /Users/tahatesser/Code/sdk
• Java binary at: /Applications/Android
Studio.app/Contents/jre/jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build
1.8.0_242-release-1644-b3-6915495)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 12.2)
• Xcode at /Volumes/Extreme/Xcode.app/Contents/Developer
• Xcode 12.2, Build version 12B45b
• CocoaPods version 1.10.0
[✓] Chrome - develop for the web
• Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
[✓] Android Studio (version 4.1)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build
1.8.0_242-release-1644-b3-6915495)
[✓] VS Code (version 1.51.1)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.16.0
[✓] Connected device (5 available)
• RMX2001 (mobile) • EUYTFEUSQSRGDA6D • android-arm64 •
Android 10 (API 29)
• Taha’s iPad (mobile) • 00008020-000255113EE8402E • ios • iOS
14.2
• macOS (desktop) • macos • darwin-x64 • macOS
11.0.1 20B29 darwin-x64
• Web Server (web) • web-server • web-javascript •
Flutter Tools
• Chrome (web) • chrome • web-javascript • Google
Chrome 87.0.4280.67
• No issues found! |
Hi @TahaTesser, thanks for getting back on my issue. Yeah I understand it's not an issue with the SliverAppBar, the issue for me would still be that I can't add a black background as the image can change based on the user. Is that the last option or is there something else I can do? |
See also: #64828 Can you check your layout to see if the widget is being aligned on a pixel boundary? |
@bsfdeep the edges of a blur will be affected by the opacity of the colors near the edges of the source and its sampling mode. We don't really provide control over the edge sampling mode in Flutter so everything tends to default to pretending that the edges of a source bitmap extend to infinity (as opposed to pretending that samples beyond the edge of a bitmap are transparent, or repeat, etc). The ImageFilter being applied is using the rendering of a widget as its source. If the widget is aligned to pixel boundaries and it is rendering an opaque content, then its rendered bitmap will be opaque at its edges and if those are extended to infinity then the edges of the blur will be sampling and blurring the edges of the opaque image at the edges of the blur and the edges of the blur will also be opaque. Note that I'm not talking about the fact that the container has a decoration that comes from an image and whether that source image is opaque, I'm talking about when the container goes to render that decoration whether it renders it on pixel boundaries on the destination surface. The opaque image can be rendered onto that temp surface (which will eventually be used as the source of the ImageFilter) at a sub-pixel translation and then the edge pixels of the temp surface may not be opaque even if the edges of the image being tiled/centered/stretched/etc. are opaque. So, if the source widget's device space boundary is not aligned with pixels then when they get rendered, they will leave the edge pixels of the source semi-transparent. Now that semi-transparent edge pixel is the one that is sampled out to infinity by the blur when it does its averaging near the edges and so the edges of the blur will be averaging together those semi-transparent values and allowing the background to shine through. This is all discussed in the issue I linked. |
@flar That is a great explanation, thank you so much for taking the time. How do I know if my widget is being aligned on a pixel boundary, do I wrap it in a
I did fix my issue by wrapping it in a |
The -3 may have just caused the app to extend out of the bounds of the Stack a little so as to push the potentially Antialiased/partially covered edge pixels to be out of sight. The real fix would be to query the DPR and to ensure that the size and the location are integers when scaled by that number (assuming no other scale in effect, but there may be a translation in effect from Scaffolds and such). The computation would be For devices with an integer DPR, just having the coordinates and sizes all be integers should be fine, but for devices with non-integer DPR, then you need to perform that calculation. Note that if you use auto-layout widgets like Center and Row/Column, etc. then you are at the mercy of their calculations. Centering an odd sized child in an even sized container, or vice versa, will put you on non-integer coordinates. It gets more complicated when Rows and Columns compute the space they want to distribute between children and how they apportion that overflow space. I'm taking a look at a series of examples of where non-integer coordinates can come into play to see what recommendations or changes can be made to make all of this easier for the developer. Unfortunately, Flutter does most layout computations behind the scenes on values that aren't easily queried by the app code (it's not rocket science, but you have to use Key objects and find the RenderObject instances on the second frame and the information can't be queried on the first frame, so it's not obvious and it's a bit klunky) so it gets a little tricky to fix these problems and I'll be looking into what we can do to make that process more natural. Your technique of just oversizing the blurred background may be the easiest workaround for now. For an example of determining actual size and positioning of your widgets, you can check out the workarounds I used in this gist that is trying to deal with an anchored rotation for an ImageFiltered matrix filter (note the _childKey and _childCenter variables and how they are created and used): https://gist.github.com/flar/639cf7fcc0988ee9d68333c269e42181 |
In the meantime I also looked more deeply into how we create blur filters and discovered that Skia has an edge sampling parameter (or "tile mode" as they call it) that we hard-code to edge sampling. They also have a decal mode which assumes transparency around the edges of the source which might work better for rotated/rotating/non-edge filled children. A variant of that property appears in our gradient constructors. |
@flar Thanks for the explanation. I just got a chance to look at the gist, though I see how it can be used I guess I'll stick to oversizing the blurred background to avoid complicating it for now. Thanks again for looking into it. |
Also, check this #57180 (comment) |
See now #71871 That issue proposes a solution for the distortions at the edge of blurred shapes and doesn't provide help or remedy for the translucent edges of a background image blur. The latter may require some new ways to control layout, or the rendering of background images. |
Using the code sample provided here and here, I am unable to replicate the behavior on latest versions. Closing as fixed. stable, master flutter doctor -v
|
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of |
When wanting to blur an image in flutter, it creates a shadow around the image. While nothing app-breaking, it is a nuisance when your lead designer wants NO shadow on the image.
Steps to Reproduce
bunch of unused imports and fields
Flutter doctor
The text was updated successfully, but these errors were encountered: