Flutter如何获取图片主色调

1,296 阅读4分钟

嗨,这里是甜瓜看代码。这篇文章跟大伙唠唠Flutter如何获取图片的主体色。

为什么要获取图片主色调?

  在移动应用开发中,颜色是界面设计的重要组成部分。有时候,我们希望根据一张图片的主要颜色来设置整体的配色方案,从而使页面具有统一的风格。而想要获取图片主色调,其实本质就是获取出现最多次的某种色值的像素点,因此我们顺着这个思路展开。

获取图片中颜色最多的像素点的步骤

下面是使用Flutter获取图片中颜色最多的像素点的步骤:

1. 导入必要的库

首先,我们需要导入Flutter的dart:ui库,它提供了访问底层图像处理功能的接口。在你的Flutter项目中的pubspec.yaml文件中添加以下依赖项,当然这一般都是默认就有的,在项目创建之初:

dependencies:
  flutter:
    sdk: flutter

dev_dependencies:
  flutter_test:
    sdk: flutter

2. 加载图片

  接下来,我们需要加载我们想要获取主要颜色的图片。使用Flutter的ImageProvider类可以轻松实现这一点。以下是加载图片的示例代码:

import 'dart:ui' as ui;

Future<ui.Image> loadImage() async {
  final Completer<ui.Image> completer = Completer();
  const imageProvider = NetworkImage('url');
  imageProvider.resolve(const ImageConfiguration()).addListener(
    ImageStreamListener((info, _) async {
      completer.complete(info.image);
    }),
  );
  return completer.future;
}

// 使用示例
final image = await loadImage();

3. 分析像素

  现在,我们已经成功加载了图片。接下来,我们将分析图片中的像素,并计算每种颜色的出现次数。以下是计算每种颜色出现次数的示例代码:

import 'dart:ui' as ui;

Future<Map<int, int>> countColors(ui.Image image) async {
  Uint8List bytes = await image
      .toByteData(format: ui.ImageByteFormat.rawRgba)
      .then((data) => data!.buffer.asUint8List());
  final colorCount = <int, int>{};

  for (int i = 0; i < bytes.lengthInBytes; i += 4) {
    final alpha = bytes[i];
    final red = bytes[i + 1];
    final green = bytes[i + 2];
    final blue = bytes[i + 3];

    final key = (blue << 24) | (red << 16) | (green << 8) | alpha;

    if (colorCount.containsKey(key)) {
      colorCount[key] = colorCount[key]! + 1;
    } else {
      colorCount[key] = 1;
    }
  }
  return colorCount;
}

// 使用示例
final colorCounts = countColors(image);

4. 找到颜色最多的像素点

  现在,我们已经计算了每种颜色出现的次数。接下来,我们需要找到颜色出现次数最多的像素点。以下是找到颜色最多的像素点的示例代码:

int findMostCommonColor(Map<int, int> colorCounts) {
  int mostCommonColor = 0;
  int maxCount = 0;

  colorCounts.forEach((color, count) {
    if (count > maxCount) {
      mostCommonColor = color;
      maxCount = count;
    }
  });

  return mostCommonColor;
}

// 使用示例
final mostCommonColor = findMostCommonColor(colorCounts);

5. 解析颜色值

  最后,我们将解析颜色值并获取其中的红、绿、蓝和透明度分量。以下是解析颜色值的示例代码:

import 'package:flutter/material.dart';

Color parseColor(int color) {
  final alpha = (color >> 24) & 0xFF;
  final red = (color >> 16) & 0xFF;
  final green = (color >> 8) & 0xFF;
  final blue = color & 0xFF;

  return Color.fromARGB(alpha, red, green, blue);
}

// 使用示例
final mostCommonColorValue = parseColor(mostCommonColor);

  现在,mostCommonColorValue将包含颜色最多的像素点的颜色值。到这里本文应该就结束了,但是使用过后发现这个实现有其局限性,因为它获取的是每个像素点的色值,这会过于精确以至于只能适用主体色调相对单一的情况。那么该如何实现呢?

Android中Palette库的实现

  在安卓中使用Palette库获取图像的主体颜色时,Palette库使用了一种基于统计的算法来提取颜色信息。该算法的主要思想是分析图像中的像素分布和颜色频率,以确定主要的颜色。

Palette库的算法主要包括以下步骤:

  1. 颜色量化:首先,算法会对图像进行颜色量化,将连续的颜色空间分割成离散的颜色桶。这有助于降低计算复杂度并提高效率。

  2. 颜色统计:接下来,算法会遍历图像中的每个像素,并将每个像素的颜色值分配给相应的颜色桶。通过统计每个颜色桶中的像素数量,算法得到颜色的频率信息。

  3. 颜色提取:根据颜色频率,算法选择一组主要的颜色作为图像的主体颜色。常见的提取方式包括选择频率最高的几个颜色,或者使用一些启发式规则来选择具有代表性的颜色。

  看完这个实现,再掂量了一下自己的能力,我觉的我不可以。不过经过一番周折,我找到了一个库,基本上是能够实现的。

color_thief_dart库实现Flutter获取图片主色调

  这里先放上库的链接:color_thief_dart

实现

final Completer<ui.Image> completer = Completer();
const imageProvider = NetworkImage(
  'https://img.zcool.cn/community/01a88c5c83d982a801217ce671e935.jpg@1280w_1l_2o_100sh.jpg');
imageProvider.resolve(const ImageConfiguration()).addListener(
ImageStreamListener((info, _) async {
  getColorFromImage(info.image);
}),
);

  getColorFromImage(info.image)的返回值作者的注释是returns the base color from the largest cluster, represented as R,G,B,意思就是返回最大簇的基色,表示为R,G,B。通过这个注释合理推测一下,作者通过获取到所有像素点的RGB值,然后通过算法对像素点进行簇类划分,之后将最大簇求RGB的平均值,最后这个返回值即主体色的RGB值。

总结

  虽然没有自己实现这个功能,但是这个过程学会了如何获取Flutter中图片的像素点,如何去计算RGB值,也算有所收获。也了解到了安卓中取色器的算法实现思路,最后通过color_thief_dart库实现了目标。

  希望这篇文章对你有所帮助。这里是甜瓜看代码,期待你的关注!