10

To my understanding the ChromeDriver itself doesn't set the background, the CSS does. Therefore if the background is transparent, why am I not getting transparent screenshots?

This is the screenshot of the supposedly transparent website: Transparent background Same screenshot but with a red div in the background to show where the transparency should lie: Red background

Here is my code:

from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from datetime import datetime options = webdriver.ChromeOptions() options.add_argument('headless') driver = webdriver.Chrome(chrome_options=options) driver.set_window_size(2560, 1600) driver.get('https://twitter.com/realDonaldTrump/status/516382177798680576') # driver.execute_script("$('body').append(`<div style='background: red; width: 100%; height: 100%;'></div>`);") driver.save_screenshot('screenshots/' + str(datetime.now()) + '.png') driver.quit() 

How would I be able to create the transparent version of that screenshot?

*** EDIT *** I made a gist of how I accomplished this. The accepted answer helped me get to the point where I could figure it out and that is what I wanted. This gist, however, is the correct solution to my problem: https://gist.github.com/colecrtr/f58834ff09ab07e3c1164667b753e77a

5
  • There that line that you have commented, did you try to change to something like this: driver.execute_script("$('body').css('background-color', 'transparent');")? Beware that all the div layers have to be background-color: transparent in order to have a really transparent background, so you'll have to do some testings and tweaking's with developer tools if it won't work by just changing body background color. Also keep in mind that the page has to have jQuery and I don't think twitter does, but I'm not really sure. Commented Oct 12, 2017 at 14:51
  • @ChristosLytras I tried setting the background-color to transparent and it is still resulting in a white background. And Twitter does use jQuery. How would I go about tweaking the developer tools? Commented Oct 12, 2017 at 15:01
  • Just hit F12 when browsing twitter, go to Elements tab and then check the styles of each DIV child element of the content for background color properties. Commented Oct 12, 2017 at 15:04
  • It's a shame the link to the gist is broken. Commented Jul 14, 2020 at 21:59
  • 1
    @BradRoot I changed my username recently and that broke the link. I’ve updated it to my new username :-) Commented Jul 14, 2020 at 22:01

4 Answers 4

10
+50

One way would be to convert each white pixel to a transparent pixel from the screenshot by setting the alpha byte to 0:

from selenium import webdriver from PIL import Image from io import BytesIO # python 3 import numpy as np def remove_color(img, rgba): data = np.array(img.convert('RGBA')) # rgba array from image pixels = data.view(dtype=np.uint32)[...,0] # pixels as rgba uint32 data[...,3] = np.where(pixels == np.uint32(rgba), np.uint8(0), np.uint8(255)) # set alpha channel return Image.fromarray(data) driver = webdriver.Chrome() driver.get("http://www.bbc.co.uk/news") # take screenshot with a transparent background with Image.open(BytesIO(driver.get_screenshot_as_png())) as img : with remove_color(img, 0xffffffff) as img2: img2.save(r"C:\temp\screenshot.png") 

However you may end up with some unexpected transparent pixels if the page content has some white pixels and the antialiassing will probably be visible.

Another solution is to use the DevTool API with Chrome to exclude the background from the screenshot:

from selenium import webdriver import json def send(cmd, params={}): resource = "/session/%s/chromium/send_command_and_get_result" % driver.session_id url = driver.command_executor._url + resource body = json.dumps({'cmd':cmd, 'params': params}) response = driver.command_executor._request('POST', url, body) if response['status']: raise Exception(response.get('value')) return response.get('value') options = webdriver.ChromeOptions() options.add_argument("disable-gpu") options.add_argument("disable-infobars") driver = webdriver.Chrome(chrome_options=options) driver.get("http://www.bbc.co.uk/news") # take screenshot with a transparent background send("Emulation.setDefaultBackgroundColorOverride", {'color': {'r': 0, 'g': 0, 'b': 0, 'a': 0}}) driver.get_screenshot_as_file(r"C:\temp\screenshot.png") send("Emulation.setDefaultBackgroundColorOverride") # restore 
Sign up to request clarification or add additional context in comments.

3 Comments

Yes, the second solution is the one that worked for me. I figured it out thanks to Tabun’s comment but I will mark this as correct for future findings.
@Cole, I'm the author of the comment leading to this solution.
My mistake, I see that now. Thank you very much!
1

A png can have transparent pixels, but a screenshot cannot. Whenever you render something you mix the rendering looking at transparency levels of layers, but the combine layer will always have a background.

A screenshot is of what has been rendered on screen and it can never be transparent. How do you display a true transparent image on a desktop? You can't because the background of desktop or something else will always have to be there.

So what you are asking has nothing to do with Chrome, ChromeDriver. Any screenshot taking tool cannot take a transparent screenshot, without you telling it what to mask.

Even tools like Photoshop use special way (grey color boxes with small changes) to show transparent background, but if you use a screenshot tool to capture that image the result would be a image with actual pixel and no transparency like below

Transparent image

9 Comments

Great points and I understand this but using a PhantomJS driver will result in a transparent image as long as there is no defined background or the background itself is defined as transparent. Therefore I know it's possible, it's just a matter of how with ChromeDriver as other drivers don't render the page correctly.
Try with chrome headless and see if it changes, because all the ones which actually render on screen will give you a background color. PhantomJS being a in memory renderer doesn't need to have a background container to render on to and loose transparency
A screenshot can have a transparent background. For instance puppeteer provides the option. With Selenium It's possible by removing the background from the PNG or by calling Emulation.setDefaultBackgroundColorOverride with a custom command with Chrome.
@FlorentB., this is using Chrome debugger APIs and not Selenium
The Chrome debugger APIs can be called with Selenium.
|
1

I know that this has already been answered, but using the accepted answer didn't work in my case and I had to make a small adjustment to it. Extending accepted answer's code, it turns out, in my case I had to add background to the body first before it could be replaced:

from selenium import webdriver import json def send(cmd, params={}): resource = "/session/%s/chromium/send_command_and_get_result" % driver.session_id url = driver.command_executor._url + resource body = json.dumps({'cmd':cmd, 'params': params}) response = driver.command_executor._request('POST', url, body) return response.get('value') options = webdriver.ChromeOptions() options.add_argument('headless') options.add_argument('disable-gpu') options.add_argument('disable-infobars') driver = webdriver.Chrome(chrome_options=options) driver.get("http://www.bbc.co.uk/news") # take screenshot with a transparent background driver.execute_script("document.getElementsByTagName('body')[0].style.backgroundColor = 'transparent';") # I had to add this line send("Emulation.setDefaultBackgroundColorOverride", {'color': {'r': 0, 'g': 0, 'b': 0, 'a': 0}}) driver.get_screenshot_as_file(r"screenshot.png") send("Emulation.setDefaultBackgroundColorOverride") # restore 

Hope this could help those who face the same issue

Comments

0

For those attempting to do this in Laravel Dusk or in PHP using Facebook's Web Driver, you have to call the executeCustomCommand function:

$browser->visit($url)->script("document.getElementsByTagName('body')[0].style.backgroundColor = 'transparent'"); $browser->driver->executeCustomCommand('/session/:sessionId/chromium/send_command', 'POST', [ 'cmd' => 'Emulation.setDefaultBackgroundColorOverride', 'params' => ['color' => ['r' => 0, 'g' => 0, 'b' => 0, 'a' => 0]], ]); $browser->screenshot('screenshot.png'); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.