imagecurves.cpp 36.2 KB
Newer Older
1
/* ============================================================
Gilles Caulier's avatar
Gilles Caulier committed
2
3
4
5
6
 *
 * This file is a part of digiKam project
 * http://www.digikam.org
 *
 * Date        : 2004-12-01
7
 * Description : image curves manipulation methods.
Gilles Caulier's avatar
Gilles Caulier committed
8
 *
Gilles Caulier's avatar
Gilles Caulier committed
9
 * Copyright (C) 2004-2012 by Gilles Caulier <caulier dot gilles at gmail dot com>
10
11
12
13
14
15
 *
 * 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, or (at your option)
 * any later version.
Gilles Caulier's avatar
Gilles Caulier committed
16
 *
17
18
19
20
 * 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.
Gilles Caulier's avatar
Gilles Caulier committed
21
 *
22
23
 * ============================================================ */

24
25
#include "imagecurves.h"

26
// C++ includes
Gilles Caulier's avatar
Gilles Caulier committed
27

28
29
30
31
32
33
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <cerrno>

34
// Qt includes
35

Gilles Caulier's avatar
Gilles Caulier committed
36
#include <QFile>
37
#include <QSharedData>
38

39
40
41
42
// KDE includes

#include <kdebug.h>

Andi Clemens's avatar
Andi Clemens committed
43
// Local includes
44

45
#include "curvescontainer.h"
46
#include "filteraction.h"
47
#include "globals.h"
48

49
50
51
namespace Digikam
{

52
53
const int ImageCurves::NUM_POINTS       = 17;
const int ImageCurves::NUM_CHANNELS     = 5;
54
55
const int ImageCurves::MULTIPLIER_16BIT = 255;

Gilles Caulier's avatar
Gilles Caulier committed
56
class ImageCurves::Private : public QSharedData
57
{
Gilles Caulier's avatar
Gilles Caulier committed
58

59
60
61
62
public:

    struct _Curves
    {
Johannes Wienke's avatar
Johannes Wienke committed
63
64
65
66
67
68
69
70
71
72
73
        /**
         * Curve types by channels (Smooth or Free).
         */
        ImageCurves::CurveType curve_type[ImageCurves::NUM_CHANNELS];
        /**
         * Curve main points in Smooth mode ([channel][point id][x,y])
         */
        int                    points[ImageCurves::NUM_CHANNELS][ImageCurves::NUM_POINTS][2];
        /**
         * Curve values by channels
         */
74
        unsigned short         curve[ImageCurves::NUM_CHANNELS][NUM_SEGMENTS_16BIT];
75
    };
Gilles Caulier's avatar
Gilles Caulier committed
76

77
78
    struct _Lut
    {
79
        unsigned short** luts;
80
81
82
83
84
        int              nchannels;
    };

public:

Gilles Caulier's avatar
Gilles Caulier committed
85
    Private() :
86
87
88
89
        curves(0),
        lut(0),
        segmentMax(0),
        dirty(false)
90
91
92
    {
    }

Gilles Caulier's avatar
Gilles Caulier committed
93
    ~Private()
94
95
96
97
98
99
100
101
    {
        if (lut)
        {
            freeLutData();
            delete lut;
        }

        if (curves)
102
        {
103
            delete curves;
104
        }
105
106
107
108
    }

    void init(bool sixteenBit)
    {
Gilles Caulier's avatar
Gilles Caulier committed
109
        lut        = new Private::_Lut;
110
        lut->luts  = NULL;
Gilles Caulier's avatar
Gilles Caulier committed
111
        curves     = new Private::_Curves;
112
113
114
        segmentMax = sixteenBit ? MAX_SEGMENT_16BIT : MAX_SEGMENT_8BIT;
    }

Gilles Caulier's avatar
Gilles Caulier committed
115
    bool isPointEnabled(const QPoint& point) const
116
117
118
119
    {
        return (point.x() > - 1) && (point.y() > -1);
    }

120
121
122
123
124
125
126
127
    void freeLutData()
    {
        if (lut->luts)
        {
            for (int i = 0 ; i < lut->nchannels ; ++i)
            {
                delete [] lut->luts[i];
            }
128

129
130
131
132
            delete [] lut->luts;
        }
    }

133
    // Curves data.
134
    struct _Curves* curves;
Gilles Caulier's avatar
Gilles Caulier committed
135

136
    // Lut data.
137
    struct _Lut*    lut;
138
139

    int             segmentMax;
Gilles Caulier's avatar
Gilles Caulier committed
140
141

    bool            dirty;
142
143
};

144
145
ImageCurves::CRMatrix CR_basis =
{
146
147
148
149
    { -0.5,  1.5, -1.5,  0.5 },
    {  1.0, -2.5,  2.0, -0.5 },
    { -0.5,  0.0,  0.5,  0.0 },
    {  0.0,  1.0,  0.0,  0.0 },
150
151
};

152
ImageCurves::ImageCurves(bool sixteenBit)
Gilles Caulier's avatar
Gilles Caulier committed
153
    : d(new Private)
154
{
155
156
157
    d->init(sixteenBit);
    curvesReset();
}
158

159
ImageCurves::ImageCurves(const CurvesContainer& container)
Gilles Caulier's avatar
Gilles Caulier committed
160
    : d(new Private)
161
162
{
    d->init(container.sixteenBit);
163
    curvesReset();
Gilles Caulier's avatar
Gilles Caulier committed
164
    setContainer(container);
165
166
}

167
ImageCurves::ImageCurves(const ImageCurves& other)
168
    : d(other.d)
Gilles Caulier's avatar
Gilles Caulier committed
169
{
170
}
Gilles Caulier's avatar
Gilles Caulier committed
171

172
173
174
ImageCurves::~ImageCurves()
{
}
Gilles Caulier's avatar
Gilles Caulier committed
175

176
177
178
179
ImageCurves& ImageCurves::operator=(const ImageCurves& other)
{
    d = other.d;
    return *this;
180
181
}

Gilles Caulier's avatar
Gilles Caulier committed
182
void ImageCurves::fillFromOtherCurves(ImageCurves* const otherCurves)
183
{
184
    //kDebug() << "Filling this curve from other curve " << otherCurves;
185
186
187
188
189
190

    curvesReset();

    // if the other curves have the same bit depth, simply copy their data
    if (isSixteenBits() == otherCurves->isSixteenBits())
    {
191
        //kDebug() << "Both curves have same type: isSixteenBits = " << isSixteenBits();
192

193
194
        for (int channel = 0; channel < NUM_CHANNELS; ++channel)
        {
195
            if (otherCurves->getCurveType(channel) == CURVE_SMOOTH)
196
            {
197
                //kDebug() << "Other is CURVE_SMOOTH";
198
                setCurveType(channel, CURVE_SMOOTH);
199

200
                for (int point = 0; point < NUM_POINTS; ++point)
201
                {
202
203
204
205
206
207
208
209
210
211
                    QPoint p = otherCurves->getCurvePoint(channel, point);

                    if (d->isPointEnabled(p))
                    {
                        setCurvePoint(channel, point, p);
                    }
                }
            }
            else
            {
212
                //kDebug() << "Other is CURVE_FREE";
213
214
215
216
217
                setCurveType(channel, CURVE_FREE);

                for (int i = 0 ; i <= d->segmentMax ; ++i)
                {
                    setCurveValue(channel, i, otherCurves->getCurveValue(channel, i));
218
219
220
221
222
223
224
                }
            }
        }
    }
    // other curve is 8 bit and this curve is 16 bit
    else if (isSixteenBits() && !otherCurves->isSixteenBits())
    {
225
        //kDebug() << "This curve is 16 bit and the other is 8 bit";
226

227
228
        for (int channel = 0; channel < NUM_CHANNELS; ++channel)
        {
229
            if (otherCurves->getCurveType(channel) == CURVE_SMOOTH)
230
            {
231
                //kDebug() << "Other is CURVE_SMOOTH";
232
                setCurveType(channel, CURVE_SMOOTH);
233

234
                for (int point = 0; point < NUM_POINTS; ++point)
235
                {
236
237
238
239
240
241
242
243
244
245
246
247
                    QPoint p = otherCurves->getCurvePoint(channel, point);

                    if (d->isPointEnabled(p))
                    {
                        p.setX(p.x() * MULTIPLIER_16BIT);
                        p.setY(p.y() * MULTIPLIER_16BIT);
                        setCurvePoint(channel, point, p);
                    }
                }
            }
            else
            {
248
                //kDebug() << "Other is CURVE_FREE";
249
250
251
252
253
                setCurveType(channel, CURVE_FREE);

                for (int i = 0 ; i <= d->segmentMax ; ++i)
                {
                    setCurveValue(channel, i * MULTIPLIER_16BIT, otherCurves->getCurveValue(channel, i) * MULTIPLIER_16BIT);
254
255
256
257
258
259
260
                }
            }
        }
    }
    // other curve is 16 bit and this is 8 bit
    else if (!isSixteenBits() && otherCurves->isSixteenBits())
    {
261
        //kDebug() << "This curve is 8 bit and the other is 16 bit";
262

263
264
        for (int channel = 0; channel < NUM_CHANNELS; ++channel)
        {
265
            if (otherCurves->getCurveType(channel) == CURVE_SMOOTH)
266
            {
267
                //kDebug() << "Other is CURVE_SMOOTH";
268
                setCurveType(channel, CURVE_SMOOTH);
269

270
271
                //kDebug() << "Adopting points of channel " << channel;
                for (int point = 0; point < NUM_POINTS; ++point)
272
                {
273
274
275
276
277
278
279
280
281
282
283
284
285
286
                    QPoint p = otherCurves->getCurvePoint(channel, point);

                    //kDebug() << "Point " << point << " in original is " << p;
                    if (d->isPointEnabled(p))
                    {
                        p.setX(p.x() / MULTIPLIER_16BIT);
                        p.setY(p.y() / MULTIPLIER_16BIT);
                        //kDebug() << "Setting curve point " << point << " to " << p;
                        setCurvePoint(channel, point, p);
                    }
                    else
                    {
                        //kDebug() << "ignoring this point";
                    }
287
                }
288
289
290
            }
            else
            {
291
                //kDebug() << "Other is CURVE_FREE";
292
293
294
                setCurveType(channel, CURVE_FREE);

                for (int i = 0 ; i <= d->segmentMax ; ++i)
295
                {
296
                    setCurveValue(channel, i, otherCurves->getCurveValue(channel, i * MULTIPLIER_16BIT) / MULTIPLIER_16BIT);
297
298
299
300
301
302
                }
            }
        }
    }
    else
    {
303
        kError() << "Bad logic error, could not fill one curve into another";
304
305
306
    }

    // invoke calculations once
307
    curvesCalculateAllCurves();
308
309
}

310
bool ImageCurves::isDirty() const
Gilles Caulier's avatar
Gilles Caulier committed
311
312
313
314
{
    return d->dirty;
}

315
bool ImageCurves::isSixteenBits() const
Gilles Caulier's avatar
Gilles Caulier committed
316
{
317
    return (d->segmentMax == MAX_SEGMENT_16BIT);
Gilles Caulier's avatar
Gilles Caulier committed
318
319
}

Gilles Caulier's avatar
Gilles Caulier committed
320
void ImageCurves::curvesReset()
321
{
Gilles Caulier's avatar
Gilles Caulier committed
322
    memset(d->curves, 0, sizeof(struct Private::_Curves));
323
    d->freeLutData();
324
325
    d->lut->luts      = NULL;
    d->lut->nchannels = 0;
Gilles Caulier's avatar
Gilles Caulier committed
326
    d->dirty          = false;
327

328
    for (int channel = 0 ; channel < NUM_CHANNELS ; ++channel)
329
    {
330
331
        setCurveType(channel, CURVE_SMOOTH);
        curvesChannelReset(channel);
332
    }
333
334
335
336
337
}

void ImageCurves::curvesChannelReset(int channel)
{
    int j;
Gilles Caulier's avatar
Gilles Caulier committed
338

339
340
341
342
    if (!d->curves)
    {
        return;
    }
343

Andi Clemens's avatar
Andi Clemens committed
344
    // Construct a linear curve.
Gilles Caulier's avatar
Gilles Caulier committed
345

346
    for (j = 0 ; j <= d->segmentMax ; ++j)
347
348
349
    {
        d->curves->curve[channel][j] = j;
    }
350
351

    // Init coordinates points to null.
Gilles Caulier's avatar
Gilles Caulier committed
352

353
    for (j = 0 ; j < NUM_POINTS ; ++j)
354
    {
355
356
        d->curves->points[channel][j][0] = -1;
        d->curves->points[channel][j][1] = -1;
357
    }
358
359

    // First and last points init.
Gilles Caulier's avatar
Gilles Caulier committed
360

Gilles Caulier's avatar
Gilles Caulier committed
361
362
    d->curves->points[channel][0][0]              = 0;
    d->curves->points[channel][0][1]              = 0;
363
364
    d->curves->points[channel][NUM_POINTS - 1][0] = d->segmentMax;
    d->curves->points[channel][NUM_POINTS - 1][1] = d->segmentMax;
365
366
367
368
369
}

void ImageCurves::curvesCalculateCurve(int channel)
{
    int i;
370
    int points[NUM_POINTS];
371
372
373
    int num_pts;
    int p1, p2, p3, p4;

374
375
376
377
    if (!d->curves)
    {
        return;
    }
378

379
    switch (d->curves->curve_type[channel])
380
    {
381
382
        case CURVE_FREE:
            break;
383

384
385
386
        case CURVE_SMOOTH:
        {
            //  Cycle through the curves
Gilles Caulier's avatar
Gilles Caulier committed
387

388
            num_pts = 0;
Gilles Caulier's avatar
Gilles Caulier committed
389

390
391
392
393
394
            for (i = 0 ; i < ImageCurves::NUM_POINTS ; ++i)
                if (d->curves->points[channel][i][0] != -1)
                {
                    points[num_pts++] = i;
                }
395

396
            //  Initialize boundary curve points
Gilles Caulier's avatar
Gilles Caulier committed
397

398
399
400
401
402
403
            if (num_pts != 0)
            {
                for (i = 0 ; i < d->curves->points[channel][points[0]][0] ; ++i)
                {
                    d->curves->curve[channel][i] = d->curves->points[channel][points[0]][1];
                }
Gilles Caulier's avatar
Gilles Caulier committed
404

405
406
407
408
409
                for (i = d->curves->points[channel][points[num_pts - 1]][0] ; i <= d->segmentMax ; ++i)
                {
                    d->curves->curve[channel][i] = d->curves->points[channel][points[num_pts - 1]][1];
                }
            }
410

411
412
413
414
415
416
            for (i = 0 ; i < num_pts - 1 ; ++i)
            {
                p1 = (i == 0) ? points[i] : points[(i - 1)];
                p2 = points[i];
                p3 = points[(i + 1)];
                p4 = (i == (num_pts - 2)) ? points[(num_pts - 1)] : points[(i + 2)];
417

418
419
                curvesPlotCurve(channel, p1, p2, p3, p4);
            }
420

421
            // Ensure that the control points are used exactly
Gilles Caulier's avatar
Gilles Caulier committed
422

423
424
425
            for (i = 0 ; i < num_pts ; ++i)
            {
                int x, y;
426

427
428
429
430
                x = d->curves->points[channel][points[i]][0];
                y = d->curves->points[channel][points[i]][1];
                d->curves->curve[channel][x] = y;
            }
431

432
433
            break;
        }
434
    }
435
436
437
438
439
440
441
442
443
}

float ImageCurves::curvesLutFunc(int n_channels, int channel, float value)
{
    float  f;
    int    index;
    double inten;
    int    j;

444
445
446
447
    if (!d->curves)
    {
        return 0.0;
    }
448
449

    if (n_channels == 1)
450
451
452
    {
        j = 0;
    }
453
    else
454
455
456
    {
        j = channel + 1;
    }
457
458
459
460
461

    inten = value;

    // For color images this runs through the loop with j = channel +1
    // the first time and j = 0 the second time.
Gilles Caulier's avatar
Gilles Caulier committed
462

463
464
    // For bw images this runs through the loop with j = 0 the first and
    // only time.
Gilles Caulier's avatar
Gilles Caulier committed
465

Andi Clemens's avatar
Andi Clemens committed
466
    for (; j >= 0 ; j -= (channel + 1))
467
    {
468
        // Don't apply the overall curve to the alpha channel.
Gilles Caulier's avatar
Gilles Caulier committed
469

Andi Clemens's avatar
Andi Clemens committed
470
        if (j == 0 && (n_channels == 2 || n_channels == 4) && channel == n_channels - 1)
471
472
473
        {
            return inten;
        }
474

475
476
        if (inten < 0.0)
        {
Andi Clemens's avatar
Andi Clemens committed
477
            inten = d->curves->curve[j][0] / (float)d->segmentMax;
478
479
480
        }
        else if (inten >= 1.0)
        {
Andi Clemens's avatar
Andi Clemens committed
481
            inten = d->curves->curve[j][d->segmentMax] / (float)(d->segmentMax);
482
483
484
485
486
487
        }
        else       // interpolate the curve.
        {
            index = (int)floor(inten * (float)(d->segmentMax));
            f = inten * (float)(d->segmentMax) - index;
            inten = ((1.0 - f) * d->curves->curve[j][index    ] +
Andi Clemens's avatar
Andi Clemens committed
488
                     (f) * d->curves->curve[j][index + 1]) / (float)(d->segmentMax);
489
        }
490
    }
491
492
493
494
495
496
497
498
499
500
501

    return inten;
}

void ImageCurves::curvesPlotCurve(int channel, int p1, int p2, int p3, int p4)
{
    CRMatrix geometry;
    CRMatrix tmp1, tmp2;
    CRMatrix deltas;
    double   x, dx, dx2, dx3;
    double   y, dy, dy2, dy3;
502
    double   d1, d2, d3;
503
504
505
    int      lastx, lasty;
    int      newx, newy;
    int      i;
506
    int      loopdiv = d->segmentMax * 3;
507

508
509
510
511
    if (!d->curves)
    {
        return;
    }
512
513

    // Construct the geometry matrix from the segment.
Gilles Caulier's avatar
Gilles Caulier committed
514

515
    for (i = 0 ; i < 4 ; ++i)
516
    {
517
518
        geometry[i][2] = 0;
        geometry[i][3] = 0;
519
    }
520

521
    for (i = 0 ; i < 2 ; ++i)
522
    {
523
524
525
526
        geometry[0][i] = d->curves->points[channel][p1][i];
        geometry[1][i] = d->curves->points[channel][p2][i];
        geometry[2][i] = d->curves->points[channel][p3][i];
        geometry[3][i] = d->curves->points[channel][p4][i];
527
    }
528
529
530

    // Subdivide the curve 1000 times.
    // n can be adjusted to give a finer or coarser curve.
Gilles Caulier's avatar
Gilles Caulier committed
531

Gilles Caulier's avatar
polish    
Gilles Caulier committed
532
    d1 = 1.0 / loopdiv;
533
534
    d2 = d1 * d1;
    d3 = d1 * d1 * d1;
535
536

    // Construct a temporary matrix for determining the forward differencing deltas.
Gilles Caulier's avatar
Gilles Caulier committed
537

538
539
540
541
542
543
544
545
    tmp2[0][0] = 0;
    tmp2[0][1] = 0;
    tmp2[0][2] = 0;
    tmp2[0][3] = 1;
    tmp2[1][0] = d3;
    tmp2[1][1] = d2;
    tmp2[1][2] = d1;
    tmp2[1][3] = 0;
Andi Clemens's avatar
Andi Clemens committed
546
547
    tmp2[2][0] = 6 * d3;
    tmp2[2][1] = 2 * d2;
548
549
    tmp2[2][2] = 0;
    tmp2[2][3] = 0;
Andi Clemens's avatar
Andi Clemens committed
550
    tmp2[3][0] = 6 * d3;
551
552
553
    tmp2[3][1] = 0;
    tmp2[3][2] = 0;
    tmp2[3][3] = 0;
554
555

    // Compose the basis and geometry matrices.
Gilles Caulier's avatar
Gilles Caulier committed
556

557
558
559
    curvesCRCompose(CR_basis, geometry, tmp1);

    // Compose the above results to get the deltas matrix.
Gilles Caulier's avatar
Gilles Caulier committed
560

561
562
563
    curvesCRCompose(tmp2, tmp1, deltas);

    // Extract the x deltas.
Gilles Caulier's avatar
Gilles Caulier committed
564

565
566
567
568
569
570
    x   = deltas[0][0];
    dx  = deltas[1][0];
    dx2 = deltas[2][0];
    dx3 = deltas[3][0];

    // Extract the y deltas.
Gilles Caulier's avatar
Gilles Caulier committed
571

572
573
574
575
576
    y   = deltas[0][1];
    dy  = deltas[1][1];
    dy2 = deltas[2][1];
    dy3 = deltas[3][1];

Andi Clemens's avatar
Andi Clemens committed
577
578
    lastx = (int)CLAMP(x, 0.0, (double)d->segmentMax);
    lasty = (int)CLAMP(y, 0.0, (double)d->segmentMax);
579

580
    d->curves->curve[channel][lastx] = lasty;
581
582

    // Loop over the curve.
Gilles Caulier's avatar
Gilles Caulier committed
583

584
    for (i = 0 ; i < loopdiv ; ++i)
585
    {
586
        // Increment the x values.
Gilles Caulier's avatar
Gilles Caulier committed
587

588
589
590
        x   += dx;
        dx  += dx2;
        dx2 += dx3;
591

592
        // Increment the y values.
Gilles Caulier's avatar
Gilles Caulier committed
593

594
595
596
        y   += dy;
        dy  += dy2;
        dy2 += dy3;
597

598
599
        newx = CLAMP((int)lround(x), 0, d->segmentMax);
        newy = CLAMP((int)lround(y), 0, d->segmentMax);
600

601
        // If this point is different than the last one...then draw it.
Gilles Caulier's avatar
Gilles Caulier committed
602

603
604
605
606
        if ((lastx != newx) || (lasty != newy))
        {
            d->curves->curve[channel][newx] = newy;
        }
607

608
609
        lastx = newx;
        lasty = newy;
610
    }
611
612
613
614
615
616
}

void ImageCurves::curvesCRCompose(CRMatrix a, CRMatrix b, CRMatrix ab)
{
    int i, j;

617
    for (i = 0 ; i < 4 ; ++i)
618
    {
619
620
621
622
623
624
625
        for (j = 0 ; j < 4 ; ++j)
        {
            ab[i][j] = (a[i][0] * b[0][j] +
                        a[i][1] * b[1][j] +
                        a[i][2] * b[2][j] +
                        a[i][3] * b[3][j]);
        }
626
    }
627
628
}

629
void ImageCurves::curvesLutSetup(int nchannels)
630
{
631
    int    i;
632
633
634
    uint   v;
    double val;

635
    curvesCalculateAllCurves();
636
637

    d->freeLutData();
638

639
640
    d->lut->nchannels = nchannels;
    d->lut->luts      = new unsigned short*[d->lut->nchannels];
Gilles Caulier's avatar
Gilles Caulier committed
641

642
    for (i = 0 ; i < d->lut->nchannels ; ++i)
643
    {
Andi Clemens's avatar
Andi Clemens committed
644
        d->lut->luts[i] = new unsigned short[d->segmentMax + 1];
645

646
647
648
        for (v = 0 ; v <= (uint)d->segmentMax ; ++v)
        {
            // To add gamma correction use func(v ^ g) ^ 1/g instead.
Gilles Caulier's avatar
Gilles Caulier committed
649

Andi Clemens's avatar
Andi Clemens committed
650
            val = (double)(d->segmentMax) * curvesLutFunc(d->lut->nchannels, i, v / (float)(d->segmentMax)) + 0.5;
Gilles Caulier's avatar
Gilles Caulier committed
651

652
653
            d->lut->luts[i][v] = (unsigned short)CLAMP(val, 0.0, (double)d->segmentMax);
        }
654
    }
655
656
}

Gilles Caulier's avatar
Gilles Caulier committed
657
void ImageCurves::curvesLutProcess(uchar* const srcPR, uchar* const destPR, int w, int h)
658
{
659
    unsigned short* lut0 = NULL, *lut1 = NULL, *lut2 = NULL, *lut3 = NULL;
660
    int i;
661

662
    if (d->lut->nchannels > 0)
663
664
665
666
    {
        lut0 = d->lut->luts[0];
    }

667
    if (d->lut->nchannels > 1)
668
669
670
671
    {
        lut1 = d->lut->luts[1];
    }

672
    if (d->lut->nchannels > 2)
673
674
675
676
    {
        lut2 = d->lut->luts[2];
    }

677
    if (d->lut->nchannels > 3)
678
679
680
    {
        lut3 = d->lut->luts[3];
    }
Gilles Caulier's avatar
Gilles Caulier committed
681

682
    if (!isSixteenBits())        // 8 bits image.
683
    {
Gilles Caulier's avatar
Gilles Caulier committed
684
        uchar red, green, blue, alpha;
685
686
        uchar* ptr = srcPR;
        uchar* dst = destPR;
Gilles Caulier's avatar
Gilles Caulier committed
687

Andi Clemens's avatar
Andi Clemens committed
688
        for (i = 0 ; i < w * h ; ++i)
689
        {
Gilles Caulier's avatar
Gilles Caulier committed
690
691
692
            blue  = ptr[0];
            green = ptr[1];
            red   = ptr[2];
693
694
            alpha = ptr[3];

Andi Clemens's avatar
Andi Clemens committed
695
            if (d->lut->nchannels > 0)
696
697
698
            {
                red = lut0[red];
            }
Gilles Caulier's avatar
Gilles Caulier committed
699

Andi Clemens's avatar
Andi Clemens committed
700
            if (d->lut->nchannels > 1)
701
702
703
            {
                green = lut1[green];
            }
Gilles Caulier's avatar
Gilles Caulier committed
704

Andi Clemens's avatar
Andi Clemens committed
705
            if (d->lut->nchannels > 2)
706
707
708
            {
                blue = lut2[blue];
            }
Gilles Caulier's avatar
Gilles Caulier committed
709

Andi Clemens's avatar
Andi Clemens committed
710
            if (d->lut->nchannels > 3)
711
712
713
            {
                alpha = lut3[alpha];
            }
Gilles Caulier's avatar
Gilles Caulier committed
714

Gilles Caulier's avatar
Gilles Caulier committed
715
716
717
            dst[0] = blue;
            dst[1] = green;
            dst[2] = red;
718
719
720
721
            dst[3] = alpha;

            ptr += 4;
            dst += 4;
722
723
        }
    }
724
725
    else               // 16 bits image.
    {
Gilles Caulier's avatar
Gilles Caulier committed
726
        unsigned short red, green, blue, alpha;
727
728
        unsigned short* ptr = (unsigned short*)srcPR;
        unsigned short* dst = (unsigned short*)destPR;
729

Andi Clemens's avatar
Andi Clemens committed
730
        for (i = 0 ; i < w * h ; ++i)
731
        {
Gilles Caulier's avatar
Gilles Caulier committed
732
733
734
            blue  = ptr[0];
            green = ptr[1];
            red   = ptr[2];
735
            alpha = ptr[3];
Gilles Caulier's avatar
Gilles Caulier committed
736

Andi Clemens's avatar
Andi Clemens committed
737
            if (d->lut->nchannels > 0)
738
739
740
            {
                red = lut0[red];
            }
Gilles Caulier's avatar
Gilles Caulier committed
741

Andi Clemens's avatar
Andi Clemens committed
742
            if (d->lut->nchannels > 1)
743
744
745
            {
                green = lut1[green];
            }
Gilles Caulier's avatar
Gilles Caulier committed
746

Andi Clemens's avatar
Andi Clemens committed
747
            if (d->lut->nchannels > 2)
748
749
750
            {
                blue = lut2[blue];
            }
Gilles Caulier's avatar
Gilles Caulier committed
751

Andi Clemens's avatar
Andi Clemens committed
752
            if (d->lut->nchannels > 3)
753
754
755
            {
                alpha = lut3[alpha];
            }
Gilles Caulier's avatar
Gilles Caulier committed
756

Gilles Caulier's avatar
Gilles Caulier committed
757
758
759
            dst[0] = blue;
            dst[1] = green;
            dst[2] = red;
760
761
762
763
764
            dst[3] = alpha;

            ptr += 4;
            dst += 4;
        }
Gilles Caulier's avatar
Gilles Caulier committed
765
    }
766
767
}

768
769
770
771
772
773
774
775
QPoint ImageCurves::getDisabledValue()
{
    return QPoint(-1, -1);
}

bool ImageCurves::isCurvePointEnabled(int channel, int point) const
{
    if (d->curves && channel >= 0 && channel < NUM_CHANNELS
776
777
778
        && point >= 0 && point < NUM_POINTS
        && d->curves->points[channel][point][0] >= 0
        && d->curves->points[channel][point][1] >= 0)
779
780
781
782
783
784
785
786
787
    {
        return true;
    }
    else
    {
        return false;
    }
}

788
QPoint ImageCurves::getCurvePoint(int channel, int point) const
789
{
Andi Clemens's avatar
Andi Clemens committed
790
791
792
    if (d->curves &&
        channel >= 0 && channel < NUM_CHANNELS &&
        point >= 0 && point < NUM_POINTS)
793
794
    {
        return(QPoint(d->curves->points[channel][point][0],
Andi Clemens's avatar
Andi Clemens committed
795
                      d->curves->points[channel][point][1]));
796
    }
Gilles Caulier's avatar
Gilles Caulier committed
797

798
    return getDisabledValue();
799
800
}

801
QPolygon ImageCurves::getCurvePoints(int channel) const
Gilles Caulier's avatar
Gilles Caulier committed
802
{
803
    QPolygon array(NUM_POINTS);
Gilles Caulier's avatar
Gilles Caulier committed
804

Andi Clemens's avatar
Andi Clemens committed
805
    if (d->curves && channel >= 0 && channel < NUM_CHANNELS)
Gilles Caulier's avatar
Gilles Caulier committed
806
    {
807
        for (int j = 0 ; j < NUM_POINTS ; ++j)
808
        {
Gilles Caulier's avatar
polish    
Gilles Caulier committed
809
            array.setPoint(j, getCurvePoint(channel, j));
810
        }
Gilles Caulier's avatar
Gilles Caulier committed
811
812
813
814
815
    }

    return array;
}

816
int ImageCurves::getCurveValue(int channel, int bin) const
817
{
Andi Clemens's avatar
Andi Clemens committed
818
819
820
    if (d->curves &&
        channel >= 0 && channel < NUM_CHANNELS &&
        bin >= 0 && bin <= d->segmentMax)
821
822
823
    {
        return(d->curves->curve[channel][bin]);
    }
824
825
826
827

    return 0;
}

828
QPolygon ImageCurves::getCurveValues(int channel) const
829
{
Andi Clemens's avatar
Andi Clemens committed
830
    QPolygon array(d->segmentMax + 1);
831
832
833
834

    if (d->curves && channel >= 0 && channel < NUM_CHANNELS)
    {
        for (int j = 0 ; j <= d->segmentMax ; ++j)
835
        {
836
            array.setPoint(j, QPoint(j, getCurveValue(channel, j)));
837
        }
838
839
840
841
    }

    return array;
}
842

843
int ImageCurves::getCurvePointX(int channel, int point) const
844
{
Andi Clemens's avatar
Andi Clemens committed
845
846
847
    if (d->curves &&
        channel >= 0 && channel < NUM_CHANNELS &&
        point >= 0 && point < NUM_POINTS)
848
849
850
    {
        return(d->curves->points[channel][point][0]);
    }
Gilles Caulier's avatar
Gilles Caulier committed
851

852
853
854
    return(-1);
}

855
int ImageCurves::getCurvePointY(int channel, int point) const
856
{
Andi Clemens's avatar
Andi Clemens committed
857
858
859
    if (d->curves &&
        channel >= 0 && channel < NUM_CHANNELS &&
        point >= 0 && point < NUM_POINTS)
860
861
862
    {
        return(d->curves->points[channel][point][1]);
    }
Gilles Caulier's avatar
Gilles Caulier committed
863

864
865
866
    return (-1);
}

867
ImageCurves::CurveType ImageCurves::getCurveType(int channel) const
868
{
Andi Clemens's avatar
Andi Clemens committed
869
    if (d->curves && channel >= 0 && channel < NUM_CHANNELS)
870
    {
Andi Clemens's avatar
Andi Clemens committed
871
        return ((ImageCurves::CurveType) d->curves->curve_type[channel]);
872
    }
Gilles Caulier's avatar
Gilles Caulier committed
873

874
    return CURVE_SMOOTH;
875
876
}

877
878
879
CurvesContainer ImageCurves::getContainer() const
{
    CurveType type = CURVE_SMOOTH;
880

881
    for (int i = 0; i < ColorChannels; ++i)
882
    {
Andi Clemens's avatar
Andi Clemens committed
883
        if ((type = getCurveType(i)) == CURVE_FREE)
884
        {
885
            type = CURVE_FREE;
886
            break;
887
        }
888
    }
889
890

    CurvesContainer c(type, isSixteenBits());
891
    c.initialize();
892

893
894
895
896
897
    if (isLinear())
    {
        return c;
    }

898
899
    if (type == CURVE_FREE)
    {
900
        for (int i = 0; i < ColorChannels; ++i)
901
        {
902
            c.values[i] = getCurveValues(i);
903
        }
904
905
906
    }
    else
    {
907
        for (int i = 0; i < ColorChannels; ++i)