pyqtgraph/pyqtgraph/exporters/ImageExporter.py

119 lines
4.6 KiB
Python

from .Exporter import Exporter
from ..parametertree import Parameter
from ..Qt import QtCore, QtGui, QtWidgets
from .. import functions as fn
import numpy as np
import sys
translate = QtCore.QCoreApplication.translate
__all__ = ['ImageExporter']
class ImageExporter(Exporter):
Name = "Image File (PNG, TIF, JPG, ...)"
allowCopy = True
def __init__(self, item):
Exporter.__init__(self, item)
tr = self.getTargetRect()
if isinstance(item, QtGui.QGraphicsItem):
scene = item.scene()
else:
scene = item
bgbrush = scene.views()[0].backgroundBrush()
bg = bgbrush.color()
if bgbrush.style() == QtCore.Qt.BrushStyle.NoBrush:
bg.setAlpha(0)
self.params = Parameter(name='params', type='group', children=[
{'name': 'width', 'title': translate("Exporter", 'width'), 'type': 'int', 'value': int(tr.width()),
'limits': (0, None)},
{'name': 'height', 'title': translate("Exporter", 'height'), 'type': 'int', 'value': int(tr.height()),
'limits': (0, None)},
{'name': 'antialias', 'title': translate("Exporter", 'antialias'), 'type': 'bool', 'value': True},
{'name': 'background', 'title': translate("Exporter", 'background'), 'type': 'color', 'value': bg},
{'name': 'invertValue', 'title': translate("Exporter", 'invertValue'), 'type': 'bool', 'value': False}
])
self.params.param('width').sigValueChanged.connect(self.widthChanged)
self.params.param('height').sigValueChanged.connect(self.heightChanged)
def widthChanged(self):
sr = self.getSourceRect()
ar = float(sr.height()) / sr.width()
self.params.param('height').setValue(int(self.params['width'] * ar), blockSignal=self.heightChanged)
def heightChanged(self):
sr = self.getSourceRect()
ar = float(sr.width()) / sr.height()
self.params.param('width').setValue(int(self.params['height'] * ar), blockSignal=self.widthChanged)
def parameters(self):
return self.params
@staticmethod
def getSupportedImageFormats():
filter = ["*."+f.data().decode('utf-8') for f in QtGui.QImageWriter.supportedImageFormats()]
preferred = ['*.png', '*.tif', '*.jpg']
for p in preferred[::-1]:
if p in filter:
filter.remove(p)
filter.insert(0, p)
return filter
def export(self, fileName=None, toBytes=False, copy=False):
if fileName is None and not toBytes and not copy:
filter = self.getSupportedImageFormats()
self.fileSaveDialog(filter=filter)
return
w = int(self.params['width'])
h = int(self.params['height'])
if w == 0 or h == 0:
raise Exception("Cannot export image with size=0 (requested "
"export size is %dx%d)" % (w, h))
targetRect = QtCore.QRect(0, 0, w, h)
sourceRect = self.getSourceRect()
self.png = QtGui.QImage(w, h, QtGui.QImage.Format.Format_ARGB32)
self.png.fill(self.params['background'])
## set resolution of image:
origTargetRect = self.getTargetRect()
resolutionScale = targetRect.width() / origTargetRect.width()
#self.png.setDotsPerMeterX(self.png.dotsPerMeterX() * resolutionScale)
#self.png.setDotsPerMeterY(self.png.dotsPerMeterY() * resolutionScale)
painter = QtGui.QPainter(self.png)
#dtr = painter.deviceTransform()
try:
self.setExportMode(True, {
'antialias': self.params['antialias'],
'background': self.params['background'],
'painter': painter,
'resolutionScale': resolutionScale})
painter.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing, self.params['antialias'])
self.getScene().render(painter, QtCore.QRectF(targetRect), QtCore.QRectF(sourceRect))
finally:
self.setExportMode(False)
painter.end()
if self.params['invertValue']:
bg = fn.ndarray_from_qimage(self.png)
if sys.byteorder == 'little':
cv = slice(0, 3)
else:
cv = slice(1, 4)
mn = bg[...,cv].min(axis=2)
mx = bg[...,cv].max(axis=2)
d = (255 - mx) - mn
bg[...,cv] += d[...,np.newaxis]
if copy:
QtWidgets.QApplication.clipboard().setImage(self.png)
elif toBytes:
return self.png
else:
return self.png.save(fileName)
ImageExporter.register()