Skip to content

Commit

Permalink
Add PDF option
Browse files Browse the repository at this point in the history
  • Loading branch information
tushuhei committed Dec 4, 2024
1 parent 99737b5 commit 23439f7
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 4 deletions.
26 changes: 24 additions & 2 deletions sphinxcontrib/screenshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,21 @@ class ScreenshotDirective(SphinxDirective):
document.querySelector('button').click();
```
Use `figclass` option if you want to specify a class name to the image.
```rst
.. screenshot:: http://www.example.com
:figclass: foo
```
It also generates a PDF file when `pdf` option is given, which might be
useful when you need scalable image assets.
```rst
.. screenshot:: http://www.example.com
:pdf:
```
"""

required_arguments = 1 # URL
Expand All @@ -81,12 +96,13 @@ class ScreenshotDirective(SphinxDirective):
'width': directives.positive_int,
'caption': directives.unchanged,
'figclass': directives.unchanged,
'pdf': directives.flag,
}
pool = ThreadPoolExecutor()

@staticmethod
def take_screenshot(url: str, width: int, height: int, filepath: str,
init_script: str, interactions: str):
init_script: str, interactions: str, generate_pdf: bool):
"""Takes a screenshot with Playwright's Chromium browser.
Args:
Expand All @@ -99,6 +115,7 @@ def take_screenshot(url: str, width: int, height: int, filepath: str,
https://playwright.dev/python/docs/api/class-page#page-add-init-script
interactions (str): JavaScript code to run before taking the screenshot
after the page was loaded.
generate_pdf (bool): Generate a PDF file along with the screenshot.
"""
with sync_playwright() as playwright:
browser = playwright.chromium.launch()
Expand All @@ -119,6 +136,10 @@ def take_screenshot(url: str, width: int, height: int, filepath: str,
raise RuntimeError('Timeout error occured at %s in executing\n%s' %
(url, interactions))
page.screenshot(path=filepath)
if generate_pdf:
page.emulate_media(media='screen')
root, ext = os.path.splitext(filepath)
page.pdf(width=f'{width}px', height=f'{height}px', path=root + '.pdf')
page.close()
browser.close()

Expand All @@ -135,6 +156,7 @@ def run(self) -> typing.List[nodes.Node]:
width = self.options.get('width', 1280)
caption_text = self.options.get('caption', '')
figclass = self.options.get('figclass', '')
pdf = 'pdf' in self.options
interactions = '\n'.join(self.content)

if urlparse(url).scheme not in {'http', 'https'}:
Expand All @@ -150,7 +172,7 @@ def run(self) -> typing.List[nodes.Node]:
if not os.path.exists(filepath):
fut = self.pool.submit(ScreenshotDirective.take_screenshot, url, width,
height, filepath, screenshot_init_script,
interactions)
interactions, pdf)
fut.result()

# Create image and figure nodes
Expand Down
5 changes: 5 additions & 0 deletions tests/test-root/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,8 @@
:width: 480
:height: 320
:figclass: round

.. screenshot:: http://www.example.com
:width: 640
:height: 640
:pdf:
17 changes: 15 additions & 2 deletions tests/test_it.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import os
from io import StringIO

import pytest
Expand All @@ -29,7 +30,7 @@ def test_default(app: SphinxTestApp, status: StringIO,

# Every screenshot directive should become an image.
imgs = soup.find_all('img')
assert len(list(imgs)) == 4
assert len(list(imgs)) == 5

# The image size should be set as specified.
img_obj = Image.open(app.outdir / imgs[0]['src'])
Expand All @@ -54,4 +55,16 @@ def test_default(app: SphinxTestApp, status: StringIO,
assert img_with_caption_a['src'] == img_with_caption_b['src']

# The figure node should have the class name specified.
assert 'round' in soup.find_all('figure')[-1]['class']
assert 'round' in soup.find_all('figure')[3]['class']

# Should generate a PDF file if specified.
img_with_pdf = imgs[4]['src']
root, ext = os.path.splitext(os.path.basename(img_with_pdf))
pdf_filepath = app.outdir / '_static' / 'screenshots' / f'{root}.pdf'
assert os.path.exists(pdf_filepath)

# Should not generate a PDF file if not specified.
img_without_pdf = imgs[2]['src']
root, ext = os.path.splitext(os.path.basename(img_without_pdf))
pdf_filepath = app.outdir / '_static' / 'screenshots' / f'{root}.pdf'
assert not os.path.exists(pdf_filepath)

0 comments on commit 23439f7

Please sign in to comment.