internal string GetFullWindowDom(IPositionProvider positionProvider) { logger_.Verbose("enter"); PositionMemento originalPosition = positionProvider.GetState(); positionProvider.SetPosition(Point.Empty); Stopwatch stopwatch = Stopwatch.StartNew(); string domJson = GetDom_(); logger_.Verbose(nameof(GetDom_) + " took {0} ms", stopwatch.Elapsed.TotalMilliseconds); positionProvider.RestoreState(originalPosition); logger_.Verbose("exit"); return(domJson); }
private void MaximizeTargetFrameInCurrentFrame_(IWebElement frameElement, IWebElement userDefinedSRE) { IWebElement currentFrameSRE = EyesSeleniumUtils.GetCurrentFrameScrollRootElement(driver_, userDefinedSRE); IPositionProvider positionProvider = SeleniumEyes.GetPositionProviderForScrollRootElement_(logger_, driver_, stitchMode_, userAgent_, currentFrameSRE); Rectangle frameRect = EyesRemoteWebElement.GetClientBoundsWithoutBorders(frameElement, driver_, logger_); if (stitchMode_ == StitchModes.Scroll) { Point pageScrollPosition = positionProvider.GetCurrentPosition(); frameRect.Offset(pageScrollPosition); } positionProvider.SetPosition(frameRect.Location); }
public void MoveToRegion(IPositionProvider positionProvider, Location location) { Logger_.Verbose("Getting current position state.."); OriginalPosition_ = positionProvider.GetState(); Logger_.Verbose("Done! Setting position..."); // We set the location to "almost" the location we were asked. This is because sometimes, moving the browser // to the specific pixel where the element begins, causes the element to be slightly out of the viewport. int dstX = location.X - VISIBILITY_OFFSET; dstX = dstX < 0 ? 0 : dstX; int dstY = location.Y - VISIBILITY_OFFSET; dstY = dstY < 0 ? 0 : dstY; positionProvider.SetPosition(new Point(dstX, dstY)); Logger_.Verbose("Done!"); }
public override Bitmap GetImage() { logger_.Verbose("Getting current position..."); Point loc; double scaleRatio = eyes_.DevicePixelRatio; FrameChain currentFrameChain = eyes_.GetDriver().GetFrameChain(); IPositionProvider positionProvider = null; if (currentFrameChain.Count == 0) { IWebElement scrollRootElement = eyes_.GetCurrentFrameScrollRootElement(); positionProvider = eyes_.GetPositionProvider(logger_, StitchModes.Scroll, jsExecutor_, scrollRootElement, userAgent_); loc = positionProvider.GetCurrentPosition(); } else { loc = currentFrameChain.GetDefaultContentScrollPosition(); } Point scaledLoc = new Point((int)Math.Round(loc.X * scaleRatio), (int)Math.Round(loc.Y * scaleRatio)); Bitmap image = base.GetImage(); EyesWebDriver driver = eyes_.GetDriver(); RectangleSize originalViewportSize = EyesSeleniumUtils.GetViewportSize(logger_, driver); RectangleSize viewportSize = originalViewportSize.Scale(scaleRatio); if (image.Height > viewportSize.Height || image.Width > viewportSize.Width) { //Damn IE driver returns full page screenshot even when not asked to! logger_.Verbose("seems IE returned full page screenshot rather than only the viewport."); eyes_.DebugScreenshotProvider.Save(image, "IE"); if (!eyes_.IsCutProviderExplicitlySet) { Bitmap croppedImage = BasicImageUtils.Crop(image, new Rectangle(scaledLoc, viewportSize)); image.Dispose(); image = croppedImage; } } positionProvider?.SetPosition(loc); return(image); }
private void StitchScreenshot_(Size stitchOffset, IPositionProvider stitchProvider, ICollection <SubregionForStitching> screenshotParts, Bitmap stitchedImage, double scaleRatio, ICutProvider scaledCutProvider, float sizeRatio) { int index = 0; logger_.Verbose($"enter: {nameof(stitchOffset)}: {{0}} ; {nameof(screenshotParts)}.Count: {{1}}, {nameof(scaleRatio)}: {{2}}", stitchOffset, screenshotParts.Count, scaleRatio); Stopwatch stopwatch = Stopwatch.StartNew(); foreach (SubregionForStitching partRegion in screenshotParts) { if (stopwatch.Elapsed > TimeSpan.FromMinutes(5)) { logger_.Log("Still Running..."); // this is so CI systems won't kill the build due to lack of activity. stopwatch.Restart(); } logger_.Verbose("Part: {0}", partRegion); // Scroll to the part's top/left Point partAbsoluteLocationInCurrentFrame = partRegion.ScrollTo; partAbsoluteLocationInCurrentFrame += stitchOffset; Point scrollPosition = new Point( (int)Math.Round(partAbsoluteLocationInCurrentFrame.X * sizeRatio), (int)Math.Round(partAbsoluteLocationInCurrentFrame.Y * sizeRatio)); Point originPosition = stitchProvider.SetPosition(scrollPosition); int dx = scrollPosition.X - originPosition.X; int dy = scrollPosition.Y - originPosition.Y; Point partPastePosition = partRegion.PasteLocation; //partPastePosition.Offset(-fullarea.Left, -fullarea.Top); partPastePosition.Offset(dx, dy); // Actually taking the screenshot. Thread.Sleep(waitBeforeScreenshots_); using (Bitmap partImage = imageProvider_.GetImage()) using (Bitmap cutPart = scaledCutProvider.Cut(partImage)) { Bitmap croppedPart; Rectangle r = partRegion.PhysicalCropArea; if ((r.Width * r.Height) != 0) { croppedPart = BasicImageUtils.Crop(cutPart, r); } else { croppedPart = cutPart; } Rectangle r2 = partRegion.LogicalCropArea; using (Bitmap scaledPartImage = BasicImageUtils.ScaleImage(croppedPart, scaleRatio)) using (Bitmap scaledCroppedPartImage = BasicImageUtils.Crop(scaledPartImage, r2)) using (Graphics g = Graphics.FromImage(stitchedImage)) { debugScreenshotsProvider_.Save(partImage, "partImage-" + originPosition.X + "_" + originPosition.Y); debugScreenshotsProvider_.Save(cutPart, "cutPart-" + originPosition.X + "_" + originPosition.Y); debugScreenshotsProvider_.Save(croppedPart, "croppedPart-" + originPosition.X + "_" + originPosition.Y); debugScreenshotsProvider_.Save(scaledPartImage, "scaledPartImage-" + originPosition.X + "_" + originPosition.Y); debugScreenshotsProvider_.Save(scaledCroppedPartImage, "scaledCroppedPartImage-" + partPastePosition.X + "_" + partPastePosition.Y); logger_.Verbose("pasting part at {0}", partPastePosition); g.DrawImage(scaledCroppedPartImage, partPastePosition); } if (!object.ReferenceEquals(croppedPart, cutPart)) { croppedPart.Dispose(); } debugScreenshotsProvider_.Save(stitchedImage, $"stitched_{index}_({partPastePosition.X}_{partPastePosition.Y})"); index++; } } debugScreenshotsProvider_.Save(stitchedImage, "stitched"); }
/// <summary> /// Encapsulates an algorithm for creating full-page images of a page. /// </summary> /// <param name="positionProvider">The position provider used for moving to the actual stitch points.</param> /// <param name="region">The region to stitch. If <see cref="Region.Empty"/>, the entire image will be stitched.</param> /// <param name="fullarea">The wanted area of the resulting image. If unknown, pass in <c>null</c> or <see cref="Region.Empty"/>.</param> /// <param name="originProvider">A position provider used for saving the state before /// starting the stitching, as well as moving to (0,0). The reason it is separated from /// the <c>stitchProvider</c>is that the stitchProvider might have side-effects /// (e.g., changing the CSS transform of the page can cause a layout change at the /// top of the page), which we can avoid for the first screenshot (since it might be a /// full page screenshot anyway).</param> /// <param name="stitchOffset"></param> /// <returns>The screenshot as Bitmap.</returns> public Bitmap GetStitchedRegion(Region region, Region fullarea, IPositionProvider positionProvider, IPositionProvider originProvider, Size stitchOffset) { ArgumentGuard.NotNull(region, nameof(region)); ArgumentGuard.NotNull(positionProvider, nameof(positionProvider)); logger_.Verbose("region: {0} ; fullarea: {1} ; positionProvider: {2}", region, fullarea, positionProvider.GetType().Name); Point originalStitchedState = positionProvider.GetCurrentPosition(); logger_.Verbose("region size: {0}, originalStitchedState: {1}", region, originalStitchedState); PositionMemento originProviderState = originProvider.GetState(); logger_.Verbose("originProviderState: {0}", originProviderState); originProvider.SetPosition(Point.Empty); Thread.Sleep(waitBeforeScreenshots_); Bitmap initialScreenshot = imageProvider_.GetImage(); Size initialPhysicalSize = initialScreenshot.Size; SaveDebugScreenshotPart_(initialScreenshot, region.ToRectangle(), "initial"); IScaleProvider scaleProvider = scaleProviderFactory_.GetScaleProvider(initialScreenshot.Width); double pixelRatio = 1 / scaleProvider.ScaleRatio; Size initialSizeScaled = new Size((int)Math.Round(initialScreenshot.Width / pixelRatio), (int)Math.Round(initialScreenshot.Height / pixelRatio)); ICutProvider scaledCutProvider = cutProvider_.Scale(pixelRatio); if (pixelRatio != 1 && !(scaledCutProvider is NullCutProvider)) { initialScreenshot = cutProvider_.Cut(initialScreenshot); debugScreenshotsProvider_.Save(initialScreenshot, "original-cut"); } Region regionInScreenshot = GetRegionInScreenshot_(region, initialScreenshot, pixelRatio); Bitmap croppedInitialScreenshot = CropScreenshot_(initialScreenshot, regionInScreenshot); debugScreenshotsProvider_.Save(croppedInitialScreenshot, "cropped"); Bitmap scaledInitialScreenshot = BasicImageUtils.ScaleImage(croppedInitialScreenshot, scaleProvider); if (!object.ReferenceEquals(scaledInitialScreenshot, croppedInitialScreenshot)) { SaveDebugScreenshotPart_(scaledInitialScreenshot, regionInScreenshot.ToRectangle(), "scaled"); } if (fullarea.IsEmpty) { Size entireSize; try { entireSize = positionProvider.GetEntireSize(); logger_.Verbose("Entire size of region context: {0}", entireSize); } catch (EyesException e) { logger_.Log("WARNING: Failed to extract entire size of region context" + e.Message); logger_.Log("Using image size instead: " + scaledInitialScreenshot.Width + "x" + scaledInitialScreenshot.Height); entireSize = new Size(scaledInitialScreenshot.Width, scaledInitialScreenshot.Height); } // Notice that this might still happen even if we used // "getImagePart", since "entirePageSize" might be that of a frame. if (scaledInitialScreenshot.Width >= entireSize.Width && scaledInitialScreenshot.Height >= entireSize.Height) { logger_.Log("WARNING: Seems the image is already a full page screenshot."); if (!object.ReferenceEquals(scaledInitialScreenshot, initialScreenshot)) { initialScreenshot.Dispose(); } return(scaledInitialScreenshot); } fullarea = new Region(Point.Empty, entireSize, CoordinatesTypeEnum.SCREENSHOT_AS_IS); } float currentFullWidth = fullarea.Width; fullarea = sizeAdjuster_.AdjustRegion(fullarea, initialSizeScaled); float sizeRatio = currentFullWidth / fullarea.Width; logger_.Verbose("adjusted fullarea: {0}", fullarea); Point scaledCropLocation = fullarea.Location; Point physicalCropLocation = new Point( (int)Math.Ceiling(scaledCropLocation.X * pixelRatio), (int)Math.Ceiling(scaledCropLocation.Y * pixelRatio)); Rectangle sourceRegion; if (regionInScreenshot.IsSizeEmpty) { Size physicalCropSize = new Size(initialPhysicalSize.Width - physicalCropLocation.X, initialPhysicalSize.Height - physicalCropLocation.Y); sourceRegion = new Rectangle(physicalCropLocation, physicalCropSize); } else { // Starting with the screenshot we already captured at (0,0). sourceRegion = regionInScreenshot.ToRectangle(); } Rectangle scaledCroppedSourceRect = cutProvider_.ToRectangle(sourceRegion.Size); scaledCroppedSourceRect.Offset(sourceRegion.Location); Rectangle scaledCroppedSourceRegion = new Rectangle( (int)Math.Ceiling(scaledCroppedSourceRect.X / pixelRatio), (int)Math.Ceiling(scaledCroppedSourceRect.Y / pixelRatio), (int)Math.Ceiling(scaledCroppedSourceRect.Width / pixelRatio), (int)Math.Ceiling(scaledCroppedSourceRect.Height / pixelRatio)); Size scaledCropSize = scaledCroppedSourceRegion.Size; // The screenshot part is a bit smaller than the screenshot size, in order to eliminate // duplicate bottom/right-side scroll bars, as well as fixed position footers. Size screenshotPartSize = new Size( Math.Max(scaledCropSize.Width, MinScreenshotPartSize_), Math.Max(scaledCropSize.Height, MinScreenshotPartSize_) ); logger_.Verbose("Screenshot part size: {0}", screenshotPartSize); // Getting the list of viewport regions composing the page (we'll take screenshot for each one). Rectangle rectInScreenshot; if (regionInScreenshot.IsSizeEmpty) { int x = Math.Max(0, fullarea.Left); int y = Math.Max(0, fullarea.Top); int w = Math.Min(fullarea.Width, scaledCropSize.Width); int h = Math.Min(fullarea.Height, scaledCropSize.Height); rectInScreenshot = new Rectangle( (int)Math.Round(x * pixelRatio), (int)Math.Round(y * pixelRatio), (int)Math.Round(w * pixelRatio), (int)Math.Round(h * pixelRatio)); } else { rectInScreenshot = regionInScreenshot.Rectangle; } fullarea = CoerceImageSize_(fullarea); ICollection <SubregionForStitching> screenshotParts = fullarea.GetSubRegions(screenshotPartSize, stitchOverlap_, pixelRatio, rectInScreenshot, logger_); Bitmap stitchedImage = new Bitmap(fullarea.Width, fullarea.Height); // Take screenshot and stitch for each screenshot part. StitchScreenshot_(stitchOffset, positionProvider, screenshotParts, stitchedImage, scaleProvider.ScaleRatio, scaledCutProvider, sizeRatio); positionProvider.SetPosition(originalStitchedState); originProvider.RestoreState(originProviderState); croppedInitialScreenshot.Dispose(); return(stitchedImage); }