代码之家  ›  专栏  ›  技术社区  ›  Robert Stevens

颤振-如何将图像与渐变颜色混合?

  •  7
  • Robert Stevens  · 技术社区  · 7 年前

    我正在尝试复制我的设计师为应用程序设计的登录屏幕。

    背景图像使用柔和灯光的混合模式,关键是它混合的颜色是渐变色。其次,实际上有两层不同的梯度(一个紫色梯度,一个蓝色梯度)

    原始图像:

    Original Image

    最终梯度图像

    Final Gradient Image

    现在我尝试使用colorBlendMode,例如。

    Image.asset(
          'assets/pioneer-party.jpg',
          fit: BoxFit.cover,
          color: Color(0xff0d69ff).withOpacity(1.0),
          colorBlendMode: BlendMode.softLight,
        ),
    

    问题是color属性只采用一种颜色。

    然后我试着做一些装饰。

    DecoratedBox(
          decoration: new BoxDecoration(
            color: const Color(0xff7c94b6),
            image: new DecorationImage(
              fit: BoxFit.cover,
              colorFilter: new ColorFilter.mode(Colors.purple.withOpacity(1.0), BlendMode.softLight),
              image: new NetworkImage(
                'http://www.allwhitebackground.com/images/2/2582-190x190.jpg',
              ),
            ),
          ),
        ),
    

    这仍然让我面临同样的问题。然后我试着把每一层都单独叠起来,然后用渐变使它看起来更接近设计,例如。

    Image.asset(
          'assets/pioneer-party.jpg',
          fit: BoxFit.cover,
          color: Color(0xff0d69ff).withOpacity(1.0),
          colorBlendMode: BlendMode.softLight,
        ),
        DecoratedBox(
          decoration: BoxDecoration(
            gradient: LinearGradient(
              begin: FractionalOffset.topCenter,
              end: FractionalOffset.bottomCenter,
              colors: [
                Color(0xff0d69ff).withOpacity(0.0),
                Color(0xff0069ff).withOpacity(0.8),
              ],
            ),
          ),
        ),
        DecoratedBox(
          decoration: BoxDecoration(
            gradient: LinearGradient(
              begin: FractionalOffset.topLeft,
              end: FractionalOffset.bottomRight,
              colors: [
                Color(0xff692eff).withOpacity(0.8),
                Color(0xff642cf4).withOpacity(0.8),
                Color(0xff602ae9).withOpacity(0.8),
                Color(0xff5224c8).withOpacity(0.8),
                Color(0xff5e29e5).withOpacity(0.8),
              ],
            stops: [0.0,0.25,0.5,0.75,1.0]
            ),
          ),
        ),
    

    这让我有点接近我想要的,但不完全是我需要的。

    有人知道实现这一目标的方法吗?

    编辑:

    我也在考虑将这两幅图像混合在一起,但除了使用不透明或其他方法外,还没有找到其他方法。理想情况下,我希望它是本地呈现的,而不是使用“黑客”来实现它。

    1 回复  |  直到 7 年前
        1
  •  74
  •   Pablo Cegarra    6 年前

    使用堆栈来获得这种效果非常简单。

       Stack(children: <Widget>[
            Container(
              decoration: BoxDecoration(
                color: Colors.transparent,
                image: DecorationImage(
                  fit: BoxFit.fill,
                  image: AssetImage(
                    'images/bg.jpg',
                  ),
                ),
              ),
              height: 350.0,
            ),
            Container(
              height: 350.0,
              decoration: BoxDecoration(
                  color: Colors.white,
                  gradient: LinearGradient(
                      begin: FractionalOffset.topCenter,
                      end: FractionalOffset.bottomCenter,
                      colors: [
                        Colors.grey.withOpacity(0.0),
                        Colors.black,
                      ],
                      stops: [
                        0.0,
                        1.0
                      ])),
            )
          ]),  
    

    干杯

        2
  •  17
  •   CopsOnRoad    6 年前

    你也可以试试这个:

    ColorFiltered(
      colorFilter: ColorFilter.mode(Colors.red.withOpacity(0.4), BlendMode.srcOver),
      child: YourWidget(),
    ) 
    
        3
  •  2
  •   Iheb Briki    3 年前

    我的解决方案是用shaderMask包装我的图像,这是一个对我有用的例子

    ShaderMask(
      shaderCallback: (bounds) {
        return LinearGradient(
          colors: node.badge!.colorsArray,
        ).createShader(bounds);
      },
      child: Image.asset(
        Assets.main_logo,
        height: 27.0,
        fit: BoxFit.cover,
      ),
      blendMode: BlendMode.srcATop,
    ),
    

    如果参考BlendMode文档 https://docs.flutter.io/flutter/dart-ui/BlendMode-class.html ,你可以找到你需要的东西 a busy cat

        4
  •  0
  •   vwk    3 年前

    编辑

    这个 const double scale = 2.04015; 在浏览器中运行“颤振”时,ontly工作。对于移动设备,使用 const double scale = 0;

    =================================================

    三年半后,我参加了聚会,但我注意到,没有一个答案能够理解想要的效果是什么。因此,让我们首先分析想要的结果,然后编写代码。

    梯度贴图

    这种效果被称为“渐变贴图”,因为每个像素值都在变化 映射 坡度 基于预定义的一组颜色。

    让我们看一看。如果输入是灰度图像, Color color1 = Colors.blue Color color2 = Colors.purple ,各个像素的颜色应按以下方式进行变换-

    Visual representation of gradient maps

    哪里

    • 黑色像素颜色-转换为蓝色
    • 白色像素颜色-转换为紫色
    • 中间颜色-转换为蓝色和紫色之间的适当颜色

    密码

    我最初的想法是拍摄一张图片,把它解码成 Uint8List 使用 getBytes() ,处理列表,最后将其编码回png。 虽然这种方法有效,但它远没有达到实时用例的性能。

    因此,第二种可行的方法是使用颜色矩阵创建效果-

    class GradientMap extends StatelessWidget {
    
      final Color color1;
      final Color color2;
      final double contrast;
      final ImageProvider imageProvider;
    
      const GradientMap({
        this.color1 = Colors.white,
        this.color2 = Colors.black,
        this.contrast = 0,
        required this.imageProvider,
        Key? key
      }) : super(key: key);
    
    
      ColorFilter grayscaleMatrix() => ColorFilter.matrix([
        0.2126,       0.7152,       0.0722,       0, 0,
        0.2126,       0.7152,       0.0722,       0, 0,
        0.2126,       0.7152,       0.0722,       0, 0,
        contrast-0.4, contrast-0.4, contrast-0.4, 1, 0,
      ]);
    
    
      ColorFilter invertMatrix() => const ColorFilter.matrix([
        -1,  0,  0, 0, 255,
         0, -1,  0, 0, 255,
         0,  0, -1, 0, 255,
         0,  0,  0, 1, 0,
      ]);
    
    
      ColorFilter tintMatrix () {
        final int r = color2.red;
        final int g = color2.green;
        final int b = color2.blue;
    
        final double rTint = r / 255;
        final double gTint = g / 255;
        final double bTint = b / 255;
    
        const double scale = 2.04015; // Use 0 on mobile instead
        const double translate = 1 - scale * 0.5;
    
        return ColorFilter.matrix(<double>[
          (rTint * scale), (rTint * scale), (rTint * scale), (0), (r * translate),
          (gTint * scale), (gTint * scale), (gTint * scale), (0), (g * translate),
          (bTint * scale), (bTint * scale), (bTint * scale), (0), (b * translate),
          (0            ), (0            ), (0            ), (1), (0            ),
        ]);
      }
    
    
      @override
      Widget build(BuildContext context) {
        return Container(
          color: color1,
          child: ColorFiltered(
            colorFilter: tintMatrix(),
            child: ColorFiltered(
              colorFilter: invertMatrix(),
              child: ColorFiltered(
                colorFilter: grayscaleMatrix(),
                child: Image(image: imageProvider)),
            ),
          ),
        );
      }
    }
    

    或者,您可以组合 grayscaleMatrix() invertMatrix() 变成一个,这样就不需要第三个了 ColorFiltered() 小装置。

    该小部件将数据作为输入

    • color1 -打火机 Color
    • color2 -黑暗的 颜色
    • contrast - double color1和color2之间的混合
    • imageProvider -图像提供者,例如 AssetImage() NetworkImage()

    并显示转换后的图像。 enter image description here

    用法

    只需按照以下方式使用此小部件包装ImageProvider-

    GradientMap(
      color1: Color.fromRGBO(158, 80, 254, 1),
      color2: Color.fromRGBO(15, 4, 192, 1),
      contrast: 0,
      imageProvider: NetworkImage("https://i.imgur.com/C5xknx8.png"),
    )
    

    缺点

    虽然这种方法性能良好,但用户无法控制两种输入颜色之间的混合算法。 此外,小部件只接受两种颜色作为输入。这消除了使用多色渐变的可能性。