James Williams
BlueskyLinkedInMastodonGithub

Extracting Colors From An Image

A couple of months ago, we announced that some packages would cease development and be deprecated as of April 30. One of them was palette_generator.

I have good news and bad news regarding a replacement. The good news is that there has been a replacement in plain sight for several years now. The bad news is that it’s not a one to one replacement. But that’s not a totally bad thing.

Background

palette_generator mirrors the Android Palette API that is pretty ancient in Android terms. The initial Android support library dates back to at least 2017. Back then, Material was only a couple years old (it just turned 10!), and public release numbers for Android were still in the single digits. Eventually, that version of the API was locked as stable in 2018.

While that library has been etched in stone, the ways we use and define color for theming have continued to evolve. I wrote a post almost a year ago detailing how to think about color in Material 3. I won’t rehash it here other than to say that the relationships between color roles are well considered in Material 3. The output of the Palette API/palette_generator wouldn’t work well in a Material theme and would likely still be limiting in a more bespoke Flutter theme.

This limited set of tones (Vibrant, Vibrant Dark, Vibrant Light, Muted, Muted Dark, Muted Light) doesn’t have affordances for contrast levels or for generating complementary colors. It simply takes the dominant colors in the image and tries to slot them into one of those roles.

What to Use Instead?

So if the palette_generator package and the Palette API is not a good solution, what should you use instead, you might be wondering. material_color_utilities[https://pub.dev/packages/material_color_utilities] is the answer. It’s bundled as a dependency of Flutter, so it’s highly available across implementations. But what if you aren’t using Material? You can still use it; you can determine how "Material-y" you want to be.

I’ve created a small sample app showing palette_generator and material_color_utilities side by side]. You only need to pay attention to the functions in this file: https://github.com/jwill/extract_palette_from_image/blob/main/lib/image.dart

If you just want the colors, use the function getColorsFromImage. The scoring algorithm will run some out as being unsuitable for a UI but it doesn’t mutate the colors. If no suitable colors are found, material_color_utilities will return blue or red (though that is an increasingly rare error condition).

Future<List<Color>> getColorsFromImage(ImageProvider provider) async {
  try {
    // Extract dominant colors from image.
    final quantizerResult = await _extractColorsFromImageProvider(provider);
    final Map<int, int> colorToCount = quantizerResult.colorToCount.map(
          (key, value) => MapEntry<int, int>(_getArgbFromAbgr(key), value),
    );

    // Score colors for color scheme suitability.
    final List<int> filteredResults = Score.score(
      colorToCount,
      desired: 1,
      filter: true,
    );
    final List<int> scoredResults = Score.score(
      colorToCount,
      desired: 4,
      filter: false,
    );
    return <dynamic>{...filteredResults, ...scoredResults}
        .toList()
        .map((argb) => Color(argb))
        .toList();
  } catch (e) {
    debugPrint('Error getting colors from image: $e');
    return [];
  }
}

You can pass any of the returned colors into ColorScheme.fromSeed() to generate a full scheme (with a shifted version of that color in the primary slot). If you want that literal color, you can call ColorScheme.fromSeed with a dynamicSchemeVariant parameter set to DynamicSchemeVariant.fidelity or DynamicSchemeVariant.content.

In the screenshots below, we can see another reason why the older API is not reliable; sometimes not all of the color roles are populated.

Side by side of palette_generator and material_color_utilities Side by side of palette_generator and material_color_utilities where palette_generator is missing colors

This is just one of the useful capabilities of material_color_utilities and related classes like ColorScheme. Flutter developers can implement more sophisticated and flexible color extraction in their apps, align with modern design principles, and choose how much they want to adhere to a specific design system.

Copyright 2025 - James Williams - Powered by kass