How to get dominant color from image in flutter?
Asked Answered
S

4

10

I want to extract dominant color from a image so that i can apply it as blending to other images. how can i achieve that??

In my current code i have given color manually but i want it to be generated by app.

class MyApp extends StatelessWidget {

  Color face = new HexColor("a8a8a8");
  @override
  Widget build(BuildContext context) {

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("Image from assets"),
        ),
        body: Column (
            mainAxisAlignment: MainAxisAlignment.center,
              children:<Widget>[
                Row(
                    mainAxisAlignment: MainAxisAlignment.start,
                    children:<Widget>[
                      new Image.asset('assets/images/6.jpg',
                        color: face, colorBlendMode:BlendMode.modulate ,
                        fit:BoxFit.cover,
                        height: 50,
                        width: 50,
                      ),


                new Image.asset('assets/images/1.jpg',
              color: face, colorBlendMode: BlendMode.modulate,
            fit:BoxFit.cover,
                  height: 200,
                  width: 200,
          ),
                    ]),
                ])),
    );
  }
}


Semifinalist answered 3/7, 2020 at 15:15 Comment(0)
S
18

I found solution using palette_generator package.. First import library

import 'package:palette_generator/palette_generator.dart';

add it in pubspec.yaml file too

The below function will return palette

Future<PaletteGenerator>_updatePaletteGenerator ()async
{
  paletteGenerator = await PaletteGenerator.fromImageProvider(
    Image.asset("assets/images/8.jfif").image,
  );
return paletteGenerator;
}

Now we can fetch it in future builder

  FutureBuilder<PaletteGenerator>(
                  future: _updatePaletteGenerator(), // async work
                  builder: (BuildContext context, AsyncSnapshot<PaletteGenerator> snapshot) {
                    switch (snapshot.connectionState) {
                      case ConnectionState.waiting: return Center(child:CircularProgressIndicator());
                      default:
                        if (snapshot.hasError)
                          return new Text('Error: ${snapshot.error}');
                        else {
                         // Color color=new Color(snapshot.data.dominantColor.color);
                          face=snapshot.data.dominantColor.color;
                           return new Text('color: ${face.toString()}');
                              }}})

This is how we can fetch dominant color easily

Semifinalist answered 5/7, 2020 at 9:14 Comment(0)
M
2

Here you have the palette_generator library, and even if you search on youtube or some other places you can find some tutorials about which results gives you.

https://pub.dev/packages/palette_generator

Molality answered 3/7, 2020 at 15:29 Comment(1)
it has bad documentation. i have read it but didn't get itSemifinalist
M
1
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:image/image.dart' as img;
import 'package:flutter/services.dart' show rootBundle;

void main() => runApp(const MaterialApp(home: MyApp()));

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String imagePath = 'assets/5.jpg';
  GlobalKey imageKey = GlobalKey();
  GlobalKey paintKey = GlobalKey();

  // CHANGE THIS FLAG TO TEST BASIC IMAGE, AND SNAPSHOT.
  bool useSnapshot = true;

  // based on useSnapshot=true ? paintKey : imageKey ;
  // this key is used in this example to keep the code shorter.
  late GlobalKey currentKey;

  final StreamController<Color> _stateController = StreamController<Color>();
  //late img.Image photo ;
  img.Image? photo;

  @override
  void initState() {
    currentKey = useSnapshot ? paintKey : imageKey;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    final String title = useSnapshot ? "snapshot" : "basic";
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(title: Text("Color picker $title")),
        body: StreamBuilder(
            initialData: Colors.green[500],
            stream: _stateController.stream,
            builder: (buildContext, snapshot) {
              Color selectedColor = snapshot.data as Color ?? Colors.green;
              return Stack(
                children: <Widget>[
                  RepaintBoundary(
                    key: paintKey,
                    child: GestureDetector(
                      onPanDown: (details) {
                        searchPixel(details.globalPosition);
                      },
                      onPanUpdate: (details) {
                        searchPixel(details.globalPosition);
                      },
                      child: Center(
                        child: Image.asset(
                          imagePath,
                          key: imageKey,
                          //color: Colors.red,
                          //colorBlendMode: BlendMode.hue,
                          //alignment: Alignment.bottomRight,
                          fit: BoxFit.contain,
                          //scale: .8,
                        ),
                      ),
                    ),
                  ),
                  Container(
                    margin: const EdgeInsets.all(70),
                    width: 50,
                    height: 50,
                    decoration: BoxDecoration(
                        shape: BoxShape.circle,
                        color: selectedColor!,
                        border: Border.all(width: 2.0, color: Colors.white),
                        boxShadow: [
                          const BoxShadow(
                              color: Colors.black12,
                              blurRadius: 4,
                              offset: Offset(0, 2))
                        ]),
                  ),
                  Positioned(
                    child: Text('${selectedColor}',
                        style: const TextStyle(
                            color: Colors.white,
                            backgroundColor: Colors.black54)),
                    left: 114,
                    top: 95,
                  ),
                ],
              );
            }),
      ),
    );
  }

  void searchPixel(Offset globalPosition) async {
    if (photo == null) {
      await (useSnapshot ? loadSnapshotBytes() : loadImageBundleBytes());
    }
    _calculatePixel(globalPosition);
  }

  void _calculatePixel(Offset globalPosition) {
    RenderBox box = currentKey.currentContext!.findRenderObject() as RenderBox;
    Offset localPosition = box.globalToLocal(globalPosition);

    double px = localPosition.dx;
    double py = localPosition.dy;

    if (!useSnapshot) {
      double widgetScale = box.size.width / photo!.width;
      print(py);
      px = (px / widgetScale);
      py = (py / widgetScale);
    }

    int pixel32 = photo!.getPixelSafe(px.toInt(), py.toInt());
    int hex = abgrToArgb(pixel32);

    _stateController.add(Color(hex));
  }

  Future<void> loadImageBundleBytes() async {
    ByteData imageBytes = await rootBundle.load(imagePath);
    setImageBytes(imageBytes);
  }

  Future<void> loadSnapshotBytes() async {
    RenderRepaintBoundary boxPaint =
        paintKey.currentContext!.findRenderObject() as RenderRepaintBoundary;
    //RenderObject? boxPaint = paintKey.currentContext.findRenderObject();
    ui.Image capture = await boxPaint.toImage();

    ByteData? imageBytes =
        await capture.toByteData(format: ui.ImageByteFormat.png);
    setImageBytes(imageBytes!);
    capture.dispose();
  }

  void setImageBytes(ByteData imageBytes) {
    List<int> values = imageBytes.buffer.asUint8List();
    photo;
    photo = img.decodeImage(values)!;
  }
}

// image lib uses uses KML color format, convert #AABBGGRR to regular #AARRGGBB
int abgrToArgb(int argbColor) {
  int r = (argbColor >> 16) & 0xFF;
  int b = argbColor & 0xFF;
  return (argbColor & 0xFF00FF00) | (b << 16) | r;
}
Michaelemichaelina answered 3/12, 2022 at 18:41 Comment(0)
D
1

Use:

ColorScheme.fromImageProvider(provider: image.image)

See Flutter documentation:

https://api.flutter.dev/flutter/material/ColorScheme/fromImageProvider.html

The example below is simplified, the future should be a class attribute to avoid recalculation on each build:

final image = Image.asset(path);

return FutureBuilder(
  future: ColorScheme.fromImageProvider(provider: image.image),
  builder: (ctx, snap) {
    if (snap.connectionState == ConnectionState.waiting) {
      return const SizedBox.shrink();
    }
    final color = snap.data!.primaryContainer;

    // ...
});
Derte answered 8/6 at 10:17 Comment(1)
Thanks You just saved my serveral days , PaletteGenerator freezes ui so we have to use isolates in order to get the paletteKriskrischer

© 2022 - 2024 — McMap. All rights reserved.