diff --git a/packages/flame/lib/src/extensions/image.dart b/packages/flame/lib/src/extensions/image.dart index b61b4a1935..160f90507b 100644 --- a/packages/flame/lib/src/extensions/image.dart +++ b/packages/flame/lib/src/extensions/image.dart @@ -4,6 +4,7 @@ import 'dart:ui'; import 'package:flame/extensions.dart'; import 'package:flame/palette.dart'; +import 'package:flutter/painting.dart'; export 'dart:ui' show Image; @@ -53,17 +54,39 @@ extension ImageExtension on Image { final newPixelData = Uint8List(pixelData.length); for (var i = 0; i < pixelData.length; i += 4) { - final color = Color.fromARGB( - pixelData[i + 3], - pixelData[i + 0], - pixelData[i + 1], - pixelData[i + 2], - ).darken(amount); - - newPixelData[i] = (color.r * 255).round(); - newPixelData[i + 1] = (color.g * 255).round(); - newPixelData[i + 2] = (color.b * 255).round(); - newPixelData[i + 3] = (color.a * 255).round(); + final a = pixelData[i + 3] / 255; + + // Lets avoid division by zero. + if (a == 0) { + newPixelData[i + 0] = pixelData[i + 0]; + newPixelData[i + 1] = pixelData[i + 1]; + newPixelData[i + 2] = pixelData[i + 2]; + newPixelData[i + 3] = pixelData[i + 3]; + continue; + } + + // Reverse premultiplied alpha. + var r = (pixelData[i + 0] / 255) / a; + var g = (pixelData[i + 1] / 255) / a; + var b = (pixelData[i + 2] / 255) / a; + + // Convert to HSL (Hue, Saturation, and Lightness). + var hsl = + HSLColor.fromColor(Color.from(alpha: a, red: r, green: g, blue: b)); + hsl = hsl.withLightness( + clampDouble(hsl.lightness * amount, 0, 1.0), + ); + + final color = hsl.toColor(); + r = color.r; + g = color.g; + b = color.b; + + // Premultiply the new color. + newPixelData[i + 0] = (r * a * 255).round(); + newPixelData[i + 1] = (g * a * 255).round(); + newPixelData[i + 2] = (b * a * 255).round(); + newPixelData[i + 3] = pixelData[i + 3]; } return fromPixels(newPixelData, width, height); } @@ -89,22 +112,24 @@ extension ImageExtension on Image { continue; } - // Unmultiply the color + // Reverse premultiplied alpha. var r = (pixelData[i + 0] / 255) / a; var g = (pixelData[i + 1] / 255) / a; var b = (pixelData[i + 2] / 255) / a; - // Brighten in a color accurate way - r = r + (1.0 - r) * amount; - g = g + (1.0 - g) * amount; - b = b + (1.0 - b) * amount; + // Convert to HSL (Hue, Saturation, and Lightness). + var hsl = + HSLColor.fromColor(Color.from(alpha: a, red: r, green: g, blue: b)); + hsl = hsl.withLightness( + clampDouble(hsl.lightness + (1 - hsl.lightness) * amount, 0, 1.0), + ); - // Clamp - r = r.clamp(0, 1.0); - g = g.clamp(0, 1.0); - b = b.clamp(0, 1.0); + final color = hsl.toColor(); + r = color.r; + g = color.g; + b = color.b; - // Pre-multiply the new color. + // Premultiply the new color. newPixelData[i + 0] = (r * a * 255).round(); newPixelData[i + 1] = (g * a * 255).round(); newPixelData[i + 2] = (b * a * 255).round();