1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.robolectric.shadows.testing.bitmapverifiers; 18 19 import android.graphics.Color; 20 21 public class BlurPixelVerifier extends BitmapVerifier { 22 23 private final int dstColor; 24 private final int srcColor; 25 26 /** 27 * Create a BitmapVerifier that compares pixel values relative to the provided source and 28 * destination colors. Pixels closer to the center of the test bitmap are expected to match closer 29 * to the source color, while pixels on the exterior of the test bitmap are expected to match the 30 * destination color more closely 31 */ BlurPixelVerifier(int srcColor, int dstColor)32 public BlurPixelVerifier(int srcColor, int dstColor) { 33 this.srcColor = srcColor; 34 this.dstColor = dstColor; 35 } 36 37 @Override verify(int[] bitmap, int offset, int stride, int width, int height)38 public boolean verify(int[] bitmap, int offset, int stride, int width, int height) { 39 40 float dstRedChannel = Color.red(dstColor); 41 float dstGreenChannel = Color.green(dstColor); 42 float dstBlueChannel = Color.blue(dstColor); 43 44 float srcRedChannel = Color.red(srcColor); 45 float srcGreenChannel = Color.green(srcColor); 46 float srcBlueChannel = Color.blue(srcColor); 47 48 // Calculate the largest rgb color difference between the source and destination 49 // colors 50 double maxDifference = 51 Math.pow(srcRedChannel - dstRedChannel, 2.0f) 52 + Math.pow(srcGreenChannel - dstGreenChannel, 2.0f) 53 + Math.pow(srcBlueChannel - dstBlueChannel, 2.0f); 54 55 // Calculate the maximum distance between pixels to the center of the test image 56 double maxPixelDistance = Math.sqrt(Math.pow(width / 2.0, 2.0) + Math.pow(height / 2.0, 2.0)); 57 58 // Additional tolerance applied to comparisons 59 float threshold = .05f; 60 for (int x = 0; x < width; x++) { 61 for (int y = 0; y < height; y++) { 62 double pixelDistance = 63 Math.sqrt(Math.pow(x - width / 2.0, 2.0) + Math.pow(y - height / 2.0, 2.0)); 64 // Calculate the threshold of the destination color expected based on the 65 // pixels position relative to the center 66 double dstPercentage = pixelDistance / maxPixelDistance + threshold; 67 68 int pixelColor = bitmap[indexFromXAndY(x, y, stride, offset)]; 69 double pixelRedChannel = Color.red(pixelColor); 70 double pixelGreenChannel = Color.green(pixelColor); 71 double pixelBlueChannel = Color.blue(pixelColor); 72 // Compare the RGB color distance between the current pixel and the destination 73 // color 74 double dstDistance = 75 Math.sqrt( 76 Math.pow(pixelRedChannel - dstRedChannel, 2.0) 77 + Math.pow(pixelGreenChannel - dstGreenChannel, 2.0) 78 + Math.pow(pixelBlueChannel - dstBlueChannel, 2.0)); 79 80 // Compare the RGB color distance between the current pixel and the source 81 // color 82 double srcDistance = 83 Math.sqrt( 84 Math.pow(pixelRedChannel - srcRedChannel, 2.0) 85 + Math.pow(pixelGreenChannel - srcGreenChannel, 2.0) 86 + Math.pow(pixelBlueChannel - srcBlueChannel, 2.0)); 87 88 // calculate the ratio between the destination color to the current pixel 89 // color relative to the maximum distance between source and destination colors 90 // If this value exceeds the threshold expected for the pixel distance from 91 // center then we are rendering an unexpected color 92 double dstFraction = dstDistance / maxDifference; 93 if (dstFraction > dstPercentage) { 94 return false; 95 } 96 97 // similarly compute the ratio between the source color to the current pixel 98 // color relative to the maximum distance between source and destination colors 99 // If this value exceeds the threshold expected for the pixel distance from 100 // center then we are rendering an unexpected source color 101 double srcFraction = srcDistance / maxDifference; 102 if (srcFraction > dstPercentage) { 103 return false; 104 } 105 } 106 } 107 return true; 108 } 109 } 110