44
55import 'dart:typed_data' ;
66import 'dart:ui' ;
7+ import 'dart:io' ;
8+ import 'package:image/image.dart' as dart_image;
79
10+ import 'package:path/path.dart' as path;
811import 'package:test/test.dart' ;
912
1013typedef CanvasCallback = void Function (Canvas canvas);
@@ -15,7 +18,7 @@ void testCanvas(CanvasCallback callback) {
1518 } catch (error) { } // ignore: empty_catches
1619}
1720
18- void main () {
21+ void testNoCrashes () {
1922 test ('canvas APIs should not crash' , () async {
2023 final Paint paint = Paint ();
2124 const Rect rect = Rect .fromLTRB (double .nan, double .nan, double .nan, double .nan);
@@ -81,3 +84,71 @@ void main() {
8184 testCanvas ((Canvas canvas) => canvas.translate (double .nan, double .nan));
8285 });
8386}
87+
88+ /// @returns true When the images are resonably similar.
89+ /// @todo Make the search actually fuzzy to a certain degree.
90+ Future <bool > fuzzyCompareImages (Image golden, Image img) async {
91+ if (golden.width != img.width || golden.height != img.height) {
92+ return false ;
93+ }
94+ int getPixel (ByteData data, int x, int y) => data.getUint32 ((x + y * golden.width) * 4 );
95+ final ByteData goldenData = await golden.toByteData ();
96+ final ByteData imgData = await img.toByteData ();
97+ for (int y = 0 ; y < golden.height; y++ ) {
98+ for (int x = 0 ; x < golden.width; x++ ) {
99+ if (getPixel (goldenData, x, y) != getPixel (imgData, x, y)) {
100+ return false ;
101+ }
102+ }
103+ }
104+ return true ;
105+ }
106+
107+ /// @returns true When the images are resonably similar.
108+ Future <bool > fuzzyGoldenImageCompare (
109+ Image image, String goldenImageName) async {
110+ final String imagesPath = path.join ('flutter' , 'testing' , 'resources' );
111+ final File file = File (path.join (imagesPath, goldenImageName));
112+ final Uint8List goldenData = await file.readAsBytes ();
113+
114+ final Codec codec = await instantiateImageCodec (goldenData);
115+ final FrameInfo frame = await codec.getNextFrame ();
116+ expect (frame.image.height, equals (image.width));
117+ expect (frame.image.width, equals (image.height));
118+
119+ final bool areEqual = await fuzzyCompareImages (frame.image, image);
120+ if (! areEqual) {
121+ final ByteData pngData = await image.toByteData ();
122+ final ByteBuffer buffer = pngData.buffer;
123+ final dart_image.Image png = dart_image.Image .fromBytes (
124+ image.width, image.height, buffer.asUint8List ());
125+ final String outPath = path.join (imagesPath, 'found_' + goldenImageName);
126+ File (outPath)..writeAsBytesSync (dart_image.encodePng (png));
127+ print ('wrote: ' + outPath);
128+ }
129+ return areEqual;
130+ }
131+
132+ void main () {
133+ testNoCrashes ();
134+
135+ test ('Simple .toImage' , () async {
136+ final PictureRecorder recorder = PictureRecorder ();
137+ final Canvas canvas = Canvas (recorder);
138+ final Path circlePath = Path ()
139+ ..addOval (
140+ Rect .fromCircle (center: const Offset (40.0 , 40.0 ), radius: 20.0 ));
141+ final Paint paint = Paint ()
142+ ..isAntiAlias = false
143+ ..style = PaintingStyle .fill;
144+ canvas.drawPath (circlePath, paint);
145+ final Picture picture = recorder.endRecording ();
146+ final Image image = await picture.toImage (100 , 100 );
147+ expect (image.width, equals (100 ));
148+ expect (image.height, equals (100 ));
149+
150+ final bool areEqual =
151+ await fuzzyGoldenImageCompare (image, 'canvas_test_toImage.png' );
152+ expect (areEqual, true );
153+ });
154+ }
0 commit comments