~ubuntu-branches/ubuntu/saucy/digikam/saucy

« back to all changes in this revision

Viewing changes to imageplugins/enhance/redeyetool.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Christian Mangold
  • Date: 2010-04-09 21:30:01 UTC
  • mfrom: (1.2.28 upstream)
  • Revision ID: james.westby@ubuntu.com-20100409213001-4bfyibrd359rn7o3
Tags: 2:1.2.0-0ubuntu1
* New upstream release (LP: #560576)
* Remove all patches, fixed upstream
  - Remove quilt build-depend

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ============================================================
 
2
 *
 
3
 * This file is a part of digiKam project
 
4
 * http://www.digikam.org
 
5
 *
 
6
 * Date        : 2004-06-06
 
7
 * Description : Red eyes correction tool for image editor
 
8
 *
 
9
 * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
 
10
 * Copyright (C) 2004-2010 by Gilles Caulier <caulier dot gilles at gmail dot com>
 
11
 *
 
12
 * This program is free software; you can redistribute it
 
13
 * and/or modify it under the terms of the GNU General
 
14
 * Public License as published by the Free Software Foundation;
 
15
 * either version 2, or (at your option)
 
16
 * any later version.
 
17
 *
 
18
 * This program is distributed in the hope that it will be useful,
 
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
21
 * GNU General Public License for more details.
 
22
 *
 
23
 * ============================================================ */
 
24
 
 
25
#include "redeyetool.moc"
 
26
 
 
27
// Qt includes
 
28
 
 
29
#include <QColor>
 
30
#include <QFrame>
 
31
#include <QGridLayout>
 
32
#include <QGroupBox>
 
33
#include <QHBoxLayout>
 
34
#include <QLabel>
 
35
#include <QPixmap>
 
36
#include <QPushButton>
 
37
#include <QToolButton>
 
38
 
 
39
// KDE includes
 
40
 
 
41
#include <kapplication.h>
 
42
#include <kcolordialog.h>
 
43
#include <kcolorvalueselector.h>
 
44
#include <kconfig.h>
 
45
#include <kconfiggroup.h>
 
46
#include <kcursor.h>
 
47
#include <kglobal.h>
 
48
#include <khuesaturationselect.h>
 
49
#include <kicon.h>
 
50
#include <kiconloader.h>
 
51
#include <klocale.h>
 
52
#include <kstandarddirs.h>
 
53
#include <kvbox.h>
 
54
 
 
55
// LibKDcraw includes
 
56
 
 
57
#include <libkdcraw/rnuminput.h>
 
58
 
 
59
// Local includes
 
60
 
 
61
#include "colorgradientwidget.h"
 
62
#include "dimg.h"
 
63
#include "blurfilter.h"
 
64
#include "editortoolsettings.h"
 
65
#include "histogramwidget.h"
 
66
#include "histogrambox.h"
 
67
#include "imageiface.h"
 
68
#include "imageguidewidget.h"
 
69
 
 
70
using namespace KDcrawIface;
 
71
 
 
72
namespace DigikamEnhanceImagePlugin
 
73
{
 
74
 
 
75
class RedEyeToolPriv
 
76
{
 
77
public:
 
78
 
 
79
    RedEyeToolPriv() :
 
80
        configGroupName("redeye Tool"),
 
81
        configHistogramChannelEntry("Histogram Channel"),
 
82
        configHistogramScaleEntry("Histogram Scale"),
 
83
        configRedThresholdEntry("RedThreshold"),
 
84
        configSmoothLevelEntry("SmoothLevel"),
 
85
        configHueColoringTintEntry("HueColoringTint"),
 
86
        configSatColoringTintEntry("SatColoringTint"),
 
87
        configValColoringTintEntry("ValColoringTint"),
 
88
        configTintLevelEntry("TintLevel"),
 
89
 
 
90
        destinationPreviewData(0),
 
91
        thresholdLabel(0),
 
92
        smoothLabel(0),
 
93
        HSSelector(0),
 
94
        VSelector(0),
 
95
        tintLevel(0),
 
96
        redThreshold(0),
 
97
        smoothLevel(0),
 
98
        previewWidget(0),
 
99
        gboxSettings(0)
 
100
        {}
 
101
 
 
102
    const QString           configGroupName;
 
103
    const QString           configHistogramChannelEntry;
 
104
    const QString           configHistogramScaleEntry;
 
105
    const QString           configRedThresholdEntry;
 
106
    const QString           configSmoothLevelEntry;
 
107
    const QString           configHueColoringTintEntry;
 
108
    const QString           configSatColoringTintEntry;
 
109
    const QString           configValColoringTintEntry;
 
110
    const QString           configTintLevelEntry;
 
111
 
 
112
    uchar*                  destinationPreviewData;
 
113
 
 
114
    QColor                  selColor;
 
115
 
 
116
    QLabel*                 thresholdLabel;
 
117
    QLabel*                 smoothLabel;
 
118
 
 
119
    KHueSaturationSelector* HSSelector;
 
120
    KColorValueSelector*    VSelector;
 
121
 
 
122
    RIntNumInput*           tintLevel;
 
123
    RIntNumInput*           redThreshold;
 
124
    RIntNumInput*           smoothLevel;
 
125
 
 
126
    ImageGuideWidget*       previewWidget;
 
127
    EditorToolSettings*     gboxSettings;
 
128
};
 
129
 
 
130
RedEyeTool::RedEyeTool(QObject* parent)
 
131
          : EditorTool(parent),
 
132
            d(new RedEyeToolPriv)
 
133
{
 
134
    setObjectName("redeye");
 
135
    setToolName(i18n("Red Eye"));
 
136
    setToolIcon(SmallIcon("redeyes"));
 
137
    setToolHelp("redeyecorrectiontool.anchor");
 
138
 
 
139
    d->destinationPreviewData = 0;
 
140
 
 
141
    d->previewWidget = new ImageGuideWidget(0, true, ImageGuideWidget::PickColorMode, Qt::red, 1, false, true);
 
142
    d->previewWidget->setToolTip(i18n("Here you can see the image selection preview with "
 
143
                                      "red eye reduction applied."));
 
144
    setToolView(d->previewWidget);
 
145
    setPreviewModeMask(PreviewToolBar::AllPreviewModes);
 
146
 
 
147
    // -------------------------------------------------------------
 
148
 
 
149
    d->gboxSettings = new EditorToolSettings;
 
150
    d->gboxSettings->setTools(EditorToolSettings::Histogram);
 
151
 
 
152
    // -------------------------------------------------------------
 
153
 
 
154
    d->thresholdLabel = new QLabel(i18n("Sensitivity:"));
 
155
    d->redThreshold   = new RIntNumInput();
 
156
    d->redThreshold->setRange(10, 90, 1);
 
157
    d->redThreshold->setSliderEnabled(true);
 
158
    d->redThreshold->setDefaultValue(20);
 
159
    d->redThreshold->setWhatsThis(i18n("<p>Control the red pixel selection threshold.</p>"
 
160
                                       "<p>Low values will select more red pixels "
 
161
                                       "(aggressive correction), high values will select fewer (mild correction). "
 
162
                                       "Use a low value if an eye has been selected exactly. "
 
163
                                       "Use a high value if other parts of the face have been selected too.</p>"));
 
164
 
 
165
    d->smoothLabel = new QLabel(i18nc("Smoothness when blurring border of changed pixels", "Smooth:"));
 
166
    d->smoothLevel = new RIntNumInput();
 
167
    d->smoothLevel->setRange(0, 5, 1);
 
168
    d->smoothLevel->setSliderEnabled(true);
 
169
    d->smoothLevel->setDefaultValue(1);
 
170
    d->smoothLevel->setWhatsThis(i18n("Sets the smoothness value when blurring the border "
 
171
                                      "of the changed pixels. "
 
172
                                      "This leads to a more naturally looking pupil."));
 
173
 
 
174
    QLabel *label3 = new QLabel(i18n("Coloring Tint:"));
 
175
 
 
176
    d->HSSelector  = new KHueSaturationSelector();
 
177
    d->HSSelector->setWhatsThis(i18n("Sets a custom color when re-colorizing the eyes."));
 
178
    d->HSSelector->setMinimumSize(200, 142);
 
179
    d->HSSelector->setChooserMode(ChooserValue);
 
180
    d->HSSelector->setColorValue(255);
 
181
 
 
182
    d->VSelector   = new KColorValueSelector();
 
183
    d->VSelector->setChooserMode(ChooserValue);
 
184
    d->VSelector->setMinimumSize(26, 142);
 
185
    d->VSelector->setIndent(false);
 
186
 
 
187
    QLabel *label4 = new QLabel(i18n("Tint Level:"));
 
188
    d->tintLevel   = new RIntNumInput();
 
189
    d->tintLevel->setRange(1, 200, 1);
 
190
    d->tintLevel->setSliderEnabled(true);
 
191
    d->tintLevel->setDefaultValue(128);
 
192
    d->tintLevel->setWhatsThis(i18n("Set the tint level to adjust the luminosity of "
 
193
                                   "the new color of the pupil."));
 
194
 
 
195
    // -------------------------------------------------------------
 
196
 
 
197
    QGridLayout* mainLayout = new QGridLayout();
 
198
    mainLayout->addWidget(d->thresholdLabel, 0, 0, 1, 5);
 
199
    mainLayout->addWidget(d->redThreshold,   1, 0, 1, 5);
 
200
    mainLayout->addWidget(d->smoothLabel,    2, 0, 1, 5);
 
201
    mainLayout->addWidget(d->smoothLevel,    3, 0, 1, 5);
 
202
    mainLayout->addWidget(label3,            4, 0, 1, 5);
 
203
    mainLayout->addWidget(d->HSSelector,     5, 0, 1, 4);
 
204
    mainLayout->addWidget(d->VSelector,      5, 4, 1, 1);
 
205
    mainLayout->addWidget(label4,            6, 0, 1, 5);
 
206
    mainLayout->addWidget(d->tintLevel,      7, 0, 1, 5);
 
207
    mainLayout->setRowStretch(8, 10);
 
208
    mainLayout->setColumnStretch(3, 10);
 
209
    mainLayout->setMargin(d->gboxSettings->spacingHint());
 
210
    mainLayout->setSpacing(d->gboxSettings->spacingHint());
 
211
    d->gboxSettings->plainPage()->setLayout(mainLayout);
 
212
 
 
213
    // -------------------------------------------------------------
 
214
 
 
215
    setToolSettings(d->gboxSettings);
 
216
    init();
 
217
 
 
218
    // -------------------------------------------------------------
 
219
 
 
220
    connect(d->previewWidget, SIGNAL(spotPositionChangedFromTarget(const Digikam::DColor&, const QPoint&)),
 
221
            this, SLOT(slotColorSelectedFromTarget(const Digikam::DColor&)));
 
222
 
 
223
    connect(d->previewWidget, SIGNAL(signalResized()),
 
224
            this, SLOT(slotEffect()));
 
225
 
 
226
    connect(d->redThreshold, SIGNAL(valueChanged(int)),
 
227
            this, SLOT(slotTimer()));
 
228
 
 
229
    connect(d->smoothLevel, SIGNAL(valueChanged(int)),
 
230
            this, SLOT(slotTimer()));
 
231
 
 
232
    connect(d->HSSelector, SIGNAL(valueChanged(int, int)),
 
233
            this, SLOT(slotHSChanged(int, int)));
 
234
 
 
235
    connect(d->VSelector, SIGNAL(valueChanged(int)),
 
236
            this, SLOT(slotVChanged(int)));
 
237
 
 
238
    connect(d->tintLevel, SIGNAL(valueChanged(int)),
 
239
            this, SLOT(slotTimer()));
 
240
}
 
241
 
 
242
RedEyeTool::~RedEyeTool()
 
243
{
 
244
    if (d->destinationPreviewData)
 
245
       delete [] d->destinationPreviewData;
 
246
 
 
247
    delete d;
 
248
}
 
249
 
 
250
void RedEyeTool::slotHSChanged(int h, int s)
 
251
{
 
252
    QColor color;
 
253
 
 
254
    int val = d->selColor.value();
 
255
 
 
256
    color.setHsv(h, s, val);
 
257
    setColor(color);
 
258
}
 
259
 
 
260
void RedEyeTool::slotVChanged(int v)
 
261
{
 
262
    QColor color;
 
263
 
 
264
    int hue = d->selColor.hue();
 
265
    int sat = d->selColor.saturation();
 
266
 
 
267
    color.setHsv(hue, sat, v);
 
268
    setColor(color);
 
269
}
 
270
 
 
271
void RedEyeTool::setColor(QColor c)
 
272
{
 
273
    if (c.isValid())
 
274
    {
 
275
        d->selColor = c;
 
276
 
 
277
        // set values
 
278
        d->HSSelector->setValues(c.hue(), c.saturation());
 
279
        d->VSelector->setValue(c.value());
 
280
 
 
281
        // set colors
 
282
        d->HSSelector->blockSignals(true);
 
283
        d->HSSelector->setHue(c.hue());
 
284
        d->HSSelector->setSaturation(c.saturation());
 
285
        d->HSSelector->setColorValue(c.value());
 
286
        d->HSSelector->updateContents();
 
287
        d->HSSelector->blockSignals(false);
 
288
        d->HSSelector->repaint();
 
289
 
 
290
        d->VSelector->blockSignals(true);
 
291
        d->VSelector->setHue(c.hue());
 
292
        d->VSelector->setSaturation(c.saturation());
 
293
        d->VSelector->setColorValue(c.value());
 
294
        d->VSelector->updateContents();
 
295
        d->VSelector->blockSignals(false);
 
296
        d->VSelector->repaint();
 
297
 
 
298
        slotTimer();
 
299
    }
 
300
}
 
301
 
 
302
void RedEyeTool::slotColorSelectedFromTarget(const DColor& color)
 
303
{
 
304
    d->gboxSettings->histogramBox()->histogram()->setHistogramGuideByColor(color);
 
305
}
 
306
 
 
307
void RedEyeTool::readSettings()
 
308
{
 
309
    KSharedConfig::Ptr config = KGlobal::config();
 
310
    KConfigGroup group        = config->group(d->configGroupName);
 
311
 
 
312
    d->gboxSettings->histogramBox()->setChannel((ChannelType)group.readEntry(d->configHistogramChannelEntry,
 
313
                        (int)LuminosityChannel));
 
314
    d->gboxSettings->histogramBox()->setScale((HistogramScale)group.readEntry(d->configHistogramScaleEntry,
 
315
                        (int)LogScaleHistogram));
 
316
 
 
317
    d->redThreshold->setValue(group.readEntry(d->configRedThresholdEntry,       d->redThreshold->defaultValue()));
 
318
    d->smoothLevel->setValue(group.readEntry(d->configSmoothLevelEntry,         d->smoothLevel->defaultValue()));
 
319
    d->HSSelector->setHue(group.readEntry(d->configHueColoringTintEntry,        0));
 
320
    d->HSSelector->setSaturation(group.readEntry(d->configSatColoringTintEntry, 128));
 
321
    d->VSelector->setValue(group.readEntry(d->configValColoringTintEntry,       255));
 
322
    d->tintLevel->setValue(group.readEntry(d->configTintLevelEntry,             d->tintLevel->defaultValue()));
 
323
 
 
324
    QColor col;
 
325
    col.setHsv(d->HSSelector->hue(),
 
326
               d->HSSelector->saturation(),
 
327
               d->VSelector->value());
 
328
    setColor(col);
 
329
}
 
330
 
 
331
void RedEyeTool::writeSettings()
 
332
{
 
333
    KSharedConfig::Ptr config = KGlobal::config();
 
334
    KConfigGroup group        = config->group(d->configGroupName);
 
335
    group.writeEntry(d->configHistogramChannelEntry, (int)d->gboxSettings->histogramBox()->channel());
 
336
    group.writeEntry(d->configHistogramScaleEntry,   (int)d->gboxSettings->histogramBox()->scale());
 
337
    group.writeEntry(d->configRedThresholdEntry,     d->redThreshold->value());
 
338
    group.writeEntry(d->configSmoothLevelEntry,      d->smoothLevel->value());
 
339
    group.writeEntry(d->configHueColoringTintEntry,  d->HSSelector->hue());
 
340
    group.writeEntry(d->configSatColoringTintEntry,  d->HSSelector->saturation());
 
341
    group.writeEntry(d->configValColoringTintEntry,  d->VSelector->value());
 
342
    group.writeEntry(d->configTintLevelEntry,        d->tintLevel->value());
 
343
 
 
344
    config->sync();
 
345
}
 
346
 
 
347
void RedEyeTool::slotResetSettings()
 
348
{
 
349
    d->redThreshold->blockSignals(true);
 
350
    d->HSSelector->blockSignals(true);
 
351
    d->VSelector->blockSignals(true);
 
352
    d->tintLevel->blockSignals(true);
 
353
 
 
354
    d->redThreshold->slotReset();
 
355
    d->smoothLevel->slotReset();
 
356
    d->tintLevel->slotReset();
 
357
 
 
358
    // Black color by default
 
359
    QColor col;
 
360
    col.setHsv(0, 0, 0);
 
361
    setColor(col);
 
362
 
 
363
    d->redThreshold->blockSignals(false);
 
364
    d->HSSelector->blockSignals(false);
 
365
    d->VSelector->blockSignals(false);
 
366
    d->tintLevel->blockSignals(false);
 
367
 
 
368
    slotEffect();
 
369
}
 
370
 
 
371
void RedEyeTool::slotEffect()
 
372
{
 
373
    kapp->setOverrideCursor( Qt::WaitCursor );
 
374
 
 
375
    d->gboxSettings->histogramBox()->histogram()->stopHistogramComputation();
 
376
 
 
377
    if (d->destinationPreviewData)
 
378
       delete [] d->destinationPreviewData;
 
379
 
 
380
    // Here, we need to use the real selection image data because we will apply
 
381
    // a Gaussian blur filter on pixels and we cannot use directly the preview scaled image
 
382
    // else the blur radius will not give the same result between preview and final rendering.
 
383
    ImageIface* iface = d->previewWidget->imageIface();
 
384
    d->destinationPreviewData  = iface->getImageSelection();
 
385
    int w                      = iface->selectedWidth();
 
386
    int h                      = iface->selectedHeight();
 
387
    bool sb                    = iface->originalSixteenBit();
 
388
    bool a                     = iface->originalHasAlpha();
 
389
    DImg selection(w, h, sb, a, d->destinationPreviewData);
 
390
 
 
391
    redEyeFilter(selection);
 
392
 
 
393
    DImg preview = selection.smoothScale(iface->previewWidth(), iface->previewHeight());
 
394
 
 
395
    iface->putPreviewImage(preview.bits());
 
396
    d->previewWidget->updatePreview();
 
397
 
 
398
    // Update histogram.
 
399
 
 
400
    memcpy(d->destinationPreviewData, selection.bits(), selection.numBytes());
 
401
    d->gboxSettings->histogramBox()->histogram()->updateData(d->destinationPreviewData, w, h, sb, 0, 0, 0, false);
 
402
 
 
403
    kapp->restoreOverrideCursor();
 
404
}
 
405
 
 
406
void RedEyeTool::finalRendering()
 
407
{
 
408
    kapp->setOverrideCursor( Qt::WaitCursor );
 
409
 
 
410
    ImageIface* iface = d->previewWidget->imageIface();
 
411
    uchar *data       = iface->getImageSelection();
 
412
    int w             = iface->selectedWidth();
 
413
    int h             = iface->selectedHeight();
 
414
    bool sixteenBit   = iface->originalSixteenBit();
 
415
    bool hasAlpha     = iface->originalHasAlpha();
 
416
    DImg selection(w, h, sixteenBit, hasAlpha, data);
 
417
    delete [] data;
 
418
 
 
419
    redEyeFilter(selection);
 
420
 
 
421
    iface->putImageSelection(i18n("Red Eyes Correction"), selection.bits());
 
422
 
 
423
    kapp->restoreOverrideCursor();
 
424
}
 
425
 
 
426
void RedEyeTool::redEyeFilter(DImg& selection)
 
427
{
 
428
    DImg mask(selection.width(), selection.height(), selection.sixteenBit(), true,
 
429
                       selection.bits(), true);
 
430
 
 
431
    selection          = mask.copy();
 
432
    float redThreshold = d->redThreshold->value()/10.0f;
 
433
    int hue            = d->VSelector->hue();
 
434
    int sat            = d->VSelector->saturation();
 
435
    int val            = d->VSelector->value();
 
436
    QColor coloring    = QColor::fromHsv(hue, sat, val);
 
437
 
 
438
    struct channel
 
439
    {
 
440
        float red_gain;
 
441
        float green_gain;
 
442
        float blue_gain;
 
443
    };
 
444
 
 
445
    channel red_chan, green_chan, blue_chan;
 
446
 
 
447
    red_chan.red_gain     = 0.1f;
 
448
    red_chan.green_gain   = 0.6f;
 
449
    red_chan.blue_gain    = 0.3f;
 
450
 
 
451
    green_chan.red_gain   = 0.0f;
 
452
    green_chan.green_gain = 1.0f;
 
453
    green_chan.blue_gain  = 0.0f;
 
454
 
 
455
    blue_chan.red_gain    = 0.0f;
 
456
    blue_chan.green_gain  = 0.0f;
 
457
    blue_chan.blue_gain   = 1.0f;
 
458
 
 
459
    float red_norm, green_norm, blue_norm;
 
460
    int   level = 201 - d->tintLevel->value();
 
461
 
 
462
    red_norm   = 1.0f / (red_chan.red_gain   + red_chan.green_gain   + red_chan.blue_gain);
 
463
    green_norm = 1.0f / (green_chan.red_gain + green_chan.green_gain + green_chan.blue_gain);
 
464
    blue_norm  = 1.0f / (blue_chan.red_gain  + blue_chan.green_gain  + blue_chan.blue_gain);
 
465
 
 
466
    red_norm   *= coloring.red()   / level;
 
467
    green_norm *= coloring.green() / level;
 
468
    blue_norm  *= coloring.blue()  / level;
 
469
 
 
470
    // Perform a red color pixels detection in selection image and create a correction mask using an alpha channel.
 
471
 
 
472
    if (!selection.sixteenBit())         // 8 bits image.
 
473
    {
 
474
        uchar* ptr  = selection.bits();
 
475
        uchar* mptr = mask.bits();
 
476
        uchar  r, g, b, r1, g1, b1;
 
477
 
 
478
        for (uint i = 0 ; i < selection.width() * selection.height() ; ++i)
 
479
        {
 
480
            b       = ptr[0];
 
481
            g       = ptr[1];
 
482
            r       = ptr[2];
 
483
            mptr[3] = 255;
 
484
 
 
485
            if (r >= ( redThreshold * g))
 
486
            {
 
487
                r1 = qMin(255, (int)(red_norm * (red_chan.red_gain   * r +
 
488
                                                 red_chan.green_gain * g +
 
489
                                                 red_chan.blue_gain  * b)));
 
490
 
 
491
                g1 = qMin(255, (int)(green_norm * (green_chan.red_gain   * r +
 
492
                                                   green_chan.green_gain * g +
 
493
                                                   green_chan.blue_gain  * b)));
 
494
 
 
495
                b1 = qMin(255, (int)(blue_norm * (blue_chan.red_gain   * r +
 
496
                                                  blue_chan.green_gain * g +
 
497
                                                  blue_chan.blue_gain  * b)));
 
498
 
 
499
                mptr[0] = b1;
 
500
                mptr[1] = g1;
 
501
                mptr[2] = r1;
 
502
                mptr[3] = qMin( (int)((r-g) / 150.0 * 255.0), 255);
 
503
            }
 
504
 
 
505
            ptr += 4;
 
506
            mptr+= 4;
 
507
        }
 
508
    }
 
509
    else                                 // 16 bits image.
 
510
    {
 
511
        unsigned short* ptr  = (unsigned short*)selection.bits();
 
512
        unsigned short* mptr = (unsigned short*)mask.bits();
 
513
        unsigned short  r, g, b, r1, g1, b1;
 
514
 
 
515
        for (uint i = 0 ; i < selection.width() * selection.height() ; ++i)
 
516
        {
 
517
            b       = ptr[0];
 
518
            g       = ptr[1];
 
519
            r       = ptr[2];
 
520
            mptr[3] = 65535;
 
521
 
 
522
            if (r >= ( redThreshold * g))
 
523
            {
 
524
                r1 = qMin(65535, (int)(red_norm * (red_chan.red_gain   * r +
 
525
                                                         red_chan.green_gain * g +
 
526
                                                         red_chan.blue_gain  * b)));
 
527
 
 
528
                g1 = qMin(65535, (int)(green_norm * (green_chan.red_gain   * r +
 
529
                                                            green_chan.green_gain * g +
 
530
                                                            green_chan.blue_gain  * b)));
 
531
 
 
532
                b1 = qMin(65535, (int)(blue_norm * (blue_chan.red_gain   * r +
 
533
                                                          blue_chan.green_gain * g +
 
534
                                                          blue_chan.blue_gain  * b)));
 
535
 
 
536
                mptr[0] = b1;
 
537
                mptr[1] = g1;
 
538
                mptr[2] = r1;
 
539
                mptr[3] = qMin( (int)((r-g) / 38400.0 * 65535.0), 65535);
 
540
            }
 
541
 
 
542
            ptr += 4;
 
543
            mptr+= 4;
 
544
        }
 
545
    }
 
546
 
 
547
    // Now, we will blur only the transparency pixels from the mask.
 
548
 
 
549
    DImg mask2 = mask.copy();
 
550
    BlurFilter blur(&mask2, 0L, d->smoothLevel->value());
 
551
    blur.startFilterDirectly();
 
552
    mask2.putImageData(blur.getTargetImage().bits());
 
553
 
 
554
    if (!selection.sixteenBit())         // 8 bits image.
 
555
    {
 
556
        uchar* mptr  = mask.bits();
 
557
        uchar* mptr2 = mask2.bits();
 
558
 
 
559
        for (uint i = 0 ; i < mask2.width() * mask2.height() ; ++i)
 
560
        {
 
561
            if (mptr2[3] < 255)
 
562
            {
 
563
                mptr[0] = mptr2[0];
 
564
                mptr[1] = mptr2[1];
 
565
                mptr[2] = mptr2[2];
 
566
                mptr[3] = mptr2[3];
 
567
            }
 
568
 
 
569
            mptr += 4;
 
570
            mptr2+= 4;
 
571
        }
 
572
    }
 
573
    else                                // 16 bits image.
 
574
    {
 
575
        unsigned short* mptr  = (unsigned short*)mask.bits();
 
576
        unsigned short* mptr2 = (unsigned short*)mask2.bits();
 
577
 
 
578
        for (uint i = 0 ; i < mask2.width() * mask2.height() ; ++i)
 
579
        {
 
580
            if (mptr2[3] < 65535)
 
581
            {
 
582
                mptr[0] = mptr2[0];
 
583
                mptr[1] = mptr2[1];
 
584
                mptr[2] = mptr2[2];
 
585
                mptr[3] = mptr2[3];
 
586
            }
 
587
 
 
588
            mptr += 4;
 
589
            mptr2+= 4;
 
590
        }
 
591
    }
 
592
 
 
593
    // - Perform pixels blending using alpha channel between the mask and the selection.
 
594
 
 
595
    DColorComposer *composer = DColorComposer::getComposer(DColorComposer::PorterDuffSrcOver);
 
596
 
 
597
    // NOTE: 'mask' is the Source image, 'selection' is the Destination image.
 
598
 
 
599
    selection.bitBlendImage(composer, &mask,
 
600
                            0, 0, mask.width(), mask.height(),
 
601
                            0, 0);
 
602
 
 
603
    delete composer;
 
604
}
 
605
 
 
606
}  // namespace DigikamEnhanceImagePlugin