fromImage static method
Extracts a ColorPalette from a source image, sampling pixels to keep the work bounded.
maxSamplePixels caps how many pixels are analyzed: larger images are
subsampled with a uniform stride, which preserves the dominant colors
while keeping extraction fast. region limits sampling to a
normalized sub-rectangle of the image (values 0..1), mirroring the
region support of the original palette_generator.
Implementation
static Future<ColorPalette> fromImage(
ui.Image image, {
int maxColors = 64,
int desiredColors = 16,
int maxSamplePixels = 128 * 128,
Rect? region,
PaletteWeights weights = const PaletteWeights(),
}) async {
final width = image.width;
final height = image.height;
if (width <= 0 || height <= 0) {
throw ArgumentError.value(image, 'image', 'must have non-empty bounds');
}
final byteData = await image.toByteData(format: ui.ImageByteFormat.rawRgba);
if (byteData == null) {
throw StateError('Failed to read pixel data from the source image');
}
final bytes = byteData.buffer.asUint8List();
// Normalized sampling region (defaults to the full image).
final rect = (region ?? Rect.zero).normalize();
final x0 = (rect.left * width).floor().clamp(0, width - 1);
final x1 = (rect.right * width).ceil().clamp(1, width);
final y0 = (rect.top * height).floor().clamp(0, height - 1);
final y1 = (rect.bottom * height).ceil().clamp(1, height);
final regionWidth = x1 - x0;
final regionHeight = y1 - y0;
final regionPixelCount = regionWidth * regionHeight;
// Uniform stride so that the number of sampled pixels stays close to
// maxSamplePixels without ever exceeding the actual region size.
final stride = regionPixelCount <= maxSamplePixels
? 1
: (regionPixelCount / maxSamplePixels).ceil();
final pixels = <int>[];
for (var y = y0; y < y1; y += stride) {
for (var x = x0; x < x1; x += stride) {
final offset = (y * width + x) * 4;
final r = bytes[offset];
final g = bytes[offset + 1];
final b = bytes[offset + 2];
pixels.add(0xFF000000 | (r << 16) | (g << 8) | b);
}
}
return extract(
pixels,
maxColors: maxColors,
desiredColors: desiredColors,
weights: weights,
);
}