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

« back to all changes in this revision

Viewing changes to imageplugins/distortionfx/distortionfx.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        : 2005-07-18
7
 
 * Description : Distortion FX threaded image filter.
8
 
 *
9
 
 * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
10
 
 * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
11
 
 *
12
 
 * Original Distortion algorithms copyrighted 2004-2005 by
13
 
 * Pieter Z. Voloshyn <pieter dot voloshyn at gmail dot com>.
14
 
 *
15
 
 * This program is free software; you can redistribute it
16
 
 * and/or modify it under the terms of the GNU General
17
 
 * Public License as published by the Free Software Foundation;
18
 
 * either version 2, or (at your option)
19
 
 * any later version.
20
 
 *
21
 
 * This program is distributed in the hope that it will be useful,
22
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24
 
 * GNU General Public License for more details.
25
 
 *
26
 
 * ============================================================ */
27
 
 
28
 
// Represents 1
29
 
#define ANGLE_RATIO        0.017453292519943295769236907685
30
 
 
31
 
 
32
 
#include "distortionfx.h"
33
 
 
34
 
// C++ includes
35
 
 
36
 
#include <cmath>
37
 
#include <cstdlib>
38
 
 
39
 
// Qt includes
40
 
 
41
 
#include <QDateTime>
42
 
 
43
 
// Local includes
44
 
 
45
 
#include "dimg.h"
46
 
#include "dimgimagefilters.h"
47
 
 
48
 
namespace DigikamDistortionFXImagesPlugin
49
 
{
50
 
 
51
 
DistortionFX::DistortionFX(Digikam::DImg *orgImage, QObject *parent, int effectType,
52
 
                           int level, int iteration, bool antialiasing)
53
 
            : Digikam::DImgThreadedFilter(orgImage, parent, "DistortionFX")
54
 
{
55
 
    m_effectType = effectType;
56
 
    m_level      = level;
57
 
    m_iteration  = iteration;
58
 
    m_antiAlias  = antialiasing;
59
 
 
60
 
    initFilter();
61
 
}
62
 
 
63
 
void DistortionFX::filterImage(void)
64
 
{
65
 
    int w = m_orgImage.width();
66
 
    int h = m_orgImage.height();
67
 
    int   l     = m_level;
68
 
    int   f     = m_iteration;
69
 
 
70
 
    switch (m_effectType)
71
 
    {
72
 
        case FishEye:
73
 
            fisheye(&m_orgImage, &m_destImage, (double)(l/5.0), m_antiAlias);
74
 
            break;
75
 
 
76
 
        case Twirl:
77
 
            twirl(&m_orgImage, &m_destImage, l, m_antiAlias);
78
 
            break;
79
 
 
80
 
        case CilindricalHor:
81
 
            cilindrical(&m_orgImage, &m_destImage, (double)l, true, false, m_antiAlias);
82
 
            break;
83
 
 
84
 
        case CilindricalVert:
85
 
            cilindrical(&m_orgImage, &m_destImage, (double)l, false, true, m_antiAlias);
86
 
            break;
87
 
 
88
 
        case CilindricalHV:
89
 
            cilindrical(&m_orgImage, &m_destImage, (double)l, true, true, m_antiAlias);
90
 
            break;
91
 
 
92
 
        case Caricature:
93
 
            fisheye(&m_orgImage, &m_destImage, (double)(-l/5.0), m_antiAlias);
94
 
            break;
95
 
 
96
 
        case MultipleCorners:
97
 
            multipleCorners(&m_orgImage, &m_destImage, l, m_antiAlias);
98
 
            break;
99
 
 
100
 
        case WavesHorizontal:
101
 
            waves(&m_orgImage, &m_destImage, l, f, true, true);
102
 
            break;
103
 
 
104
 
        case WavesVertical:
105
 
            waves(&m_orgImage, &m_destImage, l, f, true, false);
106
 
            break;
107
 
 
108
 
        case BlockWaves1:
109
 
            blockWaves(&m_orgImage, &m_destImage, l, f, false);
110
 
            break;
111
 
 
112
 
        case BlockWaves2:
113
 
            blockWaves(&m_orgImage, &m_destImage, l, f, true);
114
 
            break;
115
 
 
116
 
        case CircularWaves1:
117
 
            circularWaves(&m_orgImage, &m_destImage, w/2, h/2, (double)l, (double)f, 0.0, false, m_antiAlias);
118
 
            break;
119
 
 
120
 
        case CircularWaves2:
121
 
            circularWaves(&m_orgImage, &m_destImage, w/2, h/2, (double)l, (double)f, 25.0, true, m_antiAlias);
122
 
            break;
123
 
 
124
 
        case PolarCoordinates:
125
 
            polarCoordinates(&m_orgImage, &m_destImage, true, m_antiAlias);
126
 
            break;
127
 
 
128
 
        case UnpolarCoordinates:
129
 
            polarCoordinates(&m_orgImage, &m_destImage, false, m_antiAlias);
130
 
            break;
131
 
 
132
 
        case Tile:
133
 
            tile(&m_orgImage, &m_destImage, 200-f, 200-f, l);
134
 
            break;
135
 
    }
136
 
}
137
 
 
138
 
/*
139
 
    This code is shared by six methods.
140
 
    Write value of pixel w|h in data to pixel nw|nh in pResBits.
141
 
    Antialias if requested.
142
 
*/
143
 
void DistortionFX::setPixelFromOther(int Width, int Height, bool sixteenBit, int bytesDepth,
144
 
                                            uchar *data, uchar *pResBits,
145
 
                                            int w, int h, double nw, double nh, bool AntiAlias)
146
 
{
147
 
    Digikam::DColor color;
148
 
    int offset, offsetOther;
149
 
 
150
 
    offset = getOffset(Width, w, h, bytesDepth);
151
 
 
152
 
    if (AntiAlias)
153
 
    {
154
 
        uchar *ptr = pResBits + offset;
155
 
        if (sixteenBit)
156
 
        {
157
 
            unsigned short *ptr16 = (unsigned short *)ptr;
158
 
            Digikam::DImgImageFilters().pixelAntiAliasing16((unsigned short *)data, Width, Height, nw, nh,
159
 
                    ptr16+3, ptr16+2, ptr16+1, ptr16);
160
 
        }
161
 
        else
162
 
        {
163
 
            Digikam::DImgImageFilters().pixelAntiAliasing(data, Width, Height, nw, nh,
164
 
                    ptr+3, ptr+2, ptr+1, ptr);
165
 
        }
166
 
    }
167
 
    else
168
 
    {
169
 
        // we get the position adjusted
170
 
        offsetOther = getOffsetAdjusted(Width, Height, (int)nw, (int)nh, bytesDepth);
171
 
        // read color
172
 
        color.setColor(data + offsetOther, sixteenBit);
173
 
        // write color to destination
174
 
        color.setPixel(pResBits + offset);
175
 
    }
176
 
}
177
 
 
178
 
/* Function to apply the fisheye effect backported from ImageProcessing version 2
179
 
 *
180
 
 * data             => The image data in RGBA mode.
181
 
 * Width            => Width of image.
182
 
 * Height           => Height of image.
183
 
 * Coeff            => Distortion effect coeff. Positive value render 'Fish Eyes' effect,
184
 
 *                     and negative values render 'Caricature' effect.
185
 
 * Antialias        => Smart blurring result.
186
 
 *
187
 
 * Theory           => This is a great effect if you take employee photos
188
 
 *                     Its pure trigonometry. I think if you study hard the code you
189
 
 *                     understand very well.
190
 
 */
191
 
void DistortionFX::fisheye(Digikam::DImg *orgImage, Digikam::DImg *destImage, double Coeff, bool AntiAlias)
192
 
{
193
 
    if (Coeff == 0.0) return;
194
 
 
195
 
    int Width       = orgImage->width();
196
 
    int Height      = orgImage->height();
197
 
    uchar* data     = orgImage->bits();
198
 
    bool sixteenBit = orgImage->sixteenBit();
199
 
    int bytesDepth  = orgImage->bytesDepth();
200
 
    uchar* pResBits = destImage->bits();
201
 
 
202
 
    int h, w;
203
 
    double nh, nw, th, tw;
204
 
 
205
 
    int progress;
206
 
    int nHalfW = Width / 2, nHalfH = Height / 2;
207
 
 
208
 
    Digikam::DColor color;
209
 
    int offset;
210
 
 
211
 
    double lfXScale = 1.0, lfYScale = 1.0;
212
 
    double lfRadius, lfRadMax, lfAngle, lfCoeff, lfCoeffStep = Coeff / 1000.0;
213
 
 
214
 
    if (Width > Height)
215
 
        lfYScale = (double)Width / (double)Height;
216
 
    else if (Height > Width)
217
 
        lfXScale = (double)Height / (double)Width;
218
 
 
219
 
    lfRadMax = (double)qMax(Height, Width) / 2.0;
220
 
    lfCoeff = lfRadMax / log (fabs (lfCoeffStep) * lfRadMax + 1.0);
221
 
 
222
 
    // main loop
223
 
 
224
 
    for (h = 0; !m_cancel && (h < Height); ++h)
225
 
    {
226
 
        th = lfYScale * (double)(h - nHalfH);
227
 
 
228
 
        for (w = 0; !m_cancel && (w < Width); ++w)
229
 
        {
230
 
            tw = lfXScale * (double)(w - nHalfW);
231
 
 
232
 
            // we find the distance from the center
233
 
            lfRadius = sqrt (th * th + tw * tw);
234
 
 
235
 
            if (lfRadius < lfRadMax)
236
 
            {
237
 
                lfAngle = atan2 (th, tw);
238
 
 
239
 
                if (Coeff > 0.0)
240
 
                    lfRadius = (exp (lfRadius / lfCoeff) - 1.0) / lfCoeffStep;
241
 
                else
242
 
                    lfRadius = lfCoeff * log (1.0 + (-1.0 * lfCoeffStep) * lfRadius);
243
 
 
244
 
                nw = (double)nHalfW + (lfRadius / lfXScale) * cos (lfAngle);
245
 
                nh = (double)nHalfH + (lfRadius / lfYScale) * sin (lfAngle);
246
 
 
247
 
                setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias);
248
 
            }
249
 
            else
250
 
            {
251
 
                // copy pixel
252
 
                offset = getOffset(Width, w, h, bytesDepth);
253
 
                color.setColor(data + offset, sixteenBit);
254
 
                color.setPixel(pResBits + offset);
255
 
            }
256
 
        }
257
 
 
258
 
        // Update the progress bar in dialog.
259
 
        progress = (int) (((double)(h) * 100.0) / Height);
260
 
 
261
 
        if (progress%5 == 0)
262
 
            postProgress(progress);
263
 
    }
264
 
}
265
 
 
266
 
/* Function to apply the twirl effect backported from ImageProcessing version 2
267
 
 *
268
 
 * data             => The image data in RGBA mode.
269
 
 * Width            => Width of image.
270
 
 * Height           => Height of image.
271
 
 * Twirl            => Distance value.
272
 
 * Antialias        => Smart blurring result.
273
 
 *
274
 
 * Theory           => Take spiral studies, you will understand better, I'm studying
275
 
 *                     hard on this effect, because it is not too fast.
276
 
 */
277
 
void DistortionFX::twirl(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Twirl, bool AntiAlias)
278
 
{
279
 
    // if twirl value is zero, we do nothing
280
 
 
281
 
    if (Twirl == 0)
282
 
        return;
283
 
 
284
 
    int Width       = orgImage->width();
285
 
    int Height      = orgImage->height();
286
 
    uchar* data     = orgImage->bits();
287
 
    bool sixteenBit = orgImage->sixteenBit();
288
 
    int bytesDepth  = orgImage->bytesDepth();
289
 
    uchar* pResBits = destImage->bits();
290
 
 
291
 
    int h, w;
292
 
    double tw, th, nh, nw;
293
 
 
294
 
    Digikam::DColor color;
295
 
    int offset;
296
 
 
297
 
    int progress;
298
 
    int nHalfW = Width / 2, nHalfH = Height / 2;
299
 
 
300
 
    double lfXScale = 1.0, lfYScale = 1.0;
301
 
    double lfAngle, lfNewAngle, lfAngleStep, lfAngleSum, lfCurrentRadius, lfRadMax;
302
 
 
303
 
    if (Width > Height)
304
 
        lfYScale = (double)Width / (double)Height;
305
 
    else if (Height > Width)
306
 
        lfXScale = (double)Height / (double)Width;
307
 
 
308
 
    // the angle step is twirl divided by 10000
309
 
    lfAngleStep = Twirl / 10000.0;
310
 
    // now, we get the minimum radius
311
 
    lfRadMax = (double)qMax(Width, Height) / 2.0;
312
 
 
313
 
    // main loop
314
 
 
315
 
    for (h = 0; !m_cancel && (h < Height); ++h)
316
 
    {
317
 
        th = lfYScale * (double)(h - nHalfH);
318
 
 
319
 
        for (w = 0; !m_cancel && (w < Width); ++w)
320
 
        {
321
 
            tw = lfXScale * (double)(w - nHalfW);
322
 
 
323
 
            // now, we get the distance
324
 
            lfCurrentRadius = sqrt (th * th + tw * tw);
325
 
 
326
 
            // if distance is less than maximum radius...
327
 
            if (lfCurrentRadius < lfRadMax)
328
 
            {
329
 
                // we find the angle from the center
330
 
                lfAngle = atan2 (th, tw);
331
 
                // we get the accumuled angle
332
 
                lfAngleSum = lfAngleStep * (-1.0 * (lfCurrentRadius - lfRadMax));
333
 
                // ok, we sum angle with accumuled to find a new angle
334
 
                lfNewAngle = lfAngle + lfAngleSum;
335
 
 
336
 
                // now we find the exact position's x and y
337
 
                nw = (double)nHalfW + cos (lfNewAngle) * (lfCurrentRadius / lfXScale);
338
 
                nh = (double)nHalfH + sin (lfNewAngle) * (lfCurrentRadius / lfYScale);
339
 
 
340
 
                setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias);
341
 
            }
342
 
            else
343
 
            {
344
 
                // copy pixel
345
 
                offset = getOffset(Width, w, h, bytesDepth);
346
 
                color.setColor(data + offset, sixteenBit);
347
 
                color.setPixel(pResBits + offset);
348
 
            }
349
 
        }
350
 
 
351
 
        // Update the progress bar in dialog.
352
 
        progress = (int) (((double)h * 100.0) / Height);
353
 
 
354
 
        if (progress%5 == 0)
355
 
            postProgress(progress);
356
 
    }
357
 
}
358
 
 
359
 
/* Function to apply the Cilindrical effect backported from ImageProcessing version 2
360
 
 *
361
 
 * data             => The image data in RGBA mode.
362
 
 * Width            => Width of image.
363
 
 * Height           => Height of image.
364
 
 * Coeff            => Cilindrical value.
365
 
 * Horizontal       => Apply horizontally.
366
 
 * Vertical         => Apply vertically.
367
 
 * Antialias        => Smart blurring result.
368
 
 *
369
 
 * Theory           => This is a great effect, similar to Spherize (Photoshop).
370
 
 *                     If you understand FishEye, you will understand Cilindrical
371
 
 *                     FishEye apply a logarithm function using a sphere radius,
372
 
 *                     Spherize use the same function but in a rectangular
373
 
 *                     environment.
374
 
 */
375
 
void DistortionFX::cilindrical(Digikam::DImg *orgImage, Digikam::DImg *destImage, double Coeff,
376
 
                               bool Horizontal, bool Vertical, bool AntiAlias)
377
 
 
378
 
{
379
 
    if ((Coeff == 0.0) || (! (Horizontal || Vertical)))
380
 
        return;
381
 
 
382
 
    int Width       = orgImage->width();
383
 
    int Height      = orgImage->height();
384
 
    uchar* data     = orgImage->bits();
385
 
    bool sixteenBit = orgImage->sixteenBit();
386
 
    int bytesDepth  = orgImage->bytesDepth();
387
 
    uchar* pResBits = destImage->bits();
388
 
 
389
 
    int progress;
390
 
 
391
 
    int h, w;
392
 
    double nh, nw;
393
 
 
394
 
    int nHalfW = Width / 2, nHalfH = Height / 2;
395
 
    double lfCoeffX = 1.0, lfCoeffY = 1.0, lfCoeffStep = Coeff / 1000.0;
396
 
 
397
 
    if (Horizontal)
398
 
        lfCoeffX = (double)nHalfW / log (fabs (lfCoeffStep) * nHalfW + 1.0);
399
 
    if (Vertical)
400
 
        lfCoeffY = (double)nHalfH / log (fabs (lfCoeffStep) * nHalfH + 1.0);
401
 
 
402
 
    // initial copy
403
 
    memcpy (pResBits, data, orgImage->numBytes());
404
 
 
405
 
    // main loop
406
 
 
407
 
    for (h = 0; !m_cancel && (h < Height); ++h)
408
 
    {
409
 
        for (w = 0; !m_cancel && (w < Width); ++w)
410
 
        {
411
 
            // we find the distance from the center
412
 
            nh = fabs ((double)(h - nHalfH));
413
 
            nw = fabs ((double)(w - nHalfW));
414
 
 
415
 
            if (Horizontal)
416
 
            {
417
 
                if (Coeff > 0.0)
418
 
                    nw = (exp (nw / lfCoeffX) - 1.0) / lfCoeffStep;
419
 
                else
420
 
                    nw = lfCoeffX * log (1.0 + (-1.0 * lfCoeffStep) * nw);
421
 
            }
422
 
 
423
 
            if (Vertical)
424
 
            {
425
 
                if (Coeff > 0.0)
426
 
                    nh = (exp (nh / lfCoeffY) - 1.0) / lfCoeffStep;
427
 
                else
428
 
                    nh = lfCoeffY * log (1.0 + (-1.0 * lfCoeffStep) * nh);
429
 
            }
430
 
 
431
 
            nw = (double)nHalfW + ((w >= nHalfW) ? nw : -nw);
432
 
            nh = (double)nHalfH + ((h >= nHalfH) ? nh : -nh);
433
 
 
434
 
            setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias);
435
 
        }
436
 
 
437
 
        // Update the progress bar in dialog.
438
 
        progress = (int) (((double)h * 100.0) / Height);
439
 
 
440
 
        if (progress%5 == 0)
441
 
            postProgress(progress);
442
 
    }
443
 
}
444
 
 
445
 
/* Function to apply the Multiple Corners effect backported from ImageProcessing version 2
446
 
 *
447
 
 * data             => The image data in RGBA mode.
448
 
 * Width            => Width of image.
449
 
 * Height           => Height of image.
450
 
 * Factor           => nb corners.
451
 
 * Antialias        => Smart blurring result.
452
 
 *
453
 
 * Theory           => This is an amazing function, you've never seen this before.
454
 
 *                     I was testing some trigonometric functions, and I saw that if
455
 
 *                     I multiply the angle by 2, the result is an image like this
456
 
 *                     If we multiply by 3, we can create the SixCorners effect.
457
 
 */
458
 
void DistortionFX::multipleCorners(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Factor, bool AntiAlias)
459
 
{
460
 
    if (Factor == 0) return;
461
 
 
462
 
    int Width       = orgImage->width();
463
 
    int Height      = orgImage->height();
464
 
    uchar* data     = orgImage->bits();
465
 
    bool sixteenBit = orgImage->sixteenBit();
466
 
    int bytesDepth  = orgImage->bytesDepth();
467
 
    uchar* pResBits = destImage->bits();
468
 
 
469
 
    int h, w;
470
 
    double nh, nw;
471
 
    int progress;
472
 
 
473
 
    int nHalfW = Width / 2, nHalfH = Height / 2;
474
 
    double lfAngle, lfNewRadius, lfCurrentRadius, lfRadMax;
475
 
 
476
 
    lfRadMax = sqrt (Height * Height + Width * Width) / 2.0;
477
 
 
478
 
    // main loop
479
 
 
480
 
    for (h = 0; !m_cancel && (h < Height); ++h)
481
 
    {
482
 
        for (w = 0; !m_cancel && (w < Width); ++w)
483
 
        {
484
 
            // we find the distance from the center
485
 
            nh = nHalfH - h;
486
 
            nw = nHalfW - w;
487
 
 
488
 
            // now, we get the distance
489
 
            lfCurrentRadius = sqrt (nh * nh + nw * nw);
490
 
            // we find the angle from the center
491
 
            lfAngle = atan2 (nh, nw) * (double)Factor;
492
 
 
493
 
            // ok, we sum angle with accumuled to find a new angle
494
 
            lfNewRadius = lfCurrentRadius * lfCurrentRadius / lfRadMax;
495
 
 
496
 
            // now we find the exact position's x and y
497
 
            nw = (double)nHalfW - (cos (lfAngle) * lfNewRadius);
498
 
            nh = (double)nHalfH - (sin (lfAngle) * lfNewRadius);
499
 
 
500
 
            setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias);
501
 
        }
502
 
 
503
 
        // Update the progress bar in dialog.
504
 
        progress = (int) (((double)h * 100.0) / Height);
505
 
 
506
 
        if (progress%5 == 0)
507
 
            postProgress(progress);
508
 
    }
509
 
}
510
 
 
511
 
/* Function to apply the Polar Coordinates effect backported from ImageProcessing version 2
512
 
 *
513
 
 * data             => The image data in RGBA mode.
514
 
 * Width            => Width of image.
515
 
 * Height           => Height of image.
516
 
 * Type             => if true Polar Coordinate to Polar else inverse.
517
 
 * Antialias        => Smart blurring result.
518
 
 *
519
 
 * Theory           => Similar to PolarCoordinates from Photoshop. We apply the polar
520
 
 *                     transformation in a proportional (Height and Width) radius.
521
 
 */
522
 
void DistortionFX::polarCoordinates(Digikam::DImg *orgImage, Digikam::DImg *destImage, bool Type, bool AntiAlias)
523
 
{
524
 
    int Width       = orgImage->width();
525
 
    int Height      = orgImage->height();
526
 
    uchar* data     = orgImage->bits();
527
 
    bool sixteenBit = orgImage->sixteenBit();
528
 
    int bytesDepth  = orgImage->bytesDepth();
529
 
    uchar* pResBits = destImage->bits();
530
 
 
531
 
    int h, w;
532
 
    double nh, nw, th, tw;
533
 
    int progress;
534
 
 
535
 
    int nHalfW = Width / 2, nHalfH = Height / 2;
536
 
    double lfXScale = 1.0, lfYScale = 1.0;
537
 
    double lfAngle, lfRadius, lfRadMax;
538
 
 
539
 
    if (Width > Height)
540
 
        lfYScale = (double)Width / (double)Height;
541
 
    else if (Height > Width)
542
 
        lfXScale = (double)Height / (double)Width;
543
 
 
544
 
    lfRadMax = (double)qMax(Height, Width) / 2.0;
545
 
 
546
 
    // main loop
547
 
 
548
 
    for (h = 0; !m_cancel && (h < Height); ++h)
549
 
    {
550
 
        th = lfYScale * (double)(h - nHalfH);
551
 
 
552
 
        for (w = 0; !m_cancel && (w < Width); ++w)
553
 
        {
554
 
            tw = lfXScale * (double)(w - nHalfW);
555
 
 
556
 
            if (Type)
557
 
            {
558
 
                // now, we get the distance
559
 
                lfRadius = sqrt (th * th + tw * tw);
560
 
                // we find the angle from the center
561
 
                lfAngle = atan2 (tw, th);
562
 
 
563
 
                // now we find the exact position's x and y
564
 
                nh = lfRadius * (double) Height / lfRadMax;
565
 
                nw =  lfAngle * (double)  Width / (2 * M_PI);
566
 
 
567
 
                nw = (double)nHalfW + nw;
568
 
            }
569
 
            else
570
 
            {
571
 
                lfRadius = (double)(h) * lfRadMax / (double)Height;
572
 
                lfAngle  = (double)(w) * (2 * M_PI) / (double) Width;
573
 
 
574
 
                nw = (double)nHalfW - (lfRadius / lfXScale) * sin (lfAngle);
575
 
                nh = (double)nHalfH - (lfRadius / lfYScale) * cos (lfAngle);
576
 
            }
577
 
 
578
 
            setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias);
579
 
        }
580
 
 
581
 
        // Update the progress bar in dialog.
582
 
        progress = (int) (((double)h * 100.0) / Height);
583
 
 
584
 
        if (progress%5 == 0)
585
 
            postProgress(progress);
586
 
    }
587
 
}
588
 
 
589
 
/* Function to apply the circular waves effect backported from ImageProcessing version 2
590
 
 *
591
 
 * data             => The image data in RGBA mode.
592
 
 * Width            => Width of image.
593
 
 * Height           => Height of image.
594
 
 * X, Y             => Position of circle center on the image.
595
 
 * Amplitude        => Sinoidal maximum height
596
 
 * Frequency        => Frequency value.
597
 
 * Phase            => Phase value.
598
 
 * WavesType        => If true  the amplitude is proportional to radius.
599
 
 * Antialias        => Smart bluring result.
600
 
 *
601
 
 * Theory           => Similar to Waves effect, but here I apply a senoidal function
602
 
 *                     with the angle point.
603
 
 */
604
 
void DistortionFX::circularWaves(Digikam::DImg *orgImage, Digikam::DImg *destImage, int X, int Y, double Amplitude,
605
 
                                 double Frequency, double Phase, bool WavesType, bool AntiAlias)
606
 
{
607
 
    if (Amplitude < 0.0) Amplitude = 0.0;
608
 
    if (Frequency < 0.0) Frequency = 0.0;
609
 
 
610
 
    int Width       = orgImage->width();
611
 
    int Height      = orgImage->height();
612
 
    uchar* data     = orgImage->bits();
613
 
    bool sixteenBit = orgImage->sixteenBit();
614
 
    int bytesDepth  = orgImage->bytesDepth();
615
 
    uchar* pResBits = destImage->bits();
616
 
 
617
 
    int h, w;
618
 
    double nh, nw;
619
 
    int progress;
620
 
 
621
 
    double lfRadius, lfRadMax, lfNewAmp = Amplitude;
622
 
    double lfFreqAngle = Frequency * ANGLE_RATIO;
623
 
 
624
 
    Phase *= ANGLE_RATIO;
625
 
 
626
 
    lfRadMax = sqrt (Height * Height + Width * Width);
627
 
 
628
 
    for (h = 0; !m_cancel && (h < Height); ++h)
629
 
    {
630
 
        for (w = 0; !m_cancel && (w < Width); ++w)
631
 
        {
632
 
            nw = X - w;
633
 
            nh = Y - h;
634
 
 
635
 
            lfRadius = sqrt (nw * nw + nh * nh);
636
 
 
637
 
            if (WavesType)
638
 
                lfNewAmp = Amplitude * lfRadius / lfRadMax;
639
 
 
640
 
            nw = (double)w + lfNewAmp * sin(lfFreqAngle * lfRadius + Phase);
641
 
            nh = (double)h + lfNewAmp * cos(lfFreqAngle * lfRadius + Phase);
642
 
 
643
 
            setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias);
644
 
        }
645
 
 
646
 
        // Update the progress bar in dialog.
647
 
        progress = (int) (((double)h * 100.0) / Height);
648
 
 
649
 
        if (progress%5 == 0)
650
 
            postProgress(progress);
651
 
    }
652
 
}
653
 
 
654
 
/* Function to apply the waves effect
655
 
 *
656
 
 * data             => The image data in RGBA mode.
657
 
 * Width            => Width of image.
658
 
 * Height           => Height of image.
659
 
 * Amplitude        => Sinoidal maximum height.
660
 
 * Frequency        => Frequency value.
661
 
 * FillSides        => Like a boolean variable.
662
 
 * Direction        => Vertical or horizontal flag.
663
 
 *
664
 
 * Theory           => This is an amazing effect, very funny, and very simple to
665
 
 *                     understand. You just need understand how sin and cos works.
666
 
 */
667
 
void DistortionFX::waves(Digikam::DImg *orgImage, Digikam::DImg *destImage,
668
 
                         int Amplitude, int Frequency,
669
 
                         bool FillSides, bool Direction)
670
 
{
671
 
    if (Amplitude < 0) Amplitude = 0;
672
 
    if (Frequency < 0) Frequency = 0;
673
 
 
674
 
    int Width       = orgImage->width();
675
 
    int Height      = orgImage->height();
676
 
 
677
 
    int progress;
678
 
    int h, w;
679
 
 
680
 
    if (Direction)        // Horizontal
681
 
    {
682
 
        int tx;
683
 
 
684
 
        for (h = 0; !m_cancel && (h < Height); ++h)
685
 
        {
686
 
            tx = lround(Amplitude * sin ((Frequency * 2) * h * (M_PI / 180)));
687
 
            destImage->bitBltImage(orgImage, 0, h,  Width, 1,  tx, h);
688
 
 
689
 
            if (FillSides)
690
 
            {
691
 
                destImage->bitBltImage(orgImage, Width - tx, h,  tx, 1,  0, h);
692
 
                destImage->bitBltImage(orgImage, 0, h,  Width - (Width - 2 * Amplitude + tx), 1,  Width + tx, h);
693
 
            }
694
 
 
695
 
            // Update the progress bar in dialog.
696
 
            progress = (int) (((double)h * 100.0) / Height);
697
 
 
698
 
            if (progress%5 == 0)
699
 
                postProgress(progress);
700
 
        }
701
 
    }
702
 
    else
703
 
    {
704
 
        int ty;
705
 
 
706
 
        for (w = 0; !m_cancel && (w < Width); ++w)
707
 
        {
708
 
            ty = lround(Amplitude * sin ((Frequency * 2) * w * (M_PI / 180)));
709
 
            destImage->bitBltImage(orgImage, w, 0, 1, Height, w, ty);
710
 
 
711
 
            if (FillSides)
712
 
            {
713
 
                destImage->bitBltImage(orgImage, w, Height - ty,  1, ty,  w, 0);
714
 
                destImage->bitBltImage(orgImage, w, 0,  1, Height - (Height - 2 * Amplitude + ty),  w, Height + ty);
715
 
            }
716
 
 
717
 
            // Update the progress bar in dialog.
718
 
            progress = (int) (((double)w * 100.0) / Width);
719
 
 
720
 
            if (progress%5 == 0)
721
 
                postProgress(progress);
722
 
        }
723
 
    }
724
 
}
725
 
 
726
 
/* Function to apply the block waves effect
727
 
 *
728
 
 * data             => The image data in RGBA mode.
729
 
 * Width            => Width of image.
730
 
 * Height           => Height of image.
731
 
 * Amplitude        => Sinoidal maximum height
732
 
 * Frequency        => Frequency value
733
 
 * Mode             => The mode to be applied.
734
 
 *
735
 
 * Theory           => This is an amazing effect, very funny when amplitude and
736
 
 *                     frequency are small values.
737
 
 */
738
 
void DistortionFX::blockWaves(Digikam::DImg *orgImage, Digikam::DImg *destImage,
739
 
                              int Amplitude, int Frequency, bool Mode)
740
 
{
741
 
    if (Amplitude < 0) Amplitude = 0;
742
 
    if (Frequency < 0) Frequency = 0;
743
 
 
744
 
    int Width       = orgImage->width();
745
 
    int Height      = orgImage->height();
746
 
    uchar* data     = orgImage->bits();
747
 
    bool sixteenBit = orgImage->sixteenBit();
748
 
    int bytesDepth  = orgImage->bytesDepth();
749
 
    uchar* pResBits = destImage->bits();
750
 
 
751
 
    int nw, nh, progress;
752
 
    double Radius;
753
 
 
754
 
    Digikam::DColor color;
755
 
    int offset, offsetOther;
756
 
 
757
 
    int nHalfW = Width / 2, nHalfH = Height / 2;
758
 
 
759
 
    for (int w = 0; !m_cancel && (w < Width); ++w)
760
 
    {
761
 
        for (int h = 0; !m_cancel && (h < Height); ++h)
762
 
        {
763
 
            nw = nHalfW - w;
764
 
            nh = nHalfH - h;
765
 
 
766
 
            Radius = sqrt (nw * nw + nh * nh);
767
 
 
768
 
            if (Mode)
769
 
            {
770
 
                nw = (int)(w + Amplitude * sin (Frequency * nw * (M_PI / 180)));
771
 
                nh = (int)(h + Amplitude * cos (Frequency * nh * (M_PI / 180)));
772
 
            }
773
 
            else
774
 
            {
775
 
                nw = (int)(w + Amplitude * sin (Frequency * w * (M_PI / 180)));
776
 
                nh = (int)(h + Amplitude * cos (Frequency * h * (M_PI / 180)));
777
 
            }
778
 
 
779
 
            offset = getOffset(Width, w, h, bytesDepth);
780
 
            offsetOther = getOffsetAdjusted(Width, Height, (int)nw, (int)nh, bytesDepth);
781
 
 
782
 
            // read color
783
 
            color.setColor(data + offsetOther, sixteenBit);
784
 
            // write color to destination
785
 
            color.setPixel(pResBits + offset);
786
 
        }
787
 
 
788
 
        // Update the progress bar in dialog.
789
 
        progress = (int) (((double)w * 100.0) / Width);
790
 
 
791
 
        if (progress%5 == 0)
792
 
            postProgress(progress);
793
 
    }
794
 
}
795
 
 
796
 
/* Function to apply the tile effect
797
 
 *
798
 
 * data             => The image data in RGBA mode.
799
 
 * Width            => Width of image.
800
 
 * Height           => Height of image.
801
 
 * WSize            => Tile Width
802
 
 * HSize            => Tile Height
803
 
 * Random           => Maximum random value
804
 
 *
805
 
 * Theory           => Similar to Tile effect from Photoshop and very easy to
806
 
 *                     understand. We get a rectangular area using WSize and HSize and
807
 
 *                     replace in a position with a random distance from the original
808
 
 *                     position.
809
 
 */
810
 
void DistortionFX::tile(Digikam::DImg *orgImage, Digikam::DImg *destImage,
811
 
                        int WSize, int HSize, int Random)
812
 
{
813
 
    if (WSize < 1)  WSize = 1;
814
 
    if (HSize < 1)  HSize = 1;
815
 
    if (Random < 1) Random = 1;
816
 
 
817
 
    int Width       = orgImage->width();
818
 
    int Height      = orgImage->height();
819
 
 
820
 
    QDateTime dt = QDateTime::currentDateTime();
821
 
    QDateTime Y2000( QDate(2000, 1, 1), QTime(0, 0, 0) );
822
 
    uint seed = dt.secsTo(Y2000);
823
 
#ifdef WIN32
824
 
    srand(seed);
825
 
#endif
826
 
 
827
 
    int tx, ty, h, w, progress;
828
 
 
829
 
    for (h = 0; !m_cancel && (h < Height); h += HSize)
830
 
    {
831
 
        for (w = 0; !m_cancel && (w < Width); w += WSize)
832
 
        {
833
 
#ifndef _WIN32
834
 
            tx = (int)(rand_r(&seed) % Random) - (Random / 2);
835
 
            ty = (int)(rand_r(&seed) % Random) - (Random / 2);
836
 
#else
837
 
            tx = (int)(rand() % Random) - (Random / 2);
838
 
            ty = (int)(rand() % Random) - (Random / 2);
839
 
#endif
840
 
            destImage->bitBltImage(orgImage, w, h,   WSize, HSize,   w + tx, h + ty);
841
 
        }
842
 
 
843
 
        // Update the progress bar in dialog.
844
 
        progress = (int)(((double)h * 100.0) / Height);
845
 
 
846
 
        if (progress%5 == 0)
847
 
            postProgress(progress);
848
 
    }
849
 
}
850
 
 
851
 
// UNUSED
852
 
/* Function to return the maximum radius with a determined angle
853
 
 *
854
 
 * Height           => Height of the image
855
 
 * Width            => Width of the image
856
 
 * Angle            => Angle to analyze the maximum radius
857
 
 *
858
 
 * Theory           => This function calculates the maximum radius to that angle
859
 
 *                     so, we can build an oval circumference
860
 
 */
861
 
 /*
862
 
double DistortionFX::maximumRadius(int Height, int Width, double Angle)
863
 
{
864
 
    double MaxRad, MinRad;
865
 
    double Radius, DegAngle = fabs (Angle * 57.295);    // Rads -> Degrees
866
 
 
867
 
    MinRad = qMin (Height, Width) / 2.0;                // Gets the minor radius
868
 
    MaxRad = qMax (Height, Width) / 2.0;                // Gets the major radius
869
 
 
870
 
    // Find the quadrant between -PI/2 and PI/2
871
 
    if (DegAngle > 90.0)
872
 
        Radius = proportionalValue (MinRad, MaxRad, (DegAngle * (255.0 / 90.0)));
873
 
    else
874
 
        Radius = proportionalValue (MaxRad, MinRad, ((DegAngle - 90.0) * (255.0 / 90.0)));
875
 
    return (Radius);
876
 
}
877
 
 */
878
 
 
879
 
}  // namespace DigikamDistortionFXImagesPlugin