# palette_generator_plus

[![pub version](https://img.shields.io/pub/v/palette_generator_plus.svg)](https://pub.dev/packages/palette_generator_plus)
[![pub points](https://img.shields.io/pub/points/palette_generator_plus)](https://pub.dev/packages/palette_generator_plus/score)
[![likes](https://img.shields.io/pub/likes/palette_generator_plus)](https://pub.dev/packages/palette_generator_plus/score)
[![CI](https://github.com/KEREM-BAS/palette_generator_plus/actions/workflows/ci.yaml/badge.svg)](https://github.com/KEREM-BAS/palette_generator_plus/actions/workflows/ci.yaml)
[![License: BSD-3-Clause](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)](LICENSE)

The maintained, modernized **successor to Flutter's discontinued
[`palette_generator`](https://pub.dev/packages/palette_generator)** package
(officially discontinued in
[flutter/flutter#162963](https://github.com/flutter/flutter/issues/162963), which
invited a sustainable community fork).

`palette_generator_plus` extracts the prominent colors — dominant, vibrant,
muted, and their light/dark variants — from any image, and adds the modern
capabilities the original never had:

- 🧵 **Isolate-based extraction** by default, with a transparent main-thread
  fallback on the web.
- 🎨 **Pluggable quantizers** — a `material_color_utilities`-backed
  `CelebiQuantizer` (default) and the original median-cut `LegacyQuantizer` for
  byte-identical legacy output.
- 🧩 **One-call Material 3 bridge** — turn any image into a complete
  `ColorScheme`.
- ♿ **WCAG-accessible text colors** — exact WCAG 2.1 contrast math and helpers.
- 🔁 **Drop-in compatible** — the entire original public API is preserved.

## Migrating from `palette_generator`

Migration is a **single import-line change**. Every existing class, method,
parameter, and getter keeps the same name and a compatible signature:

```diff
- import 'package:palette_generator/palette_generator.dart';
+ import 'package:palette_generator_plus/palette_generator_plus.dart';
```

Your existing code compiles and runs unchanged. Everything else this package adds
is **strictly additive**.

> **Note:** colors are extracted with the modern `CelebiQuantizer` by default.
> For output that is byte-identical to `palette_generator 0.3.3+7`, pass
> `quantizer: const LegacyQuantizer()` to any `from*` constructor.

## Why this package?

| Capability | `palette_generator_plus` | `palette_generator` (discontinued) | `ColorScheme.fromImageProvider` |
| --- | :---: | :---: | :---: |
| Maintained | ✅ | ❌ | ✅ |
| Raw swatches + population counts | ✅ | ✅ | ❌ |
| Named targets (vibrant / muted / …) | ✅ | ✅ | ❌ |
| Drop-in API of `palette_generator` | ✅ | — | ❌ |
| Isolate extraction (off the UI thread) | ✅ | ❌ | ❌ |
| Pluggable quantizer | ✅ | ❌ | ❌ |
| Material 3 `ColorScheme` in one call | ✅ | ❌ | ✅ |
| WCAG contrast helpers | ✅ | ❌ | ❌ |
| Modern color API, zero deprecations | ✅ | ❌ | ✅ |
| All 6 platforms | ✅ | ✅ | ✅ |

## Quickstart

Add the dependency:

```yaml
dependencies:
  palette_generator_plus: ^1.0.0
```

### Basic extraction

```dart
import 'package:palette_generator_plus/palette_generator_plus.dart';

final PaletteGenerator palette = await PaletteGenerator.fromImageProvider(
  const AssetImage('assets/landscape.png'),
);

final Color? dominant = palette.dominantColor?.color;
for (final PaletteColor swatch in palette.paletteColors) {
  print('${swatch.color} occurs ${swatch.population} times');
}
```

### Named swatches

```dart
final Color? vibrant = palette.vibrantColor?.color;
final Color? darkMuted = palette.darkMutedColor?.color;
final Color? lightVibrant = palette.lightVibrantColor?.color;
```

### Material 3 `ColorScheme` in one call

```dart
final ColorScheme scheme = palette.toColorScheme(
  brightness: Brightness.dark,
);
final ThemeData theme = ThemeData.from(colorScheme: scheme);

// Or just grab the seed for ThemeData(colorSchemeSeed: ...):
final Color seed = palette.seedColor;
```

### WCAG-accessible text colors

```dart
// A fully-opaque black or white that reads accessibly on the swatch:
final Color textColor = palette.dominantColor!.accessibleOnColor(
  level: WcagLevel.aaa,
);

// Or use the standalone helpers on any color:
final double ratio = contrastRatio(Colors.black, Colors.white); // 21.0
final Color onSurface = wcagTextColor(scheme.surface);
```

### Choose the quantizer / run on the main thread

```dart
final PaletteGenerator legacy = await PaletteGenerator.fromImageProvider(
  const AssetImage('assets/landscape.png'),
  quantizer: const LegacyQuantizer(), // byte-identical to the original
  runInIsolate: false,                // opt out of the background isolate
);
```

See the [`example/`](example/) directory for a complete app (it also runs as a
live web demo via `flutter build web`).

## API overview

| Symbol | Description |
| --- | --- |
| `PaletteGenerator.fromImage` / `.fromImageProvider` / `.fromByteData` | Extract a palette from an image. |
| `PaletteColor` | A swatch: `color`, `population`, `titleTextColor`, `bodyTextColor`, `accessibleOnColor`. |
| `PaletteTarget` | A tunable target in HSL space; predefined `vibrant`, `muted`, etc. |
| `PaletteFilter` / `avoidRedBlackWhitePaletteFilter` | Filter which colors are eligible. |
| `Quantizer` / `CelebiQuantizer` / `LegacyQuantizer` | Pluggable color-reduction algorithms. |
| `PaletteGenerator.seedColor` / `.toColorScheme()` | Material 3 bridge. |
| `contrastRatio` / `wcagTextColor` / `WcagLevel` | WCAG 2.1 accessibility helpers. |
| `EncodedImage` | Raw RGBA pixel data for `fromByteData`. |

## Compatibility

Pure Dart/Flutter — no platform channels or native code. Runs on **Android, iOS,
web, Windows, macOS and Linux**. On the web, where `dart:isolate` is
unavailable, `runInIsolate` transparently falls back to the main thread; the
result is identical regardless of where it runs.

## Acknowledgements

This package is a community-maintained fork and successor of the discontinued
[`palette_generator`](https://pub.dev/packages/palette_generator) package, last
published as `palette_generator 0.3.3+7`, originally created by **The Flutter
Authors / Google** and distributed under the BSD-3-Clause license.

Files derived from the original retain their original copyright headers; see
[`LICENSE`](LICENSE) and [`NOTICE`](NOTICE). The discontinuation and community
fork invitation are tracked in
[flutter/flutter#162960](https://github.com/flutter/flutter/issues/162960) and
[flutter/flutter#162963](https://github.com/flutter/flutter/issues/162963).

Color science is powered by
[`material_color_utilities`](https://pub.dev/packages/material_color_utilities),
the same library behind Flutter's dynamic color and Android's Material You.

## Contributing

Issues and pull requests are welcome at
<https://github.com/KEREM-BAS/palette_generator_plus>. Please run
`dart format .`, `flutter analyze` and `flutter test` before submitting.

## License

BSD-3-Clause. See [`LICENSE`](LICENSE).
