Simplify Matcher code and apply formatting
Bug: 299062874
Test: HumanEyeMatcherTest, AlmostPerfectMatcherTest
Change-Id: I79f2b4e92dfdeb641fe2be6a537cb9624bb38e44
diff --git a/libraries/screenshot/src/main/java/platform/test/screenshot/matchers/AlmostPerfectMatcher.kt b/libraries/screenshot/src/main/java/platform/test/screenshot/matchers/AlmostPerfectMatcher.kt
index 72be598..bbab511 100644
--- a/libraries/screenshot/src/main/java/platform/test/screenshot/matchers/AlmostPerfectMatcher.kt
+++ b/libraries/screenshot/src/main/java/platform/test/screenshot/matchers/AlmostPerfectMatcher.kt
@@ -73,8 +73,7 @@
val blue = Color.blue(referenceColor) - Color.blue(testColor)
val red = Color.red(referenceColor) - Color.red(testColor)
val redMean = (Color.red(referenceColor) + Color.red(testColor)) / 2
- val redScalar = if (redMean < 128) 2 else 3
- val blueScalar = if (redMean < 128) 3 else 2
+ val (redScalar, blueScalar) = if (redMean < 128) Pair(2, 3) else Pair(3, 2)
val greenScalar = 4
val correction = sqrt((
(redScalar * red * red) +
diff --git a/libraries/screenshot/src/main/java/platform/test/screenshot/matchers/HumanEyeMatcher.kt b/libraries/screenshot/src/main/java/platform/test/screenshot/matchers/HumanEyeMatcher.kt
index 2554da6..b6dee94 100644
--- a/libraries/screenshot/src/main/java/platform/test/screenshot/matchers/HumanEyeMatcher.kt
+++ b/libraries/screenshot/src/main/java/platform/test/screenshot/matchers/HumanEyeMatcher.kt
@@ -3,9 +3,9 @@
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.Rect
-import platform.test.screenshot.proto.ScreenshotResultProto
import kotlin.math.max
import kotlin.math.sqrt
+import platform.test.screenshot.proto.ScreenshotResultProto
/**
* A matcher designed to replicate a human checking an image to see if there are differences.
@@ -15,21 +15,21 @@
* pixel that is not the same as the golden will be given more leniency than a line or circle of
* pixels that are different from the golden.
*
- * [accountForTransparency] The matcher will apply a background to any non-opaque pixel so the
- * color diffing is only comparing opaque colours. Multiple different backgrounds will be used to
- * ensure pixels close to the background color fail if their alpha is significantly different from
- * the golden.
+ * [accountForTransparency] The matcher will apply a background to any non-opaque pixel so the color
+ * diffing is only comparing opaque colours. Multiple different backgrounds will be used to ensure
+ * pixels close to the background color fail if their alpha is significantly different from the
+ * golden.
*/
class HumanEyeMatcher(
- private val accountForGrouping: Boolean = true,
- private val accountForTransparency: Boolean = true,
-): BitmapMatcher() {
+ private val accountForGrouping: Boolean = true,
+ private val accountForTransparency: Boolean = true,
+) : BitmapMatcher() {
override fun compareBitmaps(
- expected: IntArray,
- given: IntArray,
- width: Int,
- height: Int,
- regions: List<Rect>
+ expected: IntArray,
+ given: IntArray,
+ width: Int,
+ height: Int,
+ regions: List<Rect>
): MatchResult {
check(expected.size == given.size) {
"Pixels in expected (${expected.size}) does not match pixels in actual (${given.size})"
@@ -38,39 +38,41 @@
var ignored = 0
// Prepare colorDiffArray
- val colorDiffArray = DoubleArray(width * height) { index ->
- val x = index % width
- val y = index / width
+ val colorDiffArray =
+ DoubleArray(width * height) { index ->
+ val x = index % width
+ val y = index / width
- if (regions.isEmpty() || regions.any { it.containsInclusive(x, y) }) {
- if (accountForTransparency) {
- colorDiffWithTransparency(expected[index], given[index])
+ if (regions.isEmpty() || regions.any { it.containsInclusive(x, y) }) {
+ if (accountForTransparency) {
+ colorDiffWithTransparency(expected[index], given[index])
+ } else {
+ colorDiff(expected[index], given[index])
+ }
} else {
- colorDiff(expected[index], given[index])
+ ignored++
+ IGNORED_COLOR_DIFF
}
- } else {
- ignored++
- IGNORED_COLOR_DIFF
}
- }
fun isIndexSameForLargeArea(index: Int) = isSameForLargeArea(colorDiffArray[index])
if (!accountForGrouping) {
- val diffArray = IntArray(width * height) { index ->
- if (isIndexSameForLargeArea(index)) Color.TRANSPARENT else Color.MAGENTA
- }
+ val diffArray =
+ IntArray(width * height) { index ->
+ if (isIndexSameForLargeArea(index)) Color.TRANSPARENT else Color.MAGENTA
+ }
return createMatchResult(
- width,
- height,
- diffArray.count { diff -> diff == Color.TRANSPARENT } - ignored,
- diffArray.count { diff -> diff == Color.MAGENTA },
- ignored,
- diffArray,
+ width,
+ height,
+ diffArray.count { diff -> diff == Color.TRANSPARENT } - ignored,
+ diffArray.count { diff -> diff == Color.MAGENTA },
+ ignored,
+ diffArray,
)
}
- fun getEasiestThresholdFailed(index: Int): Double? {
+ fun getEasiestThresholdFailed(index: Int): Double? {
val colorDiff = colorDiffArray[index]
return when {
colorDiff == IGNORED_COLOR_DIFF -> null
@@ -82,53 +84,60 @@
}
}
- val diffArray = IntArray(colorDiffArray.size) { index ->
- // Also covers the ignored case
- if (isIndexSameForLargeArea(index)) return@IntArray Color.TRANSPARENT
+ val diffArray =
+ IntArray(colorDiffArray.size) { index ->
+ // Also covers the ignored case
+ if (isIndexSameForLargeArea(index)) return@IntArray Color.TRANSPARENT
- val x = index % width
- val y = index / width
+ val x = index % width
+ val y = index / width
- val currThreshold = getEasiestThresholdFailed(index)!!
- // null = ignored or out of bounds of image
- val upThreshold = if (y > 0) getEasiestThresholdFailed(x + width * (y - 1)) else null
- val downThreshold = if (y < height - 1) getEasiestThresholdFailed(x + width * (y + 1)) else null
- val leftThreshold = if (x > 0) getEasiestThresholdFailed(x - 1 + width * y) else null
- val rightThreshold = if (x < width - 1) getEasiestThresholdFailed(x + 1 + width * y) else null
+ val currThreshold = getEasiestThresholdFailed(index)!!
+ // null = ignored or out of bounds of image
+ val upThreshold =
+ if (y > 0) getEasiestThresholdFailed(x + width * (y - 1)) else null
+ val downThreshold =
+ if (y < height - 1) getEasiestThresholdFailed(x + width * (y + 1)) else null
+ val leftThreshold =
+ if (x > 0) getEasiestThresholdFailed(x - 1 + width * y) else null
+ val rightThreshold =
+ if (x < width - 1) getEasiestThresholdFailed(x + 1 + width * y) else null
- // Pixels with lower diff thresholds are not counted as neighbouring diffs
- var neighbouringDiffs = 4
- if (upThreshold != null && currThreshold > upThreshold) neighbouringDiffs--
- if (downThreshold != null && currThreshold > downThreshold) neighbouringDiffs--
- if (leftThreshold != null && currThreshold > leftThreshold) neighbouringDiffs--
- if (rightThreshold != null && currThreshold > rightThreshold) neighbouringDiffs--
+ // Pixels with lower diff thresholds are not counted as neighbouring diffs
+ var neighbouringDiffs = 4
+ if (upThreshold != null && currThreshold > upThreshold) neighbouringDiffs--
+ if (downThreshold != null && currThreshold > downThreshold) neighbouringDiffs--
+ if (leftThreshold != null && currThreshold > leftThreshold) neighbouringDiffs--
+ if (rightThreshold != null && currThreshold > rightThreshold) neighbouringDiffs--
- if (isSame(colorDiffArray[index], neighbouringDiffs)) {
- Color.TRANSPARENT
- } else {
- Color.MAGENTA
+ if (isSame(colorDiffArray[index], neighbouringDiffs)) {
+ Color.TRANSPARENT
+ } else {
+ Color.MAGENTA
+ }
}
- }
return createMatchResult(
- width,
- height,
- diffArray.count { diff -> diff == Color.TRANSPARENT } - ignored,
- diffArray.count { diff -> diff == Color.MAGENTA },
- ignored,
- diffArray,
+ width,
+ height,
+ diffArray.count { diff -> diff == Color.TRANSPARENT } - ignored,
+ diffArray.count { diff -> diff == Color.MAGENTA },
+ ignored,
+ diffArray,
)
}
private fun colorDiffWithTransparency(referenceColor: Int, testColor: Int): Double {
- val diffWithWhite = colorDiff(
+ val diffWithWhite =
+ colorDiff(
blendWithBackground(referenceColor, Color.WHITE),
blendWithBackground(testColor, Color.WHITE)
- )
- val diffWithBlack = colorDiff(
+ )
+ val diffWithBlack =
+ colorDiff(
blendWithBackground(referenceColor, Color.BLACK),
blendWithBackground(testColor, Color.BLACK)
- )
+ )
return max(diffWithWhite, diffWithBlack)
}
@@ -141,15 +150,13 @@
val blue = Color.blue(referenceColor) - Color.blue(testColor)
val red = Color.red(referenceColor) - Color.red(testColor)
val redMean = (Color.red(referenceColor) + Color.red(testColor)) / 2
- val redScalar = if (redMean < 128) 2 else 3
- val blueScalar = if (redMean < 128) 3 else 2
+ val (redScalar, blueScalar) = if (redMean < 128) Pair(2, 3) else Pair(3, 2)
val greenScalar = 4
- return sqrt((
- (redScalar * red * red) +
- (greenScalar * green * green) +
- (blueScalar * blue * blue))
- .toDouble())
+ return sqrt(
+ ((redScalar * red * red) + (greenScalar * green * green) + (blueScalar * blue * blue))
+ .toDouble()
+ )
}
/**
@@ -158,22 +165,24 @@
* color differences in very small objects as compared to larger ones.
*/
private fun getThreshold(neighbouringDiffs: Int): Double =
- when (neighbouringDiffs) {
- 0, 1 -> THRESHOLD_ISOLATED_PIXEL
- 2 -> THRESHOLD_1PX_LINE_OF_PIXELS
- 3 -> THRESHOLD_2PX_LINE_OF_PIXELS
- 4 -> THRESHOLD_BLOCK_OF_PIXELS
- else -> throw IllegalArgumentException("Unsupported neighbouringDiffs value: $neighbouringDiffs")
- }
+ when (neighbouringDiffs) {
+ 0,
+ 1 -> THRESHOLD_ISOLATED_PIXEL
+ 2 -> THRESHOLD_1PX_LINE_OF_PIXELS
+ 3 -> THRESHOLD_2PX_LINE_OF_PIXELS
+ 4 -> THRESHOLD_BLOCK_OF_PIXELS
+ else ->
+ throw IllegalArgumentException(
+ "Unsupported neighbouringDiffs value: $neighbouringDiffs"
+ )
+ }
private fun isSameForLargeArea(colorDiff: Double) = colorDiff <= THRESHOLD_BLOCK_OF_PIXELS
private fun isSame(colorDiff: Double, neighbouringDiffs: Int) =
- colorDiff <= getThreshold(neighbouringDiffs)
+ colorDiff <= getThreshold(neighbouringDiffs)
- /**
- * Any alpha component of the [backgroundColor] will be ignored.
- */
+ /** Any alpha component of the [backgroundColor] will be ignored. */
private fun blendWithBackground(color: Int, backgroundColor: Int): Int {
val alpha: Float = Color.alpha(color) / 255f
if (alpha == 1f) return color
@@ -187,15 +196,15 @@
}
private fun createMatchResult(
- width: Int,
- height: Int,
- samePixels: Int,
- differentPixels: Int,
- ignoredPixels: Int,
- diffBitmapArray: IntArray,
+ width: Int,
+ height: Int,
+ samePixels: Int,
+ differentPixels: Int,
+ ignoredPixels: Int,
+ diffBitmapArray: IntArray,
): MatchResult {
- val stats = ScreenshotResultProto.DiffResult.ComparisonStatistics
- .newBuilder()
+ val stats =
+ ScreenshotResultProto.DiffResult.ComparisonStatistics.newBuilder()
.setNumberPixelsCompared(width * height)
.setNumberPixelsIdentical(samePixels)
.setNumberPixelsDifferent(differentPixels)
@@ -220,4 +229,4 @@
private fun Rect.containsInclusive(x: Int, y: Int) = x in left..right && y in top..bottom
}
-}
\ No newline at end of file
+}