Repository: ipython/ipython

Issue:
nbconvert does not process SVGs into PDFs
nbconvert does not manage to take the final step to transform SVGs into PDFs and hence breaks figure inclusion in the final `pdflatex` call to generate PDF files using, for example, the --format="latex" and --format="sphinx_howto"  options.

This is despite the technology being ready and waiting in `IPython/nbconvert/transformers/svg2pdf.py`. (Requires `inkscape` to do the conversion.)

Crucial for 1.0.

By the way, I am on Mac OS but installed `inkscape` with `brew`, so the logic to choose the `Mac OS` version of `inkscape` will fail in my case. It should check if the command line `inkscape` is not already available.



Discussion:
I can confirm this on linux as well. The SVGs get embedded like "ordinary" images without any conversion.
Maybe @jdfreder can bring some light into this issue?

Thanks guys, I'll check this out right now

I've got this just about figured out - the main issue is that SVG2PDF is before extract figures in the transformer list, so it doesn't do anything.

That could be a problem... haha
Also, another possibility is the data priority (in the nbconvert base class).  It may need to be overwriten for the Latex case, svg excluded.
Lastly, the templates themselves may current have 'svg' instead of 'pdf'

That definitely sounds like the culprit!

On Fri, Jul 19, 2013 at 12:11 PM, Min RK notifications@github.com wrote:

> I've got this just about figured out - the main issue is that SVG2PDF is
> before extract figures in the transformer list, so it doesn't do anything.
> 
> —
> Reply to this email directly or view it on GitHubhttps://github.com/ipython/ipython/issues/3693#issuecomment-21263184
> .

## 

Dr. David P. Sanders

Profesor Titular "A" / Associate Professor
Departamento de Física, Facultad de Ciencias
Universidad Nacional Autónoma de México (UNAM)

dpsanders@gmail.com
http://sistemas.fciencias.unam.mx/~dsanders

Cubículo / office: #414, 4o. piso del Depto. de Física

Tel.: +52 55 5622 4965


Resolving patch:
diff --git a/IPython/nbconvert/exporters/latex.py b/IPython/nbconvert/exporters/latex.py
--- a/IPython/nbconvert/exporters/latex.py
+++ b/IPython/nbconvert/exporters/latex.py
@@ -86,7 +86,7 @@ def _init_filters(self):
     def default_config(self):
         c = Config({
             'NbConvertBase': {
-                'display_data_priority' : ['latex', 'png', 'jpg', 'svg', 'jpeg', 'text']
+                'display_data_priority' : ['latex', 'pdf', 'png', 'jpg', 'svg', 'jpeg', 'text']
                 },
              'ExtractFigureTransformer': {
                     'enabled':True
diff --git a/IPython/nbconvert/transformers/convertfigures.py b/IPython/nbconvert/transformers/convertfigures.py
--- a/IPython/nbconvert/transformers/convertfigures.py
+++ b/IPython/nbconvert/transformers/convertfigures.py
@@ -49,31 +49,16 @@ def transform_cell(self, cell, resources, cell_index):
         #Loop through all of the datatypes of the outputs in the cell.
         for index, cell_out in enumerate(cell.get('outputs', [])):
             for data_type, data in cell_out.items():
-
-                #Get the name of the file exported by the extract figure 
-                #transformer.  Do not try to convert the figure if the extract
-                #fig transformer hasn't touched it
-                filename = cell_out.get(data_type + '_filename', None)
-                if filename:
-                    figure_name = filename[:filename.rfind('.')]
-                    self._convert_figure(cell_out, figure_name, resources, data_type, data)
+                # this must run *before* extract figures,
+                # so figure_name and filename do not exist
+                self._convert_figure(cell_out, resources, data_type, data)
         return cell, resources
 
 
-    def _convert_figure(self, cell_out, resources, figure_name, data_type, data):
+    def _convert_figure(self, cell_out, resources, data_type, data):
         """
         Convert a figure and output the results to the cell output
         """
-
-        if not self.to_format in cell_out:
-            if data_type == self.from_format:
-                filename = figure_name + '.' + self.to_format
-                if filename not in resources['figures']:
-
-                    #On the cell, make the figure available via 
-                    #   cell.outputs[i].pdf_filename  ... etc (PDF in example)
-                    cell_out[self.to_format + '_filename'] = filename
-
-                    #In the resources, make the figure available via
-                    #   resources['figures']['filename'] = data
-                    resources['figures'][filename] = self.convert_figure(data_type, data)
+        if not self.to_format in cell_out and data_type == self.from_format:
+            data = self.convert_figure(data_type, data)
+            cell_out[self.to_format] = data
diff --git a/IPython/nbconvert/transformers/svg2pdf.py b/IPython/nbconvert/transformers/svg2pdf.py
--- a/IPython/nbconvert/transformers/svg2pdf.py
+++ b/IPython/nbconvert/transformers/svg2pdf.py
@@ -13,6 +13,7 @@
 # Imports
 #-----------------------------------------------------------------------------
 
+import base64
 import os
 import sys
 import subprocess
@@ -37,16 +38,34 @@
 
 class SVG2PDFTransformer(ConvertFiguresTransformer):
     """
-    Converts all of the outputs in a notebook from one format to another.
+    Converts all of the outputs in a notebook from SVG to PDF.
     """
 
     from_format = Unicode('svg', config=True, help='Format the converter accepts')
     to_format = Unicode('pdf', config=False, help='Format the converter writes')
+    command = Unicode(config=True,
+        help="""The command to use for converting SVG to PDF
+        
+        This string is a template, which will be formatted with the keys
+        to_filename and from_filename.
+        
+        The conversion call must read the SVG from {from_flename},
+        and write a PDF to {to_filename}.
+        """)
+    
+    def _command_default(self):
+        if sys.platform == "darwin":
+            return INKSCAPE_OSX_COMMAND
+        elif sys.platform == "win32":
+            # windows not yet supported
+            return ""
+        else:
+            return INKSCAPE_COMMAND
 
 
     def convert_figure(self, data_format, data):
         """
-        Convert a single Svg figure.  Returns converted data.
+        Convert a single SVG figure to PDF.  Returns converted data.
         """
 
         #Work in a temporary directory
@@ -54,24 +73,20 @@ def convert_figure(self, data_format, data):
             
             #Write fig to temp file
             input_filename = os.path.join(tmpdir, 'figure.' + data_format)
-            with open(input_filename, 'w') as f:
+            with open(input_filename, 'wb') as f:
                 f.write(data)
 
-            #Determine command (different on Mac OSX)
-            command = INKSCAPE_COMMAND 
-            if sys.platform == 'darwin':
-                command = INKSCAPE_OSX_COMMAND
-
             #Call conversion application
             output_filename = os.path.join(tmpdir, 'figure.pdf')
-            shell = command.format(from_filename=input_filename, 
+            shell = self.command.format(from_filename=input_filename, 
                                    to_filename=output_filename)
             subprocess.call(shell, shell=True) #Shell=True okay since input is trusted.
 
             #Read output from drive
+            # return value expects a filename
             if os.path.isfile(output_filename):
                 with open(output_filename, 'rb') as f:
-                    return f.read().encode("base64") #PDF is a nb supported binary
-                                                     #data type, so base64 encode.
+                    # PDF is a nb supported binary, data type, so base64 encode.
+                    return base64.encodestring(f.read())
             else:
                 return TypeError("Inkscape svg to png conversion failed")


Test patch: