~ubuntu-branches/ubuntu/intrepid/digikam/intrepid

« back to all changes in this revision

Viewing changes to digikam/imageplugins/colorfx/imageeffect_colorfx.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Mark Purcell
  • Date: 2008-07-17 20:25:39 UTC
  • mfrom: (1.3.2 upstream) (37 hardy)
  • mto: This revision was merged to the branch mainline in revision 39.
  • Revision ID: james.westby@ubuntu.com-20080717202539-1bw3w3nrsso7yj4z
* New upstream release
  - digiKam 0.9.4 Release Plan (KDE3) ~ 13 July 08 (Closes: #490144)
* DEB_CONFIGURE_EXTRA_FLAGS := --without-included-sqlite3
* Debhelper compatibility level V7
* Install pixmaps in debian/*.install
* Add debian/digikam.lintian-overrides

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-02-14
 
7
 * Description : a digiKam image plugin for to apply a color 
 
8
 *               effect to an image.
 
9
 *
 
10
 * Copyright (C) 2004-2005 by Renchi Raju <renchi@pooh.tam.uiuc.edu>
 
11
 * Copyright (C) 2006-2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
 
12
 * 
 
13
 * This program is free software; you can redistribute it
 
14
 * and/or modify it under the terms of the GNU General
 
15
 * Public License as published by the Free Software Foundation;
 
16
 * either version 2, or (at your option)
 
17
 * any later version.
 
18
 * 
 
19
 * This program is distributed in the hope that it will be useful,
 
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
22
 * GNU General Public License for more details.
 
23
 * 
 
24
 * ============================================================ */
 
25
 
 
26
// Qt includes.
 
27
 
 
28
#include <qvgroupbox.h>
 
29
#include <qhgroupbox.h>
 
30
#include <qhbuttongroup.h> 
 
31
#include <qcombobox.h>
 
32
#include <qlabel.h>
 
33
#include <qpushbutton.h>
 
34
#include <qwhatsthis.h>
 
35
#include <qlayout.h>
 
36
#include <qframe.h>
 
37
#include <qvbox.h>
 
38
#include <qtooltip.h>
 
39
 
 
40
// KDE includes.
 
41
 
 
42
#include <kconfig.h>
 
43
#include <knuminput.h>
 
44
#include <klocale.h>
 
45
#include <kcursor.h>
 
46
#include <kaboutdata.h>
 
47
#include <khelpmenu.h>
 
48
#include <kiconloader.h>
 
49
#include <kapplication.h>
 
50
#include <kpopupmenu.h>
 
51
#include <kstandarddirs.h>
 
52
 
 
53
// Local includes.
 
54
 
 
55
#include "version.h"
 
56
#include "ddebug.h"
 
57
#include "dimg.h"
 
58
#include "dimgimagefilters.h"
 
59
#include "imageiface.h"
 
60
#include "imagewidget.h"
 
61
#include "imagecurves.h"
 
62
#include "imagehistogram.h"
 
63
#include "histogramwidget.h"
 
64
#include "colorgradientwidget.h"
 
65
#include "imageeffect_colorfx.h"
 
66
#include "imageeffect_colorfx.moc"
 
67
 
 
68
namespace DigikamColorFXImagesPlugin
 
69
{
 
70
 
 
71
ImageEffect_ColorFX::ImageEffect_ColorFX(QWidget* parent)
 
72
                    : Digikam::ImageDlgBase(parent, 
 
73
                      i18n("Apply Color Special Effects to Photograph"), 
 
74
                      "coloreffect", false, false)
 
75
{
 
76
    m_destinationPreviewData = 0;
 
77
 
 
78
    // About data and help button.
 
79
 
 
80
    KAboutData *about = new KAboutData("digikam",
 
81
                            I18N_NOOP("Color Effects"),
 
82
                            digikam_version,
 
83
                            I18N_NOOP("A digiKam plugin to apply special color effects to an image."),
 
84
                            KAboutData::License_GPL,
 
85
                            "(c) 2004-2005, Renchi Raju\n(c) 2006-2008, Gilles Caulier",
 
86
                            0,
 
87
                            "http://www.digikam.org");
 
88
 
 
89
    about->addAuthor("Renchi Raju", I18N_NOOP("Original Author"),
 
90
                     "renchi@pooh.tam.uiuc.edu");
 
91
    
 
92
    about->addAuthor("Caulier Gilles", I18N_NOOP("Maintainer"),
 
93
                     "caulier dot gilles at gmail dot com");
 
94
 
 
95
    setAboutData(about);
 
96
 
 
97
    // -------------------------------------------------------------
 
98
 
 
99
    m_previewWidget = new Digikam::ImageWidget("coloreffect Tool Dialog", plainPage(),
 
100
                          i18n("<p>This is the color effect preview"));
 
101
 
 
102
    setPreviewAreaWidget(m_previewWidget); 
 
103
 
 
104
    // -------------------------------------------------------------
 
105
 
 
106
    QWidget *gboxSettings     = new QWidget(plainPage());
 
107
    QGridLayout* gridSettings = new QGridLayout( gboxSettings, 9, 4, spacingHint());
 
108
 
 
109
    QLabel *label1 = new QLabel(i18n("Channel:"), gboxSettings);
 
110
    label1->setAlignment ( Qt::AlignRight | Qt::AlignVCenter );
 
111
    m_channelCB = new QComboBox( false, gboxSettings );
 
112
    m_channelCB->insertItem( i18n("Luminosity") );
 
113
    m_channelCB->insertItem( i18n("Red") );
 
114
    m_channelCB->insertItem( i18n("Green") );
 
115
    m_channelCB->insertItem( i18n("Blue") );
 
116
    QWhatsThis::add( m_channelCB, i18n("<p>Select the histogram channel to display here:<p>"
 
117
                                       "<b>Luminosity</b>: display the image's luminosity values.<p>"
 
118
                                       "<b>Red</b>: display the red image-channel values.<p>"
 
119
                                       "<b>Green</b>: display the green image-channel values.<p>"
 
120
                                       "<b>Blue</b>: display the blue image-channel values.<p>"));
 
121
 
 
122
    m_scaleBG = new QHButtonGroup(gboxSettings);
 
123
    m_scaleBG->setExclusive(true);
 
124
    m_scaleBG->setFrameShape(QFrame::NoFrame);
 
125
    m_scaleBG->setInsideMargin( 0 );
 
126
    QWhatsThis::add( m_scaleBG, i18n("<p>Select the histogram scale here.<p>"
 
127
                                     "If the image's maximal counts are small, you can use the linear scale.<p>"
 
128
                                     "Logarithmic scale can be used when the maximal counts are big; "
 
129
                                     "if it is used, all values (small and large) will be visible on the graph."));
 
130
    
 
131
    QPushButton *linHistoButton = new QPushButton( m_scaleBG );
 
132
    QToolTip::add( linHistoButton, i18n( "<p>Linear" ) );
 
133
    m_scaleBG->insert(linHistoButton, Digikam::HistogramWidget::LinScaleHistogram);
 
134
    KGlobal::dirs()->addResourceType("histogram-lin", KGlobal::dirs()->kde_default("data") + "digikam/data");
 
135
    QString directory = KGlobal::dirs()->findResourceDir("histogram-lin", "histogram-lin.png");
 
136
    linHistoButton->setPixmap( QPixmap( directory + "histogram-lin.png" ) );
 
137
    linHistoButton->setToggleButton(true);
 
138
    
 
139
    QPushButton *logHistoButton = new QPushButton( m_scaleBG );
 
140
    QToolTip::add( logHistoButton, i18n( "<p>Logarithmic" ) );
 
141
    m_scaleBG->insert(logHistoButton, Digikam::HistogramWidget::LogScaleHistogram);
 
142
    KGlobal::dirs()->addResourceType("histogram-log", KGlobal::dirs()->kde_default("data") + "digikam/data");
 
143
    directory = KGlobal::dirs()->findResourceDir("histogram-log", "histogram-log.png");
 
144
    logHistoButton->setPixmap( QPixmap( directory + "histogram-log.png" ) );
 
145
    logHistoButton->setToggleButton(true);       
 
146
 
 
147
    QHBoxLayout* l1 = new QHBoxLayout();
 
148
    l1->addWidget(label1);
 
149
    l1->addWidget(m_channelCB);
 
150
    l1->addStretch(10);
 
151
    l1->addWidget(m_scaleBG);
 
152
    
 
153
    gridSettings->addMultiCellLayout(l1, 0, 0, 0, 4);
 
154
 
 
155
    // -------------------------------------------------------------
 
156
 
 
157
    QVBox *histoBox   = new QVBox(gboxSettings);
 
158
    m_histogramWidget = new Digikam::HistogramWidget(256, 140, histoBox, false, true, true);
 
159
    QWhatsThis::add( m_histogramWidget, i18n("<p>Here you can see the target preview image histogram drawing "
 
160
                                             "of the selected image channel. This one is re-computed at any "
 
161
                                             "settings changes."));
 
162
    QLabel *space = new QLabel(histoBox);
 
163
    space->setFixedHeight(1);    
 
164
    m_hGradient = new Digikam::ColorGradientWidget( Digikam::ColorGradientWidget::Horizontal, 10, histoBox );
 
165
    m_hGradient->setColors( QColor( "black" ), QColor( "white" ) );
 
166
    
 
167
    gridSettings->addMultiCellWidget(histoBox, 1, 2, 0, 4);
 
168
 
 
169
    // -------------------------------------------------------------
 
170
 
 
171
    m_effectTypeLabel = new QLabel(i18n("Type:"), gboxSettings);
 
172
    
 
173
    m_effectType = new QComboBox( false, gboxSettings );
 
174
    m_effectType->insertItem( i18n("Solarize") );
 
175
    m_effectType->insertItem( i18n("Vivid") );
 
176
    m_effectType->insertItem( i18n("Neon") );    
 
177
    m_effectType->insertItem( i18n("Find Edges") );    
 
178
    QWhatsThis::add( m_effectType, i18n("<p>Select the effect type to apply to the image here.<p>"
 
179
                                        "<b>Solarize</b>: simulates solarization of photograph.<p>"
 
180
                                        "<b>Vivid</b>: simulates the Velvia(tm) slide film colors.<p>"
 
181
                                        "<b>Neon</b>: coloring the edges in a photograph to "
 
182
                                        "reproduce a fluorescent light effect.<p>"
 
183
                                        "<b>Find Edges</b>: detects the edges in a photograph "
 
184
                                        "and their strength."
 
185
                                        ));
 
186
    gridSettings->addMultiCellWidget(m_effectTypeLabel, 3, 3, 0, 4);
 
187
    gridSettings->addMultiCellWidget(m_effectType, 4, 4, 0, 4);
 
188
                                                  
 
189
    m_levelLabel = new QLabel(i18n("Level:"), gboxSettings);
 
190
    m_levelInput = new KIntNumInput(gboxSettings);
 
191
    m_levelInput->setRange(0, 100, 1, true);
 
192
    QWhatsThis::add( m_levelInput, i18n("<p>Set here the level of the effect."));
 
193
    
 
194
    gridSettings->addMultiCellWidget(m_levelLabel, 5, 5, 0, 4);
 
195
    gridSettings->addMultiCellWidget(m_levelInput, 6, 6, 0, 4);
 
196
        
 
197
    m_iterationLabel = new QLabel(i18n("Iteration:"), gboxSettings);
 
198
    m_iterationInput = new KIntNumInput(gboxSettings);
 
199
    m_iterationInput->setRange(0, 100, 1, true);
 
200
    QWhatsThis::add( m_iterationInput, i18n("<p>This value controls the number of iterations "
 
201
                                            "to use with the Neon and Find Edges effects."));
 
202
    
 
203
    gridSettings->addMultiCellWidget(m_iterationLabel, 7, 7, 0, 4);
 
204
    gridSettings->addMultiCellWidget(m_iterationInput, 8, 8, 0, 4);
 
205
 
 
206
    gridSettings->setRowStretch(9, 10);
 
207
    setUserAreaWidget(gboxSettings);
 
208
 
 
209
    // -------------------------------------------------------------
 
210
 
 
211
    connect(m_channelCB, SIGNAL(activated(int)),
 
212
            this, SLOT(slotChannelChanged(int)));
 
213
 
 
214
    connect(m_scaleBG, SIGNAL(released(int)),
 
215
            this, SLOT(slotScaleChanged(int)));
 
216
 
 
217
    connect(m_previewWidget, SIGNAL(spotPositionChangedFromTarget( const Digikam::DColor &, const QPoint & )),
 
218
            this, SLOT(slotColorSelectedFromTarget( const Digikam::DColor & )));
 
219
 
 
220
    connect(m_levelInput, SIGNAL(valueChanged(int)),
 
221
            this, SLOT(slotTimer()));            
 
222
            
 
223
    connect(m_iterationInput, SIGNAL(valueChanged(int)),
 
224
            this, SLOT(slotTimer()));      
 
225
 
 
226
    connect(m_previewWidget, SIGNAL(signalResized()),
 
227
            this, SLOT(slotEffect()));
 
228
 
 
229
    connect(m_effectType, SIGNAL(activated(int)),
 
230
            this, SLOT(slotEffectTypeChanged(int)));
 
231
}
 
232
 
 
233
ImageEffect_ColorFX::~ImageEffect_ColorFX()
 
234
{
 
235
    m_histogramWidget->stopHistogramComputation();
 
236
 
 
237
    if (m_destinationPreviewData) 
 
238
       delete [] m_destinationPreviewData;
 
239
 
 
240
    delete m_previewWidget;
 
241
}
 
242
 
 
243
void ImageEffect_ColorFX::readUserSettings()
 
244
{
 
245
    KConfig* config = kapp->config();
 
246
    config->setGroup("coloreffect Tool Dialog");
 
247
    m_effectType->setCurrentItem(config->readNumEntry("EffectType", ColorFX));
 
248
    m_levelInput->setValue(config->readNumEntry("LevelAjustment", 0));
 
249
    m_iterationInput->setValue(config->readNumEntry("IterationAjustment", 3));
 
250
    slotEffectTypeChanged(m_effectType->currentItem());  //check for enable/disable of iteration
 
251
}
 
252
 
 
253
void ImageEffect_ColorFX::writeUserSettings()
 
254
{
 
255
    KConfig* config = kapp->config();
 
256
    config->setGroup("coloreffect Tool Dialog");
 
257
    config->writeEntry("EffectType", m_effectType->currentItem());
 
258
    config->writeEntry("LevelAjustment", m_levelInput->value());
 
259
    config->writeEntry("IterationAjustment", m_iterationInput->value());
 
260
    config->sync();
 
261
}
 
262
 
 
263
void ImageEffect_ColorFX::resetValues()
 
264
{
 
265
    m_levelInput->setValue(0);
 
266
}
 
267
 
 
268
void ImageEffect_ColorFX::slotChannelChanged(int channel)
 
269
{
 
270
    switch(channel)
 
271
    {
 
272
        case LuminosityChannel:
 
273
            m_histogramWidget->m_channelType = Digikam::HistogramWidget::ValueHistogram;
 
274
            m_hGradient->setColors( QColor( "black" ), QColor( "white" ) );
 
275
            break;
 
276
    
 
277
        case RedChannel:
 
278
            m_histogramWidget->m_channelType = Digikam::HistogramWidget::RedChannelHistogram;
 
279
            m_hGradient->setColors( QColor( "black" ), QColor( "red" ) );
 
280
            break;
 
281
    
 
282
        case GreenChannel:         
 
283
            m_histogramWidget->m_channelType = Digikam::HistogramWidget::GreenChannelHistogram;
 
284
            m_hGradient->setColors( QColor( "black" ), QColor( "green" ) );
 
285
            break;
 
286
    
 
287
        case BlueChannel:         
 
288
            m_histogramWidget->m_channelType = Digikam::HistogramWidget::BlueChannelHistogram;
 
289
            m_hGradient->setColors( QColor( "black" ), QColor( "blue" ) );
 
290
            break;
 
291
    }
 
292
 
 
293
    m_histogramWidget->repaint(false);
 
294
}
 
295
 
 
296
void ImageEffect_ColorFX::slotScaleChanged(int scale)
 
297
{
 
298
    m_histogramWidget->m_scaleType = scale;
 
299
    m_histogramWidget->repaint(false);
 
300
}
 
301
 
 
302
void ImageEffect_ColorFX::slotColorSelectedFromTarget( const Digikam::DColor &color )
 
303
{
 
304
    m_histogramWidget->setHistogramGuideByColor(color);
 
305
}
 
306
 
 
307
void ImageEffect_ColorFX::slotEffectTypeChanged(int type)
 
308
{
 
309
    m_levelInput->setEnabled(true);
 
310
    m_levelLabel->setEnabled(true);
 
311
 
 
312
    m_levelInput->blockSignals(true);
 
313
    m_iterationInput->blockSignals(true);
 
314
    m_levelInput->setRange(0, 100, 1, true);
 
315
    m_levelInput->setValue(25);
 
316
 
 
317
    switch (type)
 
318
       {
 
319
       case ColorFX:
 
320
          m_levelInput->setRange(0, 100, 1, true);
 
321
          m_levelInput->setValue(0);
 
322
          m_iterationInput->setEnabled(false);
 
323
          m_iterationLabel->setEnabled(false);
 
324
          break;
 
325
 
 
326
       case Vivid:
 
327
          m_levelInput->setRange(0, 50, 1, true);
 
328
          m_levelInput->setValue(5);
 
329
          m_iterationInput->setEnabled(false);
 
330
          m_iterationLabel->setEnabled(false);
 
331
          break;
 
332
 
 
333
       case Neon:
 
334
       case FindEdges:
 
335
          m_levelInput->setRange(0, 5, 1, true);
 
336
          m_levelInput->setValue(3);
 
337
          m_iterationInput->setEnabled(true);
 
338
          m_iterationLabel->setEnabled(true);
 
339
          m_iterationInput->setRange(0, 5, 1, true);
 
340
          m_iterationInput->setValue(2);
 
341
          break;
 
342
       }
 
343
 
 
344
    m_levelInput->blockSignals(false);
 
345
    m_iterationInput->blockSignals(false);
 
346
 
 
347
    slotEffect();
 
348
}
 
349
 
 
350
void ImageEffect_ColorFX::slotEffect()
 
351
{
 
352
    kapp->setOverrideCursor( KCursor::waitCursor() );
 
353
 
 
354
    m_histogramWidget->stopHistogramComputation();
 
355
 
 
356
    if (m_destinationPreviewData) 
 
357
       delete [] m_destinationPreviewData;
 
358
 
 
359
    Digikam::ImageIface* iface      = m_previewWidget->imageIface();
 
360
    uchar *m_destinationPreviewData = iface->getPreviewImage();
 
361
    int w                           = iface->previewWidth();
 
362
    int h                           = iface->previewHeight();
 
363
    bool sb                         = iface->previewSixteenBit();
 
364
 
 
365
    colorEffect(m_destinationPreviewData, w, h, sb);
 
366
 
 
367
    iface->putPreviewImage(m_destinationPreviewData);
 
368
    m_previewWidget->updatePreview();
 
369
 
 
370
    // Update histogram.
 
371
   
 
372
    m_histogramWidget->updateData(m_destinationPreviewData, w, h, sb, 0, 0, 0, false);
 
373
 
 
374
    kapp->restoreOverrideCursor();
 
375
}
 
376
 
 
377
void ImageEffect_ColorFX::finalRendering()
 
378
{
 
379
    kapp->setOverrideCursor( KCursor::waitCursor() );
 
380
    Digikam::ImageIface* iface = m_previewWidget->imageIface();
 
381
    uchar *data                = iface->getOriginalImage();
 
382
    int w                      = iface->originalWidth();
 
383
    int h                      = iface->originalHeight();
 
384
    bool sb                    = iface->originalSixteenBit();
 
385
 
 
386
    if (data)
 
387
    {
 
388
        colorEffect(data, w, h, sb);
 
389
        QString name;
 
390
 
 
391
        switch (m_effectType->currentItem())
 
392
        {
 
393
            case ColorFX:
 
394
                name = i18n("ColorFX");
 
395
                break;
 
396
    
 
397
            case Vivid:
 
398
                name = i18n("Vivid");
 
399
                break;
 
400
    
 
401
            case Neon:
 
402
                name = i18n("Neon");
 
403
                break;
 
404
    
 
405
            case FindEdges:
 
406
                name = i18n("Find Edges");
 
407
                break;
 
408
        }
 
409
 
 
410
        iface->putOriginalImage(name, data);
 
411
        delete [] data;
 
412
    }
 
413
 
 
414
    kapp->restoreOverrideCursor();
 
415
    accept();
 
416
}
 
417
 
 
418
void ImageEffect_ColorFX::colorEffect(uchar *data, int w, int h, bool sb)
 
419
{
 
420
    switch (m_effectType->currentItem())
 
421
    {
 
422
        case ColorFX:
 
423
            solarize(m_levelInput->value(), data, w, h, sb);
 
424
            break;
 
425
 
 
426
        case Vivid:
 
427
            vivid(m_levelInput->value(), data, w, h, sb);
 
428
            break;
 
429
 
 
430
        case Neon:
 
431
            neon(data, w, h, sb, m_levelInput->value(), m_iterationInput->value());
 
432
            break;
 
433
 
 
434
        case FindEdges:
 
435
            findEdges(data, w, h, sb, m_levelInput->value(), m_iterationInput->value());
 
436
            break;
 
437
    }
 
438
}
 
439
 
 
440
void ImageEffect_ColorFX::solarize(int factor, uchar *data, int w, int h, bool sb)
 
441
{
 
442
    bool stretch = true;
 
443
 
 
444
    if (!sb)        // 8 bits image.
 
445
    {
 
446
        uint threshold = (uint)((100-factor)*(255+1)/100);
 
447
        threshold      = QMAX(1, threshold);
 
448
        uchar *ptr = data;
 
449
        uchar  a, r, g, b;
 
450
 
 
451
        for (int x=0 ; x < w*h ; x++)
 
452
        {
 
453
            b = ptr[0];
 
454
            g = ptr[1];
 
455
            r = ptr[2];
 
456
            a = ptr[3];
 
457
 
 
458
            if (stretch) 
 
459
            {
 
460
                r = (r > threshold) ? (255-r)*255/(255-threshold) : r*255/threshold;
 
461
                g = (g > threshold) ? (255-g)*255/(255-threshold) : g*255/threshold;
 
462
                b = (b > threshold) ? (255-b)*255/(255-threshold) : b*255/threshold;
 
463
            }
 
464
            else 
 
465
            {
 
466
                if (r > threshold)
 
467
                    r = (255-r);
 
468
                if (g > threshold)
 
469
                    g = (255-g);
 
470
                if (b > threshold)
 
471
                    b = (255-b);
 
472
            }
 
473
 
 
474
            ptr[0] = b;
 
475
            ptr[1] = g;
 
476
            ptr[2] = r;
 
477
            ptr[3] = a;
 
478
 
 
479
            ptr += 4;
 
480
        }
 
481
    }
 
482
    else                            // 16 bits image.
 
483
    {
 
484
        uint threshold = (uint)((100-factor)*(65535+1)/100);
 
485
        threshold      = QMAX(1, threshold);
 
486
        unsigned short *ptr = (unsigned short *)data;
 
487
        unsigned short  a, r, g, b;
 
488
 
 
489
        for (int x=0 ; x < w*h ; x++)
 
490
        {
 
491
            b = ptr[0];
 
492
            g = ptr[1];
 
493
            r = ptr[2];
 
494
            a = ptr[3];
 
495
 
 
496
            if (stretch) 
 
497
            {
 
498
                r = (r > threshold) ? (65535-r)*65535/(65535-threshold) : r*65535/threshold;
 
499
                g = (g > threshold) ? (65535-g)*65535/(65535-threshold) : g*65535/threshold;
 
500
                b = (b > threshold) ? (65535-b)*65535/(65535-threshold) : b*65535/threshold;
 
501
            }
 
502
            else 
 
503
            {
 
504
                if (r > threshold)
 
505
                    r = (65535-r);
 
506
                if (g > threshold)
 
507
                    g = (65535-g);
 
508
                if (b > threshold)
 
509
                    b = (65535-b);
 
510
            }
 
511
 
 
512
            ptr[0] = b;
 
513
            ptr[1] = g;
 
514
            ptr[2] = r;
 
515
            ptr[3] = a;
 
516
 
 
517
            ptr += 4;
 
518
        }
 
519
    }
 
520
}
 
521
 
 
522
void ImageEffect_ColorFX::vivid(int factor, uchar *data, int w, int h, bool sb)
 
523
{   
 
524
    float amount = factor/100.0;  
 
525
 
 
526
    Digikam::DImgImageFilters filter;
 
527
 
 
528
    // Apply Channel Mixer adjustments.
 
529
 
 
530
    filter.channelMixerImage(
 
531
                             data, w, h, sb,                       // Image data.
 
532
                             true,                                 // Preserve Luminosity 
 
533
                             false,                                // Disable Black & White mode.
 
534
                             1.0 + amount + amount, (-1.0)*amount, (-1.0)*amount, // Red Gains.
 
535
                             (-1.0)*amount, 1.0 + amount + amount, (-1.0)*amount, // Green Gains.
 
536
                             (-1.0)*amount, (-1.0)*amount, 1.0 + amount + amount  // Blue Gains.
 
537
                            ); 
 
538
 
 
539
    // Allocate the destination image data.
 
540
 
 
541
    uchar *dest = new uchar[w*h*(sb ? 8 : 4)];
 
542
 
 
543
    // And now apply the curve correction.
 
544
 
 
545
    Digikam::ImageCurves Curves(sb);
 
546
 
 
547
    if (!sb)        // 8 bits image.
 
548
    {
 
549
        Curves.setCurvePoint(Digikam::ImageHistogram::ValueChannel, 0,  QPoint(0,   0));
 
550
        Curves.setCurvePoint(Digikam::ImageHistogram::ValueChannel, 5,  QPoint(63,  60));
 
551
        Curves.setCurvePoint(Digikam::ImageHistogram::ValueChannel, 10, QPoint(191, 194));
 
552
        Curves.setCurvePoint(Digikam::ImageHistogram::ValueChannel, 16, QPoint(255, 255));
 
553
    }
 
554
    else                    // 16 bits image.
 
555
    {                       
 
556
        Curves.setCurvePoint(Digikam::ImageHistogram::ValueChannel, 0,  QPoint(0,     0));
 
557
        Curves.setCurvePoint(Digikam::ImageHistogram::ValueChannel, 5,  QPoint(16128, 15360));
 
558
        Curves.setCurvePoint(Digikam::ImageHistogram::ValueChannel, 10, QPoint(48896, 49664));
 
559
        Curves.setCurvePoint(Digikam::ImageHistogram::ValueChannel, 16, QPoint(65535, 65535));
 
560
   }
 
561
 
 
562
    Curves.curvesCalculateCurve(Digikam::ImageHistogram::AlphaChannel);   // Calculate cure on all channels.
 
563
    Curves.curvesLutSetup(Digikam::ImageHistogram::AlphaChannel);         // ... and apply it on all channels
 
564
    Curves.curvesLutProcess(data, dest, w, h);
 
565
 
 
566
    memcpy(data, dest, w*h*(sb ? 8 : 4));
 
567
    delete [] dest;
 
568
}
 
569
 
 
570
/* Function to apply the Neon effect                                            
 
571
 *                                                                                  
 
572
 * data             => The image data in RGBA mode.                            
 
573
 * Width            => Width of image.                          
 
574
 * Height           => Height of image.  
 
575
 * Intensity        => Intensity value                                                
 
576
 * BW               => Border Width                            
 
577
 *                                                                                  
 
578
 * Theory           => Wow, this is a great effect, you've never seen a Neon effect   
 
579
 *                     like this on PSC. Is very similar to Growing Edges (photoshop)  
 
580
 *                     Some pictures will be very interesting   
 
581
 */
 
582
void ImageEffect_ColorFX::neon(uchar *data, int w, int h, bool sb, int Intensity, int BW)
 
583
{
 
584
    neonFindEdges(data, w, h, sb, true, Intensity, BW);
 
585
}
 
586
 
 
587
/* Function to apply the Find Edges effect                                            
 
588
 *                                                                                  
 
589
 * data             => The image data in RGBA mode.                            
 
590
 * Width            => Width of image.                          
 
591
 * Height           => Height of image.  
 
592
 * Intensity        => Intensity value                                                
 
593
 * BW               => Border Width                            
 
594
 *                                                                                  
 
595
 * Theory           => Wow, another Photoshop filter (FindEdges). Do you understand  
 
596
 *                     Neon effect ? This is the same engine, but is inversed with   
 
597
 *                     255 - color.  
 
598
 */
 
599
void ImageEffect_ColorFX::findEdges(uchar *data, int w, int h, bool sb, int Intensity, int BW)
 
600
{
 
601
    neonFindEdges(data, w, h, sb, false, Intensity, BW);
 
602
}
 
603
 
 
604
// Implementation of neon and FindEdges. They share 99% of their code.
 
605
void ImageEffect_ColorFX::neonFindEdges(uchar *data, int w, int h, bool sb, bool neon, int Intensity, int BW)
 
606
{
 
607
    int Width       = w;
 
608
    int Height      = h;
 
609
    bool sixteenBit = sb;
 
610
    int bytesDepth  = sb ? 8 : 4;
 
611
    uchar* pResBits = new uchar[Width*Height*bytesDepth];
 
612
 
 
613
    Intensity = (Intensity < 0) ? 0 : (Intensity > 5) ? 5 : Intensity;
 
614
    BW = (BW < 1) ? 1 : (BW > 5) ? 5 : BW;
 
615
 
 
616
    uchar *ptr, *ptr1, *ptr2;
 
617
 
 
618
    // these must be uint, we need full 2^32 range for 16 bit
 
619
    uint color_1, color_2, colorPoint, colorOther1, colorOther2;
 
620
 
 
621
    // initial copy
 
622
    memcpy (pResBits, data, Width*Height*bytesDepth);
 
623
 
 
624
    double intensityFactor = sqrt( 1 << Intensity );
 
625
 
 
626
    for (int h = 0; h < Height; h++)
 
627
    {
 
628
        for (int w = 0; w < Width; w++)
 
629
        {
 
630
            ptr  = pResBits + getOffset(Width, w, h, bytesDepth);
 
631
            ptr1 = pResBits + getOffset(Width, w + Lim_Max (w, BW, Width), h, bytesDepth);
 
632
            ptr2 = pResBits + getOffset(Width, w, h + Lim_Max (h, BW, Height), bytesDepth);
 
633
 
 
634
            if (sixteenBit)
 
635
            {
 
636
                for (int k = 0; k <= 2; k++)
 
637
                {
 
638
                    colorPoint  = ((unsigned short *)ptr)[k];
 
639
                    colorOther1 = ((unsigned short *)ptr1)[k];
 
640
                    colorOther2 = ((unsigned short *)ptr2)[k];
 
641
                    color_1 = (colorPoint - colorOther1) * (colorPoint - colorOther1);
 
642
                    color_2 = (colorPoint - colorOther2) * (colorPoint - colorOther2);
 
643
 
 
644
                    // old algorithm was
 
645
                    // sqrt ((color_1 + color_2) << Intensity)
 
646
                    // As (a << I) = a * (1 << I) = a * (2^I), and we can split the square root
 
647
 
 
648
                    if (neon)
 
649
                        ((unsigned short *)ptr)[k] = CLAMP065535 ((int)( sqrt(color_1 + color_2) * intensityFactor ));
 
650
                    else
 
651
                        ((unsigned short *)ptr)[k] = 65535 - CLAMP065535 ((int)( sqrt(color_1 + color_2) * intensityFactor ));
 
652
                }
 
653
            }
 
654
            else
 
655
            {
 
656
                for (int k = 0; k <= 2; k++)
 
657
                {
 
658
                    colorPoint  = ptr[k];
 
659
                    colorOther1 = ptr1[k];
 
660
                    colorOther2 = ptr2[k];
 
661
                    color_1 = (colorPoint - colorOther1) * (colorPoint - colorOther1);
 
662
                    color_2 = (colorPoint - colorOther2) * (colorPoint - colorOther2);
 
663
 
 
664
                    if (neon)
 
665
                        ptr[k] = CLAMP0255 ((int)( sqrt(color_1 + color_2) * intensityFactor ));
 
666
                    else
 
667
                        ptr[k] = 255 - CLAMP0255 ((int)( sqrt(color_1 + color_2) * intensityFactor ));
 
668
                }
 
669
            }
 
670
        }
 
671
    }
 
672
 
 
673
    memcpy (data, pResBits, Width*Height*bytesDepth);
 
674
    delete [] pResBits;
 
675
}
 
676
 
 
677
int ImageEffect_ColorFX::getOffset(int Width, int X, int Y, int bytesDepth)
 
678
{
 
679
    return (Y * Width * bytesDepth) + (X * bytesDepth);
 
680
}
 
681
 
 
682
inline int ImageEffect_ColorFX::Lim_Max(int Now, int Up, int Max) 
 
683
{
 
684
    --Max;
 
685
    while (Now > Max - Up) --Up;
 
686
    return (Up);
 
687
}
 
688
 
 
689
}  // NameSpace DigikamColorFXImagesPlugin
 
690