# -*- coding: utf-8 -*-
#
# Copyright © 2012 CEA
# Pierre Raybaut
# Licensed under the terms of the CECILL License
# (see guiqwt/__init__.py for details)
"""
rotatecrop
----------
The `rotatecrop` module provides a dialog box providing essential GUI elements
for rotating (arbitrary angle) and cropping an image:
* :py:class:`guiqwt.widgets.rotatecrop.RotateCropDialog`: dialog box
* :py:class:`guiqwt.widgets.rotatecrop.RotateCropWidget`: equivalent widget
Reference
~~~~~~~~~
.. autoclass:: RotateCropDialog
:members:
:inherited-members:
.. autoclass:: RotateCropWidget
:members:
:inherited-members:
"""
from qtpy.QtWidgets import QCheckBox
# Local imports
from guiqwt.config import _
from guiqwt.builder import make
from guiqwt.image import get_image_in_shape
from guiqwt.widgets import base
class RotateCropMixin(base.BaseTransformMixin):
"""Rotate & Crop mixin class, to be mixed with a class providing the
get_plot method, like ImageDialog or RotateCropWidget (see below)"""
def __init__(self):
base.BaseTransformMixin.__init__(self)
self.crop_rect = None
# ------BaseTransformMixin API----------------------------------------------
def add_buttons_to_layout(self, layout):
"""Add tool buttons to layout"""
# Show crop rectangle checkbox
show_crop = QCheckBox(_("Show cropping rectangle"), self)
show_crop.setChecked(True)
show_crop.toggled.connect(self.show_crop_rect)
layout.addWidget(show_crop)
layout.addSpacing(15)
base.BaseTransformMixin.add_buttons_to_layout(self, layout)
def set_item(self, item):
"""Set associated item -- must be a TrImageItem object"""
base.BaseTransformMixin.set_item(self, item)
crect = make.annotated_rectangle(0, 0, 1, 1, _("Cropping rectangle"))
self.crop_rect = crect
crect.annotationparam.format = "%.1f cm"
plot = self.get_plot()
plot.add_item(crect)
plot.set_active_item(crect)
x0, y0, x1, y1 = self.item.get_crop_coordinates()
crect.set_rect(x0, y0, x1, y1)
plot.replot()
def reset_transformation(self):
"""Reset transformation"""
x0, y0, x1, y1 = self.item.border_rect.get_rect()
self.crop_rect.set_rect(x0, y0, x1, y1)
def apply_transformation(self):
"""Apply transformation, e.g. crop or rotate"""
# Let's crop!
i_points = self.item.border_rect.get_points()
xmin, ymin = i_points.min(axis=0)
xmax, ymax = i_points.max(axis=0)
xc0, yc0, xc1, yc1 = self.crop_rect.shape.get_rect()
left = max([0, xc0 - xmin])
right = max([0, xmax - xc1])
top = max([0, yc0 - ymin])
bottom = max([0, ymax - yc1])
self.item.set_crop(left, top, right, bottom)
# print "set_crop:", left, top, right, bottom
self.item.compute_bounds()
self.get_plot().replot()
def compute_transformation(self):
"""Compute transformation, return compute output array"""
return get_image_in_shape(self.crop_rect, apply_interpolation=False)
# ------Private API---------------------------------------------------------
def show_crop_rect(self, state):
"""Show/hide cropping rectangle shape"""
self.crop_rect.setVisible(state)
self.crop_rect.label.setVisible(state)
self.get_plot().replot()
[docs]class RotateCropDialog(base.BaseTransformDialog, RotateCropMixin):
"""Rotate & Crop Dialog
Rotate and crop a :py:class:`guiqwt.image.TrImageItem` plot item"""
def __init__(self, parent, wintitle=None, options=None, resize_to=None):
RotateCropMixin.__init__(self)
base.BaseTransformDialog.__init__(
self, parent, wintitle=wintitle, options=options, resize_to=resize_to
)
class MultipleRotateCropWidget(base.BaseMultipleTransformWidget):
"""Multiple Rotate & Crop Widget
Rotate and crop several :py:class:`guiqwt.image.TrImageItem` plot items"""
TRANSFORM_WIDGET_CLASS = RotateCropWidget