File indexing completed on 2025-01-19 03:51:16

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2004-12-23
0007  * Description : a tool to shear an image
0008  *
0009  * SPDX-FileCopyrightText: 2004-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 "sheartool.h"
0016 
0017 // Qt includes
0018 
0019 #include <QCheckBox>
0020 #include <QGridLayout>
0021 #include <QImage>
0022 #include <QLabel>
0023 #include <QIcon>
0024 
0025 // KDE includes
0026 
0027 #include <ksharedconfig.h>
0028 #include <kconfiggroup.h>
0029 #include <klocalizedstring.h>
0030 
0031 // Local includes
0032 
0033 #include "dlayoutbox.h"
0034 #include "dnuminput.h"
0035 #include "dimg.h"
0036 #include "editortoolsettings.h"
0037 #include "imageiface.h"
0038 #include "imageguidewidget.h"
0039 #include "shearfilter.h"
0040 #include "dexpanderbox.h"
0041 
0042 namespace DigikamEditorShearToolPlugin
0043 {
0044 
0045 class Q_DECL_HIDDEN ShearTool::Private
0046 {
0047 public:
0048 
0049     explicit Private()
0050       : newWidthLabel       (nullptr),
0051         newHeightLabel      (nullptr),
0052         antialiasInput      (nullptr),
0053         mainHAngleInput     (nullptr),
0054         mainVAngleInput     (nullptr),
0055         fineHAngleInput     (nullptr),
0056         fineVAngleInput     (nullptr),
0057         previewWidget       (nullptr),
0058         gboxSettings        (nullptr)
0059     {
0060     }
0061 
0062     static const QString configGroupName;
0063     static const QString configAntiAliasingEntry;
0064     static const QString configMainHAngleEntry;
0065     static const QString configMainVAngleEntry;
0066     static const QString configFineHAngleEntry;
0067     static const QString configFineVAngleEntry;
0068 
0069     QLabel*              newWidthLabel;
0070     QLabel*              newHeightLabel;
0071 
0072     QCheckBox*           antialiasInput;
0073 
0074     DIntNumInput*        mainHAngleInput;
0075     DIntNumInput*        mainVAngleInput;
0076 
0077     DDoubleNumInput*     fineHAngleInput;
0078     DDoubleNumInput*     fineVAngleInput;
0079 
0080     ImageGuideWidget*    previewWidget;
0081     EditorToolSettings*  gboxSettings;
0082 };
0083 
0084 const QString ShearTool::Private::configGroupName(QLatin1String("shear Tool"));
0085 const QString ShearTool::Private::configAntiAliasingEntry(QLatin1String("Anti Aliasing"));
0086 const QString ShearTool::Private::configMainHAngleEntry(QLatin1String("Main HAngle"));
0087 const QString ShearTool::Private::configMainVAngleEntry(QLatin1String("Main VAngle"));
0088 const QString ShearTool::Private::configFineHAngleEntry(QLatin1String("Fine HAngle"));
0089 const QString ShearTool::Private::configFineVAngleEntry(QLatin1String("Fine VAngle"));
0090 
0091 // --------------------------------------------------------
0092 
0093 ShearTool::ShearTool(QObject* const parent)
0094     : EditorToolThreaded(parent),
0095       d                 (new Private)
0096 {
0097     setObjectName(QLatin1String("sheartool"));
0098 
0099     d->previewWidget = new ImageGuideWidget(nullptr, true, ImageGuideWidget::HVGuideMode);
0100     d->previewWidget->setWhatsThis(i18n("This is the shear operation preview. "
0101                                         "If you move the mouse cursor on this preview, "
0102                                         "a vertical and horizontal dashed line will be drawn "
0103                                         "to guide you in adjusting the shear correction. "
0104                                         "Release the left mouse button to freeze the dashed "
0105                                         "line's position."));
0106 
0107     setToolView(d->previewWidget);
0108     setPreviewModeMask(PreviewToolBar::UnSplitPreviewModes);
0109 
0110     // -------------------------------------------------------------
0111 
0112     QString temp;
0113     ImageIface iface;
0114 
0115     d->gboxSettings = new EditorToolSettings(nullptr);
0116     d->gboxSettings->setTools(EditorToolSettings::ColorGuide);
0117 
0118     // -------------------------------------------------------------
0119 
0120     QLabel* label1   = new QLabel(i18n("New width:"));
0121     d->newWidthLabel = new QLabel(temp.setNum(iface.originalSize().width()) + i18n(" px"));
0122     d->newWidthLabel->setAlignment(Qt::AlignBottom | Qt::AlignRight);
0123 
0124     QLabel* label2    = new QLabel(i18n("New height:"));
0125     d->newHeightLabel = new QLabel(temp.setNum(iface.originalSize().height()) + i18n(" px"));
0126     d->newHeightLabel->setAlignment(Qt::AlignBottom | Qt::AlignRight);
0127 
0128     QLabel* label3     = new QLabel(i18n("Main horizontal angle:"));
0129     d->mainHAngleInput = new DIntNumInput;
0130     d->mainHAngleInput->setRange(-45, 45, 1);
0131     d->mainHAngleInput->setDefaultValue(0);
0132     d->mainHAngleInput->setWhatsThis( i18n("The main horizontal shearing angle, in degrees."));
0133 
0134     QLabel* label4     = new QLabel(i18n("Fine horizontal angle:"));
0135     d->fineHAngleInput = new DDoubleNumInput;
0136     d->fineHAngleInput->setRange(-1.0, 1.0, 0.01);
0137     d->fineHAngleInput->setDefaultValue(0);
0138     d->fineHAngleInput->setWhatsThis( i18n("This value in degrees will be added to main "
0139                                            "horizontal angle value to set fine adjustments."));
0140     QLabel* label5     = new QLabel(i18n("Main vertical angle:"));
0141     d->mainVAngleInput = new DIntNumInput;
0142     d->mainVAngleInput->setRange(-45, 45, 1);
0143     d->mainVAngleInput->setDefaultValue(0);
0144     d->mainVAngleInput->setWhatsThis( i18n("The main vertical shearing angle, in degrees."));
0145 
0146     QLabel* label6     = new QLabel(i18n("Fine vertical angle:"));
0147     d->fineVAngleInput = new DDoubleNumInput;
0148     d->fineVAngleInput->setRange(-1.0, 1.0, 0.01);
0149     d->fineVAngleInput->setDefaultValue(0);
0150     d->fineVAngleInput->setWhatsThis( i18n("This value in degrees will be added to main vertical "
0151                                            "angle value to set fine adjustments."));
0152 
0153     d->antialiasInput = new QCheckBox(i18n("Anti-Aliasing"));
0154     d->antialiasInput->setWhatsThis( i18n("Enable this option to apply the anti-aliasing filter "
0155                                           "to the sheared image. "
0156                                           "To smooth the target image, it will be blurred a little."));
0157 
0158     DLineWidget* line = new DLineWidget(Qt::Horizontal);
0159 
0160     // -------------------------------------------------------------
0161 
0162     const int spacing = d->gboxSettings->spacingHint();
0163 
0164     QGridLayout* grid = new QGridLayout;
0165     grid->setSpacing(0);
0166     grid->addWidget(label1,              0, 0, 1, 1);
0167     grid->addWidget(d->newWidthLabel,    0, 1, 1, 2);
0168     grid->addWidget(label2,              1, 0, 1, 1);
0169     grid->addWidget(d->newHeightLabel,   1, 1, 1, 2);
0170     grid->addWidget(line,                2, 0, 1, 3);
0171     grid->addWidget(label3,              3, 0, 1, 3);
0172     grid->addWidget(d->mainHAngleInput,  4, 0, 1, 3);
0173     grid->addWidget(label4,              5, 0, 1, 3);
0174     grid->addWidget(d->fineHAngleInput,  6, 0, 1, 3);
0175     grid->addWidget(label5,              7, 0, 1, 1);
0176     grid->addWidget(d->mainVAngleInput,  8, 0, 1, 3);
0177     grid->addWidget(label6,              9, 0, 1, 3);
0178     grid->addWidget(d->fineVAngleInput, 10, 0, 1, 3);
0179     grid->addWidget(d->antialiasInput,  11, 0, 1, 3);
0180     grid->setRowStretch(12, 10);
0181     grid->setContentsMargins(spacing, spacing, spacing, spacing);
0182     grid->setSpacing(spacing);
0183     d->gboxSettings->plainPage()->setLayout(grid);
0184 
0185     // -------------------------------------------------------------
0186 
0187     setToolSettings(d->gboxSettings);
0188 
0189     // -------------------------------------------------------------
0190 
0191     connect(d->mainHAngleInput, SIGNAL(valueChanged(int)),
0192             this, SLOT(slotTimer()));
0193 
0194     connect(d->fineHAngleInput, SIGNAL(valueChanged(double)),
0195             this, SLOT(slotTimer()));
0196 
0197     connect(d->mainVAngleInput, SIGNAL(valueChanged(int)),
0198             this, SLOT(slotTimer()));
0199 
0200     connect(d->fineVAngleInput, SIGNAL(valueChanged(double)),
0201             this, SLOT(slotTimer()));
0202 
0203     connect(d->antialiasInput, SIGNAL(toggled(bool)),
0204             this, SLOT(slotPreview()));
0205 
0206     connect(d->gboxSettings, SIGNAL(signalColorGuideChanged()),
0207             this, SLOT(slotColorGuideChanged()));
0208 }
0209 
0210 ShearTool::~ShearTool()
0211 {
0212     delete d;
0213 }
0214 
0215 void ShearTool::slotColorGuideChanged()
0216 {
0217     d->previewWidget->slotChangeGuideColor(d->gboxSettings->guideColor());
0218     d->previewWidget->slotChangeGuideSize(d->gboxSettings->guideSize());
0219 }
0220 
0221 void ShearTool::readSettings()
0222 {
0223     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0224     KConfigGroup group        = config->group(d->configGroupName);
0225     //    d->mainHAngleInput->setValue(group.readEntry(d->configMainHAngleEntry, d->mainHAngleInput->defaultValue()));
0226     //    d->mainVAngleInput->setValue(group.readEntry(d->configMainVAngleEntry, d->mainVAngleInput->defaultValue()));
0227     //    d->fineHAngleInput->setValue(group.readEntry(d->configFineHAngleEntry, d->fineHAngleInput->defaultValue()));
0228     //    d->fineVAngleInput->setValue(group.readEntry(d->configFineVAngleEntry, d->fineVAngleInput->defaultValue()));
0229     d->antialiasInput->setChecked(group.readEntry(d->configAntiAliasingEntry, true));
0230     slotPreview();
0231 }
0232 
0233 void ShearTool::writeSettings()
0234 {
0235     KSharedConfig::Ptr config = KSharedConfig::openConfig();
0236     KConfigGroup group        = config->group(d->configGroupName);
0237     //    group.writeEntry(d->configMainHAngleEntry, d->mainHAngleInput->value());
0238     //    group.writeEntry(d->configMainVAngleEntry, d->mainVAngleInput->value());
0239     //    group.writeEntry(d->configFineHAngleEntry, d->fineHAngleInput->value());
0240     //    group.writeEntry(d->configFineVAngleEntry, d->fineVAngleInput->value());
0241     group.writeEntry(d->configAntiAliasingEntry, d->antialiasInput->isChecked());
0242 
0243     config->sync();
0244 }
0245 
0246 void ShearTool::slotResetSettings()
0247 {
0248     d->mainHAngleInput->blockSignals(true);
0249     d->mainVAngleInput->blockSignals(true);
0250     d->fineHAngleInput->blockSignals(true);
0251     d->fineVAngleInput->blockSignals(true);
0252     d->antialiasInput->blockSignals(true);
0253 
0254     d->mainHAngleInput->slotReset();
0255     d->mainVAngleInput->slotReset();
0256     d->fineHAngleInput->slotReset();
0257     d->fineVAngleInput->slotReset();
0258     d->antialiasInput->setChecked(true);
0259 
0260     d->mainHAngleInput->blockSignals(false);
0261     d->mainVAngleInput->blockSignals(false);
0262     d->fineHAngleInput->blockSignals(false);
0263     d->fineVAngleInput->blockSignals(false);
0264     d->antialiasInput->blockSignals(false);
0265 
0266     slotPreview();
0267 }
0268 
0269 void ShearTool::preparePreview()
0270 {
0271     float hAngle            = d->mainHAngleInput->value() + d->fineHAngleInput->value();
0272     float vAngle            = d->mainVAngleInput->value() + d->fineVAngleInput->value();
0273     bool antialiasing       = d->antialiasInput->isChecked();
0274     QColor background       = Qt::black;
0275 
0276     ImageIface* const iface = d->previewWidget->imageIface();
0277     int orgW                = iface->originalSize().width();
0278     int orgH                = iface->originalSize().height();
0279     DImg preview            = iface->preview();
0280     setFilter(new ShearFilter(&preview, this, hAngle, vAngle, antialiasing, background, orgW, orgH));
0281 }
0282 
0283 void ShearTool::prepareFinal()
0284 {
0285     float hAngle         = d->mainHAngleInput->value() + d->fineHAngleInput->value();
0286     float vAngle         = d->mainVAngleInput->value() + d->fineVAngleInput->value();
0287     bool antialiasing    = d->antialiasInput->isChecked();
0288     QColor background    = Qt::black;
0289 
0290     ImageIface iface;
0291     int orgW             = iface.originalSize().width();
0292     int orgH             = iface.originalSize().height();
0293     DImg* const orgImage = iface.original();
0294     setFilter(new ShearFilter(orgImage, this, hAngle, vAngle, antialiasing, background, orgW, orgH));
0295 }
0296 
0297 void ShearTool::setPreviewImage()
0298 {
0299     ImageIface* const iface = d->previewWidget->imageIface();
0300     int w                   = iface->previewSize().width();
0301     int h                   = iface->previewSize().height();
0302     DImg imTemp             = filter()->getTargetImage().smoothScale(w, h, Qt::KeepAspectRatio);
0303     DImg imDest( w, h, filter()->getTargetImage().sixteenBit(), filter()->getTargetImage().hasAlpha() );
0304 
0305     imDest.fill( DColor(d->previewWidget->palette().color(QPalette::Window).rgb(),
0306                         filter()->getTargetImage().sixteenBit()) );
0307     imDest.bitBltImage(&imTemp, (w-imTemp.width())/2, (h-imTemp.height())/2);
0308 
0309     iface->setPreview(imDest.smoothScale(iface->previewSize()));
0310 
0311     d->previewWidget->updatePreview();
0312 
0313     ShearFilter* const tool = dynamic_cast<ShearFilter*>(filter());
0314 
0315     if (tool)
0316     {
0317         QSize newSize = tool->getNewSize();
0318         QString temp;
0319         d->newWidthLabel->setText(temp.setNum( newSize.width())   + i18n(" px") );
0320         d->newHeightLabel->setText(temp.setNum( newSize.height()) + i18n(" px") );
0321     }
0322 }
0323 
0324 void ShearTool::setFinalImage()
0325 {
0326     ImageIface iface;
0327     DImg targetImage = filter()->getTargetImage();
0328     iface.setOriginal(i18n("Shear Tool"), filter()->filterAction(), targetImage);
0329 }
0330 
0331 } // namespace DigikamEditorShearToolPlugin
0332 
0333 #include "moc_sheartool.cpp"