Source code for plugin_image_exporter
# Copyright (c) 2016, Combine Control Systems AB
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Combine Control Systems AB nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.
# IN NO EVENT SHALL COMBINE CONTROL SYSTEMS AB BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import (print_function, division, unicode_literals,
absolute_import)
import os.path
from sympathy.api import exporters
from sympathy.api import node as synode
from sympathy.api import qt as qt_compat
QtGui = qt_compat.import_module('QtGui')
def installed_packages():
import pip
try:
return pip.get_installed_distributions()
except AttributeError:
import pkg_resources
return pkg_resources.working_set
PAPERSIZES = [
('Custom', (None, None)),
('A4', (210, 297)),
('A5', (148, 210)),
('A6', (105, 148)),
('Letter', (215.9, 279.4)),
('Legal', (215.9, 355.6)),
('Ledger', (279.4, 431.8)),
('B4', (250, 353)),
('B5', (176, 250)),
('B6', (125, 176)),
]
def create_papersize_labels():
labels = []
for l, (w, h) in PAPERSIZES:
if w is not None or h is not None:
size = '({}mm x {}mm)'.format(w, h)
else:
size = ''
labels.append('{} {}'.format(l, size))
return labels
class TabbedSizeChoiceWidget(QtGui.QWidget):
filename_changed = qt_compat.Signal()
def __init__(self, parameter_root, *args, **kwargs):
super(TabbedSizeChoiceWidget, self).__init__(*args, **kwargs)
self._parameter_root = parameter_root
self._init_gui()
def _init_gui(self):
parameters = self._parameter_root
vlayout = QtGui.QVBoxLayout()
vlayout.setContentsMargins(0, 10, 0, 0)
self._strategy_widget = parameters['selected_strategy'].gui()
self._strategy_widget.setVisible(False)
self._strategy_combobox = self._strategy_widget.editor().combobox()
self._size_tabwidget = QtGui.QTabWidget()
vlayout.addWidget(self._strategy_widget)
vlayout.addWidget(self._size_tabwidget)
# Size by setting pixels
pixels_tab = QtGui.QWidget()
pixels_flayout = QtGui.QFormLayout()
self._width_widget = parameters['width'].gui()
self._height_widget = parameters['height'].gui()
for widget in [self._width_widget, self._height_widget]:
pixels_flayout.addRow(widget.label_widget(), widget.editor())
pixels_tab.setLayout(pixels_flayout)
# Size by setting size in mm and dpi
pagesize_tab = QtGui.QWidget()
pagesize_flayout = QtGui.QFormLayout()
self._size_width_widget = parameters['size_width'].gui()
self._size_height_widget = parameters['size_height'].gui()
self._paper_size_widget = parameters['paper_size'].gui()
self._paper_size_combo = self._paper_size_widget.editor().combobox()
self._p_orient_widget = parameters['paper_orientation'].gui()
self._paper_orient_combo = self._p_orient_widget.editor().combobox()
for widget in [self._size_width_widget, self._size_height_widget,
self._paper_size_widget, self._p_orient_widget]:
pagesize_flayout.addRow(widget.label_widget(), widget.editor())
pagesize_tab.setLayout(pagesize_flayout)
self._size_tabwidget.addTab(pixels_tab, 'Set Pixels')
self._size_tabwidget.addTab(pagesize_tab, 'Set Page Size')
self._dpi_widget = parameters['dpi'].gui()
vlayout.addWidget(self._dpi_widget)
extension_gui = parameters['extension'].gui()
vlayout.addWidget(extension_gui)
extension_gui.editor().combobox().currentIndexChanged[int].connect(
self._filename_changed)
self.setLayout(vlayout)
self._size_tabwidget.setCurrentIndex(
self._strategy_combobox.currentIndex())
self._strategy_combobox.currentIndexChanged[int].connect(
self._strategy_combobox_changed)
self._size_tabwidget.currentChanged[int].connect(self._tab_changed)
self._paper_size_combo.currentIndexChanged[int].connect(
self._paper_size_changed)
self._paper_orient_combo.currentIndexChanged.connect(
self._orientation_changed)
def _strategy_combobox_changed(self, index):
self._size_tabwidget.setCurrentIndex(index)
def _tab_changed(self, index):
self._strategy_combobox.setCurrentIndex(index)
def _orientation_changed(self):
index = self._paper_size_combo.currentIndex()
self._paper_size_changed(index)
def _paper_size_changed(self, index):
label, (size_width, size_height) = PAPERSIZES[index]
if size_width is not None and size_height is not None:
orientation = self._parameter_root['paper_orientation'].selected
if orientation == 'landscape':
size_width, size_height = size_height, size_width
self._size_width_widget.editor().set_value(size_width)
self._size_height_widget.editor().set_value(size_height)
def _filename_changed(self):
self.filename_changed.emit()
[docs]class DataExportFigure(exporters.FigureDataExporterBase):
"""Exporter for Figure files."""
EXPORTER_NAME = "Image"
FILENAME_EXTENSION = None
def __init__(self, parameters):
super(DataExportFigure, self).__init__(parameters)
flat_installed_packages = [package.project_name for package in
installed_packages()]
if 'xelatex' in flat_installed_packages:
plist = ['eps', 'pdf', 'pgf', 'png', 'ps', 'svg', 'svgz']
else:
plist = ['eps', 'pdf', 'png', 'ps', 'svg', 'svgz']
if 'extension' not in self._parameters:
self._parameters.set_list(
'extension',
label='Filename extension:',
description=('The extension to be used for exporting '
'the figures.'),
value=[1],
plist=plist,
editor=synode.Util.combo_editor())
if 'selected_strategy' not in self._parameters:
self._parameters.set_list(
'selected_strategy',
label='Image size strategy',
description=('Choose who to set the size of the saved '
'image(s).'),
plist=['Set Pixels', 'Set Page Size'],
editor=synode.Util.combo_editor())
if 'width' not in self._parameters:
self._parameters.set_integer(
'width',
label='Image width (px):',
description='The image width in pixels.',
value=800,
editor=synode.Util.bounded_spinbox_editor(
100, 1000000000, 1))
if 'height' not in self._parameters:
self._parameters.set_integer(
'height',
label='Image height (px):',
description='The image height in pixels.',
value=600,
editor=synode.Util.bounded_spinbox_editor(
100, 1000000000, 1))
if 'size_width' not in self._parameters:
self._parameters.set_float(
'size_width',
label='Image width (mm):',
description='The image width in millimeter.',
value=297,
editor=synode.Util.bounded_decimal_spinbox_editor(
0., 1000000000, 1, 3))
if 'size_height' not in self._parameters:
self._parameters.set_float(
'size_height',
label='Image height (mm):',
description='The image height in millimeter.',
value=210,
editor=synode.Util.bounded_decimal_spinbox_editor(
0., 1000000000, 1, 3))
if 'paper_size' not in self._parameters:
self._parameters.set_list(
'paper_size',
label='Paper size:',
description='The paper size in millimeter.',
value=[0],
plist=create_papersize_labels(),
editor=synode.Util.combo_editor())
if 'paper_orientation' not in self._parameters:
self._parameters.set_list(
'paper_orientation',
label='Orientation:',
description='The paper orientation (portrait or landscape).',
plist=['portrait', 'landscape'],
editor=synode.Util.combo_editor())
if 'dpi' not in self._parameters:
self._parameters.set_integer(
'dpi',
label='Dots-per-inch',
description='The dots-per-inch of the figure.',
value=120,
editor=synode.Util.bounded_spinbox_editor(
1, 100000, 1))
def create_filenames(self, input_list, filename, *args):
ext = self._parameters['extension'].selected
return super(DataExportFigure, self).create_filenames(
input_list, filename, *args,
ext=ext)
def parameter_view(self, input_list):
return TabbedSizeChoiceWidget(self._parameters)
def export_data(self, figure, fq_outfilename, progress=None):
"""Export Figure to Image."""
strategy = self._parameters['selected_strategy'].selected
dpi = self._parameters['dpi'].value
if strategy == 'Set Pixels':
width = self._parameters['width'].value
height = self._parameters['height'].value
else:
size_width = self._parameters['size_width'].value
size_height = self._parameters['size_height'].value
# convert size in mm to inch and multiply with dpi to get image
# size in pixel
width = int(size_width * 0.039370 * dpi)
height = int(size_height * 0.039370 * dpi)
kwargs = {'dpi': dpi,
'size': (width, height)}
if not os.path.exists(os.path.dirname(fq_outfilename)):
os.makedirs(os.path.dirname(fq_outfilename))
figure.save_figure(fq_outfilename, **kwargs)