mirror of
https://github.com/aykhans/AzSuicideDataVisualization.git
synced 2025-04-22 10:28:02 +00:00
154 lines
5.3 KiB
Python
154 lines
5.3 KiB
Python
"""Module containing a preprocessor that converts outputs in the notebook from
|
|
one format to another.
|
|
"""
|
|
|
|
# Copyright (c) Jupyter Development Team.
|
|
# Distributed under the terms of the Modified BSD License.
|
|
|
|
import base64
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from shutil import which
|
|
from tempfile import TemporaryDirectory
|
|
|
|
from traitlets import List, Unicode, Union, default
|
|
|
|
from ..utils.io import FormatSafeDict
|
|
from .convertfigures import ConvertFiguresPreprocessor
|
|
|
|
# inkscape path for darwin (macOS)
|
|
INKSCAPE_APP = "/Applications/Inkscape.app/Contents/Resources/bin/inkscape"
|
|
# Recent versions of Inkscape (v1.0) moved the executable from
|
|
# Resources/bin/inkscape to MacOS/inkscape
|
|
INKSCAPE_APP_v1 = "/Applications/Inkscape.app/Contents/MacOS/inkscape"
|
|
|
|
if sys.platform == "win32":
|
|
try:
|
|
import winreg
|
|
except ImportError:
|
|
import _winreg as winreg
|
|
|
|
|
|
class SVG2PDFPreprocessor(ConvertFiguresPreprocessor):
|
|
"""
|
|
Converts all of the outputs in a notebook from SVG to PDF.
|
|
"""
|
|
|
|
@default("from_format")
|
|
def _from_format_default(self):
|
|
return "image/svg+xml"
|
|
|
|
@default("to_format")
|
|
def _to_format_default(self):
|
|
return "application/pdf"
|
|
|
|
inkscape_version = Unicode(
|
|
help="""The version of inkscape being used.
|
|
|
|
This affects how the conversion command is run.
|
|
"""
|
|
).tag(config=True)
|
|
|
|
@default("inkscape_version")
|
|
def _inkscape_version_default(self):
|
|
p = subprocess.Popen(
|
|
[self.inkscape, "--version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
|
|
)
|
|
output, _ = p.communicate()
|
|
if p.returncode != 0:
|
|
raise RuntimeError("Unable to find inkscape executable --version")
|
|
return output.decode("utf-8").split(" ")[1]
|
|
|
|
# FIXME: Deprecate passing a string here
|
|
command = Union(
|
|
[Unicode(), List()],
|
|
help="""
|
|
The command to use for converting SVG to PDF
|
|
|
|
This traitlet is a template, which will be formatted with the keys
|
|
to_filename and from_filename.
|
|
|
|
The conversion call must read the SVG from {from_filename},
|
|
and write a PDF to {to_filename}.
|
|
|
|
It could be a List (recommended) or a String. If string, it will
|
|
be passed to a shell for execution.
|
|
""",
|
|
).tag(config=True)
|
|
|
|
@default("command")
|
|
def _command_default(self):
|
|
major_version = self.inkscape_version.split(".")[0]
|
|
command = [self.inkscape]
|
|
|
|
if int(major_version) < 1:
|
|
# --without-gui is only needed for inkscape 0.x
|
|
command.append("--without-gui")
|
|
# --export-pdf is old name for --export-filename
|
|
command.append("--export-pdf={to_filename}")
|
|
else:
|
|
command.append("--export-filename={to_filename}")
|
|
|
|
command.append("{from_filename}")
|
|
return command
|
|
|
|
inkscape = Unicode(help="The path to Inkscape, if necessary").tag(config=True)
|
|
|
|
@default("inkscape")
|
|
def _inkscape_default(self):
|
|
inkscape_path = which("inkscape")
|
|
if inkscape_path is not None:
|
|
return inkscape_path
|
|
if sys.platform == "darwin":
|
|
if os.path.isfile(INKSCAPE_APP_v1):
|
|
return INKSCAPE_APP_v1
|
|
# Order is important. If INKSCAPE_APP exists, prefer it over
|
|
# the executable in the MacOS directory.
|
|
if os.path.isfile(INKSCAPE_APP):
|
|
return INKSCAPE_APP
|
|
if sys.platform == "win32":
|
|
wr_handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
|
|
try:
|
|
rkey = winreg.OpenKey(wr_handle, "SOFTWARE\\Classes\\inkscape.svg\\DefaultIcon")
|
|
inkscape = winreg.QueryValueEx(rkey, "")[0]
|
|
except FileNotFoundError:
|
|
raise FileNotFoundError("Inkscape executable not found")
|
|
return inkscape
|
|
return "inkscape"
|
|
|
|
def convert_figure(self, data_format, data):
|
|
"""
|
|
Convert a single SVG figure to PDF. Returns converted data.
|
|
"""
|
|
|
|
# Work in a temporary directory
|
|
with TemporaryDirectory() as tmpdir:
|
|
|
|
# Write fig to temp file
|
|
input_filename = os.path.join(tmpdir, "figure.svg")
|
|
# SVG data is unicode text
|
|
with open(input_filename, "w", encoding="utf8") as f:
|
|
f.write(data)
|
|
|
|
# Call conversion application
|
|
output_filename = os.path.join(tmpdir, "figure.pdf")
|
|
|
|
template_vars = {"from_filename": input_filename, "to_filename": output_filename}
|
|
if isinstance(self.command, list):
|
|
full_cmd = [s.format_map(FormatSafeDict(**template_vars)) for s in self.command]
|
|
else:
|
|
# For backwards compatibility with specifying strings
|
|
# Okay-ish, since the string is trusted
|
|
full_cmd = self.command.format(*template_vars)
|
|
subprocess.call(full_cmd, shell=isinstance(full_cmd, str))
|
|
|
|
# Read output from drive
|
|
# return value expects a filename
|
|
if os.path.isfile(output_filename):
|
|
with open(output_filename, "rb") as f:
|
|
# PDF is a nb supported binary, data type, so base64 encode.
|
|
return base64.encodebytes(f.read())
|
|
else:
|
|
raise TypeError("Inkscape svg to pdf conversion failed")
|