Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to take Retina Screenshots with Xvfb and Selenium

I want to take some screenshots of my hybrid app for itunes connect automatically. I am running Ubuntu 14.04. chromedriver 2.15.322448

Taking screenshots automatically is easy with Selenium and Xvfb. But it is not easy to get retina screenshots.

I started my Xvfb with a higher dpi:

/usr/bin/Xvfb :99 -screen 0 2000x2000x24 -dpi 200

When I check the display information everything seems to be right:

xdpyinfo -display :99

...
screen #0:
  dimensions:    2000x2000 pixels (254x254 millimeters)
  resolution:    200x200 dots per inch
  depths (6):    24, 1, 4, 8, 16, 32
...

Then I start my chromedriver like this

private WebDriver getChromeDriver ( Phone phone )
{
    Map<String, Object> deviceMetrics = new HashMap<String, Object>();
    deviceMetrics.put("width", 320);
    deviceMetrics.put("height", 460);
    deviceMetrics.put("pixelRatio", 2);
    Map<String, Object> mobileEmulation = new HashMap<String, Object>();
    mobileEmulation.put("deviceMetrics", deviceMetrics);
    mobileEmulation.put("userAgent", "iphone4");

    ChromeDriverService cds = new ChromeDriverService.Builder().withEnvironment(ImmutableMap.of("DISPLAY", ":99")).build();

    Map<String, Object> chromeOptions = new HashMap<String, Object>();
    chromeOptions.put("mobileEmulation", mobileEmulation);
    DesiredCapabilities capabilities = DesiredCapabilities.chrome();
    capabilities.setCapability(ChromeOptions.CAPABILITY, chromeOptions);
    WebDriver driver = new ChromeDriver(cds, capabilities);
    return driver;
}

and after some other boring code, I take the screenshot:

 File srcFile = ( (TakesScreenshot) driver ).getScreenshotAs(OutputType.FILE);

This does not work. The screenshot is in regular dpi. So the image of the website captured is only 320x460 and not 640x960 as it should be.

I set a breakpoint just before the Screenshot was taken and dumped the framebuffer like this:

export DISPLAY=:99 
xwd -root -silent | xwdtopnm |pnmtojpeg > screen.jpg

Result of xwd dumping the content of the virtual framebuffer

As you can see the title bar is rendered in respect to higher dpi but the rest of the browser window does not.

So how can I run a chromedriver with more dpi to take retina screenshots? Is it possible?

like image 988
Janning Avatar asked Jul 14 '15 07:07

Janning


2 Answers

If you just want to take some screenhosts you can use google chrome headless tool. For example getting a retina screenshot is as easy as

$ google-chrome --headless --hide-scrollbars --disable-gpu \
                --screenshot --force-device-scale-factor=2 \
                --window-size=750,1334 https://www.kicktipp.de/
like image 81
Janning Avatar answered Dec 27 '22 07:12

Janning


I'm facing the same problem and still stuck but the following may be useful. It allowed me to rule out either xvfb or chrome by attaching a VNC connection to the xvfb framebuffer.

#!/bin/bash
export GEOMETRY="$SCREEN_WIDTH""x""$SCREEN_HEIGHT""x""$SCREEN_DEPTH"

function shutdown {
  kill -s SIGTERM $NODE_PID
  wait $NODE_PID
}

sudo -E -i -u seluser \
  DISPLAY=$DISPLAY \
  xvfb-run --server-args="$DISPLAY -screen 0 $GEOMETRY -dpi 300 -ac +extension RANDR" \
  java -jar /opt/selenium/selenium-server-standalone.jar &
NODE_PID=$!

trap shutdown SIGTERM SIGINT
for i in $(seq 1 10)
do
  xdpyinfo -display $DISPLAY >/dev/null 2>&1
  if [ $? -eq 0 ]; then
    break
  fi
  echo Waiting xvfb...
  sleep 0.5
done

fluxbox -display $DISPLAY &

x11vnc -forever -usepw -shared -rfbport 5900 -display $DISPLAY &

wait $NODE_PID

After VNC'ing in, google-chrome GUI can be loaded from the terminal. Navigation to web pages confirm that Chrome is rendering the pages with the correct DPI. Screenshot http://i.stack.imgur.com/iEjo0.jpg

I would really like to get this working too so please reach out if you have any new developments. I used https://registry.hub.docker.com/u/selenium/standalone-chrome-debug/ BTW.

like image 33
Dean Chen Avatar answered Dec 27 '22 07:12

Dean Chen