File indexing completed on 2025-01-05 03:53:13

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2002-30-09
0007  * Description : a tool to print images
0008  *
0009  * SPDX-FileCopyrightText: 2002-2003 by Todd Shoemaker <todd at theshoemakers dot net>
0010  * SPDX-FileCopyrightText: 2007-2012 by Angelo Naselli <anaselli at linux dot it>
0011  * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #include "advprintcropframe.h"
0018 
0019 // C++ includes
0020 
0021 #include <cmath>
0022 #include <cstdio>
0023 
0024 // Qt includes
0025 
0026 #include <QPixmap>
0027 #include <QImage>
0028 #include <QPainter>
0029 #include <QMouseEvent>
0030 #include <QtGlobal>
0031 
0032 // Local includes
0033 
0034 #include "digikam_debug.h"
0035 #include "advprintphoto.h"
0036 #include "advprintwizard.h"
0037 
0038 namespace DigikamGenericPrintCreatorPlugin
0039 {
0040 
0041 class Q_DECL_HIDDEN AdvPrintCropFrame::Private
0042 {
0043 public:
0044 
0045     explicit Private()
0046       : photo    (nullptr),
0047         mouseDown(false),
0048         image    (nullptr),
0049         imageX   (0),
0050         imageY   (0),
0051         color    (Qt::red),
0052         drawRec  (true)
0053     {
0054     }
0055 
0056     AdvPrintPhoto* photo;
0057     bool           mouseDown;
0058     QImage         image;
0059     int            imageX;
0060     int            imageY;
0061 
0062     QColor         color;
0063 
0064     QRect          cropRegion;
0065     bool           drawRec;
0066 
0067     QTransform     matrix;
0068 };
0069 
0070 AdvPrintCropFrame::AdvPrintCropFrame(QWidget* const parent)
0071     : QWidget(parent),
0072       d      (new Private)
0073 {
0074 }
0075 
0076 AdvPrintCropFrame::~AdvPrintCropFrame()
0077 {
0078     delete d;
0079 }
0080 
0081 void AdvPrintCropFrame::init(AdvPrintPhoto* const photo,
0082                              int  woutlay,
0083                              int  houtlay,
0084                              bool autoRotate,
0085                              bool paint)
0086 {
0087     d->photo  = photo;
0088     d->matrix = d->photo->updateCropRegion(woutlay, houtlay, autoRotate);
0089 
0090     if (paint)
0091     {
0092         updateImage();
0093         update();
0094     }
0095 }
0096 
0097 QRect AdvPrintCropFrame::screenToPhotoRect(const QRect& r) const
0098 {
0099     // 'r' is given in screen coordinates, and we want to convert that to photo coordinates.
0100 
0101     double xRatio = 0.0;
0102     double yRatio = 0.0;
0103 
0104     // Flip the photo dimensions if rotated
0105 
0106     int photoW;
0107     int photoH;
0108 
0109     if ((d->photo->m_rotation == 0) || (d->photo->m_rotation == 180))
0110     {
0111         photoW = d->photo->width();
0112         photoH = d->photo->height();
0113     }
0114     else
0115     {
0116         photoW = d->photo->height();
0117         photoH = d->photo->width();
0118     }
0119 
0120     if (d->image.width() > 0)
0121     {
0122         xRatio = (double) photoW / (double) d->image.width();
0123     }
0124 
0125     if (d->image.height() > 0)
0126     {
0127         yRatio = (double) photoH / (double) d->image.height();
0128     }
0129 
0130     int x1 = AdvPrintWizard::normalizedInt((r.left() - d->imageX) * xRatio);
0131     int y1 = AdvPrintWizard::normalizedInt((r.top()  - d->imageY) * yRatio);
0132 
0133     int w  = AdvPrintWizard::normalizedInt(r.width()  * xRatio);
0134     int h  = AdvPrintWizard::normalizedInt(r.height() * yRatio);
0135 
0136     QRect result;
0137     result.setRect(x1, y1, w, h);
0138 
0139     return result;
0140 }
0141 
0142 QRect AdvPrintCropFrame::photoToScreenRect(const QRect& r) const
0143 {
0144     // 'r' is given in photo coordinates, and we want to convert that to screen coordinates
0145 
0146     double xRatio = 0.0;
0147     double yRatio = 0.0;
0148 
0149     // Flip the photo dimensions if rotated
0150 
0151     int photoW;
0152     int photoH;
0153 
0154     if ((d->photo->m_rotation == 0) || (d->photo->m_rotation == 180))
0155     {
0156         photoW = d->photo->width();
0157         photoH = d->photo->height();
0158     }
0159     else
0160     {
0161         photoW = d->photo->height();
0162         photoH = d->photo->width();
0163     }
0164 
0165     if (d->photo->width() > 0)
0166     {
0167         xRatio = (double) d->image.width() / (double) photoW;
0168     }
0169 
0170     if (d->photo->height() > 0)
0171     {
0172         yRatio = (double)d->image.height() / (double)photoH;
0173     }
0174 
0175     int x1 = AdvPrintWizard::normalizedInt(r.left() * xRatio + d->imageX);
0176     int y1 = AdvPrintWizard::normalizedInt(r.top()  * yRatio + d->imageY);
0177 
0178     int w  = AdvPrintWizard::normalizedInt(r.width()  * xRatio);
0179     int h  = AdvPrintWizard::normalizedInt(r.height() * yRatio);
0180 
0181     QRect result;
0182     result.setRect(x1, y1, w, h);
0183 
0184     return result;
0185 }
0186 
0187 void AdvPrintCropFrame::updateImage()
0188 {
0189     if (d->photo)
0190     {
0191         d->image      = d->photo->loadPhoto().copyQImage();
0192         d->image      = d->image.transformed(d->matrix);
0193         d->image      = d->image.scaled(width(), height(), Qt::KeepAspectRatio);
0194         d->imageX     = (width()  / 2) - (d->image.width()  / 2);
0195         d->imageY     = (height() / 2) - (d->image.height() / 2);
0196         d->cropRegion = photoToScreenRect(d->photo->m_cropRegion);
0197     }
0198 }
0199 
0200 void AdvPrintCropFrame::resizeEvent(QResizeEvent*)
0201 {
0202     updateImage();
0203     update();
0204 }
0205 
0206 void AdvPrintCropFrame::paintEvent(QPaintEvent*)
0207 {
0208     updateImage();
0209 
0210     QPixmap bmp(this->width(), this->height());
0211     QPainter p;
0212     p.begin(&bmp);
0213 
0214     p.eraseRect(0, 0, this->width(), this->height());
0215 
0216     // Draw the background image
0217 
0218     p.drawImage(d->imageX, d->imageY, d->image);
0219 
0220     if (d->drawRec)
0221     {
0222         // Draw the rectangle
0223 
0224         p.setPen(QPen(d->color, 2));
0225         p.drawRect(d->cropRegion);
0226 
0227         // Draw the crosshairs
0228 
0229         int midX = d->cropRegion.left() + d->cropRegion.width()  / 2;
0230         int midY = d->cropRegion.top()  + d->cropRegion.height() / 2;
0231         p.drawLine(midX - 10, midY,      midX + 10, midY);
0232         p.drawLine(midX,      midY - 10, midX,      midY + 10);
0233     }
0234 
0235     p.end();
0236 
0237     QPainter newp(this);
0238     newp.drawPixmap(0, 0, bmp);
0239 }
0240 
0241 void AdvPrintCropFrame::mousePressEvent(QMouseEvent* e)
0242 {
0243     if (e && (e->button() == Qt::LeftButton))
0244     {
0245         d->mouseDown = true;
0246         QWidget::mouseMoveEvent(e);
0247     }
0248 }
0249 
0250 void AdvPrintCropFrame::mouseReleaseEvent(QMouseEvent* e)
0251 {
0252     if (e && (e->button() == Qt::LeftButton))
0253     {
0254         d->mouseDown = false;
0255     }
0256 }
0257 
0258 void AdvPrintCropFrame::mouseMoveEvent(QMouseEvent* e)
0259 {
0260     if (d->mouseDown)
0261     {
0262         // Don't let the rectangle float off the image.
0263 
0264         int newW = d->cropRegion.width();
0265         int newH = d->cropRegion.height();
0266 
0267 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0268 
0269         int newX = e->position().toPoint().x() - (newW / 2);
0270         int newY = e->position().toPoint().y() - (newH / 2);
0271 
0272 #else
0273 
0274         int newX = e->x() - (newW / 2);
0275         int newY = e->y() - (newH / 2);
0276 
0277 #endif
0278 
0279         newX     = qMax(d->imageX, newX);
0280         newX     = qMin(d->imageX + d->image.width() - newW, newX);
0281 
0282         newY     = qMax(d->imageY, newY);
0283         newY     = qMin(d->imageY + d->image.height() - newH, newY);
0284 
0285         d->cropRegion.setRect(newX, newY, newW, newH);
0286         d->photo->m_cropRegion = screenToPhotoRect(d->cropRegion);
0287         update();
0288     }
0289 }
0290 
0291 void AdvPrintCropFrame::keyReleaseEvent(QKeyEvent* e)
0292 {
0293     int newX = d->cropRegion.x();
0294     int newY = d->cropRegion.y();
0295 
0296     switch (e->key())
0297     {
0298         case Qt::Key_Up:
0299         {
0300             newY--;
0301             break;
0302         }
0303 
0304         case Qt::Key_Down:
0305         {
0306             newY++;
0307             break;
0308         }
0309 
0310         case Qt::Key_Left:
0311         {
0312             newX--;
0313             break;
0314         }
0315 
0316         case Qt::Key_Right:
0317         {
0318             newX++;
0319             break;
0320         }
0321     }
0322 
0323     // Keep inside the image
0324 
0325     int w = d->cropRegion.width();
0326     int h = d->cropRegion.height();
0327 
0328     newX  = qMax(d->imageX, newX);
0329     newX  = qMin(d->imageX + d->image.width() - w,  newX);
0330 
0331     newY  = qMax(d->imageY, newY);
0332     newY  = qMin(d->imageY + d->image.height() - h, newY);
0333 
0334     d->cropRegion.setRect(newX, newY, w, h);
0335     d->photo->m_cropRegion = screenToPhotoRect(d->cropRegion);
0336     update();
0337 }
0338 
0339 void AdvPrintCropFrame::setColor(const QColor& c)
0340 {
0341     d->color = c;
0342     update();
0343 }
0344 
0345 QColor AdvPrintCropFrame::color() const
0346 {
0347     return d->color;
0348 }
0349 
0350 void AdvPrintCropFrame::drawCropRectangle(bool draw)
0351 {
0352     d->drawRec = draw;
0353 }
0354 
0355 } // Namespace Digikam
0356 
0357 #include "moc_advprintcropframe.cpp"