Why 1920x1080 videos are displayed very slow using JavaFX - javafx

I am trying to play some videos with resolution 1920x1080 using JavaFX frame by frame because I want to apply some modifications on each frame but when I start the program I see the video played very slow.
What is the cause? How can I improve it?
How I do it:
#Override
public void run() {
synchronized (this) {
while (runnable) {
if (webSource.grab()) {
try {
webSource.retrieve(frame);
numberOfFrames++;
Mat resize_blur_Img = frame.clone();
Imgproc.GaussianBlur(resize_blur_Img, resize_blur_Img, new Size(9, 9), 2, 2);
Mat fgMask = new Mat();
mog2.apply(resize_blur_Img, fgMask, 0.01);
Mat output = new Mat();
Mat closeElement = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(7, 7),
new Point(3, 3));
Imgproc.morphologyEx(fgMask, output, Imgproc.MORPH_CLOSE, closeElement);
Imgproc.morphologyEx(output, output, Imgproc.MORPH_CLOSE, closeElement);
Imgproc.threshold(output, output, 127, 255, Imgproc.THRESH_BINARY);
contourImg = new Mat();
contourImg = output.clone();
findContours(contourImg);
Imgcodecs.imencode(".bmp", frame, mem);
image = ImageIO.read(new ByteArrayInputStream(mem.toArray()));
BufferedImage bufferedImage = (BufferedImage) image;
imgView.setImage(SwingFXUtils.toFXImage(bufferedImage, null));
Imgcodecs.imencode(".bmp", output, mem2);
image2 = ImageIO.read(new ByteArrayInputStream(mem2.toArray()));
BufferedImage bufferedImage2 = (BufferedImage) image2;
imgViewLeft3.setImage(SwingFXUtils.toFXImage(bufferedImage2, null));
if (runnable == false) {
System.out.println("Going to wait() -> DaemonThread");
this.wait();
}
} catch (Exception ex) {
System.out.println("Error");
}
} else {
runnable = false;
}
}
}
}

Related

How do you print TextArea to a USB Thermal Printer 58mm?(JAVAFX)

So I'm trying to make a billing system in which I want to print a receipt.I was able to do it with some code that I found online,but the font size is too big to print in the 58mm wide paper.I'm not able to adjust the font size.Any kind of help with this issue will be highly appreciated.Thank You.
Here is The Code :
public class PrinterService implements Printable {
public List<String> getPrinters(){
DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
PrintService printServices[] = PrintServiceLookup.lookupPrintServices(
flavor, pras);
List<String> printerList = new ArrayList<String>();
for(PrintService printerService: printServices){
printerList.add( printerService.getName());
}
return printerList;
}
#Override
public int print(Graphics g, PageFormat pf, int page)
throws PrinterException {
if (page > 0) { /* We have only one page, and 'page' is zero-based */
return NO_SUCH_PAGE;
}
/*
* User (0,0) is typically outside the imageable area, so we must
* translate by the X and Y values in the PageFormat to avoid clipping
*/
Graphics2D g2d = (Graphics2D) g;
g2d.translate(pf.getImageableX(), pf.getImageableY());
/* Now we perform our rendering */
g.setFont(new Font("Roman", 0, 8));
g.drawString("Hello world !", 0, 10);
return PAGE_EXISTS;
}
public void printString(String printerName, String text) {
// find the printService of name printerName
DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
PrintService printService[] = PrintServiceLookup.lookupPrintServices(
flavor, pras);
PrintService service = findPrintService(printerName, printService);
DocPrintJob job = service.createPrintJob();
try {
byte[] bytes;
// important for umlaut chars
bytes = text.getBytes("CP437");
Doc doc = new SimpleDoc(bytes, flavor, null);
job.print(doc, null);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void printBytes(String printerName, byte[] bytes) {
DocFlavor flavor = DocFlavor.BYTE_ARRAY.AUTOSENSE;
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
PrintService printService[] = PrintServiceLookup.lookupPrintServices(
flavor, pras);
PrintService service = findPrintService(printerName, printService);
DocPrintJob job = service.createPrintJob();
try {
Doc doc = new SimpleDoc(bytes, flavor, null);
job.print(doc, null);
} catch (Exception e) {
e.printStackTrace();
}
}
private PrintService findPrintService(String printerName,
PrintService[] services) {
for (PrintService service : services) {
if (service.getName().equalsIgnoreCase(printerName)) {
return service;
}
}
return null;
}
}
#FXML
public void printit(ActionEvent actionEvent)
{
PrinterService printerService = new PrinterService();
System.out.println(printerService.getPrinters());
//print some stuff
printerService.printString("POS-58-Series", area.getText());
}

No 'output' extra specified Exception

I use the Google Photo app to pick gallery photo and then when I crop the picture and save, it catches an exception, Here is my code :
goto_picture.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
intent = new Intent(Intent.ACTION_PICK, null);
intent.setDataAndType(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
IMAGE_UNSPECIFIED);
startActivityForResult(intent, PHOTO_ZOOM);
dialog.cancel();
}
});
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
if (requestCode == PHOTO_GRAPH) {
startPhotoZoom(Uri.fromFile(file));
String imagePath = SystemUtils.getSDPath() + "/temp.jpg";
File picture = new File(imagePath);
if (picture.exists()) {
pictureBitmap = BitmapFactory.decodeFile(imagePath);
ImageUtils.SaveCacheBitmap(pictureBitmap);
rvEditAvatar.setImageBitmap(pictureBitmap);
}
}
if (requestCode == PHOTO_ZOOM) {
startPhotoZoom(data.getData());
}
if (requestCode == PHOTO_RESULT) {
Bundle extras = data.getExtras();
if (extras != null) {
pictureBitmap = extras.getParcelable("data");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
pictureBitmap.compress(Bitmap.CompressFormat.JPEG, 100,
stream);
ImageUtils.SaveCacheBitmap(pictureBitmap);
rvEditAvatar.setImageBitmap(pictureBitmap);
}
}
}
}
public void startPhotoZoom(Uri uri) {
Intent intent = new Intent("com.android.camera.action.CROP");
intent.setDataAndType(uri, "image/*");
intent.putExtra("crop", "true");
intent.putExtra("aspectX", 1);
intent.putExtra("aspectY", 1);
intent.putExtra("outputX", 180);
intent.putExtra("outputY", 180);
intent.putExtra("return-data", true);
intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
startActivityForResult(intent, PHOTO_RESULT);
}
Logcat:
Process: com.google.android.apps.photos, PID: 7031
java.lang.RuntimeException: Unable to resume activity
{com.google.android.apps.photos/com.google.android.apps.photos.photoeditor.intents.EditActivity}:
java.lang.UnsupportedOperationException: No 'output' extra specified
and can not save to specified inputUri:
content://com.google.android.apps.photos.contentprovider/0/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F72072/ACTUAL
As the exception said, you have to specify output extra like the following code.
intent.putExtra(MediaStore.EXTRA_OUTPUT, someOutPutPath);
And return data is not secure in case of big image cropped which may cause crash. I think that's why it forces you to use an output extra but not the data directly. So you may set the return-data to false as well:
intent.putExtra("return-data", false);
I meet this problem today, and solved by double check the data pass-back.I test following code on both Android L and Android 4. On Android L the fileUri is not empty while pre Android L we got fileUri null(in this case, I got the bitmap by simply getData).
private Bitmap decodeBitmapFromCrop(Intent data) {
Bundle extras = data.getExtras();
Bitmap photo = null;
if (extras != null) {
photo = extras.getParcelable("data");
} else {
Uri fileUri = data.getData();
if (fileUri != null) {
try {
photo = MediaStore.Images.Media.getBitmap(getContentResolver(), fileUri);
} catch (IOException e) {
XXLog.d(TAG, "Media.getBitmap", e);
}
}
}
return photo;
}

How Can I edit image to android gallery and save

I access the android gallery and select image. after view photo on image view ..
this code is true work.
targetImage = (ImageView)findViewById(R.id.imageView1);
public void Onclickimage(View view){
try{
Intent intent = new Intent(Intent.ACTION_PICK,
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intent, 0);
}
catch (Exception ex)
{
Toast.makeText(this,ex.getMessage(),Toast.LENGTH_LONG).show();
}
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0 && resultCode == RESULT_OK && null != data) {
Uri selectedImage = data.getData();
String[] filePathColumn = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
picturePath = cursor.getString(columnIndex);
cursor.close();
targetImage.setImageBitmap(BitmapFactory.decodeFile(picturePath));
}
I would like another buttonclick set text on photo to imageview.
This code does not work.
public void onClick(View view) {
Bitmap bmp = drawTextToBitmap(MainActivity.this,R.id.imageView1,"MyText");
targetImage.setImageBitmap(bmp);
}
public Bitmap drawTextToBitmap(Context mContext, int resourceId, String mText) {
try {
Resources resources = mContext.getResources();
float scale = resources.getDisplayMetrics().density;
ImageView img = (ImageView)findViewById(R.id.imageView1);
float xson = img.getWidth();
float yson = img.getHeight();
Bitmap bitmap = BitmapFactory.decodeResource(resources, resourceId);
android.graphics.Bitmap.Config bitmapConfig = bitmap.getConfig();
// set default bitmap config if none
if(bitmapConfig == null) {
bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
}
// resource bitmaps are imutable,
// so we need to convert it to mutable one
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
// new antialised Paint
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// text color - #3D3D3D
paint.setColor(Color.BLACK);
// text size in pixels
paint.setTextSize((int) (12 * scale));
// text shadow
paint.setShadowLayer(1f, 0f, 1f, Color.DKGRAY);
// draw text to the Canvas center
Rect bounds = new Rect();
paint.getTextBounds(mText, 0, mText.length(), bounds);
int x = (bitmap.getWidth() - bounds.width())/4;
int y = ((bitmap.getHeight() + bounds.height())/3)+50;
paint.setColor(Color.RED);
canvas.drawRect(x * scale-15, y * scale-30,xson+15 - x * scale , yson, paint); // for background
paint.setColor(Color.BLACK); for text
canvas.drawText(mText, x * scale, y * scale, paint);
return bitmap;
} catch (Exception e) {
Toast.makeText(MainActivity.this,e.toString(),Toast.LENGTH_LONG).show();
return null;
}
I write R.id.imageview1 instead to R.drawable.recimage this code is work but for just one photo.
I solve the problem
this code is wrong
Bitmap bitmap = BitmapFactory.decodeResource(resources, resourceId);
true code
img.setDrawingCacheEnabled(true);
Bitmap bitmap = img.getDrawingCache();

download generated images automatically multiple times

I am trying to download around 1000 images. For that first I am generating random number, converting this text to image. After this on button click, I am downloading this generated image. This is working fine. Now I want to run this loop for 1000 times so that I can download thousand images. The below code works fine when the loop is running once, but when the loop is running 1000 times, its not working as I am expecting.
Also, I want to change the destination folder where this images should be downloaded. How can I do that?
Below if I change value of variable i to 1000, the output is not what I am expecting
public partial class Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
for (int i = 0; i < 1; i++)
{
CallBUttonClick();
}
}
protected void Button1_Click(object sender, EventArgs e)
{
var s = GenerateRandomCode();
RandomImage ci = new RandomImage(s.ToString(), 300, 75);
this.Response.Clear();
this.Response.ContentType = "image/jpeg";
Response.AppendHeader("Content-Disposition", "attachment; filename=downloadedFile.JPG");
ci.Image.Save(this.Response.OutputStream, ImageFormat.Jpeg);
ci.Dispose();
}
protected void CallBUttonClick()
{
Button1_Click(Button1, null);
}
private string GenerateRandomCode()
{
Random r = new Random();
string s = "";
for (int j = 0; j < 5; j++)
{
int i = r.Next(3);
int ch;
switch (i)
{
case 1:
ch = r.Next(0, 9);
s = s + ch.ToString();
break;
case 2:
ch = r.Next(65, 90);
s = s + Convert.ToChar(ch).ToString();
break;
case 3:
ch = r.Next(97, 122);
s = s + Convert.ToChar(ch).ToString();
break;
default:
ch = r.Next(97, 122);
s = s + Convert.ToChar(ch).ToString();
break;
}
r.NextDouble();
r.Next(100, 1999);
}
return s;
}
}
Adding RandomImage.cs class file
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System;
public class RandomImage
{
//Default Constructor
public RandomImage() { }
//property
public string Text
{
get { return this.text; }
}
public Bitmap Image
{
get { return this.image; }
}
public int Width
{
get { return this.width; }
}
public int Height
{
get { return this.height; }
}
//Private variable
private string text;
private int width;
private int height;
private Bitmap image;
private Random random = new Random();
//Methods declaration
public RandomImage(string s, int width, int height)
{
this.text = s;
this.SetDimensions(width, height);
this.GenerateImage();
}
public void Dispose()
{
GC.SuppressFinalize(this);
this.Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
this.image.Dispose();
}
private void SetDimensions(int width, int height)
{
if (width <= 0)
throw new ArgumentOutOfRangeException("width", width,
"Argument out of range, must be greater than zero.");
if (height <= 0)
throw new ArgumentOutOfRangeException("height", height,
"Argument out of range, must be greater than zero.");
this.width = width;
this.height = height;
}
private void GenerateImage()
{
Bitmap bmp = new Bitmap(1, 1);
Graphics graphics = Graphics.FromImage(bmp);
Font font = new Font(FontFamily.GenericSansSerif, 28);
SizeF stringSize = graphics.MeasureString(this.text, font);
bmp = new Bitmap(bmp, (int)stringSize.Width+30, (int)stringSize.Height+30);
graphics = Graphics.FromImage(bmp);
graphics.DrawString(this.text, font, Brushes.White, 0, 0);
font.Dispose();
graphics.Flush();
graphics.Dispose();
this.image = bmp;
}
}
Hi you need to save you bitmap file on physcial folder. I have modified you code. Please see below code
private void GenerateImage()
{
Bitmap bmp = new Bitmap(1, 1);
Graphics graphics = Graphics.FromImage(bmp);
Font font = new Font(FontFamily.GenericSansSerif, 28);
SizeF stringSize = graphics.MeasureString(this.text, font);
bmp = new Bitmap(bmp, (int)stringSize.Width + 30, (int)stringSize.Height + 30);
graphics = Graphics.FromImage(bmp);
graphics.DrawString(this.text, font, Brushes.White, 0, 0);
font.Dispose();
graphics.Flush();
graphics.Dispose();
bmp.Save("C:\\" + this.text + ".jpg");
this.image = bmp;
}
I have also removed below code from button click and rested, it is working fine.
//this.Response.Clear();
//this.Response.ContentType = "image/jpeg";
//Response.AppendHeader("Content-Disposition", "attachment; filename=downloadedFile.JPG");
//ci.Image.Save(this.Response.OutputStream, ImageFormat.Jpeg);
//ci.Dispose();
That's not how the ASP.NET Page Life Cycle works. If you use the Response object to serve a download, you can serve ONE file.
You are approaching the problem from the wrong side; you say "I am trying to download around 1000 images". That is a process on the client side, on the browser if you will.
Yet you are trying to solve this on the server side.
You want 1000 downloads, so you have to initiate 1000 downloads from the client, and let the server side, the one Page you're writing for that, live through that 1000 times.
In other words, you cannot "push download" multiple files from the server, you have to request them one by one.

Selenium webdriver C# - Taking full page screenshot

Can anyone help me to take a full page screenshot using Selenium webdriver. I am using c#/Nunit. The current method i am using is not taking the full browser page.
I am using the code below to take the screenshot.
public void TakeScreenShot(IWebDriver webDriver,string testName,string className)
{
string folderName = String.Format("{0}.{1}", className, testName);
// Create Screenshot folder
string createdFolderLocation = CreateFolder(folderName);
// Take the screenshot
Screenshot ss = ((ITakesScreenshot)webDriver).GetScreenshot();
string screenshot = ss.AsBase64EncodedString;
byte[] screenshotAsByteArray = ss.AsByteArray;
// Save the screenshot
ss.SaveAsFile((string.Format("{0}\\{1}",createdFolderLocation,testName + ".Jpeg")), System.Drawing.Imaging.ImageFormat.Jpeg);
ss.ToString();
}
You can use this package https://www.nuget.org/packages/Noksa.WebDriver.ScreenshotsExtensions/
In order to take a screenshot of the entire page, use the VerticalCombineDecorator:
var vcs = new VerticalCombineDecorator(new ScreenshotMaker());
var screen = _driver.TakeScreenshot(vcs);
"Full-page" screenshots are defined by WebDriver to include the entirety of the page displayed in the browser, not the browser chrome (URL bar, toolbar, window resizing handles, and so on). If you don't care about getting the full DOM in your screenshot, you don't need to use WebDriver to get your screenshot. You can use the API of your operating system to handle that instead.
This one I used in our solution:
public byte[] TakeScreenshot()
{
try
{
var getMaxSide = "return Math.max(document.body.scroll{0}, document.body.offset{0}, document.documentElement.client{0}, document.documentElement.scroll{0}, document.documentElement.offset{0})";
var scrollHeight = (Driver as IJavaScriptExecutor).ExecuteScript(string.Format(getMaxSide, "Height"));
var scrollWidth = (Driver as IJavaScriptExecutor).ExecuteScript(string.Format(getMaxSide, "Width"));
Driver.Manage().Window.Size = new Size(int.Parse(scrollWidth.ToString()), int.Parse(scrollHeight.ToString()));
return (Driver as ITakesScreenshot).GetScreenshot().AsByteArray;
}
catch
{
return Array.Empty<byte>();
}
}
Then you can use the result to attach it to e.g. Allure or NUnit test results:
private void AttachScreenshot()
{
var screenshot = _browser?.TakeScreenshot();
if (screenshot.Length > 0)
{
// add screenshot to test results
var path = DateTime.Now.Ticks.ToString() + ".png";
File.WriteAllBytes(path, screenshot);
TestContext.AddTestAttachment(path, "screenshot");
// attach screenshot to Allure report
AllureLifecycle.Instance.AddAttachment("screenshot", "image/png", screenshot);
}
}
Try changing the size of the browser window to something huge before taking your screen shot. I have the size to 10 less than the width, and 10 less than the height. Try adding rather than subtracting.
driver = new FirefoxDriver(firefoxProfile);
if (Config.MAXIMIZE_BROWSER_WINDOW)
{
driver.Manage().Window.Size = new System.Drawing.Size(System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Width - 10, System.Windows.Forms.Screen.PrimaryScreen.WorkingArea.Height - 10);
}
you may try this
IWebDriver driver = new PhantomJSDriver();
driver.Navigate().GoToUrl("http://www.google.com");
((ITakesScreenshot)driver).GetScreenshot().SaveAsFile("image.png", ImageFormat.Png);
Greetings from 2017))!
If the page size is larger than the screen size - you can use the PhantomJS driver (PhantomJS download page)
var fileName = "test.png";
var size = new Size(800, 2000);
var url = "https://stackoverflow.com/";
using (var driver = new PhantomJSDriver())
{
driver.Manage().Window.Size = size;
driver.Navigate().GoToUrl(url);
((ITakesScreenshot)driver)
.GetScreenshot()
.SaveAsFile(fileName, ImageFormat.Png);
driver.Close();
}
I remeber that ((ITakesScreenshot)webDriver).GetScreenshot(); takes full page screenshot but if you have some ajax request and other loading elements you can add scrolling and at the end to wait some seconds, after that you will know that it took full loaded page screenshot.
for (int second = 0;; second++)
{
if (second >= 4)
{
break;
}
((IJavaScriptExecutor)Global.Driver).ExecuteScript("window.scrollBy(0,800)", string.Empty);
Thread.Sleep(500);
}
Thread.Sleep(3000);
Try this hope it will work fine for u.
public void TakeScreenshot(string SSName)
{
try
{
string path = "D:\\WorkSpace\\Screenshot\\";
Screenshot ss = ((ITakesScreenshot)driver).GetScreenshot();
ss.SaveAsFile((path + SSName), System.Drawing.Imaging.ImageFormat.Jpeg);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
throw;
}
}
Changing browser height doesn't always work. This is the solution I used. It scrolls through the page and composes the full-page screenshot.
public static Image TakeFullPageScreenshot(this RemoteWebDriver driver, int maxHeight = 10000)
{
Bitmap fullPageScreenshot = null;
using (var fullMs = new MemoryStream((driver.GetScreenshot()).AsByteArray)) {
fullPageScreenshot = Image.FromStream(fullMs) as Bitmap;
}
var originalPageOffset = driver.GetPageOffset();
var prevPageOffset = 0;
var currentPageOffset = 0;
var scrollLength = (int)(driver.Manage().Window.Size.Height / 1.5);
while (fullPageScreenshot.Height < maxHeight)
{
prevPageOffset = driver.GetPageOffset().Y;
driver.ScrollPageBy(0, scrollLength);
System.Threading.Thread.Sleep(500);
currentPageOffset = driver.GetPageOffset().Y;
if (prevPageOffset == currentPageOffset)
{
break;
}
var pageMovedBy = currentPageOffset - prevPageOffset;
using (var ms = new MemoryStream(driver.GetScreenshot().AsByteArray))
{
using (var viewPortScreenshot = Image.FromStream(ms) as Bitmap)
{
var croppedScreenshot = CropBitmapAtRect(viewPortScreenshot, new Rectangle(0, viewPortScreenshot.Height - pageMovedBy, viewPortScreenshot.Width, pageMovedBy));
var newFullPage = AppendBitmap(fullPageScreenshot, croppedScreenshot);
fullPageScreenshot.Dispose();
fullPageScreenshot = newFullPage;
}
}
}
driver.ScrollPageTo(originalPageOffset.X, originalPageOffset.Y);
return fullPageScreenshot;
}
public static Bitmap CropBitmapAtRect(Bitmap b, Rectangle r)
{
Bitmap nb = new Bitmap(r.Width, r.Height);
using (Graphics g = Graphics.FromImage(nb))
{
g.DrawImage(b, -r.X, -r.Y);
return nb;
}
}
public static Bitmap AppendBitmap(Bitmap source, Bitmap target, int spacing = 0)
{
int w = Math.Max(source.Width, target.Width);
int h = source.Height + target.Height + spacing;
Bitmap bmp = new Bitmap(w, h);
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawImage(source, 0, 0);
g.DrawImage(target, 0, source.Height + spacing);
}
return bmp;
}
public static void ScrollPageBy(this RemoteWebDriver driver, int x = 0, int y = 0)
{
driver.ExecuteScript(#"window.scroll(window.pageXOffset + arguments[0], window.pageYOffset + arguments[1]);", x, y);
}
public static void ScrollPageTo(this RemoteWebDriver driver, int x = 0, int y = 0)
{
driver.ExecuteScript(#"window.scroll(arguments[0], arguments[1]);", x, y);
}
public static Point GetPageOffset(this RemoteWebDriver driver)
{
var offsetArray = driver.ExecuteScript(#"return [window.pageXOffset, window.pageYOffset];") as ReadOnlyCollection<object>;
var x = (long)offsetArray[0];
var y = (long)offsetArray[1];
return new Point((int)x, (int)y);
}
based on the answer from #Michal Kalous I created an etension class.
This also takes into account the font size currently set in widows and the real viewport size and removes the vertical scrollbar by setting body.style.overflowY to hidden.
Usage
RemoteWebDriver driver = new EdgeDriver();
driver.SetViewportSize(1200, 1200);
driver.Navigate().GoToUrl("https://www.bikereview.info/en/ktm-1290-super-duke-rr-innerhalb-von-48-minuten-ausverkauft.html");
Image tempImage = driver.TakeFullPageScreenshot();
tempImage.Save(#"c:\full.png", ImageFormat.Png);
driver.Close();
driver.Quit();
Extension-Class
using System;
using System.Drawing;
using System.IO;
using OpenQA.Selenium.Remote;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using OpenQA.Selenium;
namespace TestRenderHtmlToPng
{
public static class RemoteWebDriverExtensions
{
public static Image TakeFullPageScreenshot(this RemoteWebDriver driver, int maxHeight = 10000)
{
//Screenshots depend on fontscaleing-property in windows
double DpiScalingFactor = GetDpiScalingFactor();
Bitmap fullPageScreenshot = null;
using (var fullMs = new MemoryStream((driver.GetScreenshotOverflowHidden()).AsByteArray))
{
fullPageScreenshot = Image.FromStream(fullMs) as Bitmap;
}
var originalPageOffset = driver.GetPageOffset();
var prevPageOffset = 0;
var currentPageOffset = 0;
var scrollLength = driver.GetWindowInnerHeight();
while (fullPageScreenshot.Height < maxHeight)
{
prevPageOffset = driver.GetPageOffset().Y;
driver.ScrollPageBy(0, scrollLength);
System.Threading.Thread.Sleep(100);
currentPageOffset = driver.GetPageOffset().Y;
if (prevPageOffset == currentPageOffset)
{
break;
}
var pageMovedBy = currentPageOffset - prevPageOffset;
pageMovedBy = (int)(pageMovedBy * DpiScalingFactor);
using (var ms = new MemoryStream(driver.GetScreenshotOverflowHidden().AsByteArray))
{
Bitmap fullPageScreenshot1 = Image.FromStream(ms) as Bitmap;
using (var viewPortScreenshot = Image.FromStream(ms) as Bitmap)
{
var s = driver.Manage().Window.Size;
var croppedScreenshot = CropBitmapAtRect(viewPortScreenshot, new Rectangle(0, viewPortScreenshot.Height - pageMovedBy, viewPortScreenshot.Width, pageMovedBy));
var newFullPage = AppendBitmap(fullPageScreenshot, croppedScreenshot);
fullPageScreenshot.Dispose();
fullPageScreenshot = newFullPage;
}
}
}
driver.ScrollPageTo(originalPageOffset.X, originalPageOffset.Y);
return fullPageScreenshot;
}
private static Bitmap CropBitmapAtRect(Bitmap b, Rectangle r)
{
Bitmap nb = new Bitmap(r.Width, r.Height);
using (Graphics g = Graphics.FromImage(nb))
{
g.DrawImage(b, -r.X, -r.Y);
return nb;
}
}
private static Bitmap AppendBitmap(Bitmap source, Bitmap target, int spacing = 0)
{
int w = Math.Max(source.Width, target.Width);
int h = source.Height + target.Height + spacing;
Bitmap bmp = new Bitmap(w, h);
using (Graphics g = Graphics.FromImage(bmp))
{
g.DrawImage(source, 0, 0);
g.DrawImage(target, 0, source.Height + spacing);
}
return bmp;
}
private static Screenshot GetScreenshotOverflowHidden(this RemoteWebDriver driver)
{
driver.ExecuteScript(#" document.body.style.overflowY = ""hidden"";");
var s = driver.GetScreenshot();
driver.ExecuteScript(#" document.body.style.overflowY = """";");
return s;
}
private static void ScrollPageBy(this RemoteWebDriver driver, int x = 0, int y = 0)
{
driver.ExecuteScript(#"window.scroll(window.pageXOffset + arguments[0], window.pageYOffset + arguments[1]);", x, y);
}
private static void ScrollPageTo(this RemoteWebDriver driver, int x = 0, int y = 0)
{
driver.ExecuteScript(#"window.scroll(arguments[0], arguments[1]);", x, y);
}
public static void SetViewportSize(this RemoteWebDriver driver, int width, int height)
{
var jsGetPadding = #"return [ window.outerWidth - window.innerWidth,window.outerHeight - window.innerHeight ];";
var paddingArray = driver.ExecuteScript(jsGetPadding) as ReadOnlyCollection<object>;
driver.Manage().Window.Size = new Size(width + int.Parse(paddingArray[0].ToString()), height + int.Parse(paddingArray[1].ToString()));
}
private static Point GetPageOffset(this RemoteWebDriver driver)
{
var offsetArray = driver.ExecuteScript(#"return [window.pageXOffset, window.pageYOffset];") as ReadOnlyCollection<object>;
var x = int.Parse(offsetArray[0].ToString());
var y = int.Parse(offsetArray[1].ToString().Split(',')[0]);
return new Point((int)x, (int)y);
}
private static int GetWindowInnerHeight(this RemoteWebDriver driver)
{
var Value = driver.ExecuteScript(#"return [window.innerHeight];") as ReadOnlyCollection<object>;
return int.Parse(Value[0].ToString());
}
[DllImport("gdi32.dll")]
private static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
public enum DeviceCap
{
VERTRES = 10,
DESKTOPVERTRES = 117,
// http://pinvoke.net/default.aspx/gdi32/GetDeviceCaps.html
// https://stackoverflow.com/questions/5977445/how-to-get-windows-display-settings#answer-21450169
}
private static float GetDpiScalingFactor()
{
Graphics g = Graphics.FromHwnd(IntPtr.Zero);
IntPtr desktop = g.GetHdc();
int LogicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.VERTRES);
int PhysicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.DESKTOPVERTRES);
float ScreenScalingFactor = (float)PhysicalScreenHeight / (float)LogicalScreenHeight;
return ScreenScalingFactor; // 1.25 = 125%
}
}
}

Resources