compareLists function
Returns a ComparisonResult to describe the pixel differential of the
test
and master
image bytes provided.
Implementation
Future<ComparisonResult> compareLists(List<int>? test, List<int>? master) async {
if (test == null || master == null || test.isEmpty || master.isEmpty) {
return ComparisonResult(
passed: false,
diffPercent: 1.0,
error: 'Pixel test failed, null image provided.',
);
}
if (listEquals(test, master)) {
return ComparisonResult(
passed: true,
diffPercent: 0.0,
);
}
final Codec testImageCodec =
await instantiateImageCodec(Uint8List.fromList(test));
final Image testImage = (await testImageCodec.getNextFrame()).image;
final ByteData? testImageRgba = await testImage.toByteData();
final Codec masterImageCodec =
await instantiateImageCodec(Uint8List.fromList(master));
final Image masterImage = (await masterImageCodec.getNextFrame()).image;
final ByteData? masterImageRgba = await masterImage.toByteData();
final int width = testImage.width;
final int height = testImage.height;
if (width != masterImage.width || height != masterImage.height) {
final ComparisonResult result = ComparisonResult(
passed: false,
diffPercent: 1.0,
error: 'Pixel test failed, image sizes do not match.\n'
'Master Image: ${masterImage.width} X ${masterImage.height}\n'
'Test Image: ${testImage.width} X ${testImage.height}',
diffs: <String, Image>{
'masterImage': masterImage,
'testImage': testImage,
},
);
return result;
}
int pixelDiffCount = 0;
final int totalPixels = width * height;
final ByteData invertedMasterRgba = _invert(masterImageRgba!);
final ByteData invertedTestRgba = _invert(testImageRgba!);
final Uint8List testImageBytes = (await testImage.toByteData())!.buffer.asUint8List();
final ByteData maskedDiffRgba = ByteData(testImageBytes.length);
maskedDiffRgba.buffer.asUint8List().setRange(0, testImageBytes.length, testImageBytes);
final ByteData isolatedDiffRgba = ByteData(width * height * 4);
for (int x = 0; x < width; x++) {
for (int y =0; y < height; y++) {
final int byteOffset = (width * y + x) * 4;
final int testPixel = testImageRgba.getUint32(byteOffset);
final int masterPixel = masterImageRgba.getUint32(byteOffset);
final int diffPixel = (_readRed(testPixel) - _readRed(masterPixel)).abs()
+ (_readGreen(testPixel) - _readGreen(masterPixel)).abs()
+ (_readBlue(testPixel) - _readBlue(masterPixel)).abs()
+ (_readAlpha(testPixel) - _readAlpha(masterPixel)).abs();
if (diffPixel != 0 ) {
final int invertedMasterPixel = invertedMasterRgba.getUint32(byteOffset);
final int invertedTestPixel = invertedTestRgba.getUint32(byteOffset);
// We grab the max of the 0xAABBGGRR encoded bytes, and then convert
// back to 0xRRGGBBAA for the actual pixel value, since this is how it
// was historically done.
final int maskPixel = _toRGBA(math.max(
_toABGR(invertedMasterPixel),
_toABGR(invertedTestPixel),
));
maskedDiffRgba.setUint32(byteOffset, maskPixel);
isolatedDiffRgba.setUint32(byteOffset, maskPixel);
pixelDiffCount++;
}
}
}
if (pixelDiffCount > 0) {
final double diffPercent = pixelDiffCount / totalPixels;
return ComparisonResult(
passed: false,
diffPercent: diffPercent,
error: 'Pixel test failed, '
'${(diffPercent * 100).toStringAsFixed(2)}%, ${pixelDiffCount}px '
'diff detected.',
diffs: <String, Image>{
'masterImage' : masterImage,
'testImage' : testImage,
'maskedDiff' : await _createImage(maskedDiffRgba, width, height),
'isolatedDiff' : await _createImage(isolatedDiffRgba, width, height),
},
);
}
masterImage.dispose();
testImage.dispose();
return ComparisonResult(passed: true, diffPercent: 0.0);
}