mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add ability to control dithering on Paint (flutter/engine#13868)
This commit is contained in:
parent
3fd4cb2d55
commit
f7eb74c11f
@ -1066,6 +1066,7 @@ class Paint {
|
||||
static const int _kMaskFilterBlurStyleIndex = 10;
|
||||
static const int _kMaskFilterSigmaIndex = 11;
|
||||
static const int _kInvertColorIndex = 12;
|
||||
static const int _kDitherIndex = 13;
|
||||
|
||||
static const int _kIsAntiAliasOffset = _kIsAntiAliasIndex << 2;
|
||||
static const int _kColorOffset = _kColorIndex << 2;
|
||||
@ -1080,8 +1081,9 @@ class Paint {
|
||||
static const int _kMaskFilterBlurStyleOffset = _kMaskFilterBlurStyleIndex << 2;
|
||||
static const int _kMaskFilterSigmaOffset = _kMaskFilterSigmaIndex << 2;
|
||||
static const int _kInvertColorOffset = _kInvertColorIndex << 2;
|
||||
static const int _kDitherOffset = _kDitherIndex << 2;
|
||||
// If you add more fields, remember to update _kDataByteCount.
|
||||
static const int _kDataByteCount = 52;
|
||||
static const int _kDataByteCount = 56;
|
||||
|
||||
// Binary format must match the deserialization code in paint.cc.
|
||||
List<dynamic> _objects;
|
||||
@ -1090,6 +1092,14 @@ class Paint {
|
||||
static const int _kImageFilterIndex = 2;
|
||||
static const int _kObjectCount = 3; // Must be one larger than the largest index.
|
||||
|
||||
/// Constructs an empty [Paint] object with all fields initialized to
|
||||
/// their defaults.
|
||||
Paint() {
|
||||
if (enableDithering) {
|
||||
_dither = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether to apply anti-aliasing to lines and images drawn on the
|
||||
/// canvas.
|
||||
///
|
||||
@ -1417,6 +1427,30 @@ class Paint {
|
||||
_data.setInt32(_kInvertColorOffset, value ? 1 : 0, _kFakeHostEndian);
|
||||
}
|
||||
|
||||
bool get _dither {
|
||||
return _data.getInt32(_kDitherOffset, _kFakeHostEndian) == 1;
|
||||
}
|
||||
set _dither(bool value) {
|
||||
_data.setInt32(_kDitherOffset, value ? 1 : 0, _kFakeHostEndian);
|
||||
}
|
||||
|
||||
/// Whether to dither the output when drawing images.
|
||||
///
|
||||
/// If false, the default value, dithering will be enabled when the input
|
||||
/// color depth is higher than the output color depth. For example,
|
||||
/// drawing an RGB8 image onto an RGB565 canvas.
|
||||
///
|
||||
/// This value also controls dithering of [shader]s, which can make
|
||||
/// gradients appear smoother.
|
||||
///
|
||||
/// Whether or not dithering affects the output is implementation defined.
|
||||
/// Some implementations may choose to ignore this completely, if they're
|
||||
/// unable to control dithering.
|
||||
///
|
||||
/// To ensure that dithering is consistently enabled for your entire
|
||||
/// application, set this to true before invoking any drawing related code.
|
||||
static bool enableDithering = false;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final StringBuffer result = StringBuffer();
|
||||
@ -1475,6 +1509,8 @@ class Paint {
|
||||
}
|
||||
if (invertColors)
|
||||
result.write('${semicolon}invert: $invertColors');
|
||||
if (_dither)
|
||||
result.write('${semicolon}dither: $_dither');
|
||||
result.write(')');
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
@ -32,7 +32,8 @@ constexpr int kMaskFilterIndex = 9;
|
||||
constexpr int kMaskFilterBlurStyleIndex = 10;
|
||||
constexpr int kMaskFilterSigmaIndex = 11;
|
||||
constexpr int kInvertColorIndex = 12;
|
||||
constexpr size_t kDataByteCount = 52; // 4 * (last index + 1)
|
||||
constexpr int kDitherIndex = 13;
|
||||
constexpr size_t kDataByteCount = 56; // 4 * (last index + 1)
|
||||
|
||||
// Indices for objects.
|
||||
constexpr int kShaderIndex = 0;
|
||||
@ -154,6 +155,10 @@ Paint::Paint(Dart_Handle paint_objects, Dart_Handle paint_data) {
|
||||
paint_.setColorFilter(invert_filter);
|
||||
}
|
||||
|
||||
if (uint_data[kDitherIndex]) {
|
||||
paint_.setDither(true);
|
||||
}
|
||||
|
||||
switch (uint_data[kMaskFilterIndex]) {
|
||||
case Null:
|
||||
break;
|
||||
|
||||
@ -961,6 +961,10 @@ class PaintData {
|
||||
class Paint {
|
||||
PaintData _paintData = PaintData();
|
||||
|
||||
/// Constructs an empty [Paint] object with all fields initialized to
|
||||
/// their defaults.
|
||||
Paint();
|
||||
|
||||
/// A blend mode to apply when a shape is drawn or a layer is composited.
|
||||
///
|
||||
/// The source colors are from the shape being drawn (e.g. from
|
||||
@ -1182,6 +1186,23 @@ class Paint {
|
||||
// TODO(flutter/flutter#35156): Implement ImageFilter.
|
||||
}
|
||||
|
||||
/// Whether to dither the output when drawing images.
|
||||
///
|
||||
/// If false, the default value, dithering will be enabled when the input
|
||||
/// color depth is higher than the output color depth. For example,
|
||||
/// drawing an RGB8 image onto an RGB565 canvas.
|
||||
///
|
||||
/// This value also controls dithering of [shader]s, which can make
|
||||
/// gradients appear smoother.
|
||||
///
|
||||
/// Whether or not dithering affects the output is implementation defined.
|
||||
/// Some implementations may choose to ignore this completely, if they're
|
||||
/// unable to control dithering.
|
||||
///
|
||||
/// To ensure that dithering is consistently enabled for your entire
|
||||
/// application, set this to true before invoking any drawing related code.
|
||||
static bool enableDithering = false;
|
||||
|
||||
// True if Paint instance has used in RecordingCanvas.
|
||||
bool _frozen = false;
|
||||
|
||||
|
||||
@ -109,14 +109,20 @@ Future<bool> fuzzyGoldenImageCompare(
|
||||
Image image, String goldenImageName) async {
|
||||
final String imagesPath = path.join('flutter', 'testing', 'resources');
|
||||
final File file = File(path.join(imagesPath, goldenImageName));
|
||||
final Uint8List goldenData = await file.readAsBytes();
|
||||
|
||||
final Codec codec = await instantiateImageCodec(goldenData);
|
||||
final FrameInfo frame = await codec.getNextFrame();
|
||||
expect(frame.image.height, equals(image.width));
|
||||
expect(frame.image.width, equals(image.height));
|
||||
bool areEqual = false;
|
||||
|
||||
if (file.existsSync()) {
|
||||
final Uint8List goldenData = await file.readAsBytes();
|
||||
|
||||
final Codec codec = await instantiateImageCodec(goldenData);
|
||||
final FrameInfo frame = await codec.getNextFrame();
|
||||
expect(frame.image.height, equals(image.width));
|
||||
expect(frame.image.width, equals(image.height));
|
||||
|
||||
areEqual = await fuzzyCompareImages(frame.image, image);
|
||||
}
|
||||
|
||||
final bool areEqual = await fuzzyCompareImages(frame.image, image);
|
||||
if (!areEqual) {
|
||||
final ByteData pngData = await image.toByteData();
|
||||
final ByteBuffer buffer = pngData.buffer;
|
||||
@ -151,4 +157,44 @@ void main() {
|
||||
await fuzzyGoldenImageCompare(image, 'canvas_test_toImage.png');
|
||||
expect(areEqual, true);
|
||||
});
|
||||
|
||||
Gradient makeGradient() {
|
||||
return Gradient.linear(
|
||||
Offset.zero,
|
||||
const Offset(100, 100),
|
||||
const <Color>[Color(0xFF4C4D52), Color(0xFF202124)],
|
||||
);
|
||||
}
|
||||
|
||||
test('Simple gradient', () async {
|
||||
Paint.enableDithering = false;
|
||||
final PictureRecorder recorder = PictureRecorder();
|
||||
final Canvas canvas = Canvas(recorder);
|
||||
final Paint paint = Paint()..shader = makeGradient();
|
||||
canvas.drawPaint(paint);
|
||||
final Picture picture = recorder.endRecording();
|
||||
final Image image = await picture.toImage(100, 100);
|
||||
expect(image.width, equals(100));
|
||||
expect(image.height, equals(100));
|
||||
|
||||
final bool areEqual =
|
||||
await fuzzyGoldenImageCompare(image, 'canvas_test_gradient.png');
|
||||
expect(areEqual, true);
|
||||
});
|
||||
|
||||
test('Simple dithered gradient', () async {
|
||||
Paint.enableDithering = true;
|
||||
final PictureRecorder recorder = PictureRecorder();
|
||||
final Canvas canvas = Canvas(recorder);
|
||||
final Paint paint = Paint()..shader = makeGradient();
|
||||
canvas.drawPaint(paint);
|
||||
final Picture picture = recorder.endRecording();
|
||||
final Image image = await picture.toImage(100, 100);
|
||||
expect(image.width, equals(100));
|
||||
expect(image.height, equals(100));
|
||||
|
||||
final bool areEqual =
|
||||
await fuzzyGoldenImageCompare(image, 'canvas_test_dithered_gradient.png');
|
||||
expect(areEqual, true);
|
||||
});
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
BIN
engine/src/flutter/testing/resources/canvas_test_gradient.png
Normal file
BIN
engine/src/flutter/testing/resources/canvas_test_gradient.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
Loading…
x
Reference in New Issue
Block a user