kis_emboss_filter.cpp 5.79 KB
Newer Older
1
/*
Halla Rempt's avatar
Halla Rempt committed
2
3
4
5
 * This file is part of Krita
 *
 * Copyright (c) 2004 Michael Thaler <michael.thaler@physik.tu-muenchen.de>
 *
Halla Rempt's avatar
Halla Rempt committed
6
 * ported from digikam, Copyrighted 2004 Gilles Caulier,
7
 * Original Emboss algorithm copyrighted 2004 by
Halla Rempt's avatar
Halla Rempt committed
8
9
 * Pieter Z. Voloshyn <pieter_voloshyn at ame.com.br>.
 *
10
11
12
13
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
Halla Rempt's avatar
Halla Rempt committed
14
 *
15
16
17
18
19
20
21
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
22
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Halla Rempt's avatar
Halla Rempt committed
23
 */
Halla Rempt's avatar
Halla Rempt committed
24

Halla Rempt's avatar
Halla Rempt committed
25
#include "kis_emboss_filter.h"
26

Halla Rempt's avatar
Halla Rempt committed
27

28
29
30
#include <stdlib.h>
#include <vector>

31
32
#include <QPoint>
#include <QSpinBox>
33
34
35
36

#include <klocale.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
37
#include <kis_debug.h>
38
#include <kpluginfactory.h>
39
40
#include <knuminput.h>

41
#include "KoIntegerMaths.h"
42
#include "KoProgressUpdater.h"
Thomas Zander's avatar
Thomas Zander committed
43
#include <KoUpdater.h>
44

45
#include <kis_random_accessor_ng.h>
46
#include <filter/kis_filter_registry.h>
47
#include <kis_global.h>
48
#include <kis_selection.h>
49
#include <kis_types.h>
50
#include <filter/kis_filter_configuration.h>
Halla Rempt's avatar
Halla Rempt committed
51
#include <kis_paint_device.h>
52
#include <kis_processing_information.h>
53

54
#include "widgets/kis_multi_integer_filter_widget.h"
Cyrille Berger Skott's avatar
Cyrille Berger Skott committed
55
#include <kis_iterator_ng.h>
56

57
KisEmbossFilter::KisEmbossFilter() : KisFilter(id(), categoryEmboss(), i18n("&Emboss with Variable Depth..."))
58
{
Halla Rempt's avatar
Halla Rempt committed
59
    setSupportsPainting(false);
60
    setColorSpaceIndependence(TO_RGBA8);
61
    setSupportsThreading(false);
62
63
}

64
KisFilterConfiguration* KisEmbossFilter::factoryConfiguration(const KisPaintDeviceSP) const
Cyrille Berger's avatar
Cyrille Berger committed
65
{
66
    KisFilterConfiguration* config = new KisFilterConfiguration(id().id(), 0);
Halla Rempt's avatar
Halla Rempt committed
67
    config->setProperty("depth", 30);
Cyrille Berger's avatar
Cyrille Berger committed
68
    return config;
Cyrille Berger's avatar
Cyrille Berger committed
69
70
}

71
72
// This method have been ported from Pieter Z. Voloshyn algorithm code.

73
74
75
76
77
78
79
80
81
82
/* Function to apply the Emboss effect
 *
 * data             => The image data in RGBA mode.
 * Width            => Width of image.
 * Height           => Height of image.
 * d                => Emboss value
 *
 * Theory           => This is an amazing effect. And the theory is very simple to
 *                     understand. You get the diference between the colors and
 *                     increase it. After this, get the gray tone
83
 */
84
85
86
87
88
void KisEmbossFilter::processImpl(KisPaintDeviceSP device,
                                  const QRect& applyRect,
                                  const KisFilterConfiguration* config,
                                  KoUpdater* progressUpdater
                                  ) const
89
{
Cyrille Berger Skott's avatar
Cyrille Berger Skott committed
90
91
    QPoint srcTopLeft = applyRect.topLeft();
    Q_ASSERT(device);
92

93
    //read the filter configuration values from the KisFilterConfiguration object
Halla Rempt's avatar
Halla Rempt committed
94
    quint32 embossdepth = config ?  config->getInt("depth", 30) : 30;
95
96
97
98
99

    //the actual filter function from digikam. It needs a pointer to a quint8 array
    //with the actual pixel data.

    float Depth = embossdepth / 10.0;
100
101
    int    R = 0, G = 0, B = 0;
    uchar  Gray = 0;
Cyrille Berger Skott's avatar
Cyrille Berger Skott committed
102
103
    int Width = applyRect.width();
    int Height = applyRect.height();
104

Halla Rempt's avatar
Halla Rempt committed
105
106
    if (progressUpdater) {
        progressUpdater->setRange(0, Height);
107
    }
108

109
    KisSequentialIterator it(device, applyRect);
110
111
    QColor color1;
    QColor color2;
Cyrille Berger Skott's avatar
Cyrille Berger Skott committed
112
113
114
115
    KisRandomConstAccessorSP acc = device->createRandomAccessorNG(srcTopLeft.x(), srcTopLeft.y());
    do {
    
        // XXX: COLORSPACE_INDEPENDENCE or at least work IN RGB16A
116
117
        device->colorSpace()->toQColor(it.oldRawData(), &color1);
        acc->moveTo(srcTopLeft.x() + it.x() + Lim_Max(it.x(), 1, Width), srcTopLeft.y() + it.y() + Lim_Max(it.y(), 1, Height));
118

Cyrille Berger Skott's avatar
Cyrille Berger Skott committed
119
        device->colorSpace()->toQColor(acc->oldRawData(), &color2);
120

Cyrille Berger Skott's avatar
Cyrille Berger Skott committed
121
122
123
        R = abs((int)((color1.red() - color2.red()) * Depth + (quint8_MAX / 2)));
        G = abs((int)((color1.green() - color2.green()) * Depth + (quint8_MAX / 2)));
        B = abs((int)((color1.blue() - color2.blue()) * Depth + (quint8_MAX / 2)));
124

Cyrille Berger Skott's avatar
Cyrille Berger Skott committed
125
        Gray = CLAMP((R + G + B) / 3, 0, quint8_MAX);
126

127
128
129
        device->colorSpace()->fromQColor(QColor(Gray, Gray, Gray, color1.alpha()), it.rawData());
        if (progressUpdater) { progressUpdater->setValue(it.y()); if(progressUpdater->interrupted()) return; }
    } while(it.nextPixel());
130
}
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146

// This method have been ported from Pieter Z. Voloshyn algorithm code.

/* This function limits the max and min values
 * defined by the developer
 *
 * Now               => Original value
 * Up                => Increments
 * Max               => Maximum value
 *
 * Theory            => This function is used in some functions to limit the
 *                      "for step". E.g. I have a picture with 309 pixels (width), and
 *                      my "for step" is 5. All the code go alright until reachs the
 *                      w = 305, because in the next step w will go to 310, but we want
 *                      to analize all the pixels. So, this function will reduce the
 *                      "for step", when necessary, until reach the last possible value
147
 */
148

Halla Rempt's avatar
Halla Rempt committed
149
int KisEmbossFilter::Lim_Max(int Now, int Up, int Max) const
150
151
152
153
154
{
    --Max;
    while (Now > Max - Up)
        --Up;
    return (Up);
155
156
}

157
KisConfigWidget * KisEmbossFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP dev) const
158
{
Halla Rempt's avatar
Halla Rempt committed
159
    Q_UNUSED(dev);
160

161
    vKisIntegerWidgetParam param;
Halla Rempt's avatar
Halla Rempt committed
162
    param.push_back(KisIntegerWidgetParam(10, 300, 30, i18n("Depth"), "depth"));
163
    KisConfigWidget * w = new KisMultiIntegerFilterWidget(id().id(), parent, id().id(), param);
164
165
    Q_CHECK_PTR(w);
    return w;
166
}