从图片中选择主要颜色

时间:2018-05-21 13:06:52

标签: android ios dart flutter

我是Dart / Flutter框架的新手,我仍在探索他们的可能性。

我知道在Android中可以拍摄照片并以编程方式从中提取主要颜色值。 (Android example

我想知道,如何在纯飞镖中实现这一目标?我希望它与iOS和Android平台兼容。

2 个答案:

答案 0 :(得分:9)

这是一个简单的函数,在给定ImageProvider的情况下返回主色。这显示了Palette Generator的基本用法,而没有所有样板。

import 'package:palette_generator/palette_generator.dart';

// Calculate dominant color from ImageProvider
Future<Color> getImagePalette (ImageProvider imageProvider) async {
  final PaletteGenerator paletteGenerator = await PaletteGenerator
      .fromImageProvider(imageProvider);
  return paletteGenerator.dominantColor.color;
}

然后在输出上使用FutureBuilder来构建窗口小部件。

答案 1 :(得分:2)

我可能认为您已解决问题,但为了以后对此问题进行搜索,建议您由颤振团队检查Pallete Generator。 我将尝试对代码的工作方式进行简单的解释,但有关示例的详细信息,请转到插件的GitHub repo

下面的示例将要拍摄图像,然后从图像中选择主要颜色,然后显示颜色

首先,我们添加所需的导入

import 'package:palette_generator/palette_generator.dart';

然后,我们创建主应用程序类。

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Colors from image',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        // This is the theme of your application.
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(
        title: 'Colors from image',
        image: AssetImage(
          'assets/images/artwork_default.png',
        ),
        imageSize: Size(256.0, 170.0),
      ),
    );
  }
}

在上面的图像字段中,放置您要从中提取主色的图像,我使用了here所示的图像。

接下来,我们创建HomePage类

@immutable
class HomePage extends StatefulWidget {
  /// Creates the home page.
  const HomePage({
    Key key,
    this.title,
    this.image,
    this.imageSize,
  }) : super(key: key);

  final String title; //App title
  final ImageProvider image; //Image provider to load the colors from
  final Size imageSize; //Image dimensions

  @override
  _HomePageState createState() {
    return _HomePageState();
  }
}

我们也创建_HomePageState

class _HomePageState extends State<HomePage> {
  Rect region;
  PaletteGenerator paletteGenerator;

  final GlobalKey imageKey = GlobalKey();

  @override
  void initState() {
    super.initState();
    region = Offset.zero & widget.imageSize;
    _updatePaletteGenerator(region);
  }

  Future<void> _updatePaletteGenerator(Rect newRegion) async {
    paletteGenerator = await PaletteGenerator.fromImageProvider(
      widget.image,
      size: widget.imageSize,
      region: newRegion,
      maximumColorCount: 20,
    );
    setState(() {});
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: _kBackgroundColor,
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        mainAxisSize: MainAxisSize.max,
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          new AspectRatio(
            aspectRatio: 15 / 15,
            child: Image(
              key: imageKey,
              image: widget.image,
            ),
          ),
          Expanded(child: Swatches(generator: paletteGenerator)),
        ],
      ),
    );
  }
}

上面的代码只是布置图像和Swatches,这是下面定义的类。在initState中,我们首先选择一个区域,从该区域将得出颜色,在本例中为整个图像。

此后,我们创建一个Swatches类,该类接收一个PalleteGenerator并为其绘制色板。

class Swatches extends StatelessWidget {

  const Swatches({Key key, this.generator}) : super(key: key);

  // The PaletteGenerator that contains all of the swatches that we're going
  // to display.
  final PaletteGenerator generator;

  @override
  Widget build(BuildContext context) {
    final List<Widget> swatches = <Widget>[];
    //The generator field can be null, if so, we return an empty container
    if (generator == null || generator.colors.isEmpty) {
      return Container();
    }
    //Loop through the colors in the PaletteGenerator and add them to the list of swatches above
    for (Color color in generator.colors) {
      swatches.add(PaletteSwatch(color: color));
    }
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: <Widget>[
        //All the colors,
        Wrap(
          children: swatches,
        ),
        //The colors with ranking
        Container(height: 30.0),
        PaletteSwatch(label: 'Dominant', color: generator.dominantColor?.color),
        PaletteSwatch(
            label: 'Light Vibrant', color: generator.lightVibrantColor?.color),
        PaletteSwatch(label: 'Vibrant', color: generator.vibrantColor?.color),
        PaletteSwatch(
            label: 'Dark Vibrant', color: generator.darkVibrantColor?.color),
        PaletteSwatch(
            label: 'Light Muted', color: generator.lightMutedColor?.color),
        PaletteSwatch(label: 'Muted', color: generator.mutedColor?.color),
        PaletteSwatch(
            label: 'Dark Muted', color: generator.darkMutedColor?.color),
      ],
    );
  }
}

之后,让我们创建一个PaletteSwatch类。调色板色板只是带有可选标签的颜色正方形

@immutable
class PaletteSwatch extends StatelessWidget {
  // Creates a PaletteSwatch.
  //
  // If the [color] argument is omitted, then the swatch will show a
  // placeholder instead, to indicate that there is no color.
  const PaletteSwatch({
    Key key,
    this.color,
    this.label,
  }) : super(key: key);

  // The color of the swatch. May be null.
  final Color color;

  // The optional label to display next to the swatch.
  final String label;

  @override
  Widget build(BuildContext context) {
    // Compute the "distance" of the color swatch and the background color
    // so that we can put a border around those color swatches that are too
    // close to the background's saturation and lightness. We ignore hue for
    // the comparison.
    final HSLColor hslColor = HSLColor.fromColor(color ?? Colors.transparent);
    final HSLColor backgroundAsHsl = HSLColor.fromColor(_kBackgroundColor);
    final double colorDistance = math.sqrt(
        math.pow(hslColor.saturation - backgroundAsHsl.saturation, 2.0) +
            math.pow(hslColor.lightness - backgroundAsHsl.lightness, 2.0));

    Widget swatch = Padding(
      padding: const EdgeInsets.all(2.0),
      child: color == null
          ? const Placeholder(
              fallbackWidth: 34.0,
              fallbackHeight: 20.0,
              color: Color(0xff404040),
              strokeWidth: 2.0,
            )
          : Container(
              decoration: BoxDecoration(
                  color: color,
                  border: Border.all(
                    width: 1.0,
                    color: _kPlaceholderColor,
                    style: colorDistance < 0.2
                        ? BorderStyle.solid
                        : BorderStyle.none,
                  )),
              width: 34.0,
              height: 20.0,
            ),
    );

    if (label != null) {
      swatch = ConstrainedBox(
        constraints: const BoxConstraints(maxWidth: 130.0, minWidth: 130.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            swatch,
            Container(width: 5.0),
            Text(label),
          ],
        ),
      );
    }
    return swatch;
  }
}

希望这会有所帮助,谢谢。