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"