public override Bitmap GetImage()
        {
            Bitmap image = base.GetImage();

            logger_.Verbose("Bitmap Size: {0}x{1}", image.Width, image.Height);

            eyes_.DebugScreenshotProvider.Save(image, "ANDROID");

            if (eyes_.IsCutProviderExplicitlySet)
            {
                return(image);
            }

            Size originalViewportSize = GetViewportSize();

            logger_.Verbose("logical viewport size: " + originalViewportSize);

            int imageWidth  = image.Width;
            int imageHeight = image.Height;

            logger_.Verbose("physical device pixel size: {0}x{1}", imageWidth, imageHeight);
            float     widthRatio   = image.Width / (float)originalViewportSize.Width;
            float     height       = widthRatio * originalViewportSize.Height;
            Rectangle cropRect     = new Rectangle(0, 0, imageWidth, (int)Math.Round(height));
            Bitmap    croppedImage = BasicImageUtils.Crop(image, cropRect);

            image.Dispose();

            return(croppedImage);
        }
예제 #2
0
 /// <summary>
 /// Encapsulates an algorithm for creating full-page images of a page.
 /// </summary>
 /// <param name="positionProvider">The position provider used for stitching.</param>
 /// <returns>The screenshot as PNG byte array.</returns>
 public byte[] GetFullPageScreenshot(IPositionProvider positionProvider)
 {
     using (Bitmap screenshotImage = GetStitchedRegion(Region.Empty, Region.Empty, positionProvider, positionProvider))
     {
         return(BasicImageUtils.EncodeAsPng(screenshotImage));
     }
 }
        public Bitmap GetImage()
        {
            byte[] screenshotBytes;
            Bitmap result;

            if (eyes_.CachedViewport.IsEmpty)
            {
                try
                {
                    string screenshot64 = (string)jsExecutor_.ExecuteScript("mobile: viewportScreenshot");
                    screenshotBytes = Convert.FromBase64String(screenshot64);
                }
                catch (Exception e)
                {
                    logger_.Log("Warning: " + e);
                    screenshotBytes = tsInstance_.GetScreenshot().AsByteArray;
                }
                result = BasicImageUtils.CreateBitmap(screenshotBytes);
            }
            else
            {
                screenshotBytes = tsInstance_.GetScreenshot().AsByteArray;
                Bitmap screenshotBitmap = BasicImageUtils.CreateBitmap(screenshotBytes);
                eyes_.DebugScreenshotProvider.Save(screenshotBitmap, "DEVICE_ORIGINAL");
                result = BasicImageUtils.Crop(screenshotBitmap, eyes_.CachedViewport);
            }
            result = BasicImageUtils.ScaleImage(result, eyes_.ScaleRatio);
            return(result);
        }
        //[Test]
        //[Ignore("fails if not set up correctly")]
        public void TestSetViewportSize()
        {
            ChromeOptions options = new ChromeOptions();

            options.AddArgument("disable-infobars");
            if (TestUtils.RUN_HEADLESS)
            {
                options.AddArgument("headless");
            }
            IWebDriver driver = new RemoteWebDriver(options);

            Size expectedSize = new Size(700, 499);

            try
            {
                driver.Url = "http://viewportsizes.com/mine/";

                SeleniumEyes.SetViewportSize(driver, expectedSize);

                Bitmap screenshot = BasicImageUtils.CreateBitmap(((ITakesScreenshot)driver).GetScreenshot().AsByteArray);
                screenshot.Save($@"{logsPath_}\TestSetViewportSize.png");

                Size actualSize = SeleniumEyes.GetViewportSize(driver);

                Assert.AreEqual(expectedSize, actualSize, "Sizes differ");
            }
            finally
            {
                driver.Quit();
            }
        }
        public override EyesScreenshot GetSubScreenshot(Region region, bool throwIfClipped)
        {
            logger_.Verbose(nameof(GetSubScreenshot) + "([{0}], {1})", region, throwIfClipped);

            ArgumentGuard.NotNull(region, nameof(region));

            // We calculate intersection based on as-is coordinates.
            Region asIsSubScreenshotRegion = GetIntersectedRegion(region, CoordinatesTypeEnum.SCREENSHOT_AS_IS);

            if (asIsSubScreenshotRegion.IsSizeEmpty || (throwIfClipped && !asIsSubScreenshotRegion.Size.Equals(region.Size)))
            {
                throw new OutOfBoundsException($"Region [{region}] is out of screenshot bounds [{frameWindow_}]");
            }

            Bitmap subScreenshotImage = BasicImageUtils.Crop(Image, asIsSubScreenshotRegion.ToRectangle());

            // The frame location in the sub screenshot is the negative of the
            // context-as-is location of the region.
            Point contextAsIsRegionLocation =
                ConvertLocation(asIsSubScreenshotRegion.Location,
                                CoordinatesTypeEnum.SCREENSHOT_AS_IS,
                                CoordinatesTypeEnum.CONTEXT_AS_IS);

            Point frameLocationInSubScreenshot = new Point(-contextAsIsRegionLocation.X, -contextAsIsRegionLocation.Y);

            EyesWebDriverScreenshot result = new EyesWebDriverScreenshot(logger_,
                                                                         driver_, subScreenshotImage, subScreenshotImage.Size, Point.Empty);

            result.UpdateFrameLocationInScreenshot_(new Point(-region.Location.X, -region.Location.Y));

            result.DomUrl = DomUrl;

            logger_.Verbose("Done!");
            return(result);
        }
예제 #6
0
        public void TestScaleDownImage2()
        {
            Bitmap src      = LoadBitmapFromResource("scale_bug_to_540x768.png");
            Bitmap expected = LoadBitmapFromResource("ScaledDownTo540x768Image.png");
            Bitmap dest     = BasicImageUtils.ScaleImage(src, 540 / (double)src.Width);

            CompareBitmaps_(expected, dest);
        }
예제 #7
0
 private Bitmap CropScreenshot_(Bitmap initialScreenshot, Region regionInScreenshot)
 {
     if (!regionInScreenshot.IsSizeEmpty)
     {
         Bitmap croppedInitialScreenshot = BasicImageUtils.Crop(initialScreenshot, regionInScreenshot.ToRectangle());
         initialScreenshot.Dispose();
         initialScreenshot = croppedInitialScreenshot;
         SaveDebugScreenshotPart_(croppedInitialScreenshot, regionInScreenshot.ToRectangle(), "cropped");
     }
     return(initialScreenshot);
 }
예제 #8
0
        public override Bitmap GetImage()
        {
            Bitmap image = base.GetImage();

            logger_.Verbose("Bitmap Size: {0}x{1}", image.Width, image.Height);

            eyes_.DebugScreenshotProvider.Save(image, "SAFARI");

            if (eyes_.IsCutProviderExplicitlySet)
            {
                return(image);
            }

            double scaleRatio = eyes_.DevicePixelRatio;

            Size originalViewportSize = GetViewportSize();

            Size viewportSize = new Size(
                (int)Math.Ceiling(originalViewportSize.Width * scaleRatio),
                (int)Math.Ceiling(originalViewportSize.Height * scaleRatio));

            logger_.Verbose("logical viewport size: " + originalViewportSize);

            if (userAgent_.OS.Equals(OSNames.IOS))
            {
                image = CropIOSImage(image, originalViewportSize, logger_);
            }
            else if (!eyes_.ForceFullPageScreenshot)
            {
                Point      loc;
                FrameChain currentFrameChain = eyes_.GetDriver().GetFrameChain();

                if (currentFrameChain.Count == 0)
                {
                    IWebElement       scrollRootElement = eyes_.GetCurrentFrameScrollRootElement();
                    IPositionProvider positionProvider  = SeleniumPositionProviderFactory.GetPositionProvider(logger_, StitchModes.Scroll, jsExecutor_, scrollRootElement, userAgent_);
                    loc = positionProvider.GetCurrentPosition();
                }
                else
                {
                    loc = currentFrameChain.GetDefaultContentScrollPosition();
                }

                loc = new Point((int)Math.Ceiling(loc.X * scaleRatio), (int)Math.Ceiling(loc.Y * scaleRatio));

                image = BasicImageUtils.Crop(image, new Rectangle(loc, viewportSize));
            }
            eyes_.DebugScreenshotProvider.Save(image, "SAFARI_CROPPED");

            return(image);
        }
예제 #9
0
        internal static Bitmap CropIOSImage(Bitmap image, Size originalViewportSize, Logger logger = null)
        {
            if (logger == null)
            {
                logger = new Logger();
            }

            if (devicesRegions == null)
            {
                InitDeviceRegionsTable_();
            }

            int imageWidth  = image.Width;
            int imageHeight = image.Height;

            logger.Verbose("physical device pixel size: {0}x{1}", imageWidth, imageHeight);

            if (devicesRegions.TryGetValue(image.Size, out List <Rectangle> resolutions))
            {
                int   renderedWidth          = resolutions[0].Width;
                int   relevantViewportHeight = (renderedWidth < image.Width) ? originalViewportSize.Height - 21 : originalViewportSize.Height;
                float widthRatio             = renderedWidth / (float)originalViewportSize.Width;
                float height = widthRatio * relevantViewportHeight;
                if (Math.Abs(height - image.Height) > 1.5)
                {
                    Rectangle bestMatchingRect = resolutions[0];
                    float     bestHeightDiff   = Math.Abs(bestMatchingRect.Height - height);
                    logger.Verbose("bestMatchingRect: {0} ; bestHeightDiff: {1}", bestMatchingRect, bestHeightDiff);
                    for (int i = 1; i < resolutions.Count; ++i)
                    {
                        Rectangle rect       = resolutions[i];
                        float     heightDiff = Math.Abs(rect.Height - height);
                        logger.Verbose("rect: {0} ; heightDiff: {1} ; bestHeightDiff: {2}", rect, heightDiff, bestHeightDiff);
                        if (heightDiff < bestHeightDiff)
                        {
                            bestHeightDiff   = heightDiff;
                            bestMatchingRect = rect;
                            logger.Verbose("updated bestHeightDiff to {0} and bestMatchingRect to {1}", bestHeightDiff, bestMatchingRect);
                        }
                    }
                    logger.Verbose("closest crop rect found: {0}", bestMatchingRect);
                    image = BasicImageUtils.Crop(image, bestMatchingRect);
                }
                else
                {
                    logger.Verbose("no crop needed. must be using chrome emulator.");
                }
            }

            return(image);
        }
예제 #10
0
        public override EyesScreenshot GetSubScreenshot(Region region, bool throwIfClipped)
        {
            Region asIsSubScreenshotRegion = GetIntersectedRegion(region, CoordinatesTypeEnum.SCREENSHOT_AS_IS);

            if (asIsSubScreenshotRegion.IsSizeEmpty || (throwIfClipped && !asIsSubScreenshotRegion.Size.Equals(region.Size)))
            {
                throw new OutOfBoundsException($"Region [{region}] is out of screenshot bounds [{Image.Size}]");
            }

            Bitmap subScreenshotImage = BasicImageUtils.Crop(Image, asIsSubScreenshotRegion.ToRectangle());

            EyesImagesScreenshot result = new EyesImagesScreenshot(subScreenshotImage);

            return(result);
        }
예제 #11
0
        public void TestScaleDownImage1()
        {
            Bitmap src      = LoadBitmapFromResource("SrcImage.png");
            Bitmap expected = LoadBitmapFromResource("ScaledDownImage.png");
            Bitmap dest     = BasicImageUtils.ScaleImage(src, expected.Width / (double)src.Width);

            if (!TestUtils.RUNS_ON_CI)
            {
                Directory.CreateDirectory(testScaleDownImageOutputPath_);
                src.Save(Path.Combine(testScaleDownImageOutputPath_, "orig.png"));
                expected.Save(Path.Combine(testScaleDownImageOutputPath_, "expected.png"));
                dest.Save(Path.Combine(testScaleDownImageOutputPath_, "actual_result.png"));
            }
            CompareBitmaps_(expected, dest);
        }
예제 #12
0
        public override EyesScreenshot GetSubScreenshot(Region subregion, bool throwIfClipped)
        {
            logger_.Verbose("GetSubScreenshot([{0}], {1})", subregion, throwIfClipped);

            ArgumentGuard.NotNull(subregion, nameof(subregion));
            if (eyes_.CutProvider != null && !(eyes_.CutProvider is NullCutProvider))
            {
                subregion = new Region(Point.Empty, workingArea_.Size);
            }
            Bitmap subScreenshotImage = BasicImageUtils.Crop(Image, subregion.ToRectangle());

            subregion = subregion.Offset(workingArea_.Left, workingArea_.Top);
            EyesAppiumScreenshot result = new EyesAppiumScreenshot(logger_, subScreenshotImage, subregion, eyes_);

            logger_.Verbose("Done!");
            return(result);
        }
        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);
        }
예제 #14
0
        public override Bitmap GetImage()
        {
            logger_.Verbose("Getting screenshot...");

            EyesWebDriver eyesWebDriver = eyes_.GetDriver();
            FrameChain    frameChain    = eyesWebDriver.GetFrameChain().Clone();

            logger_.Verbose("temporarilly switching to default content.");
            eyesWebDriver.SwitchTo().DefaultContent();

            Bitmap image = BasicImageUtils.CreateBitmap(tsInstance_.GetScreenshot().AsByteArray);

            eyes_.DebugScreenshotProvider.Save(image, "FIREFOX");

            logger_.Verbose("switching back to original frame.");
            ((EyesWebDriverTargetLocator)eyesWebDriver.SwitchTo()).Frames(frameChain);

            return(image);
        }
예제 #15
0
 public virtual Bitmap GetImage()
 {
     return(BasicImageUtils.CreateBitmap(tsInstance_.GetScreenshot().AsByteArray));
 }
 public EyesLeanFTScreenshot(byte[] screenshotBytes) : base(BasicImageUtils.CreateBitmap(screenshotBytes))
 {
 }
예제 #17
0
        public static SimpleImageProvider FromBytes(byte[] screenshotBytes)
        {
            Bitmap bmp = BasicImageUtils.CreateBitmap(screenshotBytes);

            return(new SimpleImageProvider(bmp));
        }
예제 #18
0
        public Bitmap Cut(Bitmap image)
        {
            Rectangle rect = ToRectangle(image.Size);

            return(BasicImageUtils.Crop(image, rect));
        }
예제 #19
0
        public override Bitmap GetImage()
        {
            Bitmap image = base.GetImage();

            if (eyes_.CachedSessionDetails != null &&
                eyes_.CachedSessionDetails.TryGetValue("deviceOrientation", out object orientation))
            {
                if ("landscape".Equals(orientation as string, StringComparison.OrdinalIgnoreCase) && image.Width < image.Height)
                {
                    logger_.Verbose("rotating image...");
                    image.RotateFlip(RotateFlipType.Rotate270FlipNone);
                }
            }

            logger_.Verbose("Bitmap Size: {0}x{1}", image.Width, image.Height);
            eyes_.DebugScreenshotProvider.Save(image, "SAFARI");

            if (eyes_.IsCutProviderExplicitlySet)
            {
                return(image);
            }

            double scaleRatio = eyes_.DevicePixelRatio;

            Size originalViewportSize = GetViewportSize();

            Size viewportSize = new Size(
                (int)Math.Ceiling(originalViewportSize.Width * scaleRatio),
                (int)Math.Ceiling(originalViewportSize.Height * scaleRatio));

            logger_.Verbose("logical viewport size: " + originalViewportSize);

            Bitmap croppedImage = null;

            if (userAgent_.IsiOS ||
                "ios".Equals(eyes_.PlatformName, StringComparison.OrdinalIgnoreCase) ||
                (eyes_.CachedSessionDetails.TryGetValue("PlatformName", out object platformName) &&
                 "ios".Equals(platformName as string, StringComparison.OrdinalIgnoreCase)))
            {
                croppedImage = CropIOSImage(image, originalViewportSize, logger_);
            }
            else if (!eyes_.ForceFullPageScreenshot)
            {
                Point      loc;
                FrameChain currentFrameChain = eyes_.GetDriver().GetFrameChain();

                if (currentFrameChain.Count == 0)
                {
                    IWebElement       scrollRootElement = eyes_.GetCurrentFrameScrollRootElement();
                    IPositionProvider positionProvider  = eyes_.GetPositionProvider(
                        logger_, StitchModes.Scroll, jsExecutor_, scrollRootElement,
                        userAgent_);
                    loc = positionProvider.GetCurrentPosition();
                }
                else
                {
                    loc = currentFrameChain.GetDefaultContentScrollPosition();
                }

                loc = new Point((int)Math.Ceiling(loc.X * scaleRatio), (int)Math.Ceiling(loc.Y * scaleRatio));

                croppedImage = BasicImageUtils.Crop(image, new Rectangle(loc, viewportSize));
            }
            if (croppedImage != null && !ReferenceEquals(croppedImage, image))
            {
                image.Dispose();
                image = croppedImage;
            }
            eyes_.DebugScreenshotProvider.Save(image, "SAFARI_CROPPED");

            return(image);
        }
예제 #20
0
        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");
        }
예제 #21
0
        /// <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);
        }