summaryrefslogtreecommitdiffstats
path: root/digikam/imageplugins/distortionfx/distortionfx.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'digikam/imageplugins/distortionfx/distortionfx.cpp')
-rw-r--r--digikam/imageplugins/distortionfx/distortionfx.cpp869
1 files changed, 869 insertions, 0 deletions
diff --git a/digikam/imageplugins/distortionfx/distortionfx.cpp b/digikam/imageplugins/distortionfx/distortionfx.cpp
new file mode 100644
index 0000000..d6d79e4
--- /dev/null
+++ b/digikam/imageplugins/distortionfx/distortionfx.cpp
@@ -0,0 +1,869 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2005-07-18
+ * Description : Distortion FX threaded image filter.
+ *
+ * Copyright (C) 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
+ *
+ * Original Distortion algorithms copyrighted 2004-2005 by
+ * Pieter Z. Voloshyn <pieter dot voloshyn at gmail dot com>.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * ============================================================ */
+
+// Represents 1
+#define ANGLE_RATIO 0.017453292519943295769236907685
+
+// C++ includes.
+
+#include <cmath>
+#include <cstdlib>
+
+// Qt includes.
+
+#include <qdatetime.h>
+
+// Local includes.
+
+#include "dimg.h"
+#include "dimgimagefilters.h"
+#include "distortionfx.h"
+
+namespace DigikamDistortionFXImagesPlugin
+{
+
+DistortionFX::DistortionFX(Digikam::DImg *orgImage, QObject *parent, int effectType,
+ int level, int iteration, bool antialiasing)
+ : Digikam::DImgThreadedFilter(orgImage, parent, "DistortionFX")
+{
+ m_effectType = effectType;
+ m_level = level;
+ m_iteration = iteration;
+ m_antiAlias = antialiasing;
+
+ initFilter();
+}
+
+void DistortionFX::filterImage(void)
+{
+ int w = m_orgImage.width();
+ int h = m_orgImage.height();
+ int l = m_level;
+ int f = m_iteration;
+
+ switch (m_effectType)
+ {
+ case FishEye:
+ fisheye(&m_orgImage, &m_destImage, (double)(l/5.0), m_antiAlias);
+ break;
+
+ case Twirl:
+ twirl(&m_orgImage, &m_destImage, l, m_antiAlias);
+ break;
+
+ case CilindricalHor:
+ cilindrical(&m_orgImage, &m_destImage, (double)l, true, false, m_antiAlias);
+ break;
+
+ case CilindricalVert:
+ cilindrical(&m_orgImage, &m_destImage, (double)l, false, true, m_antiAlias);
+ break;
+
+ case CilindricalHV:
+ cilindrical(&m_orgImage, &m_destImage, (double)l, true, true, m_antiAlias);
+ break;
+
+ case Caricature:
+ fisheye(&m_orgImage, &m_destImage, (double)(-l/5.0), m_antiAlias);
+ break;
+
+ case MultipleCorners:
+ multipleCorners(&m_orgImage, &m_destImage, l, m_antiAlias);
+ break;
+
+ case WavesHorizontal:
+ waves(&m_orgImage, &m_destImage, l, f, true, true);
+ break;
+
+ case WavesVertical:
+ waves(&m_orgImage, &m_destImage, l, f, true, false);
+ break;
+
+ case BlockWaves1:
+ blockWaves(&m_orgImage, &m_destImage, l, f, false);
+ break;
+
+ case BlockWaves2:
+ blockWaves(&m_orgImage, &m_destImage, l, f, true);
+ break;
+
+ case CircularWaves1:
+ circularWaves(&m_orgImage, &m_destImage, w/2, h/2, (double)l, (double)f, 0.0, false, m_antiAlias);
+ break;
+
+ case CircularWaves2:
+ circularWaves(&m_orgImage, &m_destImage, w/2, h/2, (double)l, (double)f, 25.0, true, m_antiAlias);
+ break;
+
+ case PolarCoordinates:
+ polarCoordinates(&m_orgImage, &m_destImage, true, m_antiAlias);
+ break;
+
+ case UnpolarCoordinates:
+ polarCoordinates(&m_orgImage, &m_destImage, false, m_antiAlias);
+ break;
+
+ case Tile:
+ tile(&m_orgImage, &m_destImage, 200-f, 200-f, l);
+ break;
+ }
+}
+
+/*
+ This code is shared by six methods.
+ Write value of pixel w|h in data to pixel nw|nh in pResBits.
+ Antialias if requested.
+*/
+void DistortionFX::setPixelFromOther(int Width, int Height, bool sixteenBit, int bytesDepth,
+ uchar *data, uchar *pResBits,
+ int w, int h, double nw, double nh, bool AntiAlias)
+{
+ Digikam::DColor color;
+ int offset, offsetOther;
+
+ offset = getOffset(Width, w, h, bytesDepth);
+
+ if (AntiAlias)
+ {
+ uchar *ptr = pResBits + offset;
+ if (sixteenBit)
+ {
+ unsigned short *ptr16 = (unsigned short *)ptr;
+ Digikam::DImgImageFilters().pixelAntiAliasing16((unsigned short *)data, Width, Height, nw, nh,
+ ptr16+3, ptr16+2, ptr16+1, ptr16);
+ }
+ else
+ {
+ Digikam::DImgImageFilters().pixelAntiAliasing(data, Width, Height, nw, nh,
+ ptr+3, ptr+2, ptr+1, ptr);
+ }
+ }
+ else
+ {
+ // we get the position adjusted
+ offsetOther = getOffsetAdjusted(Width, Height, (int)nw, (int)nh, bytesDepth);
+ // read color
+ color.setColor(data + offsetOther, sixteenBit);
+ // write color to destination
+ color.setPixel(pResBits + offset);
+ }
+}
+
+/* Function to apply the fisheye effect backported from ImageProcessing version 2
+ *
+ * data => The image data in RGBA mode.
+ * Width => Width of image.
+ * Height => Height of image.
+ * Coeff => Distortion effect coeff. Positive value render 'Fish Eyes' effect,
+ * and negative values render 'Caricature' effect.
+ * Antialias => Smart bluring result.
+ *
+ * Theory => This is a great effect if you take employee photos
+ * Its pure trigonometry. I think if you study hard the code you
+ * understand very well.
+ */
+void DistortionFX::fisheye(Digikam::DImg *orgImage, Digikam::DImg *destImage, double Coeff, bool AntiAlias)
+{
+ if (Coeff == 0.0) return;
+
+ int Width = orgImage->width();
+ int Height = orgImage->height();
+ uchar* data = orgImage->bits();
+ bool sixteenBit = orgImage->sixteenBit();
+ int bytesDepth = orgImage->bytesDepth();
+ uchar* pResBits = destImage->bits();
+
+ int h, w;
+ double nh, nw, th, tw;
+
+ int progress;
+ int nHalfW = Width / 2, nHalfH = Height / 2;
+
+ Digikam::DColor color;
+ int offset;
+
+ double lfXScale = 1.0, lfYScale = 1.0;
+ double lfRadius, lfRadMax, lfAngle, lfCoeff, lfCoeffStep = Coeff / 1000.0;
+
+ if (Width > Height)
+ lfYScale = (double)Width / (double)Height;
+ else if (Height > Width)
+ lfXScale = (double)Height / (double)Width;
+
+ lfRadMax = (double)QMAX(Height, Width) / 2.0;
+ lfCoeff = lfRadMax / log (fabs (lfCoeffStep) * lfRadMax + 1.0);
+
+ // main loop
+
+ for (h = 0; !m_cancel && (h < Height); h++)
+ {
+ th = lfYScale * (double)(h - nHalfH);
+
+ for (w = 0; !m_cancel && (w < Width); w++)
+ {
+ tw = lfXScale * (double)(w - nHalfW);
+
+ // we find the distance from the center
+ lfRadius = sqrt (th * th + tw * tw);
+
+ if (lfRadius < lfRadMax)
+ {
+ lfAngle = atan2 (th, tw);
+
+ if (Coeff > 0.0)
+ lfRadius = (exp (lfRadius / lfCoeff) - 1.0) / lfCoeffStep;
+ else
+ lfRadius = lfCoeff * log (1.0 + (-1.0 * lfCoeffStep) * lfRadius);
+
+ nw = (double)nHalfW + (lfRadius / lfXScale) * cos (lfAngle);
+ nh = (double)nHalfH + (lfRadius / lfYScale) * sin (lfAngle);
+
+ setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias);
+ }
+ else
+ {
+ // copy pixel
+ offset = getOffset(Width, w, h, bytesDepth);
+ color.setColor(data + offset, sixteenBit);
+ color.setPixel(pResBits + offset);
+ }
+ }
+
+ // Update the progress bar in dialog.
+ progress = (int) (((double)(h) * 100.0) / Height);
+
+ if (progress%5 == 0)
+ postProgress(progress);
+ }
+}
+
+/* Function to apply the twirl effect backported from ImageProcessing version 2
+ *
+ * data => The image data in RGBA mode.
+ * Width => Width of image.
+ * Height => Height of image.
+ * Twirl => Distance value.
+ * Antialias => Smart bluring result.
+ *
+ * Theory => Take spiral studies, you will understand better, I'm studying
+ * hard on this effect, because it is not too fast.
+ */
+void DistortionFX::twirl(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Twirl, bool AntiAlias)
+{
+ // if twirl value is zero, we do nothing
+
+ if (Twirl == 0)
+ return;
+
+ int Width = orgImage->width();
+ int Height = orgImage->height();
+ uchar* data = orgImage->bits();
+ bool sixteenBit = orgImage->sixteenBit();
+ int bytesDepth = orgImage->bytesDepth();
+ uchar* pResBits = destImage->bits();
+
+ int h, w;
+ double tw, th, nh, nw;
+
+ Digikam::DColor color;
+ int offset;
+
+ int progress;
+ int nHalfW = Width / 2, nHalfH = Height / 2;
+
+ double lfXScale = 1.0, lfYScale = 1.0;
+ double lfAngle, lfNewAngle, lfAngleStep, lfAngleSum, lfCurrentRadius, lfRadMax;
+
+ if (Width > Height)
+ lfYScale = (double)Width / (double)Height;
+ else if (Height > Width)
+ lfXScale = (double)Height / (double)Width;
+
+ // the angle step is twirl divided by 10000
+ lfAngleStep = Twirl / 10000.0;
+ // now, we get the minimum radius
+ lfRadMax = (double)QMAX(Width, Height) / 2.0;
+
+ // main loop
+
+ for (h = 0; !m_cancel && (h < Height); h++)
+ {
+ th = lfYScale * (double)(h - nHalfH);
+
+ for (w = 0; !m_cancel && (w < Width); w++)
+ {
+ tw = lfXScale * (double)(w - nHalfW);
+
+ // now, we get the distance
+ lfCurrentRadius = sqrt (th * th + tw * tw);
+
+ // if distance is less than maximum radius...
+ if (lfCurrentRadius < lfRadMax)
+ {
+ // we find the angle from the center
+ lfAngle = atan2 (th, tw);
+ // we get the accumuled angle
+ lfAngleSum = lfAngleStep * (-1.0 * (lfCurrentRadius - lfRadMax));
+ // ok, we sum angle with accumuled to find a new angle
+ lfNewAngle = lfAngle + lfAngleSum;
+
+ // now we find the exact position's x and y
+ nw = (double)nHalfW + cos (lfNewAngle) * (lfCurrentRadius / lfXScale);
+ nh = (double)nHalfH + sin (lfNewAngle) * (lfCurrentRadius / lfYScale);
+
+ setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias);
+ }
+ else
+ {
+ // copy pixel
+ offset = getOffset(Width, w, h, bytesDepth);
+ color.setColor(data + offset, sixteenBit);
+ color.setPixel(pResBits + offset);
+ }
+ }
+
+ // Update the progress bar in dialog.
+ progress = (int) (((double)h * 100.0) / Height);
+
+ if (progress%5 == 0)
+ postProgress(progress);
+ }
+}
+
+/* Function to apply the Cilindrical effect backported from ImageProcessing version 2
+ *
+ * data => The image data in RGBA mode.
+ * Width => Width of image.
+ * Height => Height of image.
+ * Coeff => Cilindrical value.
+ * Horizontal => Apply horizontally.
+ * Vertical => Apply vertically.
+ * Antialias => Smart bluring result.
+ *
+ * Theory => This is a great effect, similar to Spherize (Photoshop).
+ * If you understand FishEye, you will understand Cilindrical
+ * FishEye apply a logarithm function using a sphere radius,
+ * Spherize use the same function but in a rectangular
+ * environment.
+ */
+void DistortionFX::cilindrical(Digikam::DImg *orgImage, Digikam::DImg *destImage, double Coeff,
+ bool Horizontal, bool Vertical, bool AntiAlias)
+
+{
+ if ((Coeff == 0.0) || (! (Horizontal || Vertical)))
+ return;
+
+ int Width = orgImage->width();
+ int Height = orgImage->height();
+ uchar* data = orgImage->bits();
+ bool sixteenBit = orgImage->sixteenBit();
+ int bytesDepth = orgImage->bytesDepth();
+ uchar* pResBits = destImage->bits();
+
+ int progress;
+
+ int h, w;
+ double nh, nw;
+
+ int nHalfW = Width / 2, nHalfH = Height / 2;
+ double lfCoeffX = 1.0, lfCoeffY = 1.0, lfCoeffStep = Coeff / 1000.0;
+
+ if (Horizontal)
+ lfCoeffX = (double)nHalfW / log (fabs (lfCoeffStep) * nHalfW + 1.0);
+ if (Vertical)
+ lfCoeffY = (double)nHalfH / log (fabs (lfCoeffStep) * nHalfH + 1.0);
+
+ // initial copy
+ memcpy (pResBits, data, orgImage->numBytes());
+
+ // main loop
+
+ for (h = 0; !m_cancel && (h < Height); h++)
+ {
+ for (w = 0; !m_cancel && (w < Width); w++)
+ {
+ // we find the distance from the center
+ nh = fabs ((double)(h - nHalfH));
+ nw = fabs ((double)(w - nHalfW));
+
+ if (Horizontal)
+ {
+ if (Coeff > 0.0)
+ nw = (exp (nw / lfCoeffX) - 1.0) / lfCoeffStep;
+ else
+ nw = lfCoeffX * log (1.0 + (-1.0 * lfCoeffStep) * nw);
+ }
+
+ if (Vertical)
+ {
+ if (Coeff > 0.0)
+ nh = (exp (nh / lfCoeffY) - 1.0) / lfCoeffStep;
+ else
+ nh = lfCoeffY * log (1.0 + (-1.0 * lfCoeffStep) * nh);
+ }
+
+ nw = (double)nHalfW + ((w >= nHalfW) ? nw : -nw);
+ nh = (double)nHalfH + ((h >= nHalfH) ? nh : -nh);
+
+ setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias);
+ }
+
+ // Update the progress bar in dialog.
+ progress = (int) (((double)h * 100.0) / Height);
+
+ if (progress%5 == 0)
+ postProgress(progress);
+ }
+}
+
+/* Function to apply the Multiple Corners effect backported from ImageProcessing version 2
+ *
+ * data => The image data in RGBA mode.
+ * Width => Width of image.
+ * Height => Height of image.
+ * Factor => nb corners.
+ * Antialias => Smart bluring result.
+ *
+ * Theory => This is an amazing function, you've never seen this before.
+ * I was testing some trigonometric functions, and I saw that if
+ * I multiply the angle by 2, the result is an image like this
+ * If we multiply by 3, we can create the SixCorners effect.
+ */
+void DistortionFX::multipleCorners(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Factor, bool AntiAlias)
+{
+ if (Factor == 0) return;
+
+ int Width = orgImage->width();
+ int Height = orgImage->height();
+ uchar* data = orgImage->bits();
+ bool sixteenBit = orgImage->sixteenBit();
+ int bytesDepth = orgImage->bytesDepth();
+ uchar* pResBits = destImage->bits();
+
+ int h, w;
+ double nh, nw;
+ int progress;
+
+ int nHalfW = Width / 2, nHalfH = Height / 2;
+ double lfAngle, lfNewRadius, lfCurrentRadius, lfRadMax;
+
+ lfRadMax = sqrt (Height * Height + Width * Width) / 2.0;
+
+ // main loop
+
+ for (h = 0; !m_cancel && (h < Height); h++)
+ {
+ for (w = 0; !m_cancel && (w < Width); w++)
+ {
+ // we find the distance from the center
+ nh = nHalfH - h;
+ nw = nHalfW - w;
+
+ // now, we get the distance
+ lfCurrentRadius = sqrt (nh * nh + nw * nw);
+ // we find the angle from the center
+ lfAngle = atan2 (nh, nw) * (double)Factor;
+
+ // ok, we sum angle with accumuled to find a new angle
+ lfNewRadius = lfCurrentRadius * lfCurrentRadius / lfRadMax;
+
+ // now we find the exact position's x and y
+ nw = (double)nHalfW - (cos (lfAngle) * lfNewRadius);
+ nh = (double)nHalfH - (sin (lfAngle) * lfNewRadius);
+
+ setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias);
+ }
+
+ // Update the progress bar in dialog.
+ progress = (int) (((double)h * 100.0) / Height);
+
+ if (progress%5 == 0)
+ postProgress(progress);
+ }
+}
+
+/* Function to apply the Polar Coordinates effect backported from ImageProcessing version 2
+ *
+ * data => The image data in RGBA mode.
+ * Width => Width of image.
+ * Height => Height of image.
+ * Type => if true Polar Coordinate to Polar else inverse.
+ * Antialias => Smart bluring result.
+ *
+ * Theory => Similar to PolarCoordinates from Photoshop. We apply the polar
+ * transformation in a proportional (Height and Width) radius.
+ */
+void DistortionFX::polarCoordinates(Digikam::DImg *orgImage, Digikam::DImg *destImage, bool Type, bool AntiAlias)
+{
+ int Width = orgImage->width();
+ int Height = orgImage->height();
+ uchar* data = orgImage->bits();
+ bool sixteenBit = orgImage->sixteenBit();
+ int bytesDepth = orgImage->bytesDepth();
+ uchar* pResBits = destImage->bits();
+
+ int h, w;
+ double nh, nw, th, tw;
+ int progress;
+
+ int nHalfW = Width / 2, nHalfH = Height / 2;
+ double lfXScale = 1.0, lfYScale = 1.0;
+ double lfAngle, lfRadius, lfRadMax;
+
+ if (Width > Height)
+ lfYScale = (double)Width / (double)Height;
+ else if (Height > Width)
+ lfXScale = (double)Height / (double)Width;
+
+ lfRadMax = (double)QMAX(Height, Width) / 2.0;
+
+ // main loop
+
+ for (h = 0; !m_cancel && (h < Height); h++)
+ {
+ th = lfYScale * (double)(h - nHalfH);
+
+ for (w = 0; !m_cancel && (w < Width); w++)
+ {
+ tw = lfXScale * (double)(w - nHalfW);
+
+ if (Type)
+ {
+ // now, we get the distance
+ lfRadius = sqrt (th * th + tw * tw);
+ // we find the angle from the center
+ lfAngle = atan2 (tw, th);
+
+ // now we find the exact position's x and y
+ nh = lfRadius * (double) Height / lfRadMax;
+ nw = lfAngle * (double) Width / (2 * M_PI);
+
+ nw = (double)nHalfW + nw;
+ }
+ else
+ {
+ lfRadius = (double)(h) * lfRadMax / (double)Height;
+ lfAngle = (double)(w) * (2 * M_PI) / (double) Width;
+
+ nw = (double)nHalfW - (lfRadius / lfXScale) * sin (lfAngle);
+ nh = (double)nHalfH - (lfRadius / lfYScale) * cos (lfAngle);
+ }
+
+ setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias);
+ }
+
+ // Update the progress bar in dialog.
+ progress = (int) (((double)h * 100.0) / Height);
+
+ if (progress%5 == 0)
+ postProgress(progress);
+ }
+}
+
+/* Function to apply the circular waves effect backported from ImageProcessing version 2
+ *
+ * data => The image data in RGBA mode.
+ * Width => Width of image.
+ * Height => Height of image.
+ * X, Y => Position of circle center on the image.
+ * Amplitude => Sinoidal maximum height
+ * Frequency => Frequency value.
+ * Phase => Phase value.
+ * WavesType => If true the amplitude is proportional to radius.
+ * Antialias => Smart bluring result.
+ *
+ * Theory => Similar to Waves effect, but here I apply a senoidal function
+ * with the angle point.
+ */
+void DistortionFX::circularWaves(Digikam::DImg *orgImage, Digikam::DImg *destImage, int X, int Y, double Amplitude,
+ double Frequency, double Phase, bool WavesType, bool AntiAlias)
+{
+ if (Amplitude < 0.0) Amplitude = 0.0;
+ if (Frequency < 0.0) Frequency = 0.0;
+
+ int Width = orgImage->width();
+ int Height = orgImage->height();
+ uchar* data = orgImage->bits();
+ bool sixteenBit = orgImage->sixteenBit();
+ int bytesDepth = orgImage->bytesDepth();
+ uchar* pResBits = destImage->bits();
+
+ int h, w;
+ double nh, nw;
+ int progress;
+
+ double lfRadius, lfRadMax, lfNewAmp = Amplitude;
+ double lfFreqAngle = Frequency * ANGLE_RATIO;
+
+ Phase *= ANGLE_RATIO;
+
+ lfRadMax = sqrt (Height * Height + Width * Width);
+
+ for (h = 0; !m_cancel && (h < Height); h++)
+ {
+ for (w = 0; !m_cancel && (w < Width); w++)
+ {
+ nw = X - w;
+ nh = Y - h;
+
+ lfRadius = sqrt (nw * nw + nh * nh);
+
+ if (WavesType)
+ lfNewAmp = Amplitude * lfRadius / lfRadMax;
+
+ nw = (double)w + lfNewAmp * sin(lfFreqAngle * lfRadius + Phase);
+ nh = (double)h + lfNewAmp * cos(lfFreqAngle * lfRadius + Phase);
+
+ setPixelFromOther(Width, Height, sixteenBit, bytesDepth, data, pResBits, w, h, nw, nh, AntiAlias);
+ }
+
+ // Update the progress bar in dialog.
+ progress = (int) (((double)h * 100.0) / Height);
+
+ if (progress%5 == 0)
+ postProgress(progress);
+ }
+}
+
+/* Function to apply the waves effect
+ *
+ * data => The image data in RGBA mode.
+ * Width => Width of image.
+ * Height => Height of image.
+ * Amplitude => Sinoidal maximum height.
+ * Frequency => Frequency value.
+ * FillSides => Like a boolean variable.
+ * Direction => Vertical or horizontal flag.
+ *
+ * Theory => This is an amazing effect, very funny, and very simple to
+ * understand. You just need understand how sin and cos works.
+ */
+void DistortionFX::waves(Digikam::DImg *orgImage, Digikam::DImg *destImage,
+ int Amplitude, int Frequency,
+ bool FillSides, bool Direction)
+{
+ if (Amplitude < 0) Amplitude = 0;
+ if (Frequency < 0) Frequency = 0;
+
+ int Width = orgImage->width();
+ int Height = orgImage->height();
+
+ int progress;
+ int h, w;
+
+ if (Direction) // Horizontal
+ {
+ int tx;
+
+ for (h = 0; !m_cancel && (h < Height); h++)
+ {
+ tx = lround(Amplitude * sin ((Frequency * 2) * h * (M_PI / 180)));
+ destImage->bitBltImage(orgImage, 0, h, Width, 1, tx, h);
+
+ if (FillSides)
+ {
+ destImage->bitBltImage(orgImage, Width - tx, h, tx, 1, 0, h);
+ destImage->bitBltImage(orgImage, 0, h, Width - (Width - 2 * Amplitude + tx), 1, Width + tx, h);
+ }
+
+ // Update the progress bar in dialog.
+ progress = (int) (((double)h * 100.0) / Height);
+
+ if (progress%5 == 0)
+ postProgress(progress);
+ }
+ }
+ else
+ {
+ int ty;
+
+ for (w = 0; !m_cancel && (w < Width); w++)
+ {
+ ty = lround(Amplitude * sin ((Frequency * 2) * w * (M_PI / 180)));
+ destImage->bitBltImage(orgImage, w, 0, 1, Height, w, ty);
+
+ if (FillSides)
+ {
+ destImage->bitBltImage(orgImage, w, Height - ty, 1, ty, w, 0);
+ destImage->bitBltImage(orgImage, w, 0, 1, Height - (Height - 2 * Amplitude + ty), w, Height + ty);
+ }
+
+ // Update the progress bar in dialog.
+ progress = (int) (((double)w * 100.0) / Width);
+
+ if (progress%5 == 0)
+ postProgress(progress);
+ }
+ }
+}
+
+/* Function to apply the block waves effect
+ *
+ * data => The image data in RGBA mode.
+ * Width => Width of image.
+ * Height => Height of image.
+ * Amplitude => Sinoidal maximum height
+ * Frequency => Frequency value
+ * Mode => The mode to be applied.
+ *
+ * Theory => This is an amazing effect, very funny when amplitude and
+ * frequency are small values.
+ */
+void DistortionFX::blockWaves(Digikam::DImg *orgImage, Digikam::DImg *destImage,
+ int Amplitude, int Frequency, bool Mode)
+{
+ if (Amplitude < 0) Amplitude = 0;
+ if (Frequency < 0) Frequency = 0;
+
+ int Width = orgImage->width();
+ int Height = orgImage->height();
+ uchar* data = orgImage->bits();
+ bool sixteenBit = orgImage->sixteenBit();
+ int bytesDepth = orgImage->bytesDepth();
+ uchar* pResBits = destImage->bits();
+
+ int nw, nh, progress;
+ double Radius;
+
+ Digikam::DColor color;
+ int offset, offsetOther;
+
+ int nHalfW = Width / 2, nHalfH = Height / 2;
+
+ for (int w = 0; !m_cancel && (w < Width); w++)
+ {
+ for (int h = 0; !m_cancel && (h < Height); h++)
+ {
+ nw = nHalfW - w;
+ nh = nHalfH - h;
+
+ Radius = sqrt (nw * nw + nh * nh);
+
+ if (Mode)
+ {
+ nw = (int)(w + Amplitude * sin (Frequency * nw * (M_PI / 180)));
+ nh = (int)(h + Amplitude * cos (Frequency * nh * (M_PI / 180)));
+ }
+ else
+ {
+ nw = (int)(w + Amplitude * sin (Frequency * w * (M_PI / 180)));
+ nh = (int)(h + Amplitude * cos (Frequency * h * (M_PI / 180)));
+ }
+
+ offset = getOffset(Width, w, h, bytesDepth);
+ offsetOther = getOffsetAdjusted(Width, Height, (int)nw, (int)nh, bytesDepth);
+
+ // read color
+ color.setColor(data + offsetOther, sixteenBit);
+ // write color to destination
+ color.setPixel(pResBits + offset);
+ }
+
+ // Update the progress bar in dialog.
+ progress = (int) (((double)w * 100.0) / Width);
+
+ if (progress%5 == 0)
+ postProgress(progress);
+ }
+}
+
+/* Function to apply the tile effect
+ *
+ * data => The image data in RGBA mode.
+ * Width => Width of image.
+ * Height => Height of image.
+ * WSize => Tile Width
+ * HSize => Tile Height
+ * Random => Maximum random value
+ *
+ * Theory => Similar to Tile effect from Photoshop and very easy to
+ * understand. We get a rectangular area using WSize and HSize and
+ * replace in a position with a random distance from the original
+ * position.
+ */
+void DistortionFX::tile(Digikam::DImg *orgImage, Digikam::DImg *destImage,
+ int WSize, int HSize, int Random)
+{
+ if (WSize < 1) WSize = 1;
+ if (HSize < 1) HSize = 1;
+ if (Random < 1) Random = 1;
+
+ int Width = orgImage->width();
+ int Height = orgImage->height();
+
+ QDateTime dt = QDateTime::currentDateTime();
+ QDateTime Y2000( QDate(2000, 1, 1), QTime(0, 0, 0) );
+ uint seed = dt.secsTo(Y2000);
+
+ int tx, ty, h, w, progress;
+
+ for (h = 0; !m_cancel && (h < Height); h += HSize)
+ {
+ for (w = 0; !m_cancel && (w < Width); w += WSize)
+ {
+ tx = (int)(rand_r(&seed) % Random) - (Random / 2);
+ ty = (int)(rand_r(&seed) % Random) - (Random / 2);
+ destImage->bitBltImage(orgImage, w, h, WSize, HSize, w + tx, h + ty);
+ }
+
+ // Update the progress bar in dialog.
+ progress = (int)(((double)h * 100.0) / Height);
+
+ if (progress%5 == 0)
+ postProgress(progress);
+ }
+}
+
+// UNUSED
+/* Function to return the maximum radius with a determined angle
+ *
+ * Height => Height of the image
+ * Width => Width of the image
+ * Angle => Angle to analize the maximum radius
+ *
+ * Theory => This function calcule the maximum radius to that angle
+ * so, we can build an oval circunference
+ */
+ /*
+double DistortionFX::maximumRadius(int Height, int Width, double Angle)
+{
+ double MaxRad, MinRad;
+ double Radius, DegAngle = fabs (Angle * 57.295); // Rads -> Degrees
+
+ MinRad = QMIN (Height, Width) / 2.0; // Gets the minor radius
+ MaxRad = QMAX (Height, Width) / 2.0; // Gets the major radius
+
+ // Find the quadrant between -PI/2 and PI/2
+ if (DegAngle > 90.0)
+ Radius = proportionalValue (MinRad, MaxRad, (DegAngle * (255.0 / 90.0)));
+ else
+ Radius = proportionalValue (MaxRad, MinRad, ((DegAngle - 90.0) * (255.0 / 90.0)));
+ return (Radius);
+}
+ */
+
+} // NameSpace DigikamDistortionFXImagesPlugin