File indexing completed on 2025-01-19 03:59:17

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2013-07-25
0007  * Description : image region widget item for image editor.
0008  *
0009  * SPDX-FileCopyrightText: 2013-2014 by Yiou Wang <geow812 at gmail dot com>
0010  * SPDX-FileCopyrightText: 2013-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "imageregionitem.h"
0017 
0018 // Qt includes
0019 
0020 #include <QPixmap>
0021 #include <QPainter>
0022 
0023 // KDE includes
0024 
0025 #include <klocalizedstring.h>
0026 
0027 // Local includes
0028 
0029 #include "digikam_debug.h"
0030 #include "dimgitems_p.h"
0031 #include "editorcore.h"
0032 #include "exposurecontainer.h"
0033 #include "iccmanager.h"
0034 #include "icctransform.h"
0035 #include "iccsettingscontainer.h"
0036 #include "imageiface.h"
0037 #include "previewtoolbar.h"
0038 
0039 namespace Digikam
0040 {
0041 
0042 class Q_DECL_HIDDEN ImageRegionItem::Private
0043 {
0044 public:
0045 
0046     explicit Private()
0047       : paintExtras              (true),
0048         onMouseMovePreviewToggled(true),
0049         renderingPreviewMode     (PreviewToolBar::PreviewBothImagesVertCont),
0050         view                     (nullptr),
0051         iface                    (nullptr)
0052     {
0053     }
0054 
0055     bool               paintExtras;
0056     bool               onMouseMovePreviewToggled;
0057     int                renderingPreviewMode;
0058 
0059     QPixmap            targetPix;    ///< Pixmap of target region to render for paint method.
0060     QRect              drawRect;
0061     QPolygon           hightlightPoints;
0062 
0063     ImageRegionWidget* view;
0064     ImageIface*        iface;
0065 };
0066 
0067 ImageRegionItem::ImageRegionItem(ImageRegionWidget* const widget, bool paintExtras)
0068     : dd(new Private)
0069 {
0070     dd->view        = widget;
0071     dd->iface       = new ImageIface;
0072     dd->paintExtras = paintExtras;
0073 
0074     setDisplayWidget(widget);
0075     setAcceptHoverEvents(true);
0076     setImage(dd->iface->original() ? dd->iface->original()->copy() : DImg());
0077 }
0078 
0079 ImageRegionItem::~ImageRegionItem()
0080 {
0081     delete dd->iface;
0082     delete dd;
0083 }
0084 
0085 QRect ImageRegionItem::getImageRegion() const
0086 {
0087     return dd->drawRect;
0088 }
0089 
0090 void ImageRegionItem::setTargetImage(const DImg& img)
0091 {
0092     dd->targetPix = dd->iface->convertToPixmap(img);
0093     update();
0094 }
0095 
0096 void ImageRegionItem::setRenderingPreviewMode(int mode)
0097 {
0098     dd->renderingPreviewMode = mode;
0099     update();
0100 }
0101 
0102 void ImageRegionItem::setHighLightPoints(const QPolygon& pointsList)
0103 {
0104     dd->hightlightPoints = pointsList;
0105 }
0106 
0107 void ImageRegionItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
0108 {
0109     Q_D(GraphicsDImgItem);
0110 
0111     dd->drawRect      = option->exposedRect.intersected(boundingRect()).toAlignedRect();
0112     QRect   pixSourceRect;
0113     QPixmap pix;
0114     QSize   completeSize = boundingRect().size().toSize();
0115 
0116     // scale "as if" scaling to whole image, but clip output to our exposed region
0117 
0118     DImg scaledImage     = d->image.smoothScaleClipped(completeSize.width(),
0119                                                        completeSize.height(),
0120                                                        dd->drawRect.x(),
0121                                                        dd->drawRect.y(),
0122                                                        dd->drawRect.width(),
0123                                                        dd->drawRect.height());
0124 
0125     if (d->cachedPixmaps.find(dd->drawRect, &pix, &pixSourceRect))
0126     {
0127         if (pixSourceRect.isNull())
0128         {
0129             painter->drawPixmap(dd->drawRect.topLeft(), pix);
0130         }
0131         else
0132         {
0133             painter->drawPixmap(dd->drawRect.topLeft(), pix, pixSourceRect);
0134         }
0135     }
0136     else
0137     {
0138         // TODO: factoring ICC settings code using ImageIface/EditorCore methods.
0139 
0140         // Apply CM settings.
0141 
0142         bool doSoftProofing              = EditorCore::defaultInstance()->softProofingEnabled();
0143         ICCSettingsContainer iccSettings = EditorCore::defaultInstance()->getICCSettings();
0144 
0145         if (iccSettings.enableCM && (iccSettings.useManagedView || doSoftProofing))
0146         {
0147             IccManager   manager(scaledImage);
0148             IccTransform monitorICCtrans;
0149 
0150             if (doSoftProofing)
0151             {
0152                 monitorICCtrans = manager.displaySoftProofingTransform(IccProfile(iccSettings.defaultProofProfile), widget);
0153             }
0154             else
0155             {
0156                 monitorICCtrans = manager.displayTransform(widget);
0157             }
0158 
0159             pix = scaledImage.convertToPixmap(monitorICCtrans);
0160         }
0161         else
0162         {
0163             pix = scaledImage.convertToPixmap();
0164         }
0165 
0166         d->cachedPixmaps.insert(dd->drawRect, pix);
0167 
0168         painter->drawPixmap(dd->drawRect.topLeft(), pix);
0169     }
0170 
0171     if (dd->paintExtras)
0172     {
0173         paintExtraData(painter);
0174     }
0175 
0176     // Show the Over/Under exposure pixels indicators
0177 
0178     ExposureSettingsContainer* const expoSettings = EditorCore::defaultInstance()->getExposureSettings();
0179 
0180     if (expoSettings)
0181     {
0182         if (expoSettings->underExposureIndicator || expoSettings->overExposureIndicator)
0183         {
0184             QImage pureColorMask = scaledImage.pureColorMask(expoSettings);
0185             QPixmap pixMask      = QPixmap::fromImage(pureColorMask);
0186             painter->drawPixmap(dd->drawRect.topLeft(), pixMask);
0187         }
0188     }
0189 }
0190 
0191 void ImageRegionItem::paintExtraData(QPainter* const p)
0192 {
0193     QRect viewportRect   = boundingRect().toAlignedRect();
0194     QRect fontRectBefore = p->fontMetrics().boundingRect(viewportRect, 0, i18n("Before"));
0195     QRect fontRectAfter  = p->fontMetrics().boundingRect(viewportRect, 0, i18n("After"));
0196 
0197     p->setRenderHint(QPainter::Antialiasing, true);
0198     p->setBackgroundMode(Qt::TransparentMode);
0199 
0200     if      ((dd->renderingPreviewMode == PreviewToolBar::PreviewOriginalImage) ||
0201              ((dd->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver) && !dd->onMouseMovePreviewToggled))
0202     {
0203         dd->view->drawText(p, QRectF(QPointF(dd->drawRect.topLeft().x() + 20,
0204                                              dd->drawRect.topLeft().y() + 20),
0205                                              fontRectBefore.size()), i18n("Before"));
0206     }
0207 
0208     else if ((dd->renderingPreviewMode == PreviewToolBar::PreviewTargetImage) ||
0209              (dd->renderingPreviewMode == PreviewToolBar::NoPreviewMode)      ||
0210              ((dd->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver) && dd->onMouseMovePreviewToggled))
0211     {
0212         p->drawPixmap(dd->drawRect.x(), dd->drawRect.y(), dd->targetPix,
0213                       0, 0, dd->drawRect.width(), dd->drawRect.height());
0214 
0215         if ((dd->renderingPreviewMode == PreviewToolBar::PreviewTargetImage) ||
0216             (dd->renderingPreviewMode == PreviewToolBar::PreviewToggleOnMouseOver))
0217         {
0218             dd->view->drawText(p, QRectF(QPointF(dd->drawRect.topLeft().x() + 20,
0219                                                  dd->drawRect.topLeft().y() + 20),
0220                                                  fontRectAfter.size()), i18n("After"));
0221         }
0222     }
0223 
0224     else if ((dd->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVert) ||
0225              (dd->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVertCont))
0226     {
0227         if (dd->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVert)
0228         {
0229             p->drawPixmap(dd->drawRect.x() + dd->drawRect.width() / 2, dd->drawRect.y(),
0230                           dd->targetPix, 0, 0, dd->drawRect.width()/2, dd->drawRect.height());
0231         }
0232 
0233         if (dd->renderingPreviewMode == PreviewToolBar::PreviewBothImagesVertCont)
0234         {
0235             p->drawPixmap(dd->drawRect.x() + dd->drawRect.width() / 2, dd->drawRect.y(),
0236                           dd->targetPix, dd->drawRect.width()/2, 0, dd->drawRect.width(), dd->drawRect.height());
0237         }
0238 
0239         p->setPen(QPen(Qt::white, 2, Qt::SolidLine));
0240         p->drawLine(dd->drawRect.topLeft().x() + dd->drawRect.width()/2, dd->drawRect.topLeft().y(),
0241                     dd->drawRect.topLeft().x() + dd->drawRect.width()/2, dd->drawRect.bottomLeft().y());
0242         p->setPen(QPen(Qt::red, 2, Qt::DotLine));
0243         p->drawLine(dd->drawRect.topLeft().x() + dd->drawRect.width()/2, dd->drawRect.topLeft().y(),
0244                     dd->drawRect.topLeft().x() + dd->drawRect.width()/2, dd->drawRect.bottomLeft().y());
0245         dd->view->drawText(p, QRectF(QPointF(dd->drawRect.topLeft().x() + 20,
0246                                              dd->drawRect.topLeft().y() + 20),
0247                                              fontRectBefore.size()), i18n("Before"));
0248         dd->view->drawText(p, QRectF(QPointF(dd->drawRect.topLeft().x() + dd->drawRect.width()/2 + 20,
0249                                              dd->drawRect.topLeft().y() + 20),
0250                                              fontRectAfter.size()),  i18n("After"));
0251     }
0252 
0253     else if ((dd->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorz) ||
0254              (dd->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorzCont))
0255     {
0256         if (dd->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorz)
0257         {
0258             p->drawPixmap(dd->drawRect.x(), dd->drawRect.y() + dd->drawRect.height() / 2,
0259                           dd->targetPix, 0, 0, dd->drawRect.width(), dd->drawRect.height()/2);
0260         }
0261 
0262         if (dd->renderingPreviewMode == PreviewToolBar::PreviewBothImagesHorzCont)
0263         {
0264             p->drawPixmap(dd->drawRect.x(), dd->drawRect.y() + dd->drawRect.height() / 2,
0265                           dd->targetPix, 0, dd->drawRect.height()/2, dd->drawRect.width(), dd->drawRect.height());
0266         }
0267 
0268         p->setPen(QPen(Qt::white, 2, Qt::SolidLine));
0269         p->drawLine(dd->drawRect.topLeft().x()  + 1, dd->drawRect.topLeft().y() + dd->drawRect.height()/2,
0270                     dd->drawRect.topRight().x() - 1, dd->drawRect.topLeft().y() + dd->drawRect.height()/2);
0271         p->setPen(QPen(Qt::red, 2, Qt::DotLine));
0272         p->drawLine(dd->drawRect.topLeft().x()  + 1, dd->drawRect.topLeft().y() + dd->drawRect.height()/2,
0273                     dd->drawRect.topRight().x() - 1, dd->drawRect.topLeft().y() + dd->drawRect.height()/2);
0274 
0275         dd->view->drawText(p, QRectF(QPointF(dd->drawRect.topLeft().x() + 20,
0276                                              dd->drawRect.topLeft().y() + 20),
0277                                              fontRectBefore.size()), i18n("Before"));
0278         dd->view->drawText(p, QRectF(QPointF(dd->drawRect.topLeft().x() + 20,
0279                                              dd->drawRect.topLeft().y() + dd->drawRect.height()/2 + 20),
0280                                              fontRectAfter.size()),  i18n("After"));
0281     }
0282 
0283     // Drawing highlighted points.
0284 
0285     if (!dd->hightlightPoints.isEmpty())
0286     {
0287         QPoint pt;
0288         QRectF hpArea;
0289 
0290 
0291         for (int i = 0 ; i < dd->hightlightPoints.count() ; ++i)
0292         {
0293             pt                = dd->hightlightPoints.point(i);
0294             double zoomFactor = zoomSettings()->realZoomFactor();
0295             int x = (int)((double)pt.x() * zoomFactor);
0296             int y = (int)((double)pt.y() * zoomFactor);
0297 
0298             // Check if zoomed point is inside, not actual point
0299 
0300             if (dd->drawRect.contains(QPoint(x,y)))
0301             {
0302 /*
0303                 QPoint hp(contentsToViewport(QPointF(x, y)));
0304 */
0305                 QPointF hp(mapToScene(QPointF(x, y)));
0306 
0307                 hpArea.setSize(QSize((int)(16 * zoomFactor), (int)(16 * zoomFactor)));
0308                 hpArea.moveCenter(hp);
0309 
0310                 p->setPen(QPen(Qt::white, 2, Qt::SolidLine));
0311                 p->drawLine(hp.x(),                         hpArea.y(),                     hp.x(),                         hp.y() - (int)(3 * zoomFactor));
0312                 p->drawLine(hp.x(),                         hp.y() + (int)(3 * zoomFactor), hp.x(),                         hpArea.bottom());
0313                 p->drawLine(hpArea.x(),                     hp.y(),                         hp.x() - (int)(3 * zoomFactor), hp.y());
0314                 p->drawLine(hp.x() + (int)(3 * zoomFactor), hp.y(),                         hpArea.right(),                 hp.y());
0315 
0316                 p->setPen(QPen(Qt::red, 2, Qt::DotLine));
0317                 p->drawLine(hp.x(),                         hpArea.y(),                     hp.x(),                         hp.y() - (int)(3 * zoomFactor));
0318                 p->drawLine(hp.x(),                         hp.y() + (int)(3 * zoomFactor), hp.x(),                         hpArea.bottom());
0319                 p->drawLine(hpArea.x(),                     hp.y(),                         hp.x() - (int)(3 * zoomFactor), hp.y());
0320                 p->drawLine(hp.x() + (int)(3 * zoomFactor), hp.y(),                         hpArea.right(),                 hp.y());
0321             }
0322         }
0323     }
0324 }
0325 
0326 void ImageRegionItem::hoverEnterEvent(QGraphicsSceneHoverEvent*)
0327 {
0328     dd->onMouseMovePreviewToggled = false;
0329     update();
0330 }
0331 
0332 void ImageRegionItem::hoverLeaveEvent(QGraphicsSceneHoverEvent*)
0333 {
0334     dd->onMouseMovePreviewToggled = true;
0335     update();
0336 }
0337 
0338 } // namespace Digikam
0339 
0340 #include "moc_imageregionitem.cpp"