-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathimage.dart
More file actions
118 lines (105 loc) · 3.99 KB
/
Copy pathimage.dart
File metadata and controls
118 lines (105 loc) · 3.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:material_color_utilities/material_color_utilities.dart';
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 [];
}
}
// ColorScheme.fromImageProvider() utilities.
// Extracts bytes from an [ImageProvider] and returns a [QuantizerResult]
// containing the most dominant colors.
Future<QuantizerResult> _extractColorsFromImageProvider(
ImageProvider imageProvider) async {
final ui.Image scaledImage = await _imageProviderToScaled(imageProvider);
final ByteData? imageBytes = await scaledImage.toByteData();
final QuantizerResult quantizerResult = await QuantizerCelebi().quantize(
imageBytes!.buffer.asUint32List(),
128,
returnInputPixelToClusterPixel: true,
);
return quantizerResult;
}
// Scale image size down to reduce computation time of color extraction.
Future<ui.Image> _imageProviderToScaled(ImageProvider imageProvider) async {
const double maxDimension = 112.0;
final ImageStream stream = imageProvider.resolve(
const ImageConfiguration(size: Size(maxDimension, maxDimension)));
final Completer<ui.Image> imageCompleter = Completer<ui.Image>();
late ImageStreamListener listener;
late ui.Image scaledImage;
Timer? loadFailureTimeout;
listener = ImageStreamListener((ImageInfo info, bool sync) async {
loadFailureTimeout?.cancel();
stream.removeListener(listener);
final ui.Image image = info.image;
final int width = image.width;
final int height = image.height;
double paintWidth = width.toDouble();
double paintHeight = height.toDouble();
assert(width > 0 && height > 0);
final bool rescale = width > maxDimension || height > maxDimension;
if (rescale) {
paintWidth =
(width > height) ? maxDimension : (maxDimension / height) * width;
paintHeight =
(height > width) ? maxDimension : (maxDimension / width) * height;
}
final ui.PictureRecorder pictureRecorder = ui.PictureRecorder();
final Canvas canvas = Canvas(pictureRecorder);
paintImage(
canvas: canvas,
rect: Rect.fromLTRB(0, 0, paintWidth, paintHeight),
image: image,
filterQuality: FilterQuality.none);
final ui.Picture picture = pictureRecorder.endRecording();
scaledImage =
await picture.toImage(paintWidth.toInt(), paintHeight.toInt());
imageCompleter.complete(info.image);
}, onError: (Object exception, StackTrace? stackTrace) {
stream.removeListener(listener);
throw Exception('Failed to render image: $exception');
});
loadFailureTimeout = Timer(const Duration(seconds: 5), () {
stream.removeListener(listener);
imageCompleter.completeError(
TimeoutException('Timeout occurred trying to load image'));
});
stream.addListener(listener);
await imageCompleter.future;
return scaledImage;
}
// Converts AABBGGRR color int to AARRGGBB format.
int _getArgbFromAbgr(int abgr) {
const int exceptRMask = 0xFF00FFFF;
const int onlyRMask = ~exceptRMask;
const int exceptBMask = 0xFFFFFF00;
const int onlyBMask = ~exceptBMask;
final int r = (abgr & onlyRMask) >> 16;
final int b = abgr & onlyBMask;
return (abgr & exceptRMask & exceptBMask) | (b << 16) | r;
}