diff --git a/orangewidget/io.py b/orangewidget/io.py
index 0b85f3cdf..1cb6f905b 100644
--- a/orangewidget/io.py
+++ b/orangewidget/io.py
@@ -130,8 +130,7 @@ def save_pyqtgraph():
exporter = cls._get_exporter()
scene = object.scene()
if scene is None:
- cls._export(exporter(scene), filename)
- return
+ return cls._export(exporter(scene), filename)
views = scene.views()
if views:
# preserve scene rect and background brush
@@ -141,13 +140,13 @@ def save_pyqtgraph():
view = scene.views()[0]
scene.setSceneRect(view.sceneRect())
scene.setBackgroundBrush(effective_background(scene, view))
- cls._export(exporter(scene), filename)
+ return cls._export(exporter(scene), filename)
finally:
# reset scene rect and background brush
scene.setBackgroundBrush(backgroundbrush)
scene.setSceneRect(scenerect)
else:
- cls._export(exporter(scene), filename)
+ return cls._export(exporter(scene), filename)
def save_scene():
assert isinstance(object, QGraphicsScene)
@@ -155,8 +154,7 @@ def save_scene():
views = object.views()
if not views:
rect = object.itemsBoundingRect()
- _render(rect, ratio, rect.size(), object)
- return
+ return _render(rect, ratio, rect.size(), object)
# Pick the first view. If there's a widget with multiple views that
# cares which one is used, it must set graph_name to view, not scene
@@ -166,11 +164,11 @@ def save_scene():
source_rect = QRect(
int(target_rect.x()), int(target_rect.y()),
int(target_rect.width()), int(target_rect.height()))
- _render(source_rect, ratio, target_rect.size(), view)
+ return _render(source_rect, ratio, target_rect.size(), view)
def save_widget():
assert isinstance(object, QWidget)
- _render(object.rect(), object.devicePixelRatio(), object.size(),
+ return _render(object.rect(), object.devicePixelRatio(), object.size(),
object)
def _render(
@@ -203,13 +201,16 @@ def _render(
# not a core dump
painter.end()
cls._save_buffer(buffer, filename)
+ return dict(width=buffer.size().width(),
+ height=buffer.size().height(),
+ pixel_ratio=pixel_ratio)
if isinstance(object, GraphicsItem):
- save_pyqtgraph()
+ return save_pyqtgraph()
elif isinstance(object, QGraphicsScene):
- save_scene()
+ return save_scene()
elif isinstance(object, QWidget): # this includes QGraphicsView
- save_widget()
+ return save_widget()
else:
raise TypeError(f"{cls.__name__} "
f"cannot imagine {type(object).__name__}")
@@ -218,7 +219,7 @@ def _render(
def write(cls, filename, scene):
if type(scene) == dict:
scene = scene['scene']
- cls.write_image(filename, scene)
+ return cls.write_image(filename, scene)
@classproperty
def img_writers(cls): # type: () -> Mapping[str, Type[ImgFormat]]
@@ -260,7 +261,11 @@ def _setup_painter(cls, painter, object, source_rect, buffer):
@staticmethod
def _save_buffer(buffer, filename):
- buffer.save(filename, "png")
+ image = buffer.toImage()
+ dpm = 2835 * image.devicePixelRatio()
+ image.setDotsPerMeterX(dpm)
+ image.setDotsPerMeterY(dpm)
+ image.save(filename, "png")
@staticmethod
def _get_exporter():
@@ -300,6 +305,9 @@ def export(self, fileName=None, toBytes=False, copy=False):
QtGui.QImage.Format.Format_ARGB32)
self.png.fill(self.params['background'])
self.png.setDevicePixelRatio(self.ratio)
+ dpm = 2835 * self.ratio
+ self.png.setDotsPerMeterX(dpm)
+ self.png.setDotsPerMeterY(dpm)
## set resolution of image:
origTargetRect = self.getTargetRect()
@@ -348,6 +356,9 @@ def export(self, fileName=None, toBytes=False, copy=False):
def _export(exporter, filename):
buffer = exporter.export(toBytes=True)
buffer.save(filename, "png")
+ return dict(width=buffer.size().width(),
+ height=buffer.size().height(),
+ pixel_ratio=buffer.devicePixelRatio())
class ClipboardFormat(PngFormat):
diff --git a/orangewidget/report/report.py b/orangewidget/report/report.py
index 15f8c1bb8..c2d3910c7 100644
--- a/orangewidget/report/report.py
+++ b/orangewidget/report/report.py
@@ -627,13 +627,17 @@ def get_html_img(
byte_array = QByteArray()
filename = QBuffer(byte_array)
filename.open(QIODevice.WriteOnly)
- PngFormat.write(filename, scene)
+ img_data = PngFormat.write(filename, scene)
+
img_encoded = byte_array.toBase64().data().decode("utf-8")
- return ''.format(
- ("" if max_height is None
- else 'style="max-height: {}px"'.format(max_height)),
- img_encoded
- )
+
+ style_opts = []
+ if max_height is not None:
+ style_opts.append(f"max-height: {max_height}px")
+ if img_data is not None and (ratio := img_data.get("pixel_ratio", 1)) != 1:
+ style_opts.append(f"zoom: {1 / ratio:.1f}")
+ style = f' style="{"; ".join(style_opts)}"' if style_opts else ''
+ return f''
def get_icon_html(icon: QIcon, size: QSize) -> str: