diff options
Diffstat (limited to 'src/imageplugins/blurfx')
-rw-r--r-- | src/imageplugins/blurfx/Makefile.am | 34 | ||||
-rw-r--r-- | src/imageplugins/blurfx/blurfx.cpp | 1445 | ||||
-rw-r--r-- | src/imageplugins/blurfx/blurfx.h | 191 | ||||
-rw-r--r-- | src/imageplugins/blurfx/blurfxtool.cpp | 402 | ||||
-rw-r--r-- | src/imageplugins/blurfx/blurfxtool.h | 93 | ||||
-rw-r--r-- | src/imageplugins/blurfx/digikamimageplugin_blurfx.desktop | 49 | ||||
-rw-r--r-- | src/imageplugins/blurfx/digikamimageplugin_blurfx_ui.rc | 20 | ||||
-rw-r--r-- | src/imageplugins/blurfx/imageeffect_blurfx.cpp | 388 | ||||
-rw-r--r-- | src/imageplugins/blurfx/imageeffect_blurfx.h | 80 | ||||
-rw-r--r-- | src/imageplugins/blurfx/imageplugin_blurfx.cpp | 70 | ||||
-rw-r--r-- | src/imageplugins/blurfx/imageplugin_blurfx.h | 56 |
11 files changed, 2828 insertions, 0 deletions
diff --git a/src/imageplugins/blurfx/Makefile.am b/src/imageplugins/blurfx/Makefile.am new file mode 100644 index 00000000..51a78977 --- /dev/null +++ b/src/imageplugins/blurfx/Makefile.am @@ -0,0 +1,34 @@ +METASOURCES = AUTO + +INCLUDES = -I$(top_srcdir)/src/utilities/imageeditor/editor \ + -I$(top_srcdir)/src/utilities/imageeditor/canvas \ + -I$(top_srcdir)/src/libs/histogram \ + -I$(top_srcdir)/src/libs/levels \ + -I$(top_srcdir)/src/libs/curves \ + -I$(top_srcdir)/src/libs/whitebalance \ + -I$(top_srcdir)/src/libs/widgets/common \ + -I$(top_srcdir)/src/libs/widgets/iccprofiles \ + -I$(top_srcdir)/src/libs/widgets/imageplugins \ + -I$(top_srcdir)/src/libs/dialogs \ + -I$(top_srcdir)/src/libs/dimg \ + -I$(top_srcdir)/src/libs/dmetadata \ + -I$(top_srcdir)/src/libs/dimg/filters \ + -I$(top_srcdir)/src/digikam \ + $(LIBKDCRAW_CFLAGS) \ + $(all_includes) + +digikamimageplugin_blurfx_la_SOURCES = imageplugin_blurfx.cpp \ + blurfxtool.cpp blurfx.cpp + +digikamimageplugin_blurfx_la_LIBADD = $(LIB_TDEPARTS) \ + $(top_builddir)/src/digikam/libdigikam.la + +digikamimageplugin_blurfx_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) -ltdecore -ltdeui $(LIB_TQT) -ltdefx -lkdcraw -ltdeio + +kde_services_DATA = digikamimageplugin_blurfx.desktop + +kde_module_LTLIBRARIES = digikamimageplugin_blurfx.la + +rcdir = $(kde_datadir)/digikam +rc_DATA = digikamimageplugin_blurfx_ui.rc + diff --git a/src/imageplugins/blurfx/blurfx.cpp b/src/imageplugins/blurfx/blurfx.cpp new file mode 100644 index 00000000..ec5ff30e --- /dev/null +++ b/src/imageplugins/blurfx/blurfx.cpp @@ -0,0 +1,1445 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Blur FX threaded image filter. + * + * Copyright 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Original Blur algorithms copyrighted 2004 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> +#include <cstring> + +// TQt includes. + +#include <tqdatetime.h> + +// Local includes. + +#include "dimg.h" +#include "dimggaussianblur.h" +#include "blurfx.h" + +namespace DigikamBlurFXImagesPlugin +{ + +BlurFX::BlurFX(Digikam::DImg *orgImage, TQObject *parent, int blurFXType, int distance, int level) + : Digikam::DImgThreadedFilter(orgImage, parent, "BlurFX") +{ + m_blurFXType = blurFXType; + m_distance = distance; + m_level = level; + + initFilter(); +} + +void BlurFX::filterImage(void) +{ + int w = m_orgImage.width(); + int h = m_orgImage.height(); + + switch (m_blurFXType) + { + case ZoomBlur: + zoomBlur(&m_orgImage, &m_destImage, w/2, h/2, m_distance); + break; + + case RadialBlur: + radialBlur(&m_orgImage, &m_destImage, w/2, h/2, m_distance); + break; + + case FarBlur: + farBlur(&m_orgImage, &m_destImage, m_distance); + break; + + case MotionBlur: + motionBlur(&m_orgImage, &m_destImage, m_distance, (double)m_level); + break; + + case SoftenerBlur: + softenerBlur(&m_orgImage, &m_destImage); + break; + + case ShakeBlur: + shakeBlur(&m_orgImage, &m_destImage, m_distance); + break; + + case FocusBlur: + focusBlur(&m_orgImage, &m_destImage, w/2, h/2, m_distance, m_level*10); + break; + + case SmartBlur: + smartBlur(&m_orgImage, &m_destImage, m_distance, m_level); + break; + + case FrostGlass: + frostGlass(&m_orgImage, &m_destImage, m_distance); + break; + + case Mosaic: + mosaic(&m_orgImage, &m_destImage, m_distance, m_distance); + break; + } +} + +/* Function to apply the ZoomBlur effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * X, Y => Center of zoom in the image + * Distance => Distance value + * pArea => Preview area. + * + * Theory => Here we have a effect similar to RadialBlur mode Zoom from + * Photoshop. The theory is very similar to RadialBlur, but has one + * difference. Instead we use pixels with the same radius and + * near angles, we take pixels with the same angle but near radius + * This radius is always from the center to out of the image, we + * calc a proportional radius from the center. + */ +void BlurFX::zoomBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int X, int Y, int Distance, TQRect pArea) +{ + if (Distance <= 1) return; + int progress; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + // We working on full image. + int xMin = 0; + int xMax = Width; + int yMin = 0; + int yMax = Height; + + // If we working in preview mode, else we using the preview area. + if ( pArea.isValid() ) + { + xMin = pArea.x(); + xMax = pArea.x() + pArea.width(); + yMin = pArea.y(); + yMax = pArea.y() + pArea.height(); + } + + int h, w, nh, nw, r; + int sumR, sumG, sumB, nCount; + double lfRadius, lfNewRadius, lfRadMax, lfAngle; + + Digikam::DColor color; + int offset; + + lfRadMax = sqrt (Height * Height + Width * Width); + + // number of added pixels + nCount = 0; + + // we have reached the main loop + for (h = yMin; !m_cancel && (h < yMax); h++) + { + for (w = xMin; !m_cancel && (w < xMax); w++) + { + // ...we enter this loop to sum the bits + + // we initialize the variables + sumR = sumG = sumB = nCount = 0; + + nw = X - w; + nh = Y - h; + + lfRadius = sqrt (nw * nw + nh * nh); + lfAngle = atan2 ((double)nh, (double)nw); + lfNewRadius = (lfRadius * Distance) / lfRadMax; + + for (r = 0; !m_cancel && (r <= lfNewRadius); r++) + { + // we need to calc the positions + nw = (int)(X - (lfRadius - r) * cos (lfAngle)); + nh = (int)(Y - (lfRadius - r) * sin (lfAngle)); + + if (IsInside(Width, Height, nw, nh)) + { + // read color + offset = GetOffset(Width, nw, nh, bytesDepth); + color.setColor(data + offset, sixteenBit); + + // we sum the bits + sumR += color.red(); + sumG += color.green(); + sumB += color.blue(); + nCount++; + } + } + + if (nCount == 0) nCount = 1; + + // calculate pointer + offset = GetOffset(Width, w, h, bytesDepth); + // read color to preserve alpha + color.setColor(data + offset, sixteenBit); + + // now, we have to calc the arithmetic average + color.setRed (sumR / nCount); + color.setGreen(sumG / nCount); + color.setBlue (sumB / nCount); + + // write color to destination + color.setPixel(pResBits + offset); + } + + // Update the progress bar in dialog. + progress = (int) (((double)(h - yMin) * 100.0) / (yMax - yMin)); + + if (progress%5 == 0) + postProgress(progress); + } +} + +/* Function to apply the radialBlur effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * X, Y => Center of radial in the image + * Distance => Distance value + * pArea => Preview area. + * + * Theory => Similar to RadialBlur from Photoshop, its an amazing effect + * Very easy to understand but a little hard to implement. + * We have all the image and find the center pixel. Now, we analize + * all the pixels and calc the radius from the center and find the + * angle. After this, we sum this pixel with others with the same + * radius, but different angles. Here I'm using degrees angles. + */ +void BlurFX::radialBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int X, int Y, int Distance, TQRect pArea) +{ + if (Distance <= 1) return; + int progress; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + // We working on full image. + int xMin = 0; + int xMax = Width; + int yMin = 0; + int yMax = Height; + + // If we working in preview mode, else we using the preview area. + if ( pArea.isValid() ) + { + xMin = pArea.x(); + xMax = pArea.x() + pArea.width(); + yMin = pArea.y(); + yMax = pArea.y() + pArea.height(); + } + + int sumR, sumG, sumB, nw, nh; + double Radius, Angle, AngleRad; + + Digikam::DColor color; + int offset; + + double *nMultArray = new double[Distance * 2 + 1]; + + for (int i = -Distance; i <= Distance; i++) + nMultArray[i + Distance] = i * ANGLE_RATIO; + + // number of added pixels + int nCount = 0; + + // we have reached the main loop + + for (int h = yMin; !m_cancel && (h < yMax); h++) + { + for (int w = xMin; !m_cancel && (w < xMax); w++) + { + // ...we enter this loop to sum the bits + + // we initialize the variables + sumR = sumG = sumB = nCount = 0; + + nw = X - w; + nh = Y - h; + + Radius = sqrt (nw * nw + nh * nh); + AngleRad = atan2 ((double)nh, (double)nw); + + for (int a = -Distance; !m_cancel && (a <= Distance); a++) + { + Angle = AngleRad + nMultArray[a + Distance]; + // we need to calc the positions + nw = (int)(X - Radius * cos (Angle)); + nh = (int)(Y - Radius * sin (Angle)); + + if (IsInside(Width, Height, nw, nh)) + { + // read color + offset = GetOffset(Width, nw, nh, bytesDepth); + color.setColor(data + offset, sixteenBit); + + // we sum the bits + sumR += color.red(); + sumG += color.green(); + sumB += color.blue(); + nCount++; + } + } + + if (nCount == 0) nCount = 1; + + // calculate pointer + offset = GetOffset(Width, w, h, bytesDepth); + // read color to preserve alpha + color.setColor(data + offset, sixteenBit); + + // now, we have to calc the arithmetic average + color.setRed (sumR / nCount); + color.setGreen(sumG / nCount); + color.setBlue (sumB / nCount); + + // write color to destination + color.setPixel(pResBits + offset); + } + + // Update the progress bar in dialog. + progress = (int) (((double)(h - yMin) * 100.0) / (yMax - yMin)); + + if (progress%5 == 0) + postProgress(progress); + } + + delete [] nMultArray; +} + +/* Function to apply the focusBlur effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * BlurRadius => Radius of blurred image. + * BlendRadius => Radius of blending effect. + * bInversed => If true, invert focus effect. + * pArea => Preview area. + * + */ +void BlurFX::focusBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, + int X, int Y, int BlurRadius, int BlendRadius, + bool bInversed, TQRect pArea) +{ + int progress; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + // We working on full image. + int xMin = 0; + int xMax = Width; + int yMin = 0; + int yMax = Height; + + // If we working in preview mode, else we using the preview area. + if ( pArea.isValid() ) + { + xMin = pArea.x(); + xMax = pArea.x() + pArea.width(); + yMin = pArea.y(); + yMax = pArea.y() + pArea.height(); + } + + if (pArea.isValid()) + { + //UNTESTED (unused) + + // We do not have access to the loop of the Gaussian blur, + // so we have to cut the image that we run the effect on. + int xMinBlur = xMin - BlurRadius; + int xMaxBlur = xMax + BlurRadius; + int yMinBlur = yMin - BlurRadius; + int yMaxBlur = yMax + BlurRadius; + Digikam::DImg areaImage = orgImage->copy(xMinBlur, yMaxBlur, xMaxBlur - xMinBlur, yMaxBlur - yMinBlur); + + Digikam::DImgGaussianBlur(this, *orgImage, *destImage, 10, 75, BlurRadius); + + // I am unsure about differences of 1 pixel + destImage->bitBltImage(&areaImage, xMinBlur, yMinBlur); + destImage->bitBltImage(orgImage, 0, 0, Width, yMinBlur, 0, 0); + destImage->bitBltImage(orgImage, 0, yMinBlur, xMinBlur, yMaxBlur - yMinBlur, 0, yMinBlur); + destImage->bitBltImage(orgImage, xMaxBlur + 1, yMinBlur, Width - xMaxBlur - 1, yMaxBlur - yMinBlur, yMaxBlur, yMinBlur); + destImage->bitBltImage(orgImage, 0, yMaxBlur + 1, Width, Height - yMaxBlur - 1, 0, yMaxBlur); + + postProgress(80); + } + else + { + // copy bits for blurring + memcpy(pResBits, data, orgImage->numBytes()); + + // Gaussian blur using the BlurRadius parameter. + Digikam::DImgGaussianBlur(this, *orgImage, *destImage, 10, 80, BlurRadius); + } + + // Blending results. + + int nBlendFactor; + double lfRadius; + int offset; + + Digikam::DColor colorOrgImage, colorBlurredImage; + int alpha; + uchar *ptr; + + // get composer for default blending + Digikam::DColorComposer *composer = Digikam::DColorComposer::getComposer(Digikam::DColorComposer::PorterDuffNone); + + int nh = 0, nw = 0; + + for (int h = yMin; !m_cancel && (h < yMax); h++) + { + nh = Y - h; + + for (int w = xMin; !m_cancel && (w < xMax); w++) + { + nw = X - w; + + lfRadius = sqrt (nh * nh + nw * nw); + + if (sixteenBit) + nBlendFactor = LimitValues16 ((int)(65535.0 * lfRadius / (double)BlendRadius)); + else + nBlendFactor = LimitValues8 ((int)(255.0 * lfRadius / (double)BlendRadius)); + + // Read color values + offset = GetOffset(Width, w, h, bytesDepth); + ptr = pResBits + offset; + colorOrgImage.setColor(data + offset, sixteenBit); + colorBlurredImage.setColor(ptr, sixteenBit); + + // Preserve alpha + alpha = colorOrgImage.alpha(); + + // In normal mode, the image is focused in the middle + // and less focused towards the border. + // In inversed mode, the image is more focused towards the edge + // and less focused in the middle. + // This is achieved by swapping src and dest while blending. + if (bInversed) + { + // set blending alpha value as src alpha. Original value is stored above. + colorOrgImage.setAlpha(nBlendFactor); + // compose colors, writing to dest - colorBlurredImage + composer->compose(colorBlurredImage, colorOrgImage); + // restore alpha + colorBlurredImage.setAlpha(alpha); + // write color to destination + colorBlurredImage.setPixel(ptr); + } + else + { + // set blending alpha value as src alpha. Original value is stored above. + colorBlurredImage.setAlpha(nBlendFactor); + // compose colors, writing to dest - colorOrgImage + composer->compose(colorOrgImage, colorBlurredImage); + // restore alpha + colorOrgImage.setAlpha(alpha); + // write color to destination + colorOrgImage.setPixel(ptr); + } + } + + // Update the progress bar in dialog. + progress = (int) (80.0 + ((double)(h - yMin) * 20.0) / (yMax - yMin)); + + if (progress%5 == 0) + postProgress(progress); + } + + delete composer; +} + +/* Function to apply the farBlur effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Distance => Distance value + * + * Theory => This is an interesting effect, the blur is applied in that + * way: (the value "1" means pixel to be used in a blur calc, ok?) + * e.g. With distance = 2 + * |1|1|1|1|1| + * |1|0|0|0|1| + * |1|0|C|0|1| + * |1|0|0|0|1| + * |1|1|1|1|1| + * We sum all the pixels with value = 1 and apply at the pixel with* + * the position "C". + */ +void BlurFX::farBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Distance) +{ + if (Distance < 1) return; + + // we need to create our kernel + // e.g. distance = 3, so kernel={3 1 1 2 1 1 3} + + int *nKern = new int[Distance * 2 + 1]; + + for (int i = 0; i < Distance * 2 + 1; i++) + { + // the first element is 3 + if (i == 0) + nKern[i] = 2; + // the center element is 2 + else if (i == Distance) + nKern[i] = 3; + // the last element is 3 + else if (i == Distance * 2) + nKern[i] = 3; + // all other elements will be 1 + else + nKern[i] = 1; + } + + // now, we apply a convolution with kernel + MakeConvolution(orgImage, destImage, Distance, nKern); + + // we must delete to free memory + delete [] nKern; +} + +/* Function to apply the SmartBlur effect + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Radius => blur matrix radius. + * Strenght => Color strenght. + * + * Theory => Similar to SmartBlur from Photoshop, this function has the + * same engine as Blur function, but, in a matrix with n + * dimentions, we take only colors that pass by sensibility filter + * The result is a clean image, not totally blurred, but a image + * with correction between pixels. + */ + +void BlurFX::smartBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Radius, int Strength) +{ + if (Radius <= 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 progress; + int sumR, sumG, sumB, nCount, w, h, a; + + int StrengthRange = Strength; + if (sixteenBit) + StrengthRange = (StrengthRange + 1) * 256 - 1; + + Digikam::DColor color, radiusColor, radiusColorBlur; + int offset, loopOffset; + + uchar* pBlur = new uchar[orgImage->numBytes()]; + + // We need to copy our bits to blur bits + + memcpy (pBlur, data, orgImage->numBytes()); + + // we have reached the main loop + + for (h = 0; !m_cancel && (h < Height); h++) + { + for (w = 0; !m_cancel && (w < Width); w++) + { + // we initialize the variables + sumR = sumG = sumB = nCount = 0; + + // read color + offset = GetOffset(Width, w, h, bytesDepth); + color.setColor(data + offset, sixteenBit); + + // ...we enter this loop to sum the bits + for (a = -Radius; !m_cancel && (a <= Radius); a++) + { + // verify if is inside the rect + if (IsInside( Width, Height, w + a, h)) + { + // read color + loopOffset = GetOffset(Width, w+a, h, bytesDepth); + radiusColor.setColor(data + loopOffset, sixteenBit); + + // now, we have to check if is inside the sensibility filter + if (IsColorInsideTheRange (color.red(), color.green(), color.blue(), + radiusColor.red(), radiusColor.green(), radiusColor.blue(), + StrengthRange)) + { + // finally we sum the bits + sumR += radiusColor.red(); + sumG += radiusColor.green(); + sumB += radiusColor.blue(); + } + else + { + // finally we sum the bits + sumR += color.red(); + sumG += color.green(); + sumB += color.blue(); + } + + // increment counter + nCount++; + } + } + + // now, we have to calc the arithmetic average + color.setRed (sumR / nCount); + color.setGreen(sumG / nCount); + color.setBlue (sumB / nCount); + + // write color to destination + color.setPixel(pBlur + offset); + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 50.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } + + // we have reached the second part of main loop + + for (w = 0; !m_cancel && (w < Width); w++) + { + for (h = 0;!m_cancel && ( h < Height); h++) + { + // we initialize the variables + sumR = sumG = sumB = nCount = 0; + + // read color + offset = GetOffset(Width, w, h, bytesDepth); + color.setColor(data + offset, sixteenBit); + + // ...we enter this loop to sum the bits + for (a = -Radius; !m_cancel && (a <= Radius); a++) + { + // verify if is inside the rect + if (IsInside( Width, Height, w, h + a)) + { + // read color + loopOffset = GetOffset(Width, w, h+a, bytesDepth); + radiusColor.setColor(data + loopOffset, sixteenBit); + + // now, we have to check if is inside the sensibility filter + if (IsColorInsideTheRange (color.red(), color.green(), color.blue(), + radiusColor.red(), radiusColor.green(), radiusColor.blue(), + StrengthRange)) + { + radiusColorBlur.setColor(pBlur + loopOffset, sixteenBit); + // finally we sum the bits + sumR += radiusColorBlur.red(); + sumG += radiusColorBlur.green(); + sumB += radiusColorBlur.blue(); + } + else + { + // finally we sum the bits + sumR += color.red(); + sumG += color.green(); + sumB += color.blue(); + } + + // increment counter + nCount++; + } + } + + // now, we have to calc the arithmetic average + color.setRed (sumR / nCount); + color.setGreen(sumG / nCount); + color.setBlue (sumB / nCount); + + // write color to destination + color.setPixel(pResBits + offset); + } + + // Update the progress bar in dialog. + progress = (int) (50.0 + ((double)w * 50.0) / Width); + + if (progress%5 == 0) + postProgress(progress); + } + + // now, we must free memory + delete [] pBlur; +} + +/* Function to apply the motionBlur effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Distance => Distance value + * Angle => Angle direction (degrees) + * + * Theory => Similar to MotionBlur from Photoshop, the engine is very + * simple to undertand, we take a pixel (duh!), with the angle we + * will taking near pixels. After this we blur (add and do a + * division). + */ +void BlurFX::motionBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Distance, double Angle) +{ + if (Distance == 0) return; + int progress; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + Digikam::DColor color; + int offset; + + // we try to avoid division by 0 (zero) + if (Angle == 0.0) Angle = 360.0; + + int sumR, sumG, sumB, nCount, nw, nh; + double nAngX, nAngY; + + // we initialize cos and sin for a best performance + nAngX = cos ((2.0 * M_PI) / (360.0 / Angle)); + nAngY = sin ((2.0 * M_PI) / (360.0 / Angle)); + + // total of bits to be taken is given by this formula + nCount = Distance * 2 + 1; + + // we will alloc size and calc the possible results + int *lpXArray = new int[nCount]; + int *lpYArray = new int[nCount]; + + for (int i = 0; i < nCount; i++) + { + lpXArray[i] = lround( (double)(i - Distance) * nAngX); + lpYArray[i] = lround( (double)(i - Distance) * nAngY); + } + + // we have reached the main loop + + for (int h = 0; !m_cancel && (h < Height); h++) + { + for (int w = 0; !m_cancel && (w < Width); w++) + { + // we initialize the variables + sumR = sumG = sumB = 0; + + // ...we enter this loop to sum the bits + for (int a = -Distance; !m_cancel && (a <= Distance); a++) + { + // we need to calc the positions + nw = w + lpXArray[a + Distance]; + nh = h + lpYArray[a + Distance]; + + offset = GetOffsetAdjusted(Width, Height, nw, nh, bytesDepth); + color.setColor(data + offset, sixteenBit); + + // we sum the bits + sumR += color.red(); + sumG += color.green(); + sumB += color.blue(); + } + + if (nCount == 0) nCount = 1; + + // calculate pointer + offset = GetOffset(Width, w, h, bytesDepth); + // read color to preserve alpha + color.setColor(data + offset, sixteenBit); + + // now, we have to calc the arithmetic average + color.setRed (sumR / nCount); + color.setGreen(sumG / nCount); + color.setBlue (sumB / nCount); + + // write color to destination + color.setPixel(pResBits + offset); + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 100.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } + + delete [] lpXArray; + delete [] lpYArray; +} + +/* Function to apply the softenerBlur effect + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * + * Theory => An interesting blur-like function. In dark tones we apply a + * blur with 3x3 dimentions, in light tones, we apply a blur with + * 5x5 dimentions. Easy, hun? + */ +void BlurFX::softenerBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage) +{ + int progress; + + 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 SomaR = 0, SomaG = 0, SomaB = 0; + int Gray; + + Digikam::DColor color, colorSoma; + int offset, offsetSoma; + + int grayLimit = sixteenBit ? 32767 : 127; + + for (int h = 0; !m_cancel && (h < Height); h++) + { + for (int w = 0; !m_cancel && (w < Width); w++) + { + SomaR = SomaG = SomaB = 0; + + offset = GetOffset(Width, w, h, bytesDepth); + color.setColor(data + offset, sixteenBit); + + Gray = (color.red() + color.green() + color.blue()) / 3; + + if (Gray > grayLimit) + { + // 7x7 + for (int a = -3; !m_cancel && (a <= 3); a++) + { + for (int b = -3; !m_cancel && (b <= 3); b++) + { + if ((h + a < 0) || (w + b < 0)) + offsetSoma = offset; + else + offsetSoma = GetOffset(Width, (w + Lim_Max (w, b, Width)), + (h + Lim_Max (h, a, Height)), bytesDepth); + colorSoma.setColor(data + offsetSoma, sixteenBit); + + SomaR += colorSoma.red(); + SomaG += colorSoma.green(); + SomaB += colorSoma.blue(); + } + } + + // 7*7 = 49 + color.setRed (SomaR / 49); + color.setGreen(SomaG / 49); + color.setBlue (SomaB / 49); + color.setPixel(pResBits + offset); + } + else + { + // 3x3 + for (int a = -1; !m_cancel && (a <= 1); a++) + { + for (int b = -1; !m_cancel && (b <= 1); b++) + { + if ((h + a < 0) || (w + b < 0)) + offsetSoma = offset; + else + offsetSoma = GetOffset(Width, (w + Lim_Max (w, b, Width)), + (h + Lim_Max (h, a, Height)), bytesDepth); + colorSoma.setColor(data + offsetSoma, sixteenBit); + + SomaR += colorSoma.red(); + SomaG += colorSoma.green(); + SomaB += colorSoma.blue(); + } + } + + // 3*3 = 9 + color.setRed (SomaR / 9); + color.setGreen(SomaG / 9); + color.setBlue (SomaB / 9); + 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 shake blur effect + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Distance => Distance between layers (from origin) + * + * Theory => Similar to Fragment effect from Photoshop. We create 4 layers + * each one has the same distance from the origin, but have + * different positions (top, button, left and right), with these 4 + * layers, we join all the pixels. + */ +void BlurFX::shakeBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Distance) +{ + int progress; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + Digikam::DColor color, colorLayer, color1, color2, color3, color4; + int offset, offsetLayer; + + int numBytes = orgImage->numBytes(); + uchar* Layer1 = new uchar[numBytes]; + uchar* Layer2 = new uchar[numBytes]; + uchar* Layer3 = new uchar[numBytes]; + uchar* Layer4 = new uchar[numBytes]; + + int h, w, nw, nh; + + for (h = 0; !m_cancel && (h < Height); h++) + { + for (w = 0; !m_cancel && (w < Width); w++) + { + offsetLayer = GetOffset(Width, w, h, bytesDepth); + + nh = (h + Distance >= Height) ? Height - 1 : h + Distance; + offset = GetOffset(Width, w, nh, bytesDepth); + color.setColor(data + offset, sixteenBit); + color.setPixel(Layer1 + offsetLayer); + + nh = (h - Distance < 0) ? 0 : h - Distance; + offset = GetOffset(Width, w, nh, bytesDepth); + color.setColor(data + offset, sixteenBit); + color.setPixel(Layer2 + offsetLayer); + + nw = (w + Distance >= Width) ? Width - 1 : w + Distance; + offset = GetOffset(Width, nw, h, bytesDepth); + color.setColor(data + offset, sixteenBit); + color.setPixel(Layer3 + offsetLayer); + + nw = (w - Distance < 0) ? 0 : w - Distance; + offset = GetOffset(Width, nw, h, bytesDepth); + color.setColor(data + offset, sixteenBit); + color.setPixel(Layer4 + offsetLayer); + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 50.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } + + for (int h = 0; !m_cancel && (h < Height); h++) + { + for (int w = 0; !m_cancel && (w < Width); w++) + { + offset = GetOffset(Width, w, h, bytesDepth); + // read original data to preserve alpha + color.setColor(data + offset, sixteenBit); + // read colors from all four layers + color1.setColor(Layer1 + offset, sixteenBit); + color2.setColor(Layer2 + offset, sixteenBit); + color3.setColor(Layer3 + offset, sixteenBit); + color4.setColor(Layer4 + offset, sixteenBit); + + // set color components of resulting color + color.setRed ( (color1.red() + color2.red() + color3.red() + color4.red()) / 4 ); + color.setGreen( (color1.green() + color2.green() + color3.green() + color4.green()) / 4 ); + color.setBlue ( (color1.blue() + color2.blue() + color3.blue() + color4.blue()) / 4 ); + + color.setPixel(pResBits + offset); + } + + // Update the progress bar in dialog. + progress = (int) (50.0 + ((double)h * 50.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } + + delete [] Layer1; + delete [] Layer2; + delete [] Layer3; + delete [] Layer4; +} + +/* Function to apply the frostGlass effect + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Frost => Frost value + * + * Theory => Similar to Diffuse effect, but the random byte is defined + * in a matrix. Diffuse uses a random diagonal byte. + */ +void BlurFX::frostGlass(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Frost) +{ + int progress; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + Frost = (Frost < 1) ? 1 : (Frost > 10) ? 10 : Frost; + + int h, w; + + Digikam::DColor color; + int offset; + + // Randomize. + + TQDateTime dt = TQDateTime::currentDateTime(); + TQDateTime Y2000( TQDate(2000, 1, 1), TQTime(0, 0, 0) ); + uint seed = dt.secsTo(Y2000); + + int range = sixteenBit ? 65535 : 255; + + // it is a huge optimizsation to allocate these here once + uchar *IntensityCount = new uchar[range + 1]; + uint *AverageColorR = new uint[range + 1]; + uint *AverageColorG = new uint[range + 1]; + uint *AverageColorB = new uint[range + 1]; + + for (h = 0; !m_cancel && (h < Height); h++) + { + for (w = 0; !m_cancel && (w < Width); w++) + { + offset = GetOffset(Width, w, h, bytesDepth); + // read color to preserve alpha + color.setColor(data + offset, sixteenBit); + + // get random color from surrounding of w|h + color = RandomColor (data, Width, Height, sixteenBit, bytesDepth, + w, h, Frost, color.alpha(), &seed, range, IntensityCount, + AverageColorR, AverageColorG, AverageColorB); + + // write color to destination + color.setPixel(pResBits + offset); + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 100.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } + + delete [] IntensityCount; + delete [] AverageColorR; + delete [] AverageColorG; + delete [] AverageColorB; +} + +/* Function to apply the mosaic effect backported from ImageProcessing version 2 + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Size => Size of mosaic . + * + * Theory => Ok, you can find some mosaic effects on PSC, but this one + * has a great feature, if you see a mosaic in other code you will + * see that the corner pixel doesn't change. The explanation is + * simple, the color of the mosaic is the same as the first pixel + * get. Here, the color of the mosaic is the same as the mosaic + * center pixel. + * Now the function scan the rows from the top (like photoshop). + */ +void BlurFX::mosaic(Digikam::DImg *orgImage, Digikam::DImg *destImage, int SizeW, int SizeH) +{ + int progress; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pResBits = destImage->bits(); + + // we need to check for valid values + if (SizeW < 1) SizeW = 1; + if (SizeH < 1) SizeH = 1; + if ((SizeW == 1) && (SizeH == 1)) return; + + Digikam::DColor color; + int offsetCenter, offset; + + // this loop will never look for transparent colors + + for (int h = 0; !m_cancel && (h < Height); h += SizeH) + { + for (int w = 0; !m_cancel && (w < Width); w += SizeW) + { + // we have to find the center pixel for mosaic's rectangle + + offsetCenter = GetOffsetAdjusted(Width, Height, w + (SizeW / 2), h + (SizeH / 2), bytesDepth); + color.setColor(data + offsetCenter, sixteenBit); + + // now, we fill the mosaic's rectangle with the center pixel color + + for (int subw = w; !m_cancel && (subw <= w + SizeW); subw++) + { + for (int subh = h; !m_cancel && (subh <= h + SizeH); subh++) + { + // if is inside... + if (IsInside(Width, Height, subw, subh)) + { + // set color + offset = GetOffset(Width, subw, subh, bytesDepth); + 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 get a color in a matriz with a determined size + * + * Bits => Bits array + * Width => Image width + * Height => Image height + * X => Position horizontal + * Y => Position vertical + * Radius => The radius of the matrix to be created + * + * Theory => This function takes from a distinct matrix a random color + */ +Digikam::DColor BlurFX::RandomColor(uchar *Bits, int Width, int Height, bool sixteenBit, int bytesDepth, + int X, int Y, int Radius, + int alpha, uint *randomSeed, int range, uchar *IntensityCount, + uint *AverageColorR, uint *AverageColorG, uint *AverageColorB) +{ + Digikam::DColor color; + int offset; + + int w, h, counter = 0; + + int I; + + // For 16 bit we have a problem here because this takes 255 times longer, + // and the algorithm is really slow for 16 bit, but I think this cannot be avoided. + memset(IntensityCount, 0, range ); + memset(AverageColorR, 0, range ); + memset(AverageColorG, 0, range ); + memset(AverageColorB, 0, range ); + + for (w = X - Radius; !m_cancel && (w <= X + Radius); w++) + { + for (h = Y - Radius; !m_cancel && (h <= Y + Radius); h++) + { + if ((w >= 0) && (w < Width) && (h >= 0) && (h < Height)) + { + offset = GetOffset(Width, w, h, bytesDepth); + color.setColor(Bits + offset, sixteenBit); + I = GetIntensity (color.red(), color.green(), color.blue()); + IntensityCount[I]++; + counter++; + + if (IntensityCount[I] == 1) + { + AverageColorR[I] = color.red(); + AverageColorG[I] = color.green(); + AverageColorB[I] = color.blue(); + } + else + { + AverageColorR[I] += color.red(); + AverageColorG[I] += color.green(); + AverageColorB[I] += color.blue(); + } + } + } + } + + // check for m_cancel here before entering the do loop (will crash with SIGFPE otherwise) + if (m_cancel) + return Digikam::DColor(0, 0, 0, 0, sixteenBit); + + int RandNumber, count, Index, ErrorCount = 0; + int J; + + do + { + RandNumber = abs( (int)((rand_r(randomSeed) + 1) * ((double)counter / (1 + (double) RAND_MAX))) ); + count = 0; + Index = 0; + + do + { + count += IntensityCount[Index]; + Index++; + } + while (count < RandNumber && !m_cancel); + + J = Index - 1; + ErrorCount++; + } + while ((IntensityCount[J] == 0) && (ErrorCount <= counter) && !m_cancel); + + if (m_cancel) + return Digikam::DColor(0, 0, 0, 0, sixteenBit); + + + color.setSixteenBit(sixteenBit); + color.setAlpha(alpha); + + if (ErrorCount >= counter) + { + color.setRed (AverageColorR[J] / counter); + color.setGreen(AverageColorG[J] / counter); + color.setBlue (AverageColorB[J] / counter); + } + else + { + color.setRed (AverageColorR[J] / IntensityCount[J]); + color.setGreen(AverageColorG[J] / IntensityCount[J]); + color.setBlue (AverageColorB[J] / IntensityCount[J]); + } + + return color; +} + +/* Function to simple convolve a unique pixel with a determined radius + * + * data => The image data in RGBA mode. + * Width => Width of image. + * Height => Height of image. + * Radius => kernel radius, e.g. rad=1, so array will be 3X3 + * Kernel => kernel array to apply. + * + * Theory => I've worked hard here, but I think this is a very smart + * way to convolve an array, its very hard to explain how I reach + * this, but the trick here its to store the sum used by the + * previous pixel, so we sum with the other pixels that wasn't get + */ +void BlurFX::MakeConvolution (Digikam::DImg *orgImage, Digikam::DImg *destImage, int Radius, int Kernel[]) +{ + if (Radius <= 0) return; + + int Width = orgImage->width(); + int Height = orgImage->height(); + uchar* data = orgImage->bits(); + bool sixteenBit = orgImage->sixteenBit(); + int bytesDepth = orgImage->bytesDepth(); + uchar* pOutBits = destImage->bits(); + + int progress; + int n, h, w; + + int nSumR, nSumG, nSumB, nCount; + int nKernelWidth = Radius * 2 + 1; + int range = sixteenBit ? 65536 : 256; + Digikam::DColor color; + int offset; + + uchar* pBlur = new uchar[orgImage->numBytes()]; + + // We need to copy our bits to blur bits + + memcpy (pBlur, data, orgImage->numBytes()); + + // We need to alloc a 2d array to help us to store the values + + int** arrMult = Alloc2DArray (nKernelWidth, range); + + for (int i = 0; i < nKernelWidth; i++) + for (int j = 0; j < range; j++) + arrMult[i][j] = j * Kernel[i]; + + // Now, we enter in the main loop + + for (h = 0; !m_cancel && (h < Height); h++) + { + for (w = 0; !m_cancel && (w < Width); w++) + { + // initialize the variables + nSumR = nSumG = nSumB = nCount = 0; + + // first of all, we need to blur the horizontal lines + + for (n = -Radius; !m_cancel && (n <= Radius); n++) + { + // if is inside... + if (IsInside (Width, Height, w + n, h)) + { + // read color from orgImage + offset = GetOffset(Width, w+n, h, bytesDepth); + color.setColor(data + offset, sixteenBit); + + // finally, we sum the pixels using a method similar to assigntables + nSumR += arrMult[n + Radius][color.red()]; + nSumG += arrMult[n + Radius][color.green()]; + nSumB += arrMult[n + Radius][color.blue()]; + + // we need to add the kernel value to the counter + nCount += Kernel[n + Radius]; + } + } + + if (nCount == 0) nCount = 1; + + // calculate pointer + offset = GetOffset(Width, w, h, bytesDepth); + // read color from orgImage to preserve alpha + color.setColor(data + offset, sixteenBit); + + // now, we have to calc the arithmetic average + if (sixteenBit) + { + color.setRed (LimitValues16(nSumR / nCount)); + color.setGreen(LimitValues16(nSumG / nCount)); + color.setBlue (LimitValues16(nSumB / nCount)); + } + else + { + color.setRed (LimitValues8(nSumR / nCount)); + color.setGreen(LimitValues8(nSumG / nCount)); + color.setBlue (LimitValues8(nSumB / nCount)); + } + + // write color to blur bits + color.setPixel(pBlur + offset); + } + + // Update the progress bar in dialog. + progress = (int) (((double)h * 50.0) / Height); + + if (progress%5 == 0) + postProgress(progress); + } + + // We enter in the second main loop + for (w = 0; !m_cancel && (w < Width); w++) + { + for (h = 0; !m_cancel && (h < Height); h++) + { + // initialize the variables + nSumR = nSumG = nSumB = nCount = 0; + + // first of all, we need to blur the vertical lines + for (n = -Radius; !m_cancel && (n <= Radius); n++) + { + // if is inside... + if (IsInside(Width, Height, w, h + n)) + { + // read color from blur bits + offset = GetOffset(Width, w, h+n, bytesDepth); + color.setColor(pBlur + offset, sixteenBit); + + // finally, we sum the pixels using a method similar to assigntables + nSumR += arrMult[n + Radius][color.red()]; + nSumG += arrMult[n + Radius][color.green()]; + nSumB += arrMult[n + Radius][color.blue()]; + + // we need to add the kernel value to the counter + nCount += Kernel[n + Radius]; + } + } + + if (nCount == 0) nCount = 1; + + // calculate pointer + offset = GetOffset(Width, w, h, bytesDepth); + // read color from orgImage to preserve alpha + color.setColor(data + offset, sixteenBit); + + // now, we have to calc the arithmetic average + if (sixteenBit) + { + color.setRed (LimitValues16(nSumR / nCount)); + color.setGreen(LimitValues16(nSumG / nCount)); + color.setBlue (LimitValues16(nSumB / nCount)); + } + else + { + color.setRed (LimitValues8(nSumR / nCount)); + color.setGreen(LimitValues8(nSumG / nCount)); + color.setBlue (LimitValues8(nSumB / nCount)); + } + + // write color to destination + color.setPixel(pOutBits + offset); + } + + // Update the progress bar in dialog. + progress = (int) (50.0 + ((double)w * 50.0) / Width); + + if (progress%5 == 0) + postProgress(progress); + } + + // now, we must free memory + Free2DArray (arrMult, nKernelWidth); + delete [] pBlur; +} + +} // NameSpace DigikamBlurFXImagesPlugin diff --git a/src/imageplugins/blurfx/blurfx.h b/src/imageplugins/blurfx/blurfx.h new file mode 100644 index 00000000..4a4397b4 --- /dev/null +++ b/src/imageplugins/blurfx/blurfx.h @@ -0,0 +1,191 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-05-25 + * Description : Blur FX threaded image filter. + * + * Copyright 2005-2007 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * Original Blur algorithms copyrighted 2004 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. + * + * ============================================================ */ + +#ifndef BLURFX_H +#define BLURFX_H + +// Digikam includes. + +#include "dimgthreadedfilter.h" + +namespace DigikamBlurFXImagesPlugin +{ + +class BlurFX : public Digikam::DImgThreadedFilter +{ + +public: + + BlurFX(Digikam::DImg *orgImage, TQObject *parent=0, int blurFXType=ZoomBlur, + int distance=100, int level=45); + + ~BlurFX(){}; + +public: + + enum BlurFXTypes + { + ZoomBlur=0, + RadialBlur, + FarBlur, + MotionBlur, + SoftenerBlur, + ShakeBlur, + FocusBlur, + SmartBlur, + FrostGlass, + Mosaic + }; + +private: // BlurFX filter data. + + int m_blurFXType; + int m_distance; + int m_level; + +private: // BlurFX filter methods. + + virtual void filterImage(void); + + // Backported from ImageProcessing version 1 + void softenerBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage); + void shakeBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Distance); + void frostGlass(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Frost); + + // Backported from ImageProcessing version 2 + void zoomBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, + int X, int Y, int Distance, TQRect pArea=TQRect()); + void radialBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, + int X, int Y, int Distance, TQRect pArea=TQRect()); + void focusBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, + int X, int Y, int BlurRadius, int BlendRadius, + bool bInversed=false, TQRect pArea=TQRect()); + void farBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Distance); + void motionBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Distance, double Angle=0.0); + void smartBlur(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Radius, int Strenght); + void mosaic(Digikam::DImg *orgImage, Digikam::DImg *destImage, int SizeW, int SizeH); + +private: // Internal filter methods. + + void MakeConvolution(Digikam::DImg *orgImage, Digikam::DImg *destImage, int Radius, int Kernel[]); + + Digikam::DColor RandomColor(uchar *Bits, int Width, int Height, bool sixteenBit, int bytesDepth, + int X, int Y, int Radius, + int alpha, uint *randomSeed, int range, uchar *IntensityCount, + uint *AverageColorR, uint *AverageColorG, uint *AverageColorB); + + // Return the limit defined the max and min values. + inline int Lim_Max(int Now, int Up, int Max) + { + --Max; + while (Now > Max - Up) --Up; + return (Up); + }; + + // Return the luminance (Y) component of YIQ color model. + inline int GetIntensity (int R, int G, int B) + { + return (int)(R * 0.3 + G * 0.59 + B * 0.11); + }; + + // function to allocate a 2d array + inline int** Alloc2DArray (int Columns, int Rows) + { + // First, we declare our future 2d array to be returned + int** lpcArray = NULL; + + // Now, we alloc the main pointer with Columns + lpcArray = new int*[Columns]; + + for (int i = 0; i < Columns; i++) + lpcArray[i] = new int[Rows]; + + return (lpcArray); + } + + // Function to deallocates the 2d array previously created + inline void Free2DArray (int** lpcArray, int Columns) + { + // loop to dealocate the columns + for (int i = 0; i < Columns; i++) + delete [] lpcArray[i]; + + // now, we delete the main pointer + delete [] lpcArray; + } + + inline bool IsInside (int Width, int Height, int X, int Y) + { + bool bIsWOk = ((X < 0) ? false : (X >= Width ) ? false : true); + bool bIsHOk = ((Y < 0) ? false : (Y >= Height) ? false : true); + return (bIsWOk && bIsHOk); + }; + + inline uchar LimitValues8(int ColorValue) + { + if (ColorValue > 255) ColorValue = 255; + if (ColorValue < 0) ColorValue = 0; + return ((uchar) ColorValue); + }; + + + inline int LimitValues16(int ColorValue) + { + if (ColorValue > 65535) ColorValue = 65535; + if (ColorValue < 0) ColorValue = 0; + return ColorValue; + }; + + inline int GetOffset(int Width, int X, int Y, int bytesDepth) + { + return (Y * Width * bytesDepth) + (X * bytesDepth); + }; + + inline int GetOffsetAdjusted(int Width, int Height, int X, int Y, int bytesDepth) + { + X = (X < 0) ? 0 : ((X >= Width ) ? (Width - 1) : X); + Y = (Y < 0) ? 0 : ((Y >= Height) ? (Height - 1) : Y); + return GetOffset(Width, X, Y, bytesDepth); + }; + + inline bool IsColorInsideTheRange (int cR, int cG, int cB, + int nR, int nG, int nB, + int Range) + { + if ((nR >= cR - Range) && (nR <= cR + Range)) + if ((nG >= cG - Range) && (nG <= cG + Range)) + if ((nB >= cB - Range) && (nB <= cB + Range)) + return (true); + + return (false); + }; + +}; + +} // NameSpace DigikamBlurFXImagesPlugin + +#endif /* BLURFX_H */ diff --git a/src/imageplugins/blurfx/blurfxtool.cpp b/src/imageplugins/blurfx/blurfxtool.cpp new file mode 100644 index 00000000..2998dbde --- /dev/null +++ b/src/imageplugins/blurfx/blurfxtool.cpp @@ -0,0 +1,402 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-09 + * Description : a plugin to apply Blur FX to images + * + * Copyright 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqdatetime.h> +#include <tqimage.h> +#include <tqlabel.h> +#include <tqlayout.h> +#include <tqslider.h> +#include <tqwhatsthis.h> + +// KDE includes. + +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <tdeconfig.h> +#include <tdelocale.h> +#include <kiconloader.h> + +// LibKDcraw includes. + +#include <libkdcraw/rnuminput.h> +#include <libkdcraw/rcombobox.h> + +// Local includes. + +#include "daboutdata.h" +#include "ddebug.h" +#include "imageiface.h" +#include "imagepanelwidget.h" +#include "editortoolsettings.h" +#include "blurfx.h" +#include "blurfxtool.h" +#include "blurfxtool.moc" + +using namespace KDcrawIface; +using namespace Digikam; + +namespace DigikamBlurFXImagesPlugin +{ + +BlurFXTool::BlurFXTool(TQObject* parent) + : EditorToolThreaded(parent) +{ + setName("blurfx"); + setToolName(i18n("Blur FX")); + setToolIcon(SmallIcon("blurfx")); + + // ------------------------------------------------------------- + + m_gboxSettings = new EditorToolSettings(EditorToolSettings::Default| + EditorToolSettings::Ok| + EditorToolSettings::Cancel| + EditorToolSettings::Try, + EditorToolSettings::PanIcon); + TQGridLayout* grid = new TQGridLayout( m_gboxSettings->plainPage(), 6, 1); + + m_effectTypeLabel = new TQLabel(i18n("Type:"), m_gboxSettings->plainPage()); + + m_effectType = new RComboBox(m_gboxSettings->plainPage()); + m_effectType->insertItem(i18n("Zoom Blur")); + m_effectType->insertItem(i18n("Radial Blur")); + m_effectType->insertItem(i18n("Far Blur")); + m_effectType->insertItem(i18n("Motion Blur")); + m_effectType->insertItem(i18n("Softener Blur")); + m_effectType->insertItem(i18n("Skake Blur")); + m_effectType->insertItem(i18n("Focus Blur")); + m_effectType->insertItem(i18n("Smart Blur")); + m_effectType->insertItem(i18n("Frost Glass")); + m_effectType->insertItem(i18n("Mosaic")); + m_effectType->setDefaultItem(BlurFX::ZoomBlur); + TQWhatsThis::add( m_effectType, i18n("<p>Select the blurring effect to apply to the image.<p>" + "<b>Zoom Blur</b>: blurs the image along radial lines starting from " + "a specified center point. This simulates the blur of a zooming camera.<p>" + "<b>Radial Blur</b>: blurs the image by rotating the pixels around " + "the specified center point. This simulates the blur of a rotating camera.<p>" + "<b>Far Blur</b>: blurs the image by using far pixels. This simulates the blur " + "of an unfocalized camera lens.<p>" + "<b>Motion Blur</b>: blurs the image by moving the pixels horizontally. " + "This simulates the blur of a linear moving camera.<p>" + "<b>Softener Blur</b>: blurs the image softly in dark tones and hardly in light " + "tones. This gives images a dreamy and glossy soft focus effect. It's ideal " + "for creating romantic portraits, glamour photographs, or giving images a warm " + "and subtle glow.<p>" + "<b>Skake Blur</b>: blurs the image by skaking randomly the pixels. " + "This simulates the blur of a random moving camera.<p>" + "<b>Focus Blur</b>: blurs the image corners to reproduce the astigmatism distortion " + "of a lens.<p>" + "<b>Smart Blur</b>: finds the edges of color in your image and blurs them without " + "muddying the rest of the image.<p>" + "<b>Frost Glass</b>: blurs the image by randomly disperse light coming through " + "a frosted glass.<p>" + "<b>Mosaic</b>: divides the photograph into rectangular cells and then " + "recreates it by filling those cells with average pixel value.")); + + m_distanceLabel = new TQLabel(i18n("Distance:"), m_gboxSettings->plainPage()); + m_distanceInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_distanceInput->setRange(0, 100, 1); + m_distanceInput->setDefaultValue(3); + TQWhatsThis::add( m_distanceInput, i18n("<p>Set here the blur distance in pixels.")); + + m_levelLabel = new TQLabel(i18n("Level:"), m_gboxSettings->plainPage()); + m_levelInput = new RIntNumInput(m_gboxSettings->plainPage()); + m_levelInput->setRange(0, 360, 1); + m_levelInput->setDefaultValue(128); + TQWhatsThis::add( m_levelInput, i18n("<p>This value controls the level to use with the current effect.")); + + grid->addMultiCellWidget(m_effectTypeLabel, 0, 0, 0, 1); + grid->addMultiCellWidget(m_effectType, 1, 1, 0, 1); + grid->addMultiCellWidget(m_distanceLabel, 2, 2, 0, 1); + grid->addMultiCellWidget(m_distanceInput, 3, 3, 0, 1); + grid->addMultiCellWidget(m_levelLabel, 4, 4, 0, 1); + grid->addMultiCellWidget(m_levelInput, 5, 5, 0, 1); + grid->setRowStretch(6, 10); + grid->setMargin(m_gboxSettings->spacingHint()); + grid->setSpacing(m_gboxSettings->spacingHint()); + + setToolSettings(m_gboxSettings); + + // ------------------------------------------------------------- + + m_previewWidget = new ImagePanelWidget(470, 350, "blurfx Tool", m_gboxSettings->panIconView()); + + setToolView(m_previewWidget); + init(); + + // ------------------------------------------------------------- + + connect(m_effectType, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotEffectTypeChanged(int))); + + connect(m_distanceInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_levelInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); +} + +BlurFXTool::~BlurFXTool() +{ +} + +void BlurFXTool::renderingFinished(void) +{ + + m_effectTypeLabel->setEnabled(true); + m_effectType->setEnabled(true); + m_distanceInput->setEnabled(true); + m_distanceLabel->setEnabled(true); + + switch (m_effectType->currentItem()) + { + case BlurFX::ZoomBlur: + case BlurFX::RadialBlur: + case BlurFX::FarBlur: + case BlurFX::ShakeBlur: + case BlurFX::FrostGlass: + case BlurFX::Mosaic: + break; + + case BlurFX::MotionBlur: + case BlurFX::FocusBlur: + case BlurFX::SmartBlur: + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + break; + + case BlurFX::SoftenerBlur: + m_distanceInput->setEnabled(false); + m_distanceLabel->setEnabled(false); + break; + } +} + +void BlurFXTool::readSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("blurfx Tool"); + m_effectType->blockSignals(true); + m_distanceInput->blockSignals(true); + m_levelInput->blockSignals(true); + + m_effectType->setCurrentItem(config->readNumEntry("EffectType", m_effectType->defaultItem())); + m_distanceInput->setValue(config->readNumEntry("DistanceAjustment", m_distanceInput->defaultValue())); + m_levelInput->setValue(config->readNumEntry("LevelAjustment", m_levelInput->defaultValue())); + + m_effectType->blockSignals(false); + m_distanceInput->blockSignals(false); + m_levelInput->blockSignals(false); +} + +void BlurFXTool::writeSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("blurfx Tool"); + config->writeEntry("EffectType", m_effectType->currentItem()); + config->writeEntry("DistanceAjustment", m_distanceInput->value()); + config->writeEntry("LevelAjustment", m_levelInput->value()); + m_previewWidget->writeSettings(); + config->sync(); +} + +void BlurFXTool::slotResetSettings() +{ + m_effectType->blockSignals(true); + m_distanceInput->blockSignals(true); + m_levelInput->blockSignals(true); + + m_effectType->slotReset(); + m_distanceInput->slotReset(); + m_levelInput->slotReset(); + + m_effectType->blockSignals(false); + m_distanceInput->blockSignals(false); + m_levelInput->blockSignals(false); + + slotEffectTypeChanged(m_effectType->defaultItem()); +} + +void BlurFXTool::slotEffectTypeChanged(int type) +{ + m_distanceInput->setEnabled(true); + m_distanceLabel->setEnabled(true); + + m_distanceInput->blockSignals(true); + m_levelInput->blockSignals(true); + + m_distanceInput->setRange(0, 200, 1); + m_distanceInput->setValue(100); + m_levelInput->setRange(0, 360, 1); + m_levelInput->setValue(45); + + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + + switch (type) + { + case BlurFX::ZoomBlur: + break; + + case BlurFX::RadialBlur: + case BlurFX::FrostGlass: + m_distanceInput->setRange(0, 10, 1); + m_distanceInput->setValue(3); + break; + + case BlurFX::FarBlur: + m_distanceInput->setRange(0, 20, 1); + m_distanceInput->input()->setMaxValue(20); + m_distanceInput->setValue(10); + break; + + case BlurFX::MotionBlur: + case BlurFX::FocusBlur: + m_distanceInput->setRange(0, 100, 1); + m_distanceInput->setValue(20); + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + break; + + case BlurFX::SoftenerBlur: + m_distanceInput->setEnabled(false); + m_distanceLabel->setEnabled(false); + break; + + case BlurFX::ShakeBlur: + m_distanceInput->setRange(0, 100, 1); + m_distanceInput->setValue(20); + break; + + case BlurFX::SmartBlur: + m_distanceInput->setRange(0, 20, 1); + m_distanceInput->setValue(3); + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + m_levelInput->setRange(0, 255, 1); + m_levelInput->setValue(128); + break; + + case BlurFX::Mosaic: + m_distanceInput->setRange(0, 50, 1); + m_distanceInput->setValue(3); + break; + } + + m_distanceInput->blockSignals(false); + m_levelInput->blockSignals(false); + + slotEffect(); +} + +void BlurFXTool::prepareEffect() +{ + m_effectTypeLabel->setEnabled(false); + m_effectType->setEnabled(false); + m_distanceInput->setEnabled(false); + m_distanceLabel->setEnabled(false); + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + + DImg image; + + switch (m_effectType->currentItem()) + { + case BlurFX::ZoomBlur: + case BlurFX::RadialBlur: + case BlurFX::FocusBlur: + { + ImageIface iface(0, 0); + image = *iface.getOriginalImg(); + break; + } + + case BlurFX::FarBlur: + case BlurFX::MotionBlur: + case BlurFX::SoftenerBlur: + case BlurFX::ShakeBlur: + case BlurFX::SmartBlur: + case BlurFX::FrostGlass: + case BlurFX::Mosaic: + image = m_previewWidget->getOriginalRegionImage(); + break; + } + + int t = m_effectType->currentItem(); + int d = m_distanceInput->value(); + int l = m_levelInput->value(); + + setFilter(dynamic_cast<DImgThreadedFilter*>(new BlurFX(&image, this, t, d, l))); +} + +void BlurFXTool::prepareFinal() +{ + m_effectTypeLabel->setEnabled(false); + m_effectType->setEnabled(false); + m_distanceInput->setEnabled(false); + m_distanceLabel->setEnabled(false); + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + + int t = m_effectType->currentItem(); + int d = m_distanceInput->value(); + int l = m_levelInput->value(); + + ImageIface iface(0, 0); + setFilter(dynamic_cast<DImgThreadedFilter *>(new BlurFX(iface.getOriginalImg(), this, t, d, l))); +} + +void BlurFXTool::putPreviewData() +{ + switch (m_effectType->currentItem()) + { + case BlurFX::ZoomBlur: + case BlurFX::RadialBlur: + case BlurFX::FocusBlur: + { + TQRect pRect = m_previewWidget->getOriginalImageRegionToRender(); + DImg destImg = filter()->getTargetImage().copy(pRect); + m_previewWidget->setPreviewImage(destImg); + break; + } + case BlurFX::FarBlur: + case BlurFX::MotionBlur: + case BlurFX::SoftenerBlur: + case BlurFX::ShakeBlur: + case BlurFX::SmartBlur: + case BlurFX::FrostGlass: + case BlurFX::Mosaic: + m_previewWidget->setPreviewImage(filter()->getTargetImage()); + break; + } +} + +void BlurFXTool::putFinalData() +{ + ImageIface iface(0, 0); + iface.putOriginalImage(i18n("Blur Effects"), filter()->getTargetImage().bits()); +} + +} // NameSpace DigikamBlurFXImagesPlugin diff --git a/src/imageplugins/blurfx/blurfxtool.h b/src/imageplugins/blurfx/blurfxtool.h new file mode 100644 index 00000000..9726e65d --- /dev/null +++ b/src/imageplugins/blurfx/blurfxtool.h @@ -0,0 +1,93 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-09 + * Description : a plugin to apply Blur FX to images + * + * Copyright 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef BLURFXTOOL_H +#define BLURFXTOOL_H + +// Digikam includes. + +#include "editortool.h" + +class TQLabel; + +namespace KDcrawIface +{ +class RIntNumInput; +class RComboBox; +} + +namespace Digikam +{ +class EditorToolSettings; +class ImagePanelWidget; +} + +namespace DigikamBlurFXImagesPlugin +{ + +class BlurFXTool : public Digikam::EditorToolThreaded +{ + TQ_OBJECT + + +public: + + BlurFXTool(TQObject *parent); + ~BlurFXTool(); + +private slots: + + void slotEffectTypeChanged(int type); + void slotResetSettings(); + +private: + + void readSettings(); + void writeSettings(); + void prepareEffect(); + void prepareFinal(); + void abortPreview(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQLabel *m_effectTypeLabel; + TQLabel *m_distanceLabel; + TQLabel *m_levelLabel; + + KDcrawIface::RComboBox *m_effectType; + + KDcrawIface::RIntNumInput *m_distanceInput; + KDcrawIface::RIntNumInput *m_levelInput; + + Digikam::ImagePanelWidget *m_previewWidget; + + Digikam::EditorToolSettings *m_gboxSettings; +}; + +} // NameSpace DigikamBlurFXImagesPlugin + +#endif /* BLURFXTOOL_H */ diff --git a/src/imageplugins/blurfx/digikamimageplugin_blurfx.desktop b/src/imageplugins/blurfx/digikamimageplugin_blurfx.desktop new file mode 100644 index 00000000..e7968a80 --- /dev/null +++ b/src/imageplugins/blurfx/digikamimageplugin_blurfx.desktop @@ -0,0 +1,49 @@ +[Desktop Entry] +Name=ImagePlugin_BlurFX +Name[bg]=Приставка за снимки - Ефекти за замъгляване +Name[el]=ΠρόσθετοΕικόνας_ΕφέΘολώματος +Name[fi]=Sumennus +Name[hr]=Zamućenje +Name[it]=PluginImmagini_EffettiDiSfocatura +Name[nl]=Afbeeldingsplugin_Vervaageffect +Name[sr]=Ефекти замућења +Name[sr@Latn]=Efekti zamućenja +Name[sv]=Insticksprogram för oskärpeeffekt +Name[tr]=ResimEklentisi_Bulanıklaştır +Name[xx]=xxImagePlugin_BlurFXxx +Type=Service +X-TDE-ServiceTypes=Digikam/ImagePlugin +Encoding=UTF-8 +Comment=Blur special effects plugin for digiKam +Comment[bg]=Приставка на digiKam с ефекти за замъгляване на снимки +Comment[ca]=Connector pel digiKam d'efectes especials de difuminat +Comment[da]=Digikam plugin med specialeffekter for udviskning +Comment[de]=digiKam-Modul zum Erzeugen von speziellen Unschärfe-Effekten +Comment[el]=Πρόσθετο ειδικών εφέ θολώματος για το digiKam +Comment[es]=Plugin para digiKam con efectos especiales de difusión +Comment[et]=DigiKami spetsiaalsete hägustamisefektide plugin +Comment[fa]=وصلۀ جلوههای ویژۀ محو برای digiKam +Comment[fi]=Sumennustehosteita +Comment[gl]=Un plugin de digiKam para efeitos especiais de borrón +Comment[hr]=digiKam dodatak za efekt zamućenja +Comment[is]=Íforrit fyrir digiKam sem mýkir eða afskerpir myndir +Comment[it]=Plugin degli effetti speciali di sfocatura per digiKam +Comment[ja]=digiKam ぼかし特殊効果プラグイン +Comment[nds]=digiKam-Moduul för't Opstellen vun Weekteek-Effekten +Comment[nl]=Digikam-plugin voor vervaageffect +Comment[pa]=ਡਿਜ਼ੀਕੈਮ ਲਈ ਬਲੱਰ (ਧੁੰਧਲਾਪਨ) ਖਾਸ ਪਰਭਾਵ ਪਲੱਗਇਨ +Comment[pl]=Wtyczka specjalnych efektów rozmycia do programu digiKam +Comment[pt]=Um 'plugin' do digiKam para efeitos especiais de borrão +Comment[pt_BR]=Plugin de efeitos especiais de desfocalização +Comment[ru]=Модуль специальных эффектов размытия для digiKam +Comment[sk]=digiKam plugin pre špeciálne efekty rozmazania +Comment[sr]=Прикључак ефеката замућења за digiKam +Comment[sr@Latn]=Priključak efekata zamućenja za digiKam +Comment[sv]=Digikam insticksprogram med specialeffekter för oskärpa +Comment[tr]=digiKam için bulanıklaştırma eklentisi +Comment[uk]=Втулок спеціальних ефектів розмивання для digiKam +Comment[vi]=Phần bổ sung hiệu ứng che mờ cho digiKam +Comment[xx]=xxBlur special effects plugin for digiKamxx + +X-TDE-Library=digikamimageplugin_blurfx +author=Gilles Caulier, caulier dot gilles at gmail dot com diff --git a/src/imageplugins/blurfx/digikamimageplugin_blurfx_ui.rc b/src/imageplugins/blurfx/digikamimageplugin_blurfx_ui.rc new file mode 100644 index 00000000..085b4c68 --- /dev/null +++ b/src/imageplugins/blurfx/digikamimageplugin_blurfx_ui.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui version="5" name="digikamimageplugin_blurfx" > + + <MenuBar> + + <Menu name="Filters" ><text>F&ilters</text> + <Action name="imageplugin_blurfx" /> + </Menu> + + </MenuBar> + + <ToolBar name="ToolBar" > + <text>Main Toolbar</text> + </ToolBar> + + <ActionProperties> + <Action shortcut="" name="imageplugin_blurfx" /> + </ActionProperties> + +</kpartgui> diff --git a/src/imageplugins/blurfx/imageeffect_blurfx.cpp b/src/imageplugins/blurfx/imageeffect_blurfx.cpp new file mode 100644 index 00000000..62bcd525 --- /dev/null +++ b/src/imageplugins/blurfx/imageeffect_blurfx.cpp @@ -0,0 +1,388 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-09 + * Description : a plugin to apply Blur FX to images + * + * Copyright 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +// TQt includes. + +#include <tqlabel.h> +#include <tqwhatsthis.h> +#include <tqlayout.h> +#include <tqslider.h> +#include <tqimage.h> +#include <tqcombobox.h> +#include <tqdatetime.h> + +// KDE includes. + +#include <tdeconfig.h> +#include <tdelocale.h> +#include <tdeaboutdata.h> +#include <tdeapplication.h> +#include <knuminput.h> + +// Local includes. + +#include "version.h" +#include "ddebug.h" +#include "imageiface.h" +#include "imagewidget.h" +#include "blurfx.h" +#include "imageeffect_blurfx.h" +#include "imageeffect_blurfx.moc" + +namespace DigikamBlurFXImagesPlugin +{ + +ImageEffect_BlurFX::ImageEffect_BlurFX(TQWidget* parent) + : Digikam::CtrlPanelDlg(parent, i18n("Apply Blurring Special Effect to Photograph"), + "blurfx", false, false, true, + Digikam::ImagePannelWidget::SeparateViewAll) +{ + TQString whatsThis; + + TDEAboutData* about = new TDEAboutData("digikam", + I18N_NOOP("Blur Effects"), + digikam_version, + I18N_NOOP("A digiKam image plugin to apply blurring special effect " + "to an image."), + TDEAboutData::License_GPL, + "(c) 2005, Gilles Caulier\n" + "(c) 2006-2008, Gilles Caulier and Marcel Wiesweg", + 0, + "http://www.digikam.org"); + + about->addAuthor("Gilles Caulier", I18N_NOOP("Author and maintainer"), + "caulier dot gilles at gmail dot com"); + + about->addAuthor("Pieter Z. Voloshyn", I18N_NOOP("Blurring algorithms"), + "pieter dot voloshyn at gmail dot com"); + + about->addAuthor("Marcel Wiesweg", I18N_NOOP("Developer"), + "marcel dot wiesweg at gmx dot de"); + + setAboutData(about); + + // ------------------------------------------------------------- + + TQWidget *gboxSettings = new TQWidget(m_imagePreviewWidget); + TQGridLayout* gridSettings = new TQGridLayout( gboxSettings, 5, 1, 0, spacingHint()); + + m_effectTypeLabel = new TQLabel(i18n("Type:"), gboxSettings); + + m_effectType = new TQComboBox( false, gboxSettings ); + m_effectType->insertItem( i18n("Zoom Blur") ); + m_effectType->insertItem( i18n("Radial Blur") ); + m_effectType->insertItem( i18n("Far Blur") ); + m_effectType->insertItem( i18n("Motion Blur") ); + m_effectType->insertItem( i18n("Softener Blur") ); + m_effectType->insertItem( i18n("Skake Blur") ); + m_effectType->insertItem( i18n("Focus Blur") ); + m_effectType->insertItem( i18n("Smart Blur") ); + m_effectType->insertItem( i18n("Frost Glass") ); + m_effectType->insertItem( i18n("Mosaic") ); + TQWhatsThis::add( m_effectType, i18n("<p>Select the blurring effect to apply to the image.<p>" + "<b>Zoom Blur</b>: blurs the image along radial lines starting from " + "a specified center point. This simulates the blur of a zooming camera.<p>" + "<b>Radial Blur</b>: blurs the image by rotating the pixels around " + "the specified center point. This simulates the blur of a rotating camera.<p>" + "<b>Far Blur</b>: blurs the image by using far pixels. This simulates the blur " + "of an unfocalized camera lens.<p>" + "<b>Motion Blur</b>: blurs the image by moving the pixels horizontally. " + "This simulates the blur of a linear moving camera.<p>" + "<b>Softener Blur</b>: blurs the image softly in dark tones and hardly in light " + "tones. This gives images a dreamy and glossy soft focus effect. It's ideal " + "for creating romantic portraits, glamour photographs, or giving images a warm " + "and subtle glow.<p>" + "<b>Skake Blur</b>: blurs the image by skaking randomly the pixels. " + "This simulates the blur of a random moving camera.<p>" + "<b>Focus Blur</b>: blurs the image corners to reproduce the astigmatism distortion " + "of a lens.<p>" + "<b>Smart Blur</b>: finds the edges of color in your image and blurs them without " + "muddying the rest of the image.<p>" + "<b>Frost Glass</b>: blurs the image by randomly disperse light coming through " + "a frosted glass.<p>" + "<b>Mosaic</b>: divides the photograph into rectangular cells and then " + "recreates it by filling those cells with average pixel value.")); + gridSettings->addMultiCellWidget(m_effectTypeLabel, 0, 0, 0, 1); + gridSettings->addMultiCellWidget(m_effectType, 1, 1, 0, 1); + + m_distanceLabel = new TQLabel(i18n("Distance:"), gboxSettings); + m_distanceInput = new KIntNumInput(gboxSettings); + m_distanceInput->setRange(0, 100, 1, true); + TQWhatsThis::add( m_distanceInput, i18n("<p>Set here the blur distance in pixels.")); + + gridSettings->addMultiCellWidget(m_distanceLabel, 2, 2, 0, 1); + gridSettings->addMultiCellWidget(m_distanceInput, 3, 3, 0, 1); + + m_levelLabel = new TQLabel(i18n("Level:"), gboxSettings); + m_levelInput = new KIntNumInput(gboxSettings); + m_levelInput->setRange(0, 360, 1, true); + TQWhatsThis::add( m_levelInput, i18n("<p>This value controls the level to use with the current effect.")); + + gridSettings->addMultiCellWidget(m_levelLabel, 4, 4, 0, 1); + gridSettings->addMultiCellWidget(m_levelInput, 5, 5, 0, 1); + + m_imagePreviewWidget->setUserAreaWidget(gboxSettings); + + // ------------------------------------------------------------- + + connect(m_effectType, TQ_SIGNAL(activated(int)), + this, TQ_SLOT(slotEffectTypeChanged(int))); + + connect(m_distanceInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); + + connect(m_levelInput, TQ_SIGNAL(valueChanged(int)), + this, TQ_SLOT(slotTimer())); +} + +ImageEffect_BlurFX::~ImageEffect_BlurFX() +{ +} + +void ImageEffect_BlurFX::renderingFinished(void) +{ + + m_effectTypeLabel->setEnabled(true); + m_effectType->setEnabled(true); + m_distanceInput->setEnabled(true); + m_distanceLabel->setEnabled(true); + + switch (m_effectType->currentItem()) + { + case BlurFX::ZoomBlur: + case BlurFX::RadialBlur: + case BlurFX::FarBlur: + case BlurFX::ShakeBlur: + case BlurFX::FrostGlass: + case BlurFX::Mosaic: + break; + + case BlurFX::MotionBlur: + case BlurFX::FocusBlur: + case BlurFX::SmartBlur: + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + break; + + case BlurFX::SoftenerBlur: + m_distanceInput->setEnabled(false); + m_distanceLabel->setEnabled(false); + break; + } +} + +void ImageEffect_BlurFX::readUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("blurfx Tool Dialog"); + m_effectType->blockSignals(true); + m_distanceInput->blockSignals(true); + m_levelInput->blockSignals(true); + m_effectType->setCurrentItem(config->readNumEntry("EffectType", BlurFX::ZoomBlur)); + m_distanceInput->setValue(config->readNumEntry("DistanceAjustment", 3)); + m_levelInput->setValue(config->readNumEntry("LevelAjustment", 128)); + m_effectType->blockSignals(false); + m_distanceInput->blockSignals(false); + m_levelInput->blockSignals(false); +} + +void ImageEffect_BlurFX::writeUserSettings() +{ + TDEConfig* config = kapp->config(); + config->setGroup("blurfx Tool Dialog"); + config->writeEntry("EffectType", m_effectType->currentItem()); + config->writeEntry("DistanceAjustment", m_distanceInput->value()); + config->writeEntry("LevelAjustment", m_levelInput->value()); + config->sync(); +} + +void ImageEffect_BlurFX::resetValues() +{ + m_effectType->setCurrentItem(BlurFX::ZoomBlur); + slotEffectTypeChanged(BlurFX::ZoomBlur); +} + +void ImageEffect_BlurFX::slotEffectTypeChanged(int type) +{ + m_distanceInput->setEnabled(true); + m_distanceLabel->setEnabled(true); + + m_distanceInput->blockSignals(true); + m_levelInput->blockSignals(true); + m_distanceInput->setRange(0, 200, 1, true); + m_distanceInput->setValue(100); + m_levelInput->setRange(0, 360, 1, true); + m_levelInput->setValue(45); + + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + + switch (type) + { + case BlurFX::ZoomBlur: + break; + + case BlurFX::RadialBlur: + case BlurFX::FrostGlass: + m_distanceInput->setRange(0, 10, 1, true); + m_distanceInput->setValue(3); + break; + + case BlurFX::FarBlur: + m_distanceInput->setRange(0, 20, 1, true); + m_distanceInput->setMaxValue(20); + m_distanceInput->setValue(10); + break; + + case BlurFX::MotionBlur: + case BlurFX::FocusBlur: + m_distanceInput->setRange(0, 100, 1, true); + m_distanceInput->setValue(20); + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + break; + + case BlurFX::SoftenerBlur: + m_distanceInput->setEnabled(false); + m_distanceLabel->setEnabled(false); + break; + + case BlurFX::ShakeBlur: + m_distanceInput->setRange(0, 100, 1, true); + m_distanceInput->setValue(20); + break; + + case BlurFX::SmartBlur: + m_distanceInput->setRange(0, 20, 1, true); + m_distanceInput->setValue(3); + m_levelInput->setEnabled(true); + m_levelLabel->setEnabled(true); + m_levelInput->setRange(0, 255, 1, true); + m_levelInput->setValue(128); + break; + + case BlurFX::Mosaic: + m_distanceInput->setRange(0, 50, 1, true); + m_distanceInput->setValue(3); + break; + } + + m_distanceInput->blockSignals(false); + m_levelInput->blockSignals(false); + + slotEffect(); +} + +void ImageEffect_BlurFX::prepareEffect() +{ + m_effectTypeLabel->setEnabled(false); + m_effectType->setEnabled(false); + m_distanceInput->setEnabled(false); + m_distanceLabel->setEnabled(false); + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + + Digikam::DImg image; + + switch (m_effectType->currentItem()) + { + case BlurFX::ZoomBlur: + case BlurFX::RadialBlur: + case BlurFX::FocusBlur: + { + Digikam::ImageIface iface(0, 0); + image = *iface.getOriginalImg(); + break; + } + + case BlurFX::FarBlur: + case BlurFX::MotionBlur: + case BlurFX::SoftenerBlur: + case BlurFX::ShakeBlur: + case BlurFX::SmartBlur: + case BlurFX::FrostGlass: + case BlurFX::Mosaic: + image = m_imagePreviewWidget->getOriginalRegionImage(); + break; + } + + int t = m_effectType->currentItem(); + int d = m_distanceInput->value(); + int l = m_levelInput->value(); + + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>(new BlurFX(&image, this, t, d, l)); +} + +void ImageEffect_BlurFX::prepareFinal() +{ + m_effectTypeLabel->setEnabled(false); + m_effectType->setEnabled(false); + m_distanceInput->setEnabled(false); + m_distanceLabel->setEnabled(false); + m_levelInput->setEnabled(false); + m_levelLabel->setEnabled(false); + + int t = m_effectType->currentItem(); + int d = m_distanceInput->value(); + int l = m_levelInput->value(); + + Digikam::ImageIface iface(0, 0); + m_threadedFilter = dynamic_cast<Digikam::DImgThreadedFilter *>(new BlurFX(iface.getOriginalImg(), this, t, d, l)); +} + +void ImageEffect_BlurFX::putPreviewData(void) +{ + switch (m_effectType->currentItem()) + { + case BlurFX::ZoomBlur: + case BlurFX::RadialBlur: + case BlurFX::FocusBlur: + { + TQRect pRect = m_imagePreviewWidget->getOriginalImageRegionToRender(); + Digikam::DImg destImg = m_threadedFilter->getTargetImage().copy(pRect); + m_imagePreviewWidget->setPreviewImage(destImg); + break; + } + case BlurFX::FarBlur: + case BlurFX::MotionBlur: + case BlurFX::SoftenerBlur: + case BlurFX::ShakeBlur: + case BlurFX::SmartBlur: + case BlurFX::FrostGlass: + case BlurFX::Mosaic: + m_imagePreviewWidget->setPreviewImage(m_threadedFilter->getTargetImage()); + break; + } +} + +void ImageEffect_BlurFX::putFinalData(void) +{ + Digikam::ImageIface iface(0, 0); + + iface.putOriginalImage(i18n("Blur Effects"), + m_threadedFilter->getTargetImage().bits()); +} + +} // NameSpace DigikamBlurFXImagesPlugin + diff --git a/src/imageplugins/blurfx/imageeffect_blurfx.h b/src/imageplugins/blurfx/imageeffect_blurfx.h new file mode 100644 index 00000000..e2517d4f --- /dev/null +++ b/src/imageplugins/blurfx/imageeffect_blurfx.h @@ -0,0 +1,80 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-09 + * Description : a plugin to apply Blur FX to images + * + * Copyright 2005-2008 by Gilles Caulier <caulier dot gilles at gmail dot com> + * Copyright 2006-2008 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de> + * + * 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. + * + * ============================================================ */ + +#ifndef IMAGEEFFECT_BLURFX_H +#define IMAGEEFFECT_BLURFX_H + +// Digikam includes. + +#include "ctrlpaneldlg.h" + +class TQComboBox; +class TQLabel; + +class KIntNumInput; + +namespace DigikamBlurFXImagesPlugin +{ + +class ImageEffect_BlurFX : public Digikam::CtrlPanelDlg +{ + TQ_OBJECT + + +public: + + ImageEffect_BlurFX(TQWidget *parent); + ~ImageEffect_BlurFX(); + +private slots: + + void slotEffectTypeChanged(int type); + void readUserSettings(); + +private: + + void writeUserSettings(); + void resetValues(); + void prepareEffect(); + void prepareFinal(); + void abortPreview(); + void putPreviewData(); + void putFinalData(); + void renderingFinished(); + +private: + + TQComboBox *m_effectType; + + TQLabel *m_effectTypeLabel; + TQLabel *m_distanceLabel; + TQLabel *m_levelLabel; + + KIntNumInput *m_distanceInput; + KIntNumInput *m_levelInput; +}; + +} // NameSpace DigikamBlurFXImagesPlugin + +#endif /* IMAGEEFFECT_BLURFX_H */ diff --git a/src/imageplugins/blurfx/imageplugin_blurfx.cpp b/src/imageplugins/blurfx/imageplugin_blurfx.cpp new file mode 100644 index 00000000..3bbd05e0 --- /dev/null +++ b/src/imageplugins/blurfx/imageplugin_blurfx.cpp @@ -0,0 +1,70 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-09 + * Description : a plugin to apply Blur FX to images + * + * Copyright 2005-2008 by Gilles Caulier <caulier dot gilles 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. + * + * ============================================================ */ + +// KDE includes. + +#include <tdelocale.h> +#include <kgenericfactory.h> +#include <klibloader.h> +#include <tdeaction.h> +#include <kcursor.h> +#include <tdeapplication.h> + +// Local includes. + +#include "ddebug.h" +#include "blurfxtool.h" +#include "imageplugin_blurfx.h" +#include "imageplugin_blurfx.moc" + +using namespace DigikamBlurFXImagesPlugin; + +K_EXPORT_COMPONENT_FACTORY(digikamimageplugin_blurfx, + KGenericFactory<ImagePlugin_BlurFX>("digikamimageplugin_blurfx")); + +ImagePlugin_BlurFX::ImagePlugin_BlurFX(TQObject *parent, const char*, const TQStringList &) + : Digikam::ImagePlugin(parent, "ImagePlugin_BlurFX") +{ + m_blurfxAction = new TDEAction(i18n("Blur Effects..."), "blurfx", 0, + this, TQ_SLOT(slotBlurFX()), + actionCollection(), "imageplugin_blurfx"); + + setXMLFile( "digikamimageplugin_blurfx_ui.rc" ); + + DDebug() << "ImagePlugin_BlurFX plugin loaded" << endl; +} + +ImagePlugin_BlurFX::~ImagePlugin_BlurFX() +{ +} + +void ImagePlugin_BlurFX::setEnabledActions(bool enable) +{ + m_blurfxAction->setEnabled(enable); +} + +void ImagePlugin_BlurFX::slotBlurFX() +{ + BlurFXTool *tool = new BlurFXTool(this); + loadTool(tool); +} diff --git a/src/imageplugins/blurfx/imageplugin_blurfx.h b/src/imageplugins/blurfx/imageplugin_blurfx.h new file mode 100644 index 00000000..13df6534 --- /dev/null +++ b/src/imageplugins/blurfx/imageplugin_blurfx.h @@ -0,0 +1,56 @@ +/* ============================================================ + * + * This file is a part of digiKam project + * http://www.digikam.org + * + * Date : 2005-02-09 + * Description : a plugin to apply Blur FX to images + * + * Copyright 2005-2008 by Gilles Caulier <caulier dot gilles 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. + * + * ============================================================ */ + +#ifndef IMAGEPLUGIN_BLURFX_H +#define IMAGEPLUGIN_BLURFX_H + +// Digikam includes. + +#include "imageplugin.h" +#include "digikam_export.h" + +class TDEAction; + +class DIGIKAMIMAGEPLUGINS_EXPORT ImagePlugin_BlurFX : public Digikam::ImagePlugin +{ + TQ_OBJECT + + +public: + + ImagePlugin_BlurFX(TQObject *parent, const char* name, + const TQStringList &args); + ~ImagePlugin_BlurFX(); + + void setEnabledActions(bool enable); + +private slots: + + void slotBlurFX(); + +private: + + TDEAction *m_blurfxAction; +}; + +#endif /* IMAGEPLUGIN_BLURFX_H */ |