Using Selenium and ChromeDriver, automatically scale the size of the page on print

Question:

I’m writing a script to automatically print a set of web pages in Chrome. If I were to print them manually, I’d choose "Custom" from the Scale drop down and enter 50 into the input field below.

enter image description here

I can’t figure out what arguments to pass in to replicate this setting when I automatically print these pages in bulk using Selenium with ChromeDriver.

appState = { "recentDestinations": [{
                "id": "Save as PDF",
                "origin": "local",
                "account": "",
                "printing.scaling": 'Custom', # <== Does it go here?
             }],
             "selectedDestinationId": "Save as PDF",
             "version": 2,
             "printing.scaling": 'Custom',  # <== Or here?
           }
profile = { 'printing.print_preview_sticky_settings.appState': json.dumps(appState),
            'printing.print_header_footer': False,

            # So many different versions of things I have tried :-(
            'printing.scaling': 'Custom',
            'printing.scaling_type': 'Custom',
            'print_preview.scaling': 'Custom',
            'print_preview.scaling_type': 'Custom',
            'printing.custom_scaling': True,
            'printing.fit_to_page_scaling': 50,
            'printing.page_scaling': True,
          }
chrome_options = webdriver.ChromeOptions()
chrome_options.add_experimental_option('prefs', profile)
br = webdriver.Chrome(options=chrome_options)

All of the different options shown above were guesses after reading through a lot of the Chromium source trying to get a hint.

https://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/pref_names.cc?view=markup
https://chromium.googlesource.com/chromium/src/+/master/printing/print_job_constants.cc
https://chromium.googlesource.com/chromium/src/+/master/printing/print_job_constants.h

I’m out of leads. What can I try next?

Asked By: TAH

||

Answers:

I know it’s not exactly answer to your question but might be solution to your problem.

Have you tried instead of passing preferences, just to zoom out the page content and then print the page?

driver.execute_script("document.body.style.zoom='50%'")
# continue with printing

For me zooming out and printing with Default scale option works like printing page with Scale set to 50

Answered By: puchal

I wound up using Shadow Root to change the scale.
This is what I did.

driver1.switch_to.window(driver1.window_handles[-2])  # THIS IS THE PRINT DIALOG WINDOW - This could be -1 depending on how many windows are opened

endTime = time.time() + 10
while True:
    try:  # PRESS 'More settings' TO EXPAND
        expand = driver1.execute_script(
        "return document.querySelector('print-preview-app').shadowRoot.querySelector('print-preview-sidebar#sidebar').shadowRoot.querySelector('div#container').querySelector('print-preview-more-settings').shadowRoot.querySelector('div').querySelector('cr-expand-button')")
        if expand:
            expand.click()
            break
    except:
        pass
    time.sleep(.3)
    if time.time() > endTime:  # passed the waiting period
        driver1.switch_to.window(driver1.window_handles[0])
        break

try:  # SELECT SCALE METHOD 'CUSTOM'
    scaling = Select(driver1.execute_script(
        "return document.querySelector('print-preview-app').shadowRoot.querySelector('#sidebar').shadowRoot.querySelector('#container').querySelector('#moreSettings').querySelector('print-preview-scaling-settings.settings-section').shadowRoot.querySelector('print-preview-settings-section').querySelector('div').querySelector('select.md-select')"))
    scaling.select_by_value('3')
except:
    driver1.switch_to.window(driver1.window_handles[0])

try:  # ENTER SCALE NUMBER
    time.sleep(.3)
    scaling_number = driver1.execute_script(
        "return document.querySelector('print-preview-app').shadowRoot.querySelector('#sidebar').shadowRoot.querySelector('#container').querySelector('#moreSettings').querySelector('print-preview-scaling-settings').shadowRoot.querySelector('iron-collapse').querySelector('print-preview-number-settings-section').shadowRoot.querySelector('print-preview-settings-section').querySelector('#controls').querySelector('span').querySelector('#userValue').shadowRoot.querySelector('#row-container').querySelector('#input-container').querySelector('div#inner-input-container').querySelector('#input')")
    scaling_number.clear()
    scaling_number.send_keys('50')
except:
    driver1.switch_to.window(driver1.window_handles[0])

driver1.switch_to.window(driver1.window_handles[0])  # back to main window
Answered By: timmyt123

After much searching and trial-and-error, I’ve finally found the solution! The setting lives in the appState dictionary, and is called "scalingType" but it’s an enumeration, which annoyingly only seems to accept a number, which are defined here (Github mirror) or here (googlesource). 3 gives you custom scaling, which you can then define in the "scaling" setting (which is a string!). So my setup now looks like:

chrome_options = webdriver.ChromeOptions()
appState = {"recentDestinations": [{"id": "Save as PDF", "origin": "local", "account": ""}],
            "selectedDestinationId": "Save as PDF",
            "version": 2,
            "isHeaderFooterEnabled": False,
            "isLandscapeEnabled": True,
            "scalingType": 3,
            "scaling": "141"}
prefs = {'printing.print_preview_sticky_settings.appState': json.dumps(appState),
         'savefile.default_directory': BASE_DIR}
chrome_options.add_experimental_option('prefs', prefs)
chrome_options.add_argument('kiosk-printing')

driver = webdriver.Chrome(f'{BASE_DIR}\chromedriver.exe', options=chrome_options)

Current options for scaling type are:

  • 0: default
  • 1: fit to page
  • 2: fit to paper
  • 3: custom

but I haven’t had any success with either of the ‘fit to’ options.

More generally, most of these settings/options can be determined by looking through this file of the chromium source and/or it’s containing folder.

Answered By: askvictor