File indexing completed on 2025-01-05 03:59:44

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2011-04-27
0007  * Description : image preview item for image editor.
0008  *
0009  * SPDX-FileCopyrightText: 2011-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "imagepreviewitem.h"
0016 
0017 // Qt includes
0018 
0019 #include <QStyleOptionGraphicsItem>
0020 #include <QApplication>
0021 #include <QPainter>
0022 #include <QPixmap>
0023 
0024 // Local includes
0025 
0026 #include "dimg.h"
0027 #include "exposurecontainer.h"
0028 #include "iccmanager.h"
0029 #include "iccsettingscontainer.h"
0030 #include "icctransform.h"
0031 #include "editorcore.h"
0032 #include "dimgitems_p.h"
0033 
0034 namespace Digikam
0035 {
0036 
0037 ImagePreviewItem::ImagePreviewItem()
0038 {
0039     Q_D(GraphicsDImgItem);
0040     d->init(this);
0041 }
0042 
0043 ImagePreviewItem::~ImagePreviewItem()
0044 {
0045 }
0046 
0047 void ImagePreviewItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
0048 {
0049     Q_D(GraphicsDImgItem);
0050 
0051     QRect   drawRect     = option->exposedRect.intersected(boundingRect()).toAlignedRect();
0052     QRect   pixSourceRect;
0053     QPixmap pix;
0054     QSize   completeSize = boundingRect().size().toSize();
0055 
0056     /*
0057      * For high resolution ("retina") displays, Mac OS X / Qt
0058      * report only half of the physical resolution in terms of
0059      * pixels, i.e. every logical pixels corresponds to 2x2
0060      * physical pixels. However, UI elements and fonts are
0061      * nevertheless rendered at full resolution, and pixmaps
0062      * as well, provided their resolution is high enough (that
0063      * is, higher than the reported, logical resolution).
0064      *
0065      * To work around this, we render the photos not a logical
0066      * resolution, but with the photo's full resolution, but
0067      * at the screen's aspect ratio. When we later draw this
0068      * high resolution bitmap, it is up to Qt to scale the
0069      * photo to the true physical resolution.  The ratio
0070      * computed below is the ratio between the photo and
0071      * screen resolutions, or equivalently the factor by which
0072      * we need to increase the pixel size of the rendered
0073      * pixmap.
0074      */
0075 
0076     qreal dpr             = widget->devicePixelRatio();
0077 
0078     QRect  scaledDrawRect = QRectF(dpr * drawRect.x(),
0079                                    dpr * drawRect.y(),
0080                                    dpr * drawRect.width(),
0081                                    dpr * drawRect.height()).toRect();
0082 
0083     // scale "as if" scaling to whole image, but clip output to our exposed region
0084 
0085     QSize scaledCompleteSize = QSizeF(dpr * completeSize.width(),
0086                                       dpr * completeSize.height()).toSize();
0087     DImg scaledImage         = d->image.smoothScaleClipped(scaledCompleteSize.width(),
0088                                                            scaledCompleteSize.height(),
0089                                                            scaledDrawRect.x(),
0090                                                            scaledDrawRect.y(),
0091                                                            scaledDrawRect.width(),
0092                                                            scaledDrawRect.height());
0093 
0094     if (d->cachedPixmaps.find(scaledDrawRect, &pix, &pixSourceRect))
0095     {
0096         if (pixSourceRect.isNull())
0097         {
0098             painter->drawPixmap(drawRect, pix);
0099         }
0100         else
0101         {
0102             painter->drawPixmap(drawRect, pix, pixSourceRect);
0103         }
0104     }
0105     else
0106     {
0107         // TODO: factoring ICC settings code using ImageIface/EditorCore methods.
0108 
0109         // Apply CM settings.
0110 
0111         bool doSoftProofing              = EditorCore::defaultInstance()->softProofingEnabled();
0112         ICCSettingsContainer iccSettings = EditorCore::defaultInstance()->getICCSettings();
0113 
0114         if (iccSettings.enableCM && (iccSettings.useManagedView || doSoftProofing))
0115         {
0116             IccManager   manager(scaledImage);
0117             IccTransform monitorICCtrans;
0118 
0119             if (doSoftProofing)
0120             {
0121                 monitorICCtrans = manager.displaySoftProofingTransform(IccProfile(iccSettings.defaultProofProfile), widget);
0122             }
0123             else
0124             {
0125                 monitorICCtrans = manager.displayTransform(widget);
0126             }
0127 
0128             pix = scaledImage.convertToPixmap(monitorICCtrans);
0129         }
0130         else
0131         {
0132             pix = scaledImage.convertToPixmap();
0133         }
0134 
0135         d->cachedPixmaps.insert(scaledDrawRect, pix);
0136 
0137         painter->drawPixmap(drawRect, pix);
0138     }
0139 
0140     // Show the Over/Under exposure pixels indicators
0141 
0142     ExposureSettingsContainer* const expoSettings = EditorCore::defaultInstance()->getExposureSettings();
0143 
0144     if (expoSettings)
0145     {
0146         if (expoSettings->underExposureIndicator || expoSettings->overExposureIndicator)
0147         {
0148             QImage pureColorMask = scaledImage.pureColorMask(expoSettings);
0149             QPixmap pixMask      = QPixmap::fromImage(pureColorMask);
0150             painter->drawPixmap(drawRect, pixMask);
0151         }
0152     }
0153 }
0154 
0155 } // namespace Digikam
0156 
0157 #include "moc_imagepreviewitem.cpp"