|
| 1 | +package aquality.selenium.elements.interfaces; |
| 2 | + |
| 3 | +import aquality.selenium.browser.AqualityServices; |
| 4 | +import org.opencv.core.Core; |
| 5 | +import org.opencv.core.Mat; |
| 6 | +import org.opencv.core.MatOfByte; |
| 7 | +import org.opencv.core.Point; |
| 8 | +import org.opencv.imgcodecs.Imgcodecs; |
| 9 | +import org.opencv.imgproc.Imgproc; |
| 10 | +import org.openqa.selenium.*; |
| 11 | + |
| 12 | +import java.io.File; |
| 13 | +import java.util.ArrayList; |
| 14 | +import java.util.List; |
| 15 | + |
| 16 | +public class ByImage extends By { |
| 17 | + private static boolean wasLibraryLoaded = false; |
| 18 | + private final Mat template; |
| 19 | + |
| 20 | + private static void loadLibrary() { |
| 21 | + if (!wasLibraryLoaded) { |
| 22 | + nu.pattern.OpenCV.loadShared(); |
| 23 | + System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME); |
| 24 | + wasLibraryLoaded = true; |
| 25 | + } |
| 26 | + } |
| 27 | + |
| 28 | + public ByImage(File file) { |
| 29 | + loadLibrary(); |
| 30 | + this.template = Imgcodecs.imread(file.getAbsolutePath(), Imgcodecs.IMREAD_UNCHANGED); |
| 31 | + } |
| 32 | + |
| 33 | + public ByImage(byte[] bytes) { |
| 34 | + loadLibrary(); |
| 35 | + this.template = Imgcodecs.imdecode(new MatOfByte(bytes), Imgcodecs.IMREAD_UNCHANGED); |
| 36 | + } |
| 37 | + |
| 38 | + @Override |
| 39 | + public List<WebElement> findElements(SearchContext context) { |
| 40 | + byte[] screenshotBytes = getScreenshot(context); |
| 41 | + Mat source = Imgcodecs.imdecode(new MatOfByte(screenshotBytes), Imgcodecs.IMREAD_UNCHANGED); |
| 42 | + Mat result = new Mat(); |
| 43 | + Imgproc.matchTemplate(source, template, result, Imgproc.TM_CCOEFF_NORMED); |
| 44 | + |
| 45 | + float threshold = 1 - AqualityServices.getConfiguration().getVisualizationConfiguration().getDefaultThreshold(); |
| 46 | + Core.MinMaxLocResult minMaxLoc = Core.minMaxLoc(result); |
| 47 | + |
| 48 | + if (minMaxLoc.maxVal < threshold) { |
| 49 | + AqualityServices.getLogger().warn(String.format("No elements found by image [%s]", template)); |
| 50 | + return new ArrayList<>(0); |
| 51 | + } |
| 52 | + |
| 53 | + return getElementsOnPoint(minMaxLoc.maxLoc, context); |
| 54 | + } |
| 55 | + |
| 56 | + private List<WebElement> getElementsOnPoint(Point matchLocation, SearchContext context) { |
| 57 | + int centerX = (int)(matchLocation.x + (template.width() / 2)); |
| 58 | + int centerY = (int)(matchLocation.y + (template.height() / 2)); |
| 59 | + |
| 60 | + JavascriptExecutor js; |
| 61 | + if (!(context instanceof JavascriptExecutor)) { |
| 62 | + AqualityServices.getLogger().debug("Current search context doesn't support executing scripts. " + |
| 63 | + "Will take browser js executor instead"); |
| 64 | + js = AqualityServices.getBrowser().getDriver(); |
| 65 | + } |
| 66 | + else { |
| 67 | + js = (JavascriptExecutor) context; |
| 68 | + } |
| 69 | + |
| 70 | + //noinspection unchecked |
| 71 | + return (List<WebElement>) js.executeScript("return document.elementsFromPoint(arguments[0], arguments[1]);", centerX, centerY); |
| 72 | + } |
| 73 | + |
| 74 | + private byte[] getScreenshot(SearchContext context) { |
| 75 | + byte[] screenshotBytes; |
| 76 | + |
| 77 | + if (!(context instanceof TakesScreenshot)) { |
| 78 | + AqualityServices.getLogger().debug("Current search context doesn't support taking screenshots. " + |
| 79 | + "Will take browser screenshot instead"); |
| 80 | + screenshotBytes = AqualityServices.getBrowser().getScreenshot(); |
| 81 | + } else { |
| 82 | + screenshotBytes = ((TakesScreenshot) context).getScreenshotAs(OutputType.BYTES); |
| 83 | + } |
| 84 | + |
| 85 | + return screenshotBytes; |
| 86 | + } |
| 87 | +} |
0 commit comments