mirror of
https://github.com/rbreu/beeref.git
synced 2026-03-11 08:54:28 +00:00
Add export format SVG
This commit is contained in:
parent
b0775cace4
commit
1eab4712d3
7 changed files with 686 additions and 51 deletions
|
|
@ -8,6 +8,7 @@ Added
|
||||||
settings.
|
settings.
|
||||||
* The opacity of images can be changed (Images -> Change Opacity).
|
* The opacity of images can be changed (Images -> Change Opacity).
|
||||||
* Images can be set to display as grayscale (Images -> Grayscale).
|
* Images can be set to display as grayscale (Images -> Grayscale).
|
||||||
|
* The scene can now also be exported as SVG
|
||||||
|
|
||||||
|
|
||||||
Fixed
|
Fixed
|
||||||
|
|
|
||||||
|
|
@ -13,21 +13,40 @@
|
||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with BeeRef. If not, see <https://www.gnu.org/licenses/>.
|
# along with BeeRef. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import base64
|
||||||
import logging
|
import logging
|
||||||
|
from xml.etree import ElementTree as ET
|
||||||
|
|
||||||
from PyQt6 import QtCore, QtGui
|
from PyQt6 import QtCore, QtGui
|
||||||
|
|
||||||
from .errors import BeeFileIOError
|
from .errors import BeeFileIOError
|
||||||
from beeref import constants
|
from beeref import constants, widgets
|
||||||
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class SceneToPixmapExporter:
|
class ExporterRegistry(dict):
|
||||||
"""For exporting the scene to a single image."""
|
|
||||||
|
|
||||||
MARGIN = 100
|
DEFAULT_TYPE = 'default exporter'
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
key = key.removeprefix('.')
|
||||||
|
exp = self.get(key, super().__getitem__(self.DEFAULT_TYPE))
|
||||||
|
logger.debug(f'Exporter for type {key}: {exp}')
|
||||||
|
return exp
|
||||||
|
|
||||||
|
|
||||||
|
exporter_registry = ExporterRegistry()
|
||||||
|
|
||||||
|
|
||||||
|
def register_exporter(cls):
|
||||||
|
exporter_registry[cls.TYPE] = cls
|
||||||
|
return cls
|
||||||
|
|
||||||
|
|
||||||
|
class ExporterBase:
|
||||||
|
"""For exporting the scene to a single image."""
|
||||||
|
|
||||||
def __init__(self, scene):
|
def __init__(self, scene):
|
||||||
self.scene = scene
|
self.scene = scene
|
||||||
|
|
@ -46,19 +65,40 @@ class SceneToPixmapExporter:
|
||||||
logger.debug(f'Default export margin: {self.margin}')
|
logger.debug(f'Default export margin: {self.margin}')
|
||||||
logger.debug(f'Default export size with margins: {self.default_size}')
|
logger.debug(f'Default export size with margins: {self.default_size}')
|
||||||
|
|
||||||
def render_to_image(self, size):
|
|
||||||
logger.debug(f'Final export size: {size}')
|
@register_exporter
|
||||||
margin = self.margin * size.width() / self.default_size.width()
|
class SceneToPixmapExporter(ExporterBase):
|
||||||
|
|
||||||
|
TYPE = ExporterRegistry.DEFAULT_TYPE
|
||||||
|
|
||||||
|
def get_user_input(self, parent):
|
||||||
|
"""Ask user for final export size."""
|
||||||
|
|
||||||
|
dialog = widgets.SceneToPixmapExporterDialog(
|
||||||
|
parent=parent,
|
||||||
|
default_size=self.default_size,
|
||||||
|
)
|
||||||
|
if dialog.exec():
|
||||||
|
size = dialog.value()
|
||||||
|
logger.debug(f'Got export size {size}')
|
||||||
|
self.size = size
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def render_to_image(self):
|
||||||
|
logger.debug(f'Final export size: {self.size}')
|
||||||
|
margin = self.margin * self.size.width() / self.default_size.width()
|
||||||
logger.debug(f'Final export margin: {margin}')
|
logger.debug(f'Final export margin: {margin}')
|
||||||
|
|
||||||
image = QtGui.QImage(size, QtGui.QImage.Format.Format_RGB32)
|
image = QtGui.QImage(self.size, QtGui.QImage.Format.Format_RGB32)
|
||||||
image.fill(QtGui.QColor(*constants.COLORS['Scene:Canvas']))
|
image.fill(QtGui.QColor(*constants.COLORS['Scene:Canvas']))
|
||||||
painter = QtGui.QPainter(image)
|
painter = QtGui.QPainter(image)
|
||||||
target_rect = QtCore.QRectF(
|
target_rect = QtCore.QRectF(
|
||||||
margin,
|
margin,
|
||||||
margin,
|
margin,
|
||||||
size.width() - 2 * margin,
|
self.size.width() - 2 * margin,
|
||||||
size.height() - 2 * margin)
|
self.size.height() - 2 * margin)
|
||||||
logger.trace(f'Final export target_rect: {target_rect}')
|
logger.trace(f'Final export target_rect: {target_rect}')
|
||||||
self.scene.render(painter,
|
self.scene.render(painter,
|
||||||
source=self.scene.itemsBoundingRect(),
|
source=self.scene.itemsBoundingRect(),
|
||||||
|
|
@ -66,9 +106,155 @@ class SceneToPixmapExporter:
|
||||||
painter.end()
|
painter.end()
|
||||||
return image
|
return image
|
||||||
|
|
||||||
def export(self, filename, size):
|
def export(self, filename, worker=None):
|
||||||
logger.debug(f'Exporting scene to {filename}')
|
logger.debug(f'Exporting scene to {filename}')
|
||||||
image = self.render_to_image(size)
|
if worker:
|
||||||
|
worker.begin_processing.emit(1)
|
||||||
|
|
||||||
|
image = self.render_to_image()
|
||||||
|
|
||||||
|
if worker and worker.canceled:
|
||||||
|
logger.debug('Export canceled')
|
||||||
|
worker.finished.emit(filename, [])
|
||||||
|
return
|
||||||
|
|
||||||
if not image.save(filename, quality=90):
|
if not image.save(filename, quality=90):
|
||||||
raise BeeFileIOError(
|
msg = 'Error writing file'
|
||||||
msg=str('Error writing image'), filename=filename)
|
logger.debug(f'Export failed: {msg}')
|
||||||
|
if worker:
|
||||||
|
worker.finished.emit(filename, [msg])
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
raise BeeFileIOError(msg, filename=filename)
|
||||||
|
|
||||||
|
logger.debug('Export finished')
|
||||||
|
if worker:
|
||||||
|
worker.progress.emit(1)
|
||||||
|
worker.finished.emit(filename, [])
|
||||||
|
|
||||||
|
|
||||||
|
@register_exporter
|
||||||
|
class SceneToSVGExporter(ExporterBase):
|
||||||
|
|
||||||
|
TYPE = 'svg'
|
||||||
|
|
||||||
|
def get_user_input(self, parent):
|
||||||
|
self.size = self.default_size
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _get_textstyles(self, item):
|
||||||
|
fontstylemap = {
|
||||||
|
QtGui.QFont.Style.StyleNormal: 'normal',
|
||||||
|
QtGui.QFont.Style.StyleItalic: 'italic',
|
||||||
|
QtGui.QFont.Style.StyleOblique: 'oblique',
|
||||||
|
}
|
||||||
|
|
||||||
|
font = item.font()
|
||||||
|
fontsize = font.pointSize() * item.scale()
|
||||||
|
families = ', '.join(font.families())
|
||||||
|
fontstyle = fontstylemap[font.style()]
|
||||||
|
|
||||||
|
return ('white-space:pre',
|
||||||
|
f'font-size:{fontsize}pt',
|
||||||
|
f'font-family:{families}',
|
||||||
|
f'font-weight:{font.weight()}',
|
||||||
|
f'font-stretch:{font.stretch()}',
|
||||||
|
f'font-style:{fontstyle}')
|
||||||
|
|
||||||
|
def render_to_svg(self, worker=None):
|
||||||
|
svg = ET.Element(
|
||||||
|
'svg',
|
||||||
|
attrib={'width': str(self.size.width()),
|
||||||
|
'height': str(self.size.height()),
|
||||||
|
'xmlns': 'http://www.w3.org/2000/svg',
|
||||||
|
'xmlns:xlink': 'http://www.w3.org/1999/xlink',
|
||||||
|
})
|
||||||
|
|
||||||
|
rect = self.scene.itemsBoundingRect()
|
||||||
|
offset = rect.topLeft() - QtCore.QPointF(self.margin, self.margin)
|
||||||
|
|
||||||
|
for i, item in enumerate(sorted(self.scene.items(),
|
||||||
|
key=lambda x: x.zValue())):
|
||||||
|
# z order in SVG specified via the order of elements in the tree
|
||||||
|
pos = item.pos() - offset
|
||||||
|
anchor = pos
|
||||||
|
|
||||||
|
if item.TYPE == 'text':
|
||||||
|
styles = self._get_textstyles(item)
|
||||||
|
element = ET.Element(
|
||||||
|
'text',
|
||||||
|
attrib={'style': ';'.join(styles),
|
||||||
|
'dominant-baseline': 'hanging'})
|
||||||
|
element.text = item.toPlainText()
|
||||||
|
if item.TYPE == 'pixmap':
|
||||||
|
width = item.width * item.scale()
|
||||||
|
height = item.height * item.scale()
|
||||||
|
pixmap, imgformat = item.pixmap_to_bytes(
|
||||||
|
apply_grayscale=True,
|
||||||
|
apply_crop=True)
|
||||||
|
pixmap = base64.b64encode(pixmap).decode('ascii')
|
||||||
|
element = ET.Element(
|
||||||
|
'image',
|
||||||
|
attrib={
|
||||||
|
'xlink:href':
|
||||||
|
f'data:image/{imgformat};base64,{pixmap}',
|
||||||
|
'width': str(width),
|
||||||
|
'height': str(height),
|
||||||
|
'image-rendering': ('crisp-edges' if item.scale() > 2
|
||||||
|
else 'optimizeQuality')})
|
||||||
|
pos = pos + item.crop.topLeft()
|
||||||
|
|
||||||
|
transforms = []
|
||||||
|
if item.flip() == -1:
|
||||||
|
# The following is not recognised by Inkscape and not an
|
||||||
|
# official standard:
|
||||||
|
# element.set('transform-origin', f'{anchor.x()} {anchor.y()}')
|
||||||
|
# Thus we need to fix the origin manually
|
||||||
|
transforms.append(f'translate({anchor.x()} {anchor.y()})')
|
||||||
|
transforms.append(f'scale({item.flip()} 1)')
|
||||||
|
transforms.append(f'translate(-{anchor.x()} -{anchor.y()})')
|
||||||
|
transforms.append(
|
||||||
|
f'rotate({item.rotation()} {anchor.x()} {anchor.y()})')
|
||||||
|
|
||||||
|
element.set('transform', ' '.join(transforms))
|
||||||
|
element.set('x', str(pos.x()))
|
||||||
|
element.set('y', str(pos.y()))
|
||||||
|
element.set('opacity', str(item.opacity()))
|
||||||
|
|
||||||
|
svg.append(element)
|
||||||
|
if worker:
|
||||||
|
worker.progress.emit(i)
|
||||||
|
if worker.canceled:
|
||||||
|
return
|
||||||
|
|
||||||
|
return svg
|
||||||
|
|
||||||
|
def export(self, filename, worker=None):
|
||||||
|
logger.debug(f'Exporting scene to {filename}')
|
||||||
|
if worker:
|
||||||
|
worker.begin_processing.emit(len(self.scene.items()))
|
||||||
|
|
||||||
|
svg = self.render_to_svg(worker)
|
||||||
|
|
||||||
|
if worker and worker.canceled:
|
||||||
|
logger.debug('Export canceled')
|
||||||
|
worker.finished.emit(filename, [])
|
||||||
|
return
|
||||||
|
|
||||||
|
tree = ET.ElementTree(svg)
|
||||||
|
ET.indent(tree, space=' ')
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(filename, 'w') as f:
|
||||||
|
tree.write(f, encoding='unicode', xml_declaration=True)
|
||||||
|
except OSError as e:
|
||||||
|
logger.debug(f'Export failed: {e}')
|
||||||
|
if worker:
|
||||||
|
worker.finished.emit(filename, [str(e)])
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
raise BeeFileIOError(msg=str(e), filename=filename) from e
|
||||||
|
|
||||||
|
logger.debug('Export finished')
|
||||||
|
if worker:
|
||||||
|
worker.finished.emit(filename, [])
|
||||||
|
|
|
||||||
|
|
@ -169,12 +169,20 @@ class BeePixmapItem(BeeItemMixin, QtWidgets.QGraphicsPixmapItem):
|
||||||
logger.debug(f'Found format {formt} for {self}')
|
logger.debug(f'Found format {formt} for {self}')
|
||||||
return formt
|
return formt
|
||||||
|
|
||||||
def pixmap_to_bytes(self):
|
def pixmap_to_bytes(self, apply_grayscale=False, apply_crop=False):
|
||||||
"""Convert the pixmap data to PNG bytestring."""
|
"""Convert the pixmap data to PNG bytestring."""
|
||||||
barray = QtCore.QByteArray()
|
barray = QtCore.QByteArray()
|
||||||
buffer = QtCore.QBuffer(barray)
|
buffer = QtCore.QBuffer(barray)
|
||||||
buffer.open(QtCore.QIODevice.OpenModeFlag.WriteOnly)
|
buffer.open(QtCore.QIODevice.OpenModeFlag.WriteOnly)
|
||||||
img = self.pixmap().toImage()
|
if apply_grayscale and self.grayscale:
|
||||||
|
pm = self._grayscale_pixmap
|
||||||
|
else:
|
||||||
|
pm = self.pixmap()
|
||||||
|
|
||||||
|
if apply_crop:
|
||||||
|
pm = pm.copy(self.crop.toRect())
|
||||||
|
|
||||||
|
img = pm.toImage()
|
||||||
imgformat = self.get_imgformat(img)
|
imgformat = self.get_imgformat(img)
|
||||||
img.save(buffer, imgformat.upper(), quality=90)
|
img.save(buffer, imgformat.upper(), quality=90)
|
||||||
return (barray.data(), imgformat)
|
return (barray.data(), imgformat)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ from beeref import commands
|
||||||
from beeref.config import CommandlineArgs, BeeSettings
|
from beeref.config import CommandlineArgs, BeeSettings
|
||||||
from beeref import constants
|
from beeref import constants
|
||||||
from beeref import fileio
|
from beeref import fileio
|
||||||
from beeref.fileio.export import SceneToPixmapExporter
|
from beeref.fileio.export import exporter_registry
|
||||||
from beeref import widgets
|
from beeref import widgets
|
||||||
from beeref.items import BeePixmapItem, BeeTextItem
|
from beeref.items import BeePixmapItem, BeeTextItem
|
||||||
from beeref.main_controls import MainControlsMixin
|
from beeref.main_controls import MainControlsMixin
|
||||||
|
|
@ -416,31 +416,40 @@ class BeeGraphicsView(MainControlsMixin,
|
||||||
parent=self,
|
parent=self,
|
||||||
caption='Export Scene to Image',
|
caption='Export Scene to Image',
|
||||||
directory=directory,
|
directory=directory,
|
||||||
filter=';;'.join(('Image Files (*.png *.jpg *.jpeg)',
|
filter=';;'.join(('Image Files (*.png *.jpg *.jpeg *.svg)',
|
||||||
'PNG (*.png)',
|
'PNG (*.png)',
|
||||||
'JPEG (*.jpg *.jpeg)')))
|
'JPEG (*.jpg *.jpeg)',
|
||||||
|
'SVG (*.svg)')))
|
||||||
|
|
||||||
if filename:
|
if not filename:
|
||||||
name, ext = os.path.splitext(filename)
|
return
|
||||||
if not ext:
|
|
||||||
ext = get_file_extension_from_format(formatstr)
|
name, ext = os.path.splitext(filename)
|
||||||
filename = f'{filename}.{ext}'
|
if not ext:
|
||||||
logger.debug(f'Got export filename {filename}')
|
ext = get_file_extension_from_format(formatstr)
|
||||||
exporter = SceneToPixmapExporter(self.scene)
|
filename = f'{filename}.{ext}'
|
||||||
dialog = widgets.SceneToPixmapExporterDialog(
|
logger.debug(f'Got export filename {filename}')
|
||||||
parent=self,
|
|
||||||
default_size=exporter.default_size,
|
exporter_cls = exporter_registry[ext]
|
||||||
)
|
exporter = exporter_cls(self.scene)
|
||||||
if dialog.exec():
|
if not exporter.get_user_input(self):
|
||||||
size = dialog.value()
|
return
|
||||||
logger.debug(f'Got export size {size}')
|
|
||||||
try:
|
self.worker = fileio.ThreadedIO(exporter.export, filename)
|
||||||
exporter.export(filename, size)
|
self.worker.finished.connect(self.on_export_finished)
|
||||||
except fileio.BeeFileIOError as e:
|
self.progress = widgets.BeeProgressDialog(
|
||||||
QtWidgets.QMessageBox.warning(
|
'Exporting %s' % filename,
|
||||||
self,
|
worker=self.worker,
|
||||||
'Problem exporting scene',
|
parent=self)
|
||||||
str(e))
|
self.worker.start()
|
||||||
|
|
||||||
|
def on_export_finished(self, filename, errors):
|
||||||
|
if errors:
|
||||||
|
err_msg = '</br>'.join(str(errors))
|
||||||
|
QtWidgets.QMessageBox.warning(
|
||||||
|
self,
|
||||||
|
'Problem writing file',
|
||||||
|
f'<p>Problem writing file {filename}</p><p>{err_msg}</p>')
|
||||||
|
|
||||||
def on_action_quit(self):
|
def on_action_quit(self):
|
||||||
logger.info('User quit. Exiting...')
|
logger.info('User quit. Exiting...')
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,45 @@
|
||||||
import os
|
import os
|
||||||
import stat
|
import stat
|
||||||
from unittest.mock import patch, ANY
|
from unittest.mock import patch, ANY, MagicMock
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from PyQt6 import QtGui, QtCore
|
from PyQt6 import QtGui, QtCore
|
||||||
|
|
||||||
from beeref import constants
|
from beeref import constants
|
||||||
from beeref.items import BeePixmapItem
|
from beeref.items import BeePixmapItem, BeeTextItem
|
||||||
from beeref.fileio.errors import BeeFileIOError
|
from beeref.fileio.errors import BeeFileIOError
|
||||||
from beeref.fileio.export import SceneToPixmapExporter
|
from beeref.fileio.export import (
|
||||||
|
exporter_registry,
|
||||||
|
SceneToPixmapExporter,
|
||||||
|
SceneToSVGExporter,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize('key,expected',
|
||||||
|
[('png', SceneToPixmapExporter),
|
||||||
|
('jpg', SceneToPixmapExporter),
|
||||||
|
('svg', SceneToSVGExporter)])
|
||||||
|
def test_registry(key, expected):
|
||||||
|
exporter_registry[key] == expected
|
||||||
|
|
||||||
|
|
||||||
|
@patch('beeref.widgets.SceneToPixmapExporterDialog.exec', return_value=True)
|
||||||
|
@patch('beeref.widgets.SceneToPixmapExporterDialog.value',
|
||||||
|
return_value=QtCore.QSize(100, 200))
|
||||||
|
def test_scene_to_pixmap_exporter_get_user_input(value_mock, exec_mock, view):
|
||||||
|
exporter = SceneToPixmapExporter(view.scene)
|
||||||
|
value = exporter.get_user_input(None)
|
||||||
|
assert value is True
|
||||||
|
assert exporter.size == QtCore.QSize(100, 200)
|
||||||
|
|
||||||
|
|
||||||
|
@patch('beeref.widgets.SceneToPixmapExporterDialog.exec', return_value=False)
|
||||||
|
@patch('beeref.widgets.SceneToPixmapExporterDialog.value')
|
||||||
|
def test_scene_to_pixmap_exporter_get_user_input_when_canceled(
|
||||||
|
value_mock, exec_mock, view):
|
||||||
|
exporter = SceneToPixmapExporter(view.scene)
|
||||||
|
value = exporter.get_user_input(None)
|
||||||
|
assert value is False
|
||||||
|
|
||||||
|
|
||||||
def test_scene_to_pixmap_exporter_default_size_and_margin(view):
|
def test_scene_to_pixmap_exporter_default_size_and_margin(view):
|
||||||
|
|
@ -54,7 +85,9 @@ def test_scene_to_pixmap_exporter_render_sets_margins(render_mock, view):
|
||||||
exporter = SceneToPixmapExporter(view.scene)
|
exporter = SceneToPixmapExporter(view.scene)
|
||||||
assert exporter.margin == 36
|
assert exporter.margin == 36
|
||||||
assert exporter.default_size == QtCore.QSize(1072, 1272)
|
assert exporter.default_size == QtCore.QSize(1072, 1272)
|
||||||
exporter.render_to_image(QtCore.QSize(536, 636))
|
|
||||||
|
exporter.size = QtCore.QSize(536, 636)
|
||||||
|
exporter.render_to_image()
|
||||||
|
|
||||||
render_mock.assert_called_once_with(
|
render_mock.assert_called_once_with(
|
||||||
ANY,
|
ANY,
|
||||||
|
|
@ -70,24 +103,61 @@ def test_scene_to_pixmap_exporter_render_renders_scene(view):
|
||||||
exporter = SceneToPixmapExporter(view.scene)
|
exporter = SceneToPixmapExporter(view.scene)
|
||||||
assert exporter.margin == 36
|
assert exporter.margin == 36
|
||||||
assert exporter.default_size == QtCore.QSize(1072, 1272)
|
assert exporter.default_size == QtCore.QSize(1072, 1272)
|
||||||
image = exporter.render_to_image(QtCore.QSize(536, 636))
|
|
||||||
|
exporter.size = QtCore.QSize(536, 636)
|
||||||
|
image = exporter.render_to_image()
|
||||||
assert image.pixel(1, 1) == QtGui.QColor(*constants.COLORS['Scene:Canvas'])
|
assert image.pixel(1, 1) == QtGui.QColor(*constants.COLORS['Scene:Canvas'])
|
||||||
assert image.pixel(100, 100) == QtGui.QColor(11, 22, 33)
|
assert image.pixel(100, 100) == QtGui.QColor(11, 22, 33)
|
||||||
|
|
||||||
|
|
||||||
def test_scene_to_pixmap_export_writes_image(view, tmpdir):
|
def test_scene_to_pixmap_exporter_export_writes_image(view, tmpdir):
|
||||||
filename = os.path.join(tmpdir, 'foo.png')
|
filename = os.path.join(tmpdir, 'foo.png')
|
||||||
item_img = QtGui.QImage(1000, 1200, QtGui.QImage.Format.Format_RGB32)
|
item_img = QtGui.QImage(1000, 1200, QtGui.QImage.Format.Format_RGB32)
|
||||||
item = BeePixmapItem(item_img)
|
item = BeePixmapItem(item_img)
|
||||||
view.scene.addItem(item)
|
view.scene.addItem(item)
|
||||||
exporter = SceneToPixmapExporter(view.scene)
|
exporter = SceneToPixmapExporter(view.scene)
|
||||||
exporter.export(filename, QtCore.QSize(100, 120))
|
exporter.size = QtCore.QSize(100, 120)
|
||||||
|
exporter.export(filename)
|
||||||
|
|
||||||
with open(filename, 'rb') as f:
|
with open(filename, 'rb') as f:
|
||||||
assert f.read().startswith(b'\x89PNG')
|
assert f.read().startswith(b'\x89PNG')
|
||||||
|
|
||||||
|
|
||||||
def test_scene_to_pixmap_export_when_file_not_writeable(view, tmpdir):
|
def test_scene_to_pixmap_exporter_export_with_worker(view, tmpdir):
|
||||||
|
filename = os.path.join(tmpdir, 'foo.png')
|
||||||
|
item_img = QtGui.QImage(1000, 1200, QtGui.QImage.Format.Format_RGB32)
|
||||||
|
item = BeePixmapItem(item_img)
|
||||||
|
view.scene.addItem(item)
|
||||||
|
exporter = SceneToPixmapExporter(view.scene)
|
||||||
|
exporter.size = QtCore.QSize(100, 120)
|
||||||
|
worker = MagicMock(canceled=False)
|
||||||
|
exporter.export(filename, worker)
|
||||||
|
|
||||||
|
worker.begin_processing.emit.assert_called_once_with(1)
|
||||||
|
worker.progress.emit.assert_called_once_with(1)
|
||||||
|
worker.finished.emit.assert_called_once_with(filename, [])
|
||||||
|
with open(filename, 'rb') as f:
|
||||||
|
assert f.read().startswith(b'\x89PNG')
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_to_pixmap_exporter_export_with_worker_when_canceled(
|
||||||
|
view, tmpdir):
|
||||||
|
filename = os.path.join(tmpdir, 'foo.png')
|
||||||
|
item_img = QtGui.QImage(1000, 1200, QtGui.QImage.Format.Format_RGB32)
|
||||||
|
item = BeePixmapItem(item_img)
|
||||||
|
view.scene.addItem(item)
|
||||||
|
exporter = SceneToPixmapExporter(view.scene)
|
||||||
|
exporter.size = QtCore.QSize(100, 120)
|
||||||
|
worker = MagicMock(canceled=True)
|
||||||
|
exporter.export(filename, worker)
|
||||||
|
|
||||||
|
worker.begin_processing.emit.assert_called_once_with(1)
|
||||||
|
worker.progress.emit.assert_not_called()
|
||||||
|
worker.finished.emit.assert_called_once_with(filename, [])
|
||||||
|
os.path.exists(filename) is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_to_pixmap_exporter_export_when_file_not_writeable(view, tmpdir):
|
||||||
filename = os.path.join(tmpdir, 'foo.png')
|
filename = os.path.join(tmpdir, 'foo.png')
|
||||||
with open(filename, 'w') as f:
|
with open(filename, 'w') as f:
|
||||||
f.write('foo')
|
f.write('foo')
|
||||||
|
|
@ -96,7 +166,301 @@ def test_scene_to_pixmap_export_when_file_not_writeable(view, tmpdir):
|
||||||
item = BeePixmapItem(item_img)
|
item = BeePixmapItem(item_img)
|
||||||
view.scene.addItem(item)
|
view.scene.addItem(item)
|
||||||
exporter = SceneToPixmapExporter(view.scene)
|
exporter = SceneToPixmapExporter(view.scene)
|
||||||
|
exporter.size = QtCore.QSize(100, 120)
|
||||||
|
|
||||||
with pytest.raises(BeeFileIOError) as e:
|
with pytest.raises(BeeFileIOError) as e:
|
||||||
exporter.export(filename, QtCore.QSize(100, 120))
|
exporter.export(filename)
|
||||||
assert e.filename == filename
|
assert e.filename == filename
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_to_pixmap_exporter_export_when_file_not_writeable_with_worker(
|
||||||
|
view, tmpdir):
|
||||||
|
filename = os.path.join(tmpdir, 'foo.png')
|
||||||
|
with open(filename, 'w') as f:
|
||||||
|
f.write('foo')
|
||||||
|
os.chmod(filename, stat.S_IREAD)
|
||||||
|
item_img = QtGui.QImage(1000, 1200, QtGui.QImage.Format.Format_RGB32)
|
||||||
|
item = BeePixmapItem(item_img)
|
||||||
|
view.scene.addItem(item)
|
||||||
|
exporter = SceneToPixmapExporter(view.scene)
|
||||||
|
exporter.size = QtCore.QSize(100, 120)
|
||||||
|
worker = MagicMock(canceled=False)
|
||||||
|
|
||||||
|
exporter.export(filename, worker=worker)
|
||||||
|
worker.begin_processing.emit.assert_called_once_with(1)
|
||||||
|
worker.progress.emit.assert_not_called()
|
||||||
|
worker.finished.emit.assert_called_once_with(
|
||||||
|
filename, ['Error writing file'])
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_to_svg_exporter_get_user_input(view):
|
||||||
|
item1 = BeePixmapItem(
|
||||||
|
QtGui.QImage(100, 100, QtGui.QImage.Format.Format_RGB32))
|
||||||
|
item1.setPos(QtCore.QPointF(0, 0))
|
||||||
|
view.scene.addItem(item1)
|
||||||
|
|
||||||
|
item2 = BeePixmapItem(
|
||||||
|
QtGui.QImage(100, 100, QtGui.QImage.Format.Format_RGB32))
|
||||||
|
item1.setPos(QtCore.QPointF(200, 0))
|
||||||
|
view.scene.addItem(item2)
|
||||||
|
|
||||||
|
assert view.scene.sceneRect().size().toSize() == QtCore.QSize(300, 100)
|
||||||
|
exporter = SceneToSVGExporter(view.scene)
|
||||||
|
value = exporter.get_user_input(None)
|
||||||
|
assert value is True
|
||||||
|
assert exporter.size == QtCore.QSize(318, 118)
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_to_svg_exporter_render_pixmap_items(view):
|
||||||
|
item1 = BeePixmapItem(
|
||||||
|
QtGui.QImage(100, 110, QtGui.QImage.Format.Format_RGB32))
|
||||||
|
item1.setPos(QtCore.QPointF(20, 30))
|
||||||
|
view.scene.addItem(item1)
|
||||||
|
|
||||||
|
item2 = BeePixmapItem(
|
||||||
|
QtGui.QImage(70, 77, QtGui.QImage.Format.Format_RGB32))
|
||||||
|
item2.setPos(QtCore.QPointF(50, 50))
|
||||||
|
item2.setZValue(-1)
|
||||||
|
view.scene.addItem(item2)
|
||||||
|
|
||||||
|
exporter = SceneToSVGExporter(view.scene)
|
||||||
|
exporter.size = QtCore.QSize(200, 400)
|
||||||
|
exporter.margin = 5
|
||||||
|
svg = exporter.render_to_svg()
|
||||||
|
|
||||||
|
assert svg.tag == 'svg'
|
||||||
|
assert svg.get('width') == '200'
|
||||||
|
assert svg.get('height') == '400'
|
||||||
|
assert svg.get('xmlns') == 'http://www.w3.org/2000/svg'
|
||||||
|
assert svg.get('xmlns:xlink') == 'http://www.w3.org/1999/xlink'
|
||||||
|
assert len(svg) == 2
|
||||||
|
|
||||||
|
element = svg[0] # item2
|
||||||
|
assert element.tag == 'image'
|
||||||
|
assert element.get('xlink:href').startswith('data:image/png;base64,iVBOR')
|
||||||
|
assert element.get('width') == '70.0'
|
||||||
|
assert element.get('height') == '77.0'
|
||||||
|
assert element.get('image-rendering') == 'optimizeQuality'
|
||||||
|
assert element.get('transform') == 'rotate(0.0 35.0 25.0)'
|
||||||
|
assert element.get('x') == '35.0'
|
||||||
|
assert element.get('y') == '25.0'
|
||||||
|
assert element.get('opacity') == '1.0'
|
||||||
|
|
||||||
|
element = svg[1] # item1
|
||||||
|
assert element.tag == 'image'
|
||||||
|
assert element.get('width') == '100.0'
|
||||||
|
assert element.get('height') == '110.0'
|
||||||
|
assert element.get('image-rendering') == 'optimizeQuality'
|
||||||
|
assert element.get('transform') == 'rotate(0.0 5.0 5.0)'
|
||||||
|
assert element.get('x') == '5.0'
|
||||||
|
assert element.get('y') == '5.0'
|
||||||
|
assert element.get('opacity') == '1.0'
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_to_svg_exporter_render_pixmap_with_crop(view):
|
||||||
|
item = BeePixmapItem(
|
||||||
|
QtGui.QImage(100, 110, QtGui.QImage.Format.Format_RGB32))
|
||||||
|
item.setPos(QtCore.QPointF(20, 30))
|
||||||
|
item.crop = QtCore.QRectF(20, 25, 30, 33)
|
||||||
|
view.scene.addItem(item)
|
||||||
|
exporter = SceneToSVGExporter(view.scene)
|
||||||
|
exporter.size = QtCore.QSize(200, 400)
|
||||||
|
exporter.margin = 5
|
||||||
|
svg = exporter.render_to_svg()
|
||||||
|
|
||||||
|
assert len(svg) == 1
|
||||||
|
|
||||||
|
element = svg[0]
|
||||||
|
assert element.tag == 'image'
|
||||||
|
assert element.get('width') == '30.0'
|
||||||
|
assert element.get('height') == '33.0'
|
||||||
|
assert element.get('transform') == 'rotate(0.0 -15.0 -20.0)'
|
||||||
|
assert element.get('x') == '5.0'
|
||||||
|
assert element.get('y') == '5.0'
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_to_svg_exporter_render_pixmap_with_rotation(view):
|
||||||
|
item = BeePixmapItem(
|
||||||
|
QtGui.QImage(100, 110, QtGui.QImage.Format.Format_RGB32))
|
||||||
|
item.setPos(QtCore.QPointF(20, 30))
|
||||||
|
item.setRotation(90)
|
||||||
|
view.scene.addItem(item)
|
||||||
|
exporter = SceneToSVGExporter(view.scene)
|
||||||
|
exporter.size = QtCore.QSize(200, 400)
|
||||||
|
exporter.margin = 5
|
||||||
|
svg = exporter.render_to_svg()
|
||||||
|
|
||||||
|
assert len(svg) == 1
|
||||||
|
|
||||||
|
element = svg[0]
|
||||||
|
assert element.tag == 'image'
|
||||||
|
assert element.get('transform') == 'rotate(90.0 115.0 5.0)'
|
||||||
|
assert element.get('x') == '115.0'
|
||||||
|
assert element.get('y') == '5.0'
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_to_svg_exporter_render_pixmap_with_opacity(view):
|
||||||
|
item = BeePixmapItem(
|
||||||
|
QtGui.QImage(100, 110, QtGui.QImage.Format.Format_RGB32))
|
||||||
|
item.setPos(QtCore.QPointF(20, 30))
|
||||||
|
item.setOpacity(0.75)
|
||||||
|
view.scene.addItem(item)
|
||||||
|
exporter = SceneToSVGExporter(view.scene)
|
||||||
|
exporter.size = QtCore.QSize(200, 400)
|
||||||
|
exporter.margin = 5
|
||||||
|
svg = exporter.render_to_svg()
|
||||||
|
|
||||||
|
assert len(svg) == 1
|
||||||
|
|
||||||
|
element = svg[0]
|
||||||
|
assert element.tag == 'image'
|
||||||
|
assert element.get('opacity') == '0.75'
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_to_svg_exporter_render_pixmap_with_flip(view):
|
||||||
|
item = BeePixmapItem(
|
||||||
|
QtGui.QImage(100, 110, QtGui.QImage.Format.Format_RGB32))
|
||||||
|
item.setPos(QtCore.QPointF(20, 30))
|
||||||
|
item.do_flip()
|
||||||
|
view.scene.addItem(item)
|
||||||
|
exporter = SceneToSVGExporter(view.scene)
|
||||||
|
exporter.size = QtCore.QSize(200, 400)
|
||||||
|
exporter.margin = 5
|
||||||
|
svg = exporter.render_to_svg()
|
||||||
|
|
||||||
|
assert len(svg) == 1
|
||||||
|
|
||||||
|
element = svg[0]
|
||||||
|
assert element.tag == 'image'
|
||||||
|
assert element.get('transform') == (
|
||||||
|
'translate(105.0 5.0) scale(-1.0 1)'
|
||||||
|
' translate(-105.0 -5.0) rotate(0.0 105.0 5.0)')
|
||||||
|
assert element.get('x') == '105.0'
|
||||||
|
assert element.get('y') == '5.0'
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_to_svg_exporter_render_text(view):
|
||||||
|
item = BeeTextItem('foo')
|
||||||
|
item.setPos(QtCore.QPointF(20, 30))
|
||||||
|
view.scene.addItem(item)
|
||||||
|
exporter = SceneToSVGExporter(view.scene)
|
||||||
|
exporter.size = QtCore.QSize(200, 400)
|
||||||
|
exporter.margin = 5
|
||||||
|
svg = exporter.render_to_svg()
|
||||||
|
|
||||||
|
assert len(svg) == 1
|
||||||
|
|
||||||
|
element = svg[0]
|
||||||
|
assert element.tag == 'text'
|
||||||
|
assert element.text == 'foo'
|
||||||
|
assert element.get('dominant-baseline') == 'hanging'
|
||||||
|
assert 'font-family' in element.get('style')
|
||||||
|
assert element.get('transform') == 'rotate(0.0 5.0 5.0)'
|
||||||
|
assert element.get('x') == '5.0'
|
||||||
|
assert element.get('y') == '5.0'
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_to_svg_exporter_export_when_file_not_writeable(view, tmpdir):
|
||||||
|
filename = os.path.join(tmpdir, 'foo.svg')
|
||||||
|
with open(filename, 'w') as f:
|
||||||
|
f.write('foo')
|
||||||
|
os.chmod(filename, stat.S_IREAD)
|
||||||
|
item = BeeTextItem('foo')
|
||||||
|
view.scene.addItem(item)
|
||||||
|
exporter = SceneToSVGExporter(view.scene)
|
||||||
|
exporter.size = QtCore.QSize(100, 120)
|
||||||
|
|
||||||
|
with pytest.raises(BeeFileIOError) as e:
|
||||||
|
exporter.export(filename)
|
||||||
|
assert e.filename == filename
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_to_svg_exporter_render_with_worker(view):
|
||||||
|
item = BeeTextItem('foo')
|
||||||
|
item.setPos(QtCore.QPointF(20, 30))
|
||||||
|
view.scene.addItem(item)
|
||||||
|
exporter = SceneToSVGExporter(view.scene)
|
||||||
|
exporter.size = QtCore.QSize(200, 400)
|
||||||
|
exporter.margin = 5
|
||||||
|
|
||||||
|
worker = MagicMock(canceled=False)
|
||||||
|
svg = exporter.render_to_svg(worker=worker)
|
||||||
|
assert len(svg) == 1
|
||||||
|
worker.progress.emit.assert_called_once_with(0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_to_svg_exporter_render_with_worker_canceled(view):
|
||||||
|
item = BeeTextItem('foo')
|
||||||
|
item.setPos(QtCore.QPointF(20, 30))
|
||||||
|
view.scene.addItem(item)
|
||||||
|
exporter = SceneToSVGExporter(view.scene)
|
||||||
|
exporter.size = QtCore.QSize(200, 400)
|
||||||
|
exporter.margin = 5
|
||||||
|
|
||||||
|
worker = MagicMock(canceled=True)
|
||||||
|
svg = exporter.render_to_svg(worker=worker)
|
||||||
|
assert svg is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_to_svg_exporter_export_writes_svg(view, tmpdir):
|
||||||
|
filename = os.path.join(tmpdir, 'foo.svg')
|
||||||
|
item = BeeTextItem('foo')
|
||||||
|
view.scene.addItem(item)
|
||||||
|
exporter = SceneToSVGExporter(view.scene)
|
||||||
|
exporter.size = QtCore.QSize(100, 120)
|
||||||
|
exporter.export(filename)
|
||||||
|
|
||||||
|
with open(filename, 'rb') as f:
|
||||||
|
assert f.read().startswith(b'<?xml')
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_to_svg_exporter_export_with_worker(view, tmpdir):
|
||||||
|
filename = os.path.join(tmpdir, 'foo.svg')
|
||||||
|
item = BeeTextItem('foo')
|
||||||
|
view.scene.addItem(item)
|
||||||
|
exporter = SceneToSVGExporter(view.scene)
|
||||||
|
exporter.size = QtCore.QSize(100, 120)
|
||||||
|
worker = MagicMock(canceled=False)
|
||||||
|
exporter.export(filename, worker)
|
||||||
|
|
||||||
|
worker.begin_processing.emit.assert_called_once_with(1)
|
||||||
|
worker.progress.emit.assert_called_once_with(0)
|
||||||
|
worker.finished.emit.assert_called_once_with(filename, [])
|
||||||
|
with open(filename, 'rb') as f:
|
||||||
|
assert f.read().startswith(b'<?xml')
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_to_svg_exporter_export_with_worker_canceled(view, tmpdir):
|
||||||
|
filename = os.path.join(tmpdir, 'foo.svg')
|
||||||
|
item = BeeTextItem('foo')
|
||||||
|
view.scene.addItem(item)
|
||||||
|
exporter = SceneToSVGExporter(view.scene)
|
||||||
|
exporter.size = QtCore.QSize(100, 120)
|
||||||
|
worker = MagicMock(canceled=True)
|
||||||
|
exporter.export(filename, worker)
|
||||||
|
|
||||||
|
worker.begin_processing.emit.assert_called_once_with(1)
|
||||||
|
worker.progress.emit.assert_called_once_with(0)
|
||||||
|
worker.finished.emit.assert_called_once_with(filename, [])
|
||||||
|
os.path.exists(filename) is False
|
||||||
|
|
||||||
|
|
||||||
|
def test_scene_to_svg_exporter_export_when_file_not_writeable_with_worker(
|
||||||
|
view, tmpdir):
|
||||||
|
filename = os.path.join(tmpdir, 'foo.svg')
|
||||||
|
with open(filename, 'w') as f:
|
||||||
|
f.write('foo')
|
||||||
|
os.chmod(filename, stat.S_IREAD)
|
||||||
|
item = BeeTextItem('foo')
|
||||||
|
view.scene.addItem(item)
|
||||||
|
exporter = SceneToSVGExporter(view.scene)
|
||||||
|
exporter.size = QtCore.QSize(100, 120)
|
||||||
|
worker = MagicMock(canceled=False)
|
||||||
|
|
||||||
|
exporter.export(filename, worker=worker)
|
||||||
|
worker.begin_processing.emit.assert_called_once_with(1)
|
||||||
|
worker.progress.emit.assert_called_once_with(0)
|
||||||
|
worker.finished.emit.assert_called_once()
|
||||||
|
args = worker.finished.emit.call_args.args
|
||||||
|
assert args[0] == filename
|
||||||
|
assert len(args[1]) == 1
|
||||||
|
|
|
||||||
|
|
@ -164,17 +164,73 @@ def test_get_imgformat_png_when_setting_png(
|
||||||
|
|
||||||
def test_pixmap_to_bytes_png(qapp, imgfilename3x3):
|
def test_pixmap_to_bytes_png(qapp, imgfilename3x3):
|
||||||
item = BeePixmapItem(QtGui.QImage(imgfilename3x3))
|
item = BeePixmapItem(QtGui.QImage(imgfilename3x3))
|
||||||
|
item.crop = QtCore.QRectF(0, 0, 2, 2)
|
||||||
|
item.grayscale = True
|
||||||
data, imgformat = item.pixmap_to_bytes()
|
data, imgformat = item.pixmap_to_bytes()
|
||||||
assert imgformat == 'png'
|
assert imgformat == 'png'
|
||||||
assert data.startswith(b'\x89PNG')
|
assert data.startswith(b'\x89PNG')
|
||||||
|
pixmap = QtGui.QPixmap()
|
||||||
|
pixmap.loadFromData(data)
|
||||||
|
img = pixmap.toImage()
|
||||||
|
assert img.allGray() is False
|
||||||
|
assert img.size() == QtCore.QSize(3, 3)
|
||||||
|
|
||||||
|
|
||||||
def test_pixmap_to_bytes_jpg(qapp, imgfilename3x3, settings):
|
def test_pixmap_to_bytes_jpg(qapp, imgfilename3x3, settings):
|
||||||
settings.setValue('Items/image_storage_format', 'jpg')
|
settings.setValue('Items/image_storage_format', 'jpg')
|
||||||
item = BeePixmapItem(QtGui.QImage(imgfilename3x3))
|
item = BeePixmapItem(QtGui.QImage(imgfilename3x3))
|
||||||
|
item.crop = QtCore.QRectF(0, 0, 2, 2)
|
||||||
|
item.grayscale = True
|
||||||
data, imgformat = item.pixmap_to_bytes()
|
data, imgformat = item.pixmap_to_bytes()
|
||||||
assert imgformat == 'jpg'
|
assert imgformat == 'jpg'
|
||||||
assert data.startswith(b'\xff\xd8\xff\xe0\x00\x10JFIF')
|
assert data.startswith(b'\xff\xd8\xff\xe0\x00\x10JFIF')
|
||||||
|
pixmap = QtGui.QPixmap()
|
||||||
|
pixmap.loadFromData(data)
|
||||||
|
img = pixmap.toImage()
|
||||||
|
assert img.allGray() is False
|
||||||
|
assert img.size() == QtCore.QSize(3, 3)
|
||||||
|
|
||||||
|
|
||||||
|
def test_pixmap_to_bytes_apply_grayscale(qapp, imgfilename3x3):
|
||||||
|
item = BeePixmapItem(QtGui.QImage(imgfilename3x3))
|
||||||
|
item.crop = QtCore.QRectF(0, 0, 2, 2)
|
||||||
|
item.grayscale = True
|
||||||
|
data, imgformat = item.pixmap_to_bytes(apply_grayscale=True)
|
||||||
|
assert imgformat == 'png'
|
||||||
|
assert data.startswith(b'\x89PNG')
|
||||||
|
pixmap = QtGui.QPixmap()
|
||||||
|
pixmap.loadFromData(data)
|
||||||
|
img = pixmap.toImage()
|
||||||
|
assert img.allGray() is True
|
||||||
|
assert img.size() == QtCore.QSize(3, 3)
|
||||||
|
|
||||||
|
|
||||||
|
def test_pixmap_to_bytes_apply_crop(qapp, imgfilename3x3):
|
||||||
|
item = BeePixmapItem(QtGui.QImage(imgfilename3x3))
|
||||||
|
item.crop = QtCore.QRectF(0, 0, 2, 2)
|
||||||
|
item.grayscale = True
|
||||||
|
data, imgformat = item.pixmap_to_bytes(apply_crop=True)
|
||||||
|
assert imgformat == 'png'
|
||||||
|
assert data.startswith(b'\x89PNG')
|
||||||
|
pixmap = QtGui.QPixmap()
|
||||||
|
pixmap.loadFromData(data)
|
||||||
|
img = pixmap.toImage()
|
||||||
|
assert img.allGray() is False
|
||||||
|
assert img.size() == QtCore.QSize(2, 2)
|
||||||
|
|
||||||
|
|
||||||
|
def test_pixmap_to_bytes_apply_grayscale_crop_when_not_set(
|
||||||
|
qapp, imgfilename3x3):
|
||||||
|
item = BeePixmapItem(QtGui.QImage(imgfilename3x3))
|
||||||
|
data, imgformat = item.pixmap_to_bytes(apply_grayscale=True,
|
||||||
|
apply_crop=False)
|
||||||
|
assert imgformat == 'png'
|
||||||
|
assert data.startswith(b'\x89PNG')
|
||||||
|
pixmap = QtGui.QPixmap()
|
||||||
|
pixmap.loadFromData(data)
|
||||||
|
img = pixmap.toImage()
|
||||||
|
assert img.allGray() is False
|
||||||
|
assert img.size() == QtCore.QSize(3, 3)
|
||||||
|
|
||||||
|
|
||||||
def test_pixmap_from_bytes(qapp, item, imgfilename3x3):
|
def test_pixmap_from_bytes(qapp, item, imgfilename3x3):
|
||||||
|
|
|
||||||
|
|
@ -298,7 +298,7 @@ def test_on_action_save_when_no_filename(save_as_mock, view, imgfilename3x3):
|
||||||
@patch('beeref.widgets.SceneToPixmapExporterDialog.value')
|
@patch('beeref.widgets.SceneToPixmapExporterDialog.value')
|
||||||
@patch('PyQt6.QtWidgets.QFileDialog.getSaveFileName')
|
@patch('PyQt6.QtWidgets.QFileDialog.getSaveFileName')
|
||||||
def test_on_action_export_scene(
|
def test_on_action_export_scene(
|
||||||
file_mock, value_mock, exec_mock, view, tmpdir):
|
file_mock, value_mock, exec_mock, view, tmpdir, qtbot):
|
||||||
item = BeeTextItem('foo')
|
item = BeeTextItem('foo')
|
||||||
view.scene.addItem(item)
|
view.scene.addItem(item)
|
||||||
filename = os.path.join(tmpdir, 'test.png')
|
filename = os.path.join(tmpdir, 'test.png')
|
||||||
|
|
@ -306,7 +306,11 @@ def test_on_action_export_scene(
|
||||||
file_mock.return_value = (filename, None)
|
file_mock.return_value = (filename, None)
|
||||||
exec_mock.return_value = 1
|
exec_mock.return_value = 1
|
||||||
value_mock.return_value = QtCore.QSize(100, 100)
|
value_mock.return_value = QtCore.QSize(100, 100)
|
||||||
|
view.on_export_finished = MagicMock()
|
||||||
|
|
||||||
view.on_action_export_scene()
|
view.on_action_export_scene()
|
||||||
|
qtbot.waitUntil(lambda: view.on_export_finished.called is True)
|
||||||
|
view.on_export_finished.assert_called_once_with(filename, [])
|
||||||
img = QtGui.QImage(filename)
|
img = QtGui.QImage(filename)
|
||||||
assert img.size() == QtCore.QSize(100, 100)
|
assert img.size() == QtCore.QSize(100, 100)
|
||||||
|
|
||||||
|
|
@ -315,7 +319,7 @@ def test_on_action_export_scene(
|
||||||
@patch('beeref.widgets.SceneToPixmapExporterDialog.value')
|
@patch('beeref.widgets.SceneToPixmapExporterDialog.value')
|
||||||
@patch('PyQt6.QtWidgets.QFileDialog.getSaveFileName')
|
@patch('PyQt6.QtWidgets.QFileDialog.getSaveFileName')
|
||||||
def test_on_action_export_scene_no_file_extension(
|
def test_on_action_export_scene_no_file_extension(
|
||||||
file_mock, value_mock, exec_mock, view, tmpdir):
|
file_mock, value_mock, exec_mock, view, tmpdir, qtbot):
|
||||||
item = BeeTextItem('foo')
|
item = BeeTextItem('foo')
|
||||||
view.scene.addItem(item)
|
view.scene.addItem(item)
|
||||||
filename = os.path.join(tmpdir, 'test')
|
filename = os.path.join(tmpdir, 'test')
|
||||||
|
|
@ -323,7 +327,11 @@ def test_on_action_export_scene_no_file_extension(
|
||||||
file_mock.return_value = (filename, 'PNG (*.png)')
|
file_mock.return_value = (filename, 'PNG (*.png)')
|
||||||
exec_mock.return_value = 1
|
exec_mock.return_value = 1
|
||||||
value_mock.return_value = QtCore.QSize(100, 100)
|
value_mock.return_value = QtCore.QSize(100, 100)
|
||||||
|
view.on_export_finished = MagicMock()
|
||||||
|
|
||||||
view.on_action_export_scene()
|
view.on_action_export_scene()
|
||||||
|
qtbot.waitUntil(lambda: view.on_export_finished.called is True)
|
||||||
|
view.on_export_finished.assert_called_once_with(f'{filename}.png', [])
|
||||||
img = QtGui.QImage(f'{filename}.png')
|
img = QtGui.QImage(f'{filename}.png')
|
||||||
assert img.size() == QtCore.QSize(100, 100)
|
assert img.size() == QtCore.QSize(100, 100)
|
||||||
|
|
||||||
|
|
@ -336,9 +344,12 @@ def test_on_action_export_scene_no_filename(
|
||||||
item = BeeTextItem('foo')
|
item = BeeTextItem('foo')
|
||||||
view.scene.addItem(item)
|
view.scene.addItem(item)
|
||||||
file_mock.return_value = (None, None)
|
file_mock.return_value = (None, None)
|
||||||
|
view.on_export_finished = MagicMock()
|
||||||
|
|
||||||
view.on_action_export_scene()
|
view.on_action_export_scene()
|
||||||
exec_mock.assert_not_called()
|
exec_mock.assert_not_called()
|
||||||
value_mock.assert_not_called()
|
value_mock.assert_not_called()
|
||||||
|
view.on_export_finished.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
@patch('beeref.widgets.SceneToPixmapExporterDialog.exec')
|
@patch('beeref.widgets.SceneToPixmapExporterDialog.exec')
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue