Skip to content

Commit

Permalink
Exporting console content to SVG (#2101)
Browse files Browse the repository at this point in the history
* Add skeleton export_svg and save_svg methods to Console

* Exporting SVG

* SVG export - Writing HTML foreign object into naively calculated SVG rect background

* Exporting as foreign object SVG

* Working with drop-shadow

* Update terminal output style to include tab and background/border

* Add more terminal themes, support dim, reverse in SVG output

* Fix some HTML export tests

* Allow for templating of SVG output

* Fix mypy issue involving shadowed variable in SVG export

* Remove unused code from main block in console.py

* Remove unused record=True in __main__.py Console init

* Small tidy ups in console.py SVG export

* Add test for exporting to SVG

* Add tests for export SVG and save SVG

* Update docs with info on SVG exports

* Add support for blink and blink2 to SVG export, use Fira Code webfont fallback

* Update tests for SVG exporting

* Add more information to docs about SVG exporting

* Update SVG exporting tests

* Explain how to use different terminal theme in SVG export docs

* Remove some development testing code

* Remove some more testing code

* Improve docs, fix typo

* Fixing a typo

* Add note to changelog about SVG export functionality

* Use CSS styling instead of inline styles on SVG export

* Fix issues noted in code review, fix reverse style

* Update SVG used in Rich docs
  • Loading branch information
darrenburns committed Mar 29, 2022
1 parent bb8c0d3 commit 9f43ccc
Show file tree
Hide file tree
Showing 8 changed files with 1,391 additions and 17 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/update_benchmark_website.yml
Expand Up @@ -13,7 +13,7 @@ jobs:
python-version: '3.10.2'
- run: 'pip install asv'
- run: 'asv publish'
- uses: pina/github-action-push-to-another-repository@v1.4.1
- uses: cpina/github-action-push-to-another-repository@v1.4.1
name: 'Copy files to Textualize/rich-benchmarks repo'
env:
API_TOKEN_GITHUB: ${{ secrets.PUBLISH_ASV }}
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- SVG export functionality https://github.com/Textualize/rich/pull/2101

### Fixed

- Add missing `end` keyword argument to `Text.from_markup`
Expand Down
817 changes: 817 additions & 0 deletions docs/images/svg_export.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 29 additions & 3 deletions docs/source/console.rst
Expand Up @@ -249,15 +249,41 @@ If Python's builtin :mod:`readline` module is previously loaded, elaborate line
Exporting
---------

The Console class can export anything written to it as either text or html. To enable exporting, first set ``record=True`` on the constructor. This tells Rich to save a copy of any data you ``print()`` or ``log()``. Here's an example::
The Console class can export anything written to it as either text, svg, or html. To enable exporting, first set ``record=True`` on the constructor. This tells Rich to save a copy of any data you ``print()`` or ``log()``. Here's an example::

from rich.console import Console
console = Console(record=True)

After you have written content, you can call :meth:`~rich.console.Console.export_text` or :meth:`~rich.console.Console.export_html` to get the console output as a string. You can also call :meth:`~rich.console.Console.save_text` or :meth:`~rich.console.Console.save_html` to write the contents directly to disk.
After you have written content, you can call :meth:`~rich.console.Console.export_text`, :meth:`~rich.console.Console.export_svg` or :meth:`~rich.console.Console.export_html` to get the console output as a string. You can also call :meth:`~rich.console.Console.save_text`, :meth:`~rich.console.Console.save_svg`, or :meth:`~rich.console.Console.save_html` to write the contents directly to disk.

For examples of the html output generated by Rich Console, see :ref:`appendix-colors`.

Exporting SVGs
^^^^^^^^^^^^^^

When using :meth:`~rich.console.Console.export_svg` or :meth:`~rich.console.Console.save_svg`, the width of the generated SVG will
match the width (in terms of character cells) of your terminal window. The height of the exported SVG will scale automatically to accommodate the console output.

The generated SVG can be viewed inside any web browser, and can be included on a webpage either by directly including the SVG markup
or by referencing the file itself using an ``<img>`` tag. For finer control over the dimensions, you'll have to use an ``<img>`` tag.

The image below shows an example of an SVG exported by Rich.

.. image:: ../images/svg_export.svg

You can customise the theme used during SVG export by importing the desired theme from the :mod:`rich.terminal_theme` module and passing it to
:meth:`~rich.console.Console.export_svg` or :meth:`~rich.console.Console.save_svg` via the ``theme`` parameter::


from rich.console import Console
from rich.terminal_theme import MONOKAI

console = Console(record=True)
console.save_svg("example.svg", theme=MONOKAI)

Alternatively, you can create your own theme by constructing a :class:`rich.terminal_theme.TerminalTheme` instance
yourself and passing that in.

Error console
-------------

Expand Down Expand Up @@ -381,7 +407,7 @@ If Rich detects that it is not writing to a terminal it will strip control codes
Letting Rich auto-detect terminals is useful as it will write plain text when you pipe output to a file or other application.

Interactive mode
~~~~~~~~~~~~~~~~
----------------

Rich will remove animations such as progress bars and status indicators when not writing to a terminal as you probably don't want to write these out to a text file (for example). You can override this behavior by setting the ``force_interactive`` argument on the constructor. Set it to True to enable animations or False to disable them.

Expand Down
8 changes: 6 additions & 2 deletions rich/__main__.py
Expand Up @@ -51,7 +51,6 @@ def make_test_card() -> Table:
pad_edge=False,
)
color_table.add_row(
# "[bold yellow]256[/] colors or [bold green]16.7 million[/] colors [blue](if supported by your terminal)[/].",
(
"✓ [bold green]4-bit color[/]\n"
"✓ [bold blue]8-bit color[/]\n"
Expand Down Expand Up @@ -226,7 +225,12 @@ def iter_last(values: Iterable[T]) -> Iterable[Tuple[bool, T]]:
console.print(test_card)
taken = round((process_time() - start) * 1000.0, 1)

Console().print(test_card)
c = Console(record=True)
c.print(test_card)
# c.save_svg(
# path="/Users/darrenburns/Library/Application Support/JetBrains/PyCharm2021.3/scratches/svg_export.svg",
# title="Rich can export to SVG",
# )

print(f"rendered in {pre_cache_taken}ms (cold cache)")
print(f"rendered in {taken}ms (warm cache)")
Expand Down

0 comments on commit 9f43ccc

Please sign in to comment.