File indexing completed on 2025-01-05 03:51:28

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2009-02-28
0007  * Description : batch tool to add visible watermark.
0008  *
0009  * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2010      by Mikkel Baekhoej Christensen <mbc at baekhoej dot dk>
0011  * SPDX-FileCopyrightText: 2017      by Ahmed Fathi <ahmed dot fathi dot abdelmageed at gmail dot com>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #include "watermark.h"
0018 
0019 // Qt includes
0020 
0021 #include <QFontMetrics>
0022 #include <QLabel>
0023 #include <QPainter>
0024 #include <QPen>
0025 #include <QPoint>
0026 #include <QRect>
0027 #include <QWidget>
0028 #include <QGridLayout>
0029 #include <QRadioButton>
0030 #include <QCheckBox>
0031 #include <QGroupBox>
0032 #include <QApplication>
0033 #include <QStyle>
0034 #include <QFontComboBox>
0035 #include <QComboBox>
0036 #include <QDoubleSpinBox>
0037 #include <QRandomGenerator>
0038 
0039 // KDE includes
0040 
0041 #include <klocalizedstring.h>
0042 
0043 // Local includes
0044 
0045 #include "dlayoutbox.h"
0046 #include "dnuminput.h"
0047 #include "dfileselector.h"
0048 #include "digikam_debug.h"
0049 #include "dimg.h"
0050 #include "blurfilter.h"
0051 #include "dfontproperties.h"
0052 #include "metaengine.h"
0053 #include "dcolorselector.h"
0054 #include "dtextedit.h"
0055 
0056 namespace DigikamBqmWatermarkPlugin
0057 {
0058 
0059 class Q_DECL_HIDDEN WaterMark::Private
0060 {
0061 
0062 public:
0063 
0064     enum WaterMarkPositon
0065     {
0066         TopLeft = 0,
0067         TopRight,
0068         BottomLeft,
0069         BottomRight,
0070         Center,
0071         TopCenter,
0072         BottomCenter
0073     };
0074 
0075     enum WaterMarkPlacementType
0076     {
0077         SpecifiedLocation = 0,
0078         SystematicRepetition,
0079         RandomRepetition
0080     };
0081 
0082 public:
0083 
0084     explicit Private()
0085       : textSettingsGroupBox                      (nullptr),
0086         imageSettingsGroupBox                     (nullptr),
0087         useAbsoluteImageSizeGroupBox              (nullptr),
0088         useImageRadioButton                       (nullptr),
0089         ignoreWatermarkAspectCheckBox             (nullptr),
0090         addTransparencyToWatermarkImageCheckBox   (nullptr),
0091         useAbsoluteSizeCheckBox                   (nullptr),
0092         useBackgroundCheckBox                     (nullptr),
0093         denseRepetitionCheckBox                   (nullptr),
0094         randomizeRotationCheckBox                 (nullptr),
0095         useTextRadioButton                        (nullptr),
0096         imageFileUrlRequester                     (nullptr),
0097         textEdit                                  (nullptr),
0098         placementPositionComboBox                 (nullptr),
0099         placementTypeComboBox                     (nullptr),
0100         rotationComboBox                          (nullptr),
0101         sparsityFactorSpinBox                     (nullptr),
0102         extendedFontChooserWidget                 (nullptr),
0103         fontColorButton                           (nullptr),
0104         backgroundColorButton                     (nullptr),
0105         textOpacity                               (nullptr),
0106         backgroundOpacity                         (nullptr),
0107         xMarginInput                              (nullptr),
0108         yMarginInput                              (nullptr),
0109         waterMarkSizePercent                      (nullptr),
0110         waterMarkOpacityPercent                   (nullptr),
0111         changeSettings                            (true)
0112     {
0113     }
0114 
0115     QGroupBox*       textSettingsGroupBox;
0116     QGroupBox*       imageSettingsGroupBox;
0117     QGroupBox*       useAbsoluteImageSizeGroupBox ;
0118     QRadioButton*    useImageRadioButton;
0119     QCheckBox*       ignoreWatermarkAspectCheckBox;
0120     QCheckBox*       addTransparencyToWatermarkImageCheckBox;
0121     QCheckBox*       useAbsoluteSizeCheckBox;
0122     QCheckBox*       useBackgroundCheckBox;
0123     QCheckBox*       denseRepetitionCheckBox;
0124     QCheckBox*       randomizeRotationCheckBox;
0125     QRadioButton*    useTextRadioButton;
0126 
0127     DFileSelector*   imageFileUrlRequester;
0128     DTextEdit*       textEdit;
0129 
0130     QComboBox*       placementPositionComboBox;
0131     QComboBox*       placementTypeComboBox;
0132     QComboBox*       rotationComboBox;
0133     QDoubleSpinBox*  sparsityFactorSpinBox;
0134     DFontProperties* extendedFontChooserWidget;
0135 
0136     DColorSelector*  fontColorButton;
0137     DColorSelector*  backgroundColorButton;
0138 
0139     DIntNumInput*    textOpacity;
0140     DIntNumInput*    backgroundOpacity;
0141     DIntNumInput*    xMarginInput;
0142     DIntNumInput*    yMarginInput;
0143     DIntNumInput*    waterMarkSizePercent;
0144     DIntNumInput*    waterMarkOpacityPercent;
0145 
0146     bool             changeSettings;
0147 };
0148 
0149 WaterMark::WaterMark(QObject* const parent)
0150     : BatchTool(QLatin1String("WaterMark"), DecorateTool, parent),
0151       d        (new Private)
0152 {
0153 }
0154 
0155 WaterMark::~WaterMark()
0156 {
0157     delete d;
0158 }
0159 
0160 BatchTool* WaterMark::clone(QObject* const parent) const
0161 {
0162     return new WaterMark(parent);
0163 }
0164 
0165 void WaterMark::registerSettingsWidget()
0166 {
0167     const int spacing = qMin(QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing),
0168                              QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing));
0169 
0170     DVBox* const vbox = new DVBox;
0171     vbox->setContentsMargins(spacing, spacing, spacing, spacing);
0172     vbox->setSpacing(spacing);
0173 
0174     DHBox* const hbox = new DHBox(vbox);
0175     hbox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
0176     hbox->setSpacing(spacing);
0177 
0178     d->useAbsoluteImageSizeGroupBox                       = new QGroupBox(vbox);
0179     QVBoxLayout* const useAbsoluteImageSizeGroupBoxLayout = new QVBoxLayout;
0180     useAbsoluteImageSizeGroupBoxLayout->setContentsMargins(spacing, spacing, spacing, spacing);
0181     useAbsoluteImageSizeGroupBoxLayout->addStretch(1);
0182     d->useAbsoluteImageSizeGroupBox->setLayout(useAbsoluteImageSizeGroupBoxLayout);
0183 
0184     DHBox* const useAbsoluteSizeHBox   = new DHBox();
0185     useAbsoluteSizeHBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
0186     useAbsoluteSizeHBox->setSpacing(spacing);
0187     d->useAbsoluteSizeCheckBox         = new QCheckBox(useAbsoluteSizeHBox);
0188     d->useAbsoluteSizeCheckBox->setWhatsThis(i18n("Check this if you want the watermark to use the given size of "
0189                                                   "the font or the image without any adjustment to the actual image."));
0190     QLabel* const useAbsoluteSizeLabel = new QLabel(useAbsoluteSizeHBox);
0191     useAbsoluteSizeLabel->setText(i18n("Use Absolute Size"));
0192     d->useAbsoluteSizeCheckBox->setChecked(false);
0193 
0194     useAbsoluteImageSizeGroupBoxLayout->addWidget(useAbsoluteSizeHBox);
0195 
0196     QLabel* const watermarkTypeLabel   = new QLabel(hbox);
0197     watermarkTypeLabel->setText(i18n("Watermark type: "));
0198 
0199     d->useImageRadioButton      = new QRadioButton(hbox);
0200     d->useImageRadioButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
0201     QLabel* const useImageLabel = new QLabel(hbox);
0202     useImageLabel ->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
0203     d->useTextRadioButton       = new QRadioButton(hbox);
0204     d->useTextRadioButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
0205     QLabel* const useTextLabel  = new QLabel(hbox);
0206     useTextLabel ->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
0207     useImageLabel->setText(i18n("Image"));
0208     useTextLabel->setText(i18n("Text"));
0209 
0210     useImageLabel->setAlignment(Qt::AlignLeft);
0211     useTextLabel->setAlignment(Qt::AlignLeft);
0212     d->useImageRadioButton->setChecked(true);
0213 
0214     // ---
0215 
0216     d->imageSettingsGroupBox                       = new QGroupBox(vbox);
0217     d->imageSettingsGroupBox->setTitle(i18n("Image settings"));
0218     QVBoxLayout* const imageSettingsGroupBoxLayout = new QVBoxLayout;
0219     imageSettingsGroupBoxLayout->setContentsMargins(spacing, spacing, spacing, spacing);
0220     imageSettingsGroupBoxLayout->addStretch(1);
0221     d->imageSettingsGroupBox->setLayout(imageSettingsGroupBoxLayout);
0222 
0223     DHBox* const imageSelectHBox = new DHBox();
0224     QLabel* const label          = new QLabel(imageSelectHBox);
0225     d->imageFileUrlRequester     = new DFileSelector(imageSelectHBox);
0226     d->imageFileUrlRequester->lineEdit()->setPlaceholderText(i18n("Click to select watermark image."));
0227     label->setText(i18n("Watermark image: "));
0228     imageSettingsGroupBoxLayout->addWidget(imageSelectHBox);
0229 
0230     DHBox* const ignoreWatermarkAspectRatioHBox   = new DHBox();
0231     ignoreWatermarkAspectRatioHBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
0232     ignoreWatermarkAspectRatioHBox->setSpacing(spacing);
0233 
0234     d->ignoreWatermarkAspectCheckBox              = new QCheckBox(ignoreWatermarkAspectRatioHBox);
0235     d->ignoreWatermarkAspectCheckBox->setWhatsThis(i18n("Check this if you want the watermark to ignore its own "
0236                                                         "aspect ratio and use the image's aspect ratio instead."));
0237 
0238     QLabel* const ignoreWatermarkAspectRatioLabel = new QLabel(ignoreWatermarkAspectRatioHBox);
0239     ignoreWatermarkAspectRatioLabel->setText(i18n("Ignore Watermark aspect Ratio"));
0240     d->ignoreWatermarkAspectCheckBox->setChecked(false);
0241     imageSettingsGroupBoxLayout->addWidget(ignoreWatermarkAspectRatioHBox);
0242 
0243     DHBox* const addTransparencyToWatermarkImageHBox = new DHBox();
0244     addTransparencyToWatermarkImageHBox->setContentsMargins(QMargins());
0245     addTransparencyToWatermarkImageHBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
0246     addTransparencyToWatermarkImageHBox->setSpacing(spacing);
0247 
0248     d->addTransparencyToWatermarkImageCheckBox       = new QCheckBox(addTransparencyToWatermarkImageHBox);
0249     d->addTransparencyToWatermarkImageCheckBox->setWhatsThis(i18n("Check this if you want watermark to be transparent."));
0250     d->addTransparencyToWatermarkImageCheckBox->setChecked(false);
0251 
0252     QLabel* const addTransparencyToWatermarkLabel    = new QLabel(addTransparencyToWatermarkImageHBox);
0253     addTransparencyToWatermarkLabel->setText(i18n("Add transparency to watermark image"));
0254     imageSettingsGroupBoxLayout->addWidget(addTransparencyToWatermarkImageHBox);
0255 
0256     DHBox* const watermarkImageOpacityBox = new DHBox();
0257     watermarkImageOpacityBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
0258     watermarkImageOpacityBox->setSpacing(spacing);
0259 
0260     QLabel* const opacityLabel            = new QLabel(watermarkImageOpacityBox);
0261     d->waterMarkOpacityPercent            = new DIntNumInput(watermarkImageOpacityBox);
0262     d->waterMarkOpacityPercent->setRange(0, 100, 1);
0263     d->waterMarkOpacityPercent->setDefaultValue(100);
0264     d->waterMarkOpacityPercent->setWhatsThis(i18n("Opacity of watermark"));
0265     opacityLabel->setText(i18n("Opacity (%): "));
0266     imageSettingsGroupBoxLayout->addWidget(watermarkImageOpacityBox);
0267  
0268     // ---
0269 
0270     d->textSettingsGroupBox                       = new QGroupBox(vbox);
0271     d->textSettingsGroupBox->setTitle(i18n("Text settings"));
0272     QVBoxLayout* const textSettingsGroupBoxLayout = new QVBoxLayout;
0273     textSettingsGroupBoxLayout->setContentsMargins(spacing, spacing, spacing, spacing);
0274     textSettingsGroupBoxLayout->addStretch(1);
0275     d->textSettingsGroupBox->setLayout(textSettingsGroupBoxLayout);
0276 
0277     QLabel* const textEditLabel = new QLabel(vbox);
0278     d->textEdit                 = new DTextEdit(vbox);
0279     d->textEdit->setPlaceholderText(i18n("Enter your watermark string here."));
0280     textEditLabel->setText(i18n("Watermark text: "));
0281     textSettingsGroupBoxLayout->addWidget(textEditLabel);
0282     textSettingsGroupBoxLayout->addWidget(d->textEdit);
0283 
0284     d->extendedFontChooserWidget = new DFontProperties(nullptr, DFontProperties::NoDisplayFlags);
0285     d->extendedFontChooserWidget->setSampleBoxVisible(true);
0286     d->extendedFontChooserWidget->enableColumn(0x04, false);
0287     d->extendedFontChooserWidget->setWhatsThis(i18n("Choose the font type and style. Size is auto calculated."));
0288     textSettingsGroupBoxLayout->addWidget(d->extendedFontChooserWidget);
0289 
0290     DHBox* const fontColorBox = new DHBox();
0291     QLabel* const label3 = new QLabel(fontColorBox);
0292     d->fontColorButton   = new DColorSelector(fontColorBox);
0293     d->fontColorButton->setColor(Qt::black);
0294     d->fontColorButton->setWhatsThis(i18n("Set the font color to use here."));
0295     label3->setText(i18n("Font color: "));
0296     textSettingsGroupBoxLayout->addWidget(fontColorBox);
0297 
0298     DHBox* const fontOpacityBox    = new DHBox();
0299     QLabel* const textOpacityLabel = new QLabel(fontOpacityBox);
0300     textOpacityLabel->setText(i18n("Text opacity: "));
0301     d->textOpacity                 = new DIntNumInput(fontOpacityBox);
0302     d->textOpacity->setRange(0, 100, 1);
0303     d->textOpacity->setDefaultValue(100);
0304     d->textOpacity->setWhatsThis(i18n("Set the opacity of the watermark text. "
0305                                       "100 is fully opaque, 0 is fully transparent."));
0306     textSettingsGroupBoxLayout->addWidget(fontOpacityBox);
0307 
0308     DHBox* const useBackgroundHBox   = new DHBox();
0309     useBackgroundHBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
0310     useBackgroundHBox->setSpacing(spacing);
0311 
0312     d->useBackgroundCheckBox         = new QCheckBox(useBackgroundHBox);
0313     d->useBackgroundCheckBox->setWhatsThis(i18n("Check this if you want a background fill behind the text."));
0314     QLabel* const useBackgroundLabel = new QLabel(useBackgroundHBox);
0315     useBackgroundLabel->setText(i18n("Use background"));
0316     textSettingsGroupBoxLayout->addWidget(useBackgroundHBox);
0317 
0318     DHBox* const useBackgroundColorHBox = new DHBox();
0319     QLabel* const backgroundColorLabel  = new QLabel(useBackgroundColorHBox);
0320     d->backgroundColorButton            = new DColorSelector(useBackgroundColorHBox);
0321     d->backgroundColorButton->setColor(QColor(0xCC, 0xCC, 0xCC));
0322     d->backgroundColorButton->setWhatsThis(i18n("Choose the color of the watermark background."));
0323     backgroundColorLabel ->setText(i18n("Background color: "));
0324     textSettingsGroupBoxLayout->addWidget(useBackgroundColorHBox);
0325 
0326     DHBox* const useBackgroundOpacityHBox  = new DHBox();
0327     QLabel* const backgroundOpacityLabel   = new QLabel(useBackgroundOpacityHBox);
0328     backgroundOpacityLabel->setText(i18n("Background opacity: "));
0329     d->backgroundOpacity                   = new DIntNumInput(useBackgroundOpacityHBox);
0330     d->backgroundOpacity->setRange(0, 100, 1);
0331     d->backgroundOpacity->setDefaultValue(100);
0332     d->backgroundOpacity->setWhatsThis(i18n("Set the opacity of the watermark background. "
0333                                             "100 is fully opaque, 0 is fully transparent."));
0334     textSettingsGroupBoxLayout->addWidget(useBackgroundOpacityHBox);
0335 
0336     d->imageSettingsGroupBox->setVisible(true);
0337     d->textSettingsGroupBox->setVisible(false);
0338 
0339     // ---
0340 
0341     DHBox* const placementTypeHBox = new DHBox(vbox);
0342     QLabel* const placementTypeLabel = new QLabel(placementTypeHBox);
0343     d->placementTypeComboBox         = new QComboBox(placementTypeHBox);
0344     d->placementTypeComboBox->insertItem(Private::SpecifiedLocation,    i18n("Specific Location"));
0345     d->placementTypeComboBox->insertItem(Private::SystematicRepetition, i18n("Systematic Repetition"));
0346     d->placementTypeComboBox->insertItem(Private::RandomRepetition,     i18n("Random Repetition"));
0347     placementTypeLabel->setText(i18n("Placement Type: "));
0348 
0349     DHBox* const placementHBox = new DHBox(vbox);
0350     placementHBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
0351     placementHBox->setSpacing(spacing);
0352 
0353     QLabel* const spaceLabel   = new QLabel(placementHBox);
0354     d->denseRepetitionCheckBox = new QCheckBox(placementHBox);
0355     d->denseRepetitionCheckBox->setWhatsThis(i18n("When you choose to have the watermark repeated many times in the "
0356                                                   "placement combo box, you can specify here whether the repetition."));
0357     d->denseRepetitionCheckBox->setChecked(false);
0358     d->denseRepetitionCheckBox->setEnabled(false);
0359     spaceLabel->setText(QLatin1String(" "));
0360     QLabel* const placementDensityLabel = new QLabel(placementHBox);
0361     placementDensityLabel->setText(i18n("Density of watermark repetition (Disabled in \"Specific Location\" mode)"));
0362 
0363     DHBox* const randomizeHBox          = new DHBox(vbox);
0364     randomizeHBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
0365     randomizeHBox->setSpacing(spacing);
0366 
0367     QLabel* const spaceLabel2           = new QLabel(randomizeHBox);
0368     d->randomizeRotationCheckBox        = new QCheckBox(randomizeHBox);
0369     d->randomizeRotationCheckBox->setWhatsThis(i18n("When you choose to have the watermark repeated randomly in "
0370                                                     "the placement combo box, you can specify here to randomly "
0371                                                     "rotate the watermark (0, 90, 180, 270 degrees)."));
0372     d->randomizeRotationCheckBox->setChecked(true);
0373     d->denseRepetitionCheckBox->setEnabled(false);
0374     spaceLabel2->setText(QLatin1String(" "));
0375     QLabel* const randomizeRotation   = new QLabel(randomizeHBox);
0376     randomizeRotation->setText(i18n("Randomize watermark orientation (Enabled in \"Random Repetition\" mode only)"));
0377 
0378     DHBox* const sparsityHBox         = new DHBox(vbox);
0379     sparsityHBox->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
0380     sparsityHBox->setSpacing(spacing);
0381 
0382     QLabel* const sparsityFactorLabel = new QLabel(sparsityHBox);
0383     d->sparsityFactorSpinBox          = new QDoubleSpinBox(sparsityHBox);
0384     d->sparsityFactorSpinBox->setMinimum(0.0);
0385     d->sparsityFactorSpinBox->setValue(1);
0386     d->sparsityFactorSpinBox->setSingleStep(0.1);
0387     d->sparsityFactorSpinBox->setWhatsThis(i18n("Use this to get more control over the sparsity of watermark "
0388                                            "repetition. The higher the value the sparser the watermarks get. "
0389                                            "Use floating point values, typically between 1.0 and 3.0. It can "
0390                                            "also be less than 1.0"));
0391     sparsityFactorLabel->setText(i18n("Sparsity Factor: "));
0392 
0393     DHBox* const placementPositionHBox = new DHBox(vbox);
0394     QLabel* const label4         = new QLabel(placementPositionHBox);
0395     d->placementPositionComboBox = new QComboBox(placementPositionHBox);
0396     d->placementPositionComboBox->insertItem(Private::TopLeft,      i18nc("@item: placement position", "Top left"));
0397     d->placementPositionComboBox->insertItem(Private::TopRight,     i18nc("@item: placement position", "Top right"));
0398     d->placementPositionComboBox->insertItem(Private::BottomLeft,   i18nc("@item: placement position", "Bottom left"));
0399     d->placementPositionComboBox->insertItem(Private::BottomRight,  i18nc("@item: placement position", "Bottom right"));
0400     d->placementPositionComboBox->insertItem(Private::Center,       i18nc("@item: placement position", "Center"));
0401     d->placementPositionComboBox->insertItem(Private::TopCenter,    i18nc("@item: placement position", "Top center"));
0402     d->placementPositionComboBox->insertItem(Private::BottomCenter, i18nc("@item: placement position", "Bottom center"));
0403 
0404     label4->setText(i18n("Placement Position: "));
0405 
0406     DHBox* const placementRotationHBox = new DHBox(vbox);
0407     QLabel* const labelRotation  = new QLabel(placementRotationHBox);
0408     d->rotationComboBox          = new QComboBox(placementRotationHBox);
0409     d->rotationComboBox->insertItem(0, i18n("0 degrees"));
0410     d->rotationComboBox->insertItem(1, i18n("90 degrees CW"));
0411     d->rotationComboBox->insertItem(2, i18n("180 degrees"));
0412     d->rotationComboBox->insertItem(3, i18n("270 degrees CW"));
0413     labelRotation->setText(i18n("Rotation: "));
0414 
0415     DHBox* const placementSizeHBox = new DHBox(vbox);
0416     QLabel* const label5    = new QLabel(placementSizeHBox);
0417     d->waterMarkSizePercent = new DIntNumInput(placementSizeHBox);
0418     d->waterMarkSizePercent->setRange(0, 100, 1);
0419     d->waterMarkSizePercent->setDefaultValue(30);
0420     d->waterMarkSizePercent->setWhatsThis(i18n("Size of watermark, as a percentage of the marked image."));
0421     label5->setText(i18n("Size (%): "));
0422 
0423     DHBox* const placementXMarginHBox = new DHBox(vbox);
0424     QLabel* const label6 = new QLabel(placementXMarginHBox);
0425     d->xMarginInput      = new DIntNumInput(placementXMarginHBox);
0426     d->xMarginInput->setRange(0, 100, 1);
0427     d->xMarginInput->setDefaultValue(2);
0428     d->xMarginInput->setWhatsThis(i18n("Margin from edge in X direction, as a percentage of the marked image."));
0429     label6->setText(i18n("X margin (%): "));
0430 
0431     DHBox* const placementYMarginHBox = new DHBox(vbox);
0432     QLabel* const label7 = new QLabel(placementYMarginHBox);
0433     d->yMarginInput      = new DIntNumInput(placementYMarginHBox);
0434     d->yMarginInput->setRange(0, 100, 1);
0435     d->yMarginInput->setDefaultValue(2);
0436     d->yMarginInput->setWhatsThis(i18n("Margin from edge in Y direction, as a percentage of the marked image."));
0437     label7->setText(i18n("Y margin (%): "));
0438 
0439     QLabel* const space = new QLabel(vbox);
0440     vbox->setStretchFactor(space, 10);
0441 
0442     m_settingsWidget    = vbox;
0443 
0444     // ------------------------------------------------------------------------------------------------------
0445 
0446     connect(d->useImageRadioButton, SIGNAL(toggled(bool)),
0447             this, SLOT(slotSettingsChanged()));
0448 
0449     connect(d->useTextRadioButton, SIGNAL(toggled(bool)),
0450             this, SLOT(slotSettingsChanged()));
0451 
0452     connect(d->imageFileUrlRequester->lineEdit(), SIGNAL(textChanged(QString)),
0453             this, SLOT(slotSettingsChanged()));
0454 
0455     connect(d->extendedFontChooserWidget, SIGNAL(fontSelected(QFont)),
0456             this, SLOT(slotSettingsChanged()));
0457 
0458     connect(d->fontColorButton, SIGNAL(signalColorSelected(QColor)),
0459             this, SLOT(slotSettingsChanged()));
0460 
0461     connect(d->textEdit, SIGNAL(textChanged()),
0462             this, SLOT(slotSettingsChanged()));
0463 
0464     connect(d->textOpacity, SIGNAL(valueChanged(int)),
0465             this, SLOT(slotSettingsChanged()));
0466 
0467     connect(d->useBackgroundCheckBox, SIGNAL(toggled(bool)),
0468             this, SLOT(slotSettingsChanged()));
0469 
0470     connect(d->ignoreWatermarkAspectCheckBox, SIGNAL(toggled(bool)),
0471             this, SLOT(slotSettingsChanged()));
0472 
0473     connect(d->addTransparencyToWatermarkImageCheckBox, SIGNAL(toggled(bool)),
0474             this, SLOT(slotSettingsChanged()));
0475 
0476     connect(d->useAbsoluteSizeCheckBox, SIGNAL(toggled(bool)),
0477             this, SLOT(slotSettingsChanged()));
0478 
0479     connect(d->backgroundColorButton, SIGNAL(signalColorSelected(QColor)),
0480             this, SLOT(slotSettingsChanged()));
0481 
0482     connect(d->backgroundOpacity, SIGNAL(valueChanged(int)),
0483             this, SLOT(slotSettingsChanged()));
0484 
0485     connect(d->placementTypeComboBox, SIGNAL(activated(int)),
0486             this, SLOT(slotSettingsChanged()));
0487 
0488     connect(d->placementPositionComboBox, SIGNAL(activated(int)),
0489             this, SLOT(slotSettingsChanged()));
0490 
0491     connect(d->denseRepetitionCheckBox, SIGNAL(toggled(bool)),
0492             this, SLOT(slotSettingsChanged()));
0493 
0494     connect(d->randomizeRotationCheckBox, SIGNAL(toggled(bool)),
0495             this, SLOT(slotSettingsChanged()));
0496 
0497     connect(d->sparsityFactorSpinBox, SIGNAL(valueChanged(double)),
0498             this, SLOT(slotSettingsChanged()));
0499 
0500     connect(d->rotationComboBox, SIGNAL(activated(int)),
0501             this, SLOT(slotSettingsChanged()));
0502 
0503     connect(d->waterMarkSizePercent, SIGNAL(valueChanged(int)),
0504             this, SLOT(slotSettingsChanged()));
0505 
0506     connect(d->yMarginInput, SIGNAL(valueChanged(int)),
0507             this, SLOT(slotSettingsChanged()));
0508 
0509     connect(d->xMarginInput, SIGNAL(valueChanged(int)),
0510             this, SLOT(slotSettingsChanged()));
0511 
0512     connect(d->waterMarkOpacityPercent, SIGNAL(valueChanged(int)),
0513             this, SLOT(slotSettingsChanged()));
0514 
0515     BatchTool::registerSettingsWidget();
0516 }
0517 
0518 BatchToolSettings WaterMark::defaultSettings()
0519 {
0520     BatchToolSettings settings;
0521 
0522     settings.insert(QLatin1String("Use image"),          true);
0523     settings.insert(QLatin1String("Watermark image"),    QString());
0524     settings.insert(QLatin1String("Text"),               QString());
0525     settings.insert(QLatin1String("Font"),               QFont());
0526     settings.insert(QLatin1String("Color"),              QColor(Qt::black));
0527     settings.insert(QLatin1String("Text opacity"),       100);
0528     settings.insert(QLatin1String("Use background"),     true);
0529     settings.insert(QLatin1String("Background color"),   QColor(0xCC, 0xCC, 0xCC));
0530     settings.insert(QLatin1String("Background opacity"), 0xCC);
0531     settings.insert(QLatin1String("PlacementType"),      Private::SpecifiedLocation); // specified location for the watermark
0532     settings.insert(QLatin1String("Dense Repetition"),   false);
0533     settings.insert(QLatin1String("Randomize Rotation"), true);
0534     settings.insert(QLatin1String("Sparsity Factor"),    1.0);
0535     settings.insert(QLatin1String("Placement"),          Private::BottomRight);
0536     settings.insert(QLatin1String("Rotation"),           0);
0537     settings.insert(QLatin1String("Watermark size"),     25);
0538     settings.insert(QLatin1String("X margin"),           2);
0539     settings.insert(QLatin1String("Y margin"),           2);
0540     settings.insert(QLatin1String("Opacity"),            100);
0541 
0542     return settings;
0543 }
0544 
0545 void WaterMark::slotAssignSettings2Widget()
0546 {
0547     d->changeSettings = false;
0548     d->useImageRadioButton->setChecked(settings()[QLatin1String("Use image")].toBool());
0549     d->useTextRadioButton->setChecked(!settings()[QLatin1String("Use image")].toBool());
0550     d->imageFileUrlRequester->setFileDlgPath(settings()[QLatin1String("Watermark image")].toString());
0551 
0552     QString txt       = settings()[QLatin1String("Text")].toString();
0553 
0554     if (d->textEdit->text() != txt)
0555     {
0556         d->textEdit->setText(txt);
0557     }
0558 
0559     d->extendedFontChooserWidget->setFont(qvariant_cast<QFont>(settings()[QLatin1String("Font")]));
0560     d->fontColorButton->setColor(settings()[QLatin1String("Color")].toString());
0561     d->textOpacity->setValue(settings()[QLatin1String("Text opacity")].toInt());
0562     d->useBackgroundCheckBox->setChecked(settings()[QLatin1String("Use background")].toBool());
0563     d->backgroundColorButton->setColor(settings()[QLatin1String("Background color")].toString());
0564     d->backgroundOpacity->setValue(settings()[QLatin1String("Background opacity")].toInt());
0565     d->placementPositionComboBox->setCurrentIndex(settings()[QLatin1String("PlacementType")].toInt());
0566     d->denseRepetitionCheckBox->setChecked(settings()[QLatin1String("Dense Repetition")].toBool());
0567     d->randomizeRotationCheckBox->setChecked(settings()[QLatin1String("Randomize Rotation")].toBool());
0568     d->sparsityFactorSpinBox->setValue(settings()[QLatin1String("Sparsity Factor")].toDouble());
0569     d->placementPositionComboBox->setCurrentIndex(settings()[QLatin1String("Placement")].toInt());
0570     d->rotationComboBox->setCurrentIndex(settings()[QLatin1String("Rotation")].toInt());
0571     d->waterMarkSizePercent->setValue(settings()[QLatin1String("Watermark size")].toInt());
0572     d->xMarginInput->setValue(settings()[QLatin1String("X margin")].toInt());
0573     d->yMarginInput->setValue(settings()[QLatin1String("Y margin")].toInt());
0574     d->waterMarkOpacityPercent->setValue(settings()[QLatin1String("Opacity")].toInt());
0575     d->changeSettings = true;
0576 }
0577 
0578 void WaterMark::slotSettingsChanged()
0579 {
0580     if      (d->useImageRadioButton->isChecked())
0581     {
0582         d->textSettingsGroupBox->setVisible(false);
0583         d->imageSettingsGroupBox->setVisible(true);
0584     }
0585     else if (d->useTextRadioButton->isChecked())
0586     {
0587         d->imageSettingsGroupBox->setVisible(false);
0588         d->textSettingsGroupBox->setVisible(true);
0589     }
0590 
0591     d->waterMarkSizePercent->setEnabled(!d->useAbsoluteSizeCheckBox->isChecked());
0592     d->extendedFontChooserWidget->enableColumn(0x04, d->useAbsoluteSizeCheckBox->isChecked());
0593     d->placementPositionComboBox->setEnabled(((int)d->placementTypeComboBox->currentIndex() == Private::SpecifiedLocation));
0594     d->denseRepetitionCheckBox->setEnabled(((int)d->placementTypeComboBox->currentIndex() != Private::SpecifiedLocation));
0595     d->sparsityFactorSpinBox->setEnabled(((int)d->placementTypeComboBox->currentIndex() != Private::SpecifiedLocation));
0596     d->randomizeRotationCheckBox->setEnabled(((int)d->placementTypeComboBox->currentIndex() == Private::RandomRepetition));
0597     d->rotationComboBox->setEnabled(!(d->randomizeRotationCheckBox->isEnabled() && d->randomizeRotationCheckBox->isChecked()));
0598     d->waterMarkOpacityPercent->setEnabled(d->addTransparencyToWatermarkImageCheckBox->isChecked());
0599 
0600     if (d->changeSettings)
0601     {
0602         BatchToolSettings settings;
0603         settings.insert(QLatin1String("Use image"),                     d->useImageRadioButton->isChecked());
0604         settings.insert(QLatin1String("Watermark image"),               d->imageFileUrlRequester->fileDlgPath());
0605         settings.insert(QLatin1String("Text"),                          d->textEdit->text());
0606         settings.insert(QLatin1String("Font"),                          d->extendedFontChooserWidget->font());
0607         settings.insert(QLatin1String("Color"),                         d->fontColorButton->color());
0608         settings.insert(QLatin1String("Text opacity"),                  d->textOpacity->value());
0609         settings.insert(QLatin1String("Use background"),                d->useBackgroundCheckBox->isChecked());
0610         settings.insert(QLatin1String("Ignore Watermark Aspect Ratio"), d->ignoreWatermarkAspectCheckBox->isChecked());
0611         settings.insert(QLatin1String("Use Absolute Size"),             d->useAbsoluteSizeCheckBox->isChecked());
0612         settings.insert(QLatin1String("Background color"),              d->backgroundColorButton->color());
0613         settings.insert(QLatin1String("Background opacity"),            d->backgroundOpacity->value());
0614         settings.insert(QLatin1String("Dense Repetition"),              d->denseRepetitionCheckBox->isChecked());
0615         settings.insert(QLatin1String("Randomize Rotation"),            d->randomizeRotationCheckBox->isChecked());
0616         settings.insert(QLatin1String("Sparsity Factor"),               (double)d->sparsityFactorSpinBox->value());
0617         settings.insert(QLatin1String("PlacementType"),                 (int)d->placementTypeComboBox->currentIndex());
0618         settings.insert(QLatin1String("Placement"),                     (int)d->placementPositionComboBox->currentIndex());
0619         settings.insert(QLatin1String("Rotation"),                      (int)d->rotationComboBox->currentIndex());
0620         settings.insert(QLatin1String("Watermark size"),                (int)d->waterMarkSizePercent->value());
0621         settings.insert(QLatin1String("X margin"),                      (int)d->xMarginInput->value());
0622         settings.insert(QLatin1String("Y margin"),                      (int)d->yMarginInput->value());
0623         settings.insert(QLatin1String("Opacity"),                       (int)d->waterMarkOpacityPercent->value());
0624         settings.insert(QLatin1String("Add transparency"),              d->addTransparencyToWatermarkImageCheckBox->isChecked());
0625         BatchTool::slotSettingsChanged(settings);
0626     }
0627 }
0628 
0629 bool WaterMark::toolOperations()
0630 {
0631     if (!loadToDImg())
0632     {
0633         return false;
0634     }
0635 
0636     QString fileName                             = settings()[QLatin1String("Watermark image")].toString();
0637     int placementPosition                        = settings()[QLatin1String("Placement")].toInt();
0638     int placementType                            = settings()[QLatin1String("PlacementType")].toInt();
0639     bool denseRepetition                         = settings()[QLatin1String("Dense Repetition")].toBool();
0640     bool randomizeRotation                       = settings()[QLatin1String("Randomize Rotation")].toBool();
0641     double userSparsityFactor                    = settings()[QLatin1String("Sparsity Factor")].toDouble();
0642     int size                                     = settings()[QLatin1String("Watermark size")].toInt();
0643     int xMargin                                  = settings()[QLatin1String("X margin")].toInt();
0644     int yMargin                                  = settings()[QLatin1String("Y margin")].toInt();
0645     bool useImage                                = settings()[QLatin1String("Use image")].toBool();
0646     QString text                                 = settings()[QLatin1String("Text")].toString();
0647     QFont font                                   = qvariant_cast<QFont>(settings()[QLatin1String("Font")]);
0648 
0649     QColor fontColor                             = settings()[QLatin1String("Color")].toString();
0650     int textOpacity                              = settings()[QLatin1String("Text opacity")].toInt();
0651     bool useBackground                           = settings()[QLatin1String("Use background")].toBool();
0652     QColor backgroundColor                       = settings()[QLatin1String("Background color")].toString();
0653     int backgroundOpacity                        = settings()[QLatin1String("Background opacity")].toInt();
0654     Qt::AspectRatioMode watermarkAspectRatioMode = settings()[QLatin1String("Ignore Watermark Aspect Ratio")].toBool() ?
0655                                                               Qt::IgnoreAspectRatio : Qt::KeepAspectRatio;
0656     bool useAbsoluteSize                         = settings()[QLatin1String("Use Absolute Size")].toBool();
0657 
0658     DImg watermarkImage;
0659     DColorComposer* const composer               = DColorComposer::getComposer(DColorComposer::PorterDuffNone);
0660     int marginW                                  = lround(image().width()  * (xMargin / 100.0));
0661     int marginH                                  = lround(image().height() * (yMargin / 100.0));
0662     int rotationIndex = settings()[QLatin1String("Rotation")].toInt();
0663     double opacity                               = settings()[QLatin1String("Opacity")].toInt()/100.0;
0664     bool addTransparency                         = settings()[QLatin1String("Add transparency")].toBool();
0665 
0666     DImg::ANGLE rotationAngle = (rotationIndex == 1) ? DImg::ANGLE::ROT90 :
0667                                 (rotationIndex == 2) ? DImg::ANGLE::ROT180 :
0668                                 (rotationIndex == 3) ? DImg::ANGLE::ROT270 :
0669                                                        DImg::ANGLE::ROTNONE;
0670 
0671     // rotate and/or flip the image depending on the exif information to allow for the expected watermark placement.
0672     // note that this operation is reversed after proper watermark generation to leave everything as it was.
0673 
0674     image().exifRotate(inputUrl().toLocalFile());
0675 
0676     float ratio = (float)image().height() / image().width();
0677 
0678     if ((rotationAngle == DImg::ANGLE::ROT90) || (rotationAngle == DImg::ANGLE::ROT270))
0679     {
0680         size = size * ratio;
0681     }
0682     else
0683     {
0684         // For Images whose height are much larger than their width, this helps keep
0685         // the watermark size reasonable
0686 
0687         if (ratio > 1.5)
0688         {
0689             int tempSize  = size * ratio;
0690 
0691             if (tempSize < 35)
0692             {
0693                 tempSize *= 1.5;
0694             }
0695 
0696             size          = (tempSize < 100) ? tempSize : 100;
0697         }
0698     }
0699 
0700     if (useImage)
0701     {
0702         watermarkImage = DImg(fileName);
0703 
0704         if (watermarkImage.isNull())
0705         {
0706             return false;
0707         }
0708 
0709         if (!useAbsoluteSize)
0710         {
0711             DImg tempImage = watermarkImage.smoothScale(image().width()  * size / 100,
0712                                                         image().height() * size / 100,
0713                                                         watermarkAspectRatioMode);
0714             watermarkImage = tempImage;
0715         }
0716 
0717         if (addTransparency)
0718         {
0719             if (!watermarkImage.hasAlpha())
0720             {
0721                 return false;
0722             }
0723 
0724             for (uint i = 0 ; i < watermarkImage.width() ; ++i)
0725             {
0726                 for (uint j = 0 ; j < watermarkImage.height() ; ++j)
0727                 {
0728                     DColor color = watermarkImage.getPixelColor(i, j);
0729                     color.setAlpha((int)(opacity*color.alpha()));
0730                     watermarkImage.setPixelColor(i, j, color);
0731                 }
0732             }
0733         }
0734     }
0735     else
0736     {
0737         int alignMode;
0738         const int radius = 10;
0739 
0740         if (text.isEmpty())
0741         {
0742             return false;
0743         }
0744 
0745         int fontSize = queryFontSize(text, font, size);
0746 
0747         if (fontSize == 0)
0748         {
0749             return false;
0750         }
0751 
0752         switch (placementPosition)
0753         {
0754             case Private::TopLeft:
0755             {
0756                 alignMode = Qt::AlignLeft;
0757                 break;
0758             }
0759 
0760             case Private::TopRight:
0761             {
0762                 alignMode = Qt::AlignRight;
0763                 break;
0764             }
0765 
0766             case Private::BottomLeft:
0767             {
0768                 alignMode = Qt::AlignLeft;
0769                 break;
0770             }
0771 
0772             case Private::Center:
0773             case Private::TopCenter:
0774             case Private::BottomCenter:
0775             {
0776                 alignMode = Qt::AlignCenter;
0777                 break;
0778             }
0779 
0780             default:    // BottomRight
0781             {
0782                 alignMode = Qt::AlignRight;
0783                 break;
0784             }
0785         }
0786 
0787         if (!useAbsoluteSize)
0788         {
0789             font.setPointSizeF(fontSize);
0790         }
0791 
0792         QFontMetrics fontMt(font);
0793         QRect fontRect = fontMt.boundingRect(radius, radius, image().width(), image().height(), 0, text);
0794 
0795         // Add a transparent layer.
0796 
0797         QRect backgroundRect(fontRect.x() - radius, fontRect.y() - radius,
0798                              fontRect.width() + 2 * radius, fontRect.height() + 2 * radius);
0799         DImg backgroundLayer(backgroundRect.width(), backgroundRect.height(), image().sixteenBit(), true);
0800         DColor transparent(QColor(0, 0, 0));
0801         transparent.setAlpha(0);
0802 
0803         if (image().sixteenBit())
0804         {
0805             transparent.convertToSixteenBit();
0806         }
0807 
0808         backgroundLayer.fill(transparent);
0809 
0810         DImg grayTransLayer(fontRect.width(), fontRect.height(), image().sixteenBit(), true);
0811 
0812         if (useBackground)
0813         {
0814             DColor grayTrans(backgroundColor);
0815             grayTrans.setAlpha(backgroundOpacity * 255 / 100);
0816 
0817             if (image().sixteenBit())
0818             {
0819                 grayTrans.convertToSixteenBit();
0820             }
0821 
0822             grayTransLayer.fill(grayTrans);
0823             backgroundLayer.bitBlendImage(composer, &grayTransLayer, 0, 0,
0824                                           grayTransLayer.width(), grayTransLayer.height(),
0825                                           radius, radius);
0826         }
0827 
0828         BlurFilter blur(&backgroundLayer, nullptr, radius);
0829         blur.startFilterDirectly();
0830         backgroundLayer.putImageData(blur.getTargetImage().bits());
0831 
0832         // Draw text
0833 
0834         QImage img = backgroundLayer.copyQImage(fontRect);
0835         QPainter p(&img);
0836         fontColor.setAlpha(textOpacity * 255 / 100);
0837         p.setPen(QPen(fontColor, 1));
0838         p.setFont(font);
0839         p.save();
0840         p.drawText(0, 0, fontRect.width(), fontRect.height(), alignMode, text);
0841         p.restore();
0842         p.end();
0843 
0844         watermarkImage = DImg(img);
0845     }
0846 
0847     watermarkImage.convertToDepthOfImage(&image());
0848 
0849     QRect watermarkRect(0, 0, watermarkImage.width(), watermarkImage.height());
0850 
0851     int xAdditionalValue = 0;
0852     int yAdditionalValue = 0;
0853 
0854     watermarkImage.rotate(rotationAngle);
0855 
0856     if (placementType == Private::SpecifiedLocation)
0857     {
0858         switch (placementPosition)
0859         {
0860             case Private::TopLeft:
0861             {
0862                 watermarkRect.moveTopLeft(QPoint(marginW, marginH));
0863                 break;
0864             }
0865 
0866             case Private::TopRight:
0867             {
0868                 if ((rotationAngle == DImg::ANGLE::ROT270) || (rotationAngle == DImg::ANGLE::ROT90))
0869                 {
0870                     xAdditionalValue += watermarkRect.width() - watermarkRect.height();
0871                 }
0872 
0873                 watermarkRect.moveTopRight(QPoint(image().width() + xAdditionalValue - marginW - 1,
0874                                                   marginH));
0875                 break;
0876             }
0877 
0878             case Private::BottomLeft:
0879             {
0880                 if ((rotationAngle == DImg::ANGLE::ROT90) || (rotationAngle == DImg::ANGLE::ROT270))
0881                 {
0882                     yAdditionalValue += watermarkRect.height() - watermarkRect.width();
0883                 }
0884 
0885                 watermarkRect.moveBottomLeft(QPoint(marginW,
0886                                                     image().height() + yAdditionalValue - marginH - 1));
0887                 break;
0888             }
0889 
0890             case Private::Center:
0891             {
0892                 if ((rotationAngle == DImg::ANGLE::ROT90) || (rotationAngle == DImg::ANGLE::ROT270))
0893                 {
0894                     xAdditionalValue += (watermarkRect.width()  - watermarkRect.height()) / 2;
0895                     yAdditionalValue += (watermarkRect.height() - watermarkRect.width())  / 2;
0896                 }
0897 
0898                 watermarkRect.moveCenter(QPoint((int)(image().width()  / 2 + xAdditionalValue),
0899                                                 (int)(image().height() / 2 + yAdditionalValue)));
0900                 break;
0901             }
0902 
0903             case Private::TopCenter:
0904             {
0905                 if ((rotationAngle == DImg::ANGLE::ROT90) || (rotationAngle == DImg::ANGLE::ROT270))
0906                 {
0907                     xAdditionalValue += (watermarkRect.width() - watermarkRect.height()) / 2;
0908                 }
0909 
0910                 watermarkRect.moveCenter(QPoint((int)(image().width()   / 2  + xAdditionalValue),
0911                                                 (watermarkRect.height() / 2) + marginH));
0912                 break;
0913             }
0914 
0915             case Private::BottomCenter:
0916             {
0917                 if ((rotationAngle == DImg::ANGLE::ROT90) || (rotationAngle == DImg::ANGLE::ROT270))
0918                 {
0919                     xAdditionalValue += (watermarkRect.width() - watermarkRect.height()) / 2;
0920                     yAdditionalValue += watermarkRect.height() - watermarkRect.width();
0921                 }
0922 
0923                 watermarkRect.moveCenter(QPoint((int)(image().width()   / 2  + xAdditionalValue),
0924                                                 image().height() + yAdditionalValue -
0925                                                 (watermarkRect.height() / 2) - marginH - 1));
0926                 break;
0927             }
0928 
0929             default:    // BottomRight
0930             {
0931                 if ((rotationAngle == DImg::ANGLE::ROT90) || (rotationAngle == DImg::ANGLE::ROT270))
0932                 {
0933                     xAdditionalValue += watermarkRect.width()  - watermarkRect.height();
0934                     yAdditionalValue += watermarkRect.height() - watermarkRect.width();
0935                 }
0936 
0937                 watermarkRect.moveBottomRight(QPoint(image().width()  + xAdditionalValue - marginW - 1,
0938                                                      image().height() + yAdditionalValue - marginH - 1));
0939                 break;
0940             }
0941         }
0942 
0943         image().bitBlendImage(composer,
0944                               &watermarkImage, 0, 0, watermarkImage.width(), watermarkImage.height(),
0945                               watermarkRect.left(), watermarkRect.top());
0946     }
0947     else
0948     {
0949         const float DENSE_SPACING_FACTOR  = 1.2F;
0950         const float SPARSE_SPACING_FACTOR = 1.8F;
0951         float widthRatio                  = (float)watermarkRect.width()  / image().width();
0952         float heightRatio                 = (float)watermarkRect.height() / image().height();
0953         float spacingFactor               = (denseRepetition) ? DENSE_SPACING_FACTOR : SPARSE_SPACING_FACTOR;
0954         spacingFactor                    *= userSparsityFactor;
0955 
0956         if      (placementType == Private::SystematicRepetition)
0957         {
0958             if ((rotationAngle == DImg::ANGLE::ROT270) || (rotationAngle == DImg::ANGLE::ROT90))
0959             {
0960                 widthRatio  = (float)watermarkRect.height() / image().width();
0961                 heightRatio = (float)watermarkRect.width()  / image().height();
0962             }
0963 
0964             for (uint i = 0 ; i < image().width() ; i += spacingFactor * widthRatio * image().width())
0965             {
0966                 for (uint j = 0 ; j < image().height() ; j += spacingFactor * heightRatio * image().height())
0967                 {
0968                     image().bitBlendImage(composer, &watermarkImage, 0, 0, watermarkImage.width(), watermarkImage.height(), i, j);
0969                 }
0970             }
0971         }
0972         else if (placementType == Private::RandomRepetition)
0973         {
0974             widthRatio  = (widthRatio > heightRatio) ? widthRatio : heightRatio;
0975             heightRatio = widthRatio;
0976 
0977             auto randomGenerator = QRandomGenerator::global();
0978 
0979             for (uint i = 0 ; i < image().width() ; i += spacingFactor * widthRatio * image().width())
0980             {
0981                 for (uint j = 0 ; j < image().height() ; j += spacingFactor * heightRatio * image().height())
0982                 {
0983                     int number = (denseRepetition) ? 2 : 3;
0984 
0985                     if (randomGenerator->bounded(number) == 0)
0986                     {
0987                         if (randomizeRotation)
0988                         {
0989                             int x = randomGenerator->bounded(4);
0990                             watermarkImage.rotate((DImg::ANGLE)x);
0991                         }
0992 
0993                         image().bitBlendImage(composer, &watermarkImage, 0, 0, watermarkImage.width(), watermarkImage.height(), i, j);
0994                     }
0995                 }
0996             }
0997         }
0998     }
0999 
1000     // TODO: Create watermark filter, move code there, implement FilterAction
1001 
1002     delete composer;
1003     image().reverseExifRotate(inputUrl().toLocalFile());
1004 
1005     return (savefromDImg());
1006 }
1007 
1008 int WaterMark::queryFontSize(const QString& text, const QFont& font, int length) const
1009 {
1010     // Find font size using relative length compared to image width.
1011 
1012     QFont fnt = font;
1013     QRect fontRect;
1014 
1015     for (int i = 1 ; i <= 1000 ; ++i)
1016     {
1017         fnt.setPointSizeF(i);
1018         QFontMetrics fontMt(fnt);
1019         fontRect = fontMt.boundingRect(0, 0, image().width(), image().height(), 0, text);
1020 
1021         if (fontRect.width() > lround((image().width() * length) / 100.0))
1022         {
1023             return (i - 1);
1024         }
1025     }
1026 
1027     return 0;
1028 }
1029 
1030 } // namespace DigikamBqmWatermarkPlugin
1031 
1032 #include "moc_watermark.cpp"