diff --git a/packages/palette_generator/lib/palette_generator.dart b/packages/palette_generator/lib/palette_generator.dart index 397625835c2..24225d5ff39 100644 --- a/packages/palette_generator/lib/palette_generator.dart +++ b/packages/palette_generator/lib/palette_generator.dart @@ -182,15 +182,16 @@ class PaletteGenerator extends Diagnosticable { ImageConfiguration(size: size, devicePixelRatio: 1.0), ); final Completer imageCompleter = Completer(); - Timer loadFailureTimeout; - void imageListener(ImageInfo info, bool synchronousCall) { - loadFailureTimeout?.cancel(); - stream.removeListener(imageListener); - imageCompleter.complete(info.image); - } - + final ImageStreamListener imageListener = ImageStreamListener( + (ImageInfo info, bool synchronouscall) { + imageCompleter.complete(info.image); + }, + onError: (dynamic error, StackTrace stackTrace) { + imageCompleter.completeError(error); + }, + ); if (timeout != Duration.zero) { - loadFailureTimeout = Timer(timeout, () { + Timer(timeout, () { stream.removeListener(imageListener); imageCompleter.completeError( TimeoutException( @@ -1040,8 +1041,8 @@ class _ColorCutQuantizer { final Rect region; final List filters; - Iterable _getImagePixels(ByteData pixels, int width, int height, - {Rect region}) sync* { + static Iterable _getImagePixels( + ByteData pixels, int width, int height, Rect region) sync* { final int rowStride = width * 4; int rowStart; int rowEnd; @@ -1076,7 +1077,7 @@ class _ColorCutQuantizer { assert(byteCount == ((rowEnd - rowStart) * (colEnd - colStart) * 4)); } - bool _shouldIgnoreColor(Color color) { + static bool _shouldIgnoreColor(Color color, List filters) { final HSLColor hslColor = HSLColor.fromColor(color); if (filters != null && filters.isNotEmpty) { for (PaletteFilter filter in filters) { @@ -1089,31 +1090,47 @@ class _ColorCutQuantizer { } Future> _quantizeColors(ui.Image image) async { - const int quantizeWordWidth = 5; - const int quantizeChannelWidth = 8; - const int quantizeShift = quantizeChannelWidth - quantizeWordWidth; - const int quantizeWordMask = - ((1 << quantizeWordWidth) - 1) << quantizeShift; - - Color quantizeColor(Color color) { - return Color.fromARGB( - color.alpha, - color.red & quantizeWordMask, - color.green & quantizeWordMask, - color.blue & quantizeWordMask, - ); - } - final ByteData imageData = await image.toByteData(format: ui.ImageByteFormat.rawRgba); + if (filters == null) + return await compute(_quantizefromByte, { + 'byteData': imageData, + 'maxColors': maxColors, + 'width': image.width, + 'height': image.height, + 'region': region, + 'paletteColors': _paletteColors, + 'filters': null + }); + else + return _quantizefromByte({ + 'byteData': imageData, + 'maxColors': maxColors, + 'width': image.width, + 'height': image.height, + 'region': region, + 'paletteColors': _paletteColors, + 'filters': filters + }); + } + + static List _quantizefromByte(Map map) { + ByteData bd = map['byteData']; + int maxColors = map['maxColors']; + int width = map['width']; + int height = map['height']; + Rect region = map['region']; + List filters = map['filters']; + List _paletteColors = map['paletteColors']; + final ByteData imageData = bd; final Iterable pixels = - _getImagePixels(imageData, image.width, image.height, region: region); + _getImagePixels(imageData, width, height, region); final Map hist = {}; for (Color pixel in pixels) { // Update the histogram, but only for non-zero alpha values, and for the // ones we do add, make their alphas opaque so that we can use a Color as // the histogram key. - final Color quantizedColor = quantizeColor(pixel); + final Color quantizedColor = _quantizeColor(pixel); final Color colorKey = quantizedColor.withAlpha(0xff); // Skip pixels that are entirely transparent. if (quantizedColor.alpha != 0x0) { @@ -1122,7 +1139,7 @@ class _ColorCutQuantizer { } // Now let's remove any colors that the filters want to ignore. hist.removeWhere((Color color, int _) { - return _shouldIgnoreColor(color); + return _shouldIgnoreColor(color, filters); }); if (hist.length <= maxColors) { // The image has fewer colors than the maximum requested, so just return @@ -1134,15 +1151,31 @@ class _ColorCutQuantizer { } else { // We need use quantization to reduce the number of colors _paletteColors.clear(); - _paletteColors.addAll(_quantizePixels(maxColors, hist)); + _paletteColors.addAll(_quantizePixels( + {'maxColors': maxColors, 'histogram': hist}, filters)); } return _paletteColors; } - List _quantizePixels( - int maxColors, - Map histogram, - ) { + static Color _quantizeColor(Color color) { + const int quantizeWordWidth = 5; + const int quantizeChannelWidth = 8; + const int quantizeShift = quantizeChannelWidth - quantizeWordWidth; + const int quantizeWordMask = + ((1 << quantizeWordWidth) - 1) << quantizeShift; + return Color.fromARGB( + color.alpha, + color.red & quantizeWordMask, + color.green & quantizeWordMask, + color.blue & quantizeWordMask, + ); + } + + static List _quantizePixels( + Map args, List filters) { + int maxColors = args['maxColors']; + Map histogram = args['histogram']; + int volumeComparator(_ColorVolumeBox a, _ColorVolumeBox b) { return b.getVolume().compareTo(a.getVolume()); } @@ -1158,7 +1191,7 @@ class _ColorCutQuantizer { // or there are no more boxes to split _splitBoxes(priorityQueue, maxColors); // Finally, return the average colors of the color boxes. - return _generateAverageColors(priorityQueue); + return _generateAverageColors(priorityQueue, filters); } // Iterate through the [PriorityQueue], popping [_ColorVolumeBox] objects @@ -1166,7 +1199,8 @@ class _ColorCutQuantizer { // remaining box are offered back to the queue. // // The `maxSize` is the maximum number of boxes to split. - void _splitBoxes(PriorityQueue<_ColorVolumeBox> queue, final int maxSize) { + static void _splitBoxes( + PriorityQueue<_ColorVolumeBox> queue, final int maxSize) { while (queue.length < maxSize) { final _ColorVolumeBox colorVolumeBox = queue.removeFirst(); if (colorVolumeBox != null && colorVolumeBox.canSplit()) { @@ -1182,12 +1216,14 @@ class _ColorCutQuantizer { } // Generates the average colors from each of the boxes in the queue. - List _generateAverageColors( - PriorityQueue<_ColorVolumeBox> colorVolumeBoxes) { + static List _generateAverageColors( + PriorityQueue<_ColorVolumeBox> colorVolumeBoxes, + List filters) { final List colors = []; for (_ColorVolumeBox colorVolumeBox in colorVolumeBoxes.toList()) { final PaletteColor paletteColor = colorVolumeBox.getAverageColor(); - if (!_shouldIgnoreColor(paletteColor.color)) { + + if (!_shouldIgnoreColor(paletteColor.color, filters)) { colors.add(paletteColor); } }