diff options
Diffstat (limited to 'krita/plugins/viewplugins/dropshadow')
10 files changed, 1456 insertions, 0 deletions
diff --git a/krita/plugins/viewplugins/dropshadow/Makefile.am b/krita/plugins/viewplugins/dropshadow/Makefile.am new file mode 100644 index 00000000..c339627e --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/Makefile.am @@ -0,0 +1,30 @@ +kritarcdir = $(kde_datadir)/kritaplugins +kritarc_DATA = dropshadow.rc +EXTRA_DIST = $(kritarc_DATA) + +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../core \ + -I$(srcdir)/../../../kritacolor/ \ + -I$(srcdir)/../../../colorspaces/rgb_u8 \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) \ + $(all_includes) + + +kde_module_LTLIBRARIES = kritadropshadow.la + +kritadropshadow_la_SOURCES = wdg_dropshadow.ui \ + kis_dropshadow.cc dlg_dropshadow.cc \ + kis_dropshadow_plugin.cc + +noinst_HEADERS = wdg_dropshadow.h kis_dropshadow_plugin.h \ + kis_dropshadow.h dlg_dropshadow.h + +kritadropshadow_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +kritadropshadow_la_LIBADD = ../../../libkritacommon.la ../../../colorspaces/rgb_u8/libkritargb.la + +kde_services_DATA = kritadropshadow.desktop + +kritadropshadow_la_METASOURCES = AUTO + +KDE_OPTIONS = nofinal diff --git a/krita/plugins/viewplugins/dropshadow/dlg_dropshadow.cc b/krita/plugins/viewplugins/dropshadow/dlg_dropshadow.cc new file mode 100644 index 00000000..545f886f --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/dlg_dropshadow.cc @@ -0,0 +1,117 @@ +/* + * dlg_dropshadow.cc - part of KimageShop^WKrayon^WKrita + * + * Copyright (c) 2005 Michael Thaler <michael.thaler@physik.tu-muenchen.de> + * Copyright (c) 2006 Cyrille Berger <cberger@cberger.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <qbutton.h> +#include <qbuttongroup.h> +#include <qcheckbox.h> +#include <qcolor.h> +#include <qcombobox.h> +#include <qlabel.h> +#include <qradiobutton.h> +#include <qslider.h> + +#include <kcolorbutton.h> +#include <kconfig.h> +#include <kdebug.h> +#include <klocale.h> +#include <knuminput.h> + +#include "dlg_dropshadow.h" +#include "wdg_dropshadow.h" + +DlgDropshadow::DlgDropshadow( const QString & /*imageCS*/, + const QString & /*layerCS*/, + QWidget * parent, + const char * name) + : super (parent, name, true, i18n("Drop Shadow"), Ok | Cancel, Ok) +{ + m_page = new WdgDropshadow(this, "dropshadow"); + Q_CHECK_PTR(m_page); + setMainWidget(m_page); + resize(m_page->sizeHint()); + + KConfig * cfg = KGlobal::config(); + m_page->xOffsetSpinBox->setValue( cfg->readNumEntry("dropshadow_x", 8) ); + m_page->yOffsetSpinBox->setValue( cfg->readNumEntry("dropshadow_y", 8) ); + m_page->blurRadiusSpinBox->setValue( cfg->readNumEntry("dropshadow_blurRadius", 5) ); + QColor black(0,0,0); + m_page->shadowColorButton->setColor( cfg->readColorEntry("dropshadow_color", &black) ); + m_page->opacitySlider->setValue( cfg->readNumEntry("dropshadow_opacity", 80 ) ); + m_page->opacitySpinBox->setValue( cfg->readNumEntry("dropshadow_opacity", 80 ) ); + m_page->allowResizingCheckBox->setChecked( cfg->readBoolEntry("dropshadow_resizing", true ) ); + + connect(this, SIGNAL(okClicked()), + this, SLOT(okClicked())); +} + +DlgDropshadow::~DlgDropshadow() +{ + delete m_page; +} + +Q_INT32 DlgDropshadow::getXOffset() +{ + return m_page->xOffsetSpinBox->value(); +} + +Q_INT32 DlgDropshadow::getYOffset() +{ + return m_page->yOffsetSpinBox->value(); +} + +Q_INT32 DlgDropshadow::getBlurRadius() +{ + return m_page->blurRadiusSpinBox->value(); +} + +Q_UINT8 DlgDropshadow::getShadowOpacity() +{ + double opacity = (double)m_page->opacitySpinBox->value(); + //convert percent to a 8 bit opacity value + return (Q_UINT8)(opacity / 100 * 255); +} + +QColor DlgDropshadow::getShadowColor() +{ + return m_page->shadowColorButton->color(); +} + +bool DlgDropshadow::allowResizingChecked() +{ + return m_page->allowResizingCheckBox->isChecked(); +} + +// SLOTS + +void DlgDropshadow::okClicked() +{ + KConfig * cfg = KGlobal::config(); + cfg->writeEntry("dropshadow_x", m_page->xOffsetSpinBox->value()); + cfg->writeEntry("dropshadow_y", m_page->yOffsetSpinBox->value()); + cfg->writeEntry("dropshadow_blurRadius", m_page->blurRadiusSpinBox->value()); + cfg->writeEntry("dropshadow_color", m_page->shadowColorButton->color()); + cfg->writeEntry("dropshadow_opacity", m_page->opacitySpinBox->value()); + cfg->writeEntry("dropshadow_resizing", m_page->allowResizingCheckBox->isChecked()); + + accept(); +} + +#include "dlg_dropshadow.moc" diff --git a/krita/plugins/viewplugins/dropshadow/dlg_dropshadow.h b/krita/plugins/viewplugins/dropshadow/dlg_dropshadow.h new file mode 100644 index 00000000..8e514658 --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/dlg_dropshadow.h @@ -0,0 +1,59 @@ +/* + * dlg_dropshadow.h -- part of KimageShop^WKrayon^WKrita + * + * Copyright (c) 2005 Michael Thaler <michael.thaler@physik.tu-muenchen.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 of the License, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef DLG_DROPSHADOW +#define DLG_DROPSHADOW + +#include <kdialogbase.h> +#include <kis_dropshadow.h> + +class WdgDropshadow; +class QColor; + +/** + * This dialog allows the user to configure the decomposition of an image + * into layers: one layer for each color channel. + */ +class DlgDropshadow: public KDialogBase { + typedef KDialogBase super; + Q_OBJECT + +public: + + DlgDropshadow(const QString & imageCS, const QString & layerCS, QWidget * parent = 0, + const char* name = 0); + ~DlgDropshadow(); + +public: + + Q_INT32 getXOffset(); + Q_INT32 getYOffset(); + Q_INT32 getBlurRadius(); + Q_UINT8 getShadowOpacity(); + QColor getShadowColor(); + bool allowResizingChecked(); +private slots: + void okClicked(); + +private: + + WdgDropshadow * m_page; +}; + +#endif // DLG_DROPSHADOW diff --git a/krita/plugins/viewplugins/dropshadow/dropshadow.rc b/krita/plugins/viewplugins/dropshadow/dropshadow.rc new file mode 100644 index 00000000..e5a446b2 --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/dropshadow.rc @@ -0,0 +1,11 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui library="kritadropshadow" version="6"> +<MenuBar> + <Menu name="Layer"><text>La&yer</text> + <Separator/> + <Menu name="layerEffects"><text>Layer Effects</text> + <Action name="dropshadow"/> + </Menu> + </Menu> +</MenuBar> +</kpartgui> diff --git a/krita/plugins/viewplugins/dropshadow/kis_dropshadow.cc b/krita/plugins/viewplugins/dropshadow/kis_dropshadow.cc new file mode 100644 index 00000000..7881f568 --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/kis_dropshadow.cc @@ -0,0 +1,758 @@ +/* + * This file is part of Krita + * + * Copyright (c) 2005 Michael Thaler <michael.thaler@physik.tu-muenchen.de> + * + * The gaussian blur algoithm is ported from gimo + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include <limits.h> + +#include <stdlib.h> +#include <vector> + +#include <qcolor.h> + +#include <klocale.h> +#include <kiconloader.h> +#include <kinstance.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <ktempfile.h> +#include <kdebug.h> +#include <kgenericfactory.h> +#include <knuminput.h> + +#include <kis_doc.h> +#include <kis_image.h> +#include <kis_iterators_pixel.h> +#include <kis_layer.h> +#include <kis_paint_layer.h> +#include <kis_group_layer.h> +#include "kis_meta_registry.h" +#include <kis_transaction.h> +#include <kis_undo_adapter.h> +#include <kis_global.h> +#include <kis_types.h> +#include <kis_progress_subject.h> +#include <kis_progress_display_interface.h> +#include <kis_colorspace.h> +#include <kis_colorspace_factory_registry.h> +#include <kis_view.h> +#include <kis_paint_device.h> +#include <kis_channelinfo.h> +#include <kis_convolution_painter.h> +#include "kis_rgb_colorspace.h" + +#include "kis_dropshadow.h" + +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +KisDropshadow::KisDropshadow(KisView * view) + : m_view(view) +{ +} + +void KisDropshadow::dropshadow(KisProgressDisplayInterface * progress, Q_INT32 xoffset, Q_INT32 yoffset, Q_INT32 blurradius, QColor color, Q_UINT8 opacity, bool allowResize) +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + if (!image) return; + + KisLayerSP src = image->activeLayer(); + if (!src) return; + + KisPaintDeviceSP dev = image->activeDevice(); + if (!dev) return; + + m_cancelRequested = false; + if ( progress ) + progress->setSubject(this, true, true); + emit notifyProgressStage(i18n("Add drop shadow..."), 0); + + if (image->undo()) { + image->undoAdapter()->beginMacro(i18n("Add Drop Shadow")); + } + + KisPaintDeviceSP shadowDev = new KisPaintDevice( KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA",""),"" ), "Shadow"); + KisPaintDeviceSP bShadowDev; + KisRgbColorSpace *rgb8cs = static_cast<KisRgbColorSpace *>(shadowDev->colorSpace()); + + QRect rect = dev->exactBounds(); + + for (Q_INT32 row = 0; row < rect.height(); ++row) + { + KisHLineIteratorPixel srcIt = dev->createHLineIterator(rect.x(), rect.y() + row, rect.width(), false); + KisHLineIteratorPixel dstIt = shadowDev->createHLineIterator(rect.x(), rect.y() + row, rect.width(), true); + while( ! srcIt.isDone() ) + { + if (srcIt.isSelected()) + { + //set the shadow color + Q_UINT8 alpha = dev->colorSpace()->getAlpha(srcIt.rawData()); + rgb8cs->setPixel(dstIt.rawData(), color.red(), color.green(), color.blue(), alpha); + } + ++srcIt; + ++dstIt; + } + emit notifyProgress((row * 100) / rect.height() ); + } + + if( blurradius > 0 ) + { + bShadowDev = new KisPaintDevice( KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA",""),"" ), "bShadow"); + gaussianblur(shadowDev, bShadowDev, rect, blurradius, blurradius, BLUR_RLE, progress); + shadowDev = bShadowDev; + } + + if (!m_cancelRequested) { + shadowDev->move (xoffset,yoffset); + + KisGroupLayerSP parent = image->rootLayer(); + if (image->activeLayer()) + parent = image->activeLayer()->parent().data(); + + KisPaintLayerSP l = new KisPaintLayer(image, i18n("Drop Shadow"), opacity, shadowDev); + image->addLayer( l.data(), parent, src->siblingBelow() ); + + if (allowResize) + { + QRect shadowBounds = shadowDev->exactBounds(); + + if (!image->bounds().contains(shadowBounds)) { + + QRect newImageSize = image->bounds() | shadowBounds; + image->resize(newImageSize.width(), newImageSize.height()); + + if (shadowBounds.left() < 0 || shadowBounds.top() < 0) { + + Q_INT32 newRootX = image->rootLayer()->x(); + Q_INT32 newRootY = image->rootLayer()->y(); + + if (shadowBounds.left() < 0) { + newRootX += -shadowBounds.left(); + } + if (shadowBounds.top() < 0) { + newRootY += -shadowBounds.top(); + } + + KCommand *moveCommand = image->rootLayer()->moveCommand(QPoint(image->rootLayer()->x(), image->rootLayer()->y()), + QPoint(newRootX, newRootY)); + Q_ASSERT(moveCommand != 0); + + if (moveCommand) { + moveCommand->execute(); + if (image->undo()) { + image->undoAdapter()->addCommand(moveCommand); + } else { + delete moveCommand; + } + } + } + } + } + m_view->canvasSubject()->document()->setModified(true); + } + + if (image->undo()) { + image->undoAdapter()->endMacro(); + } + + emit notifyProgressDone(); +} + +void KisDropshadow::gaussianblur (KisPaintDeviceSP srcDev, KisPaintDeviceSP dstDev, QRect& rect, double horz, double vert, BlurMethod method, KisProgressDisplayInterface *) +{ + Q_INT32 width, height; + Q_INT32 bytes; + Q_UINT8 *dest, *dp; + Q_UINT8 *src, *sp, *sp_p, *sp_m; + Q_INT32 *buf = NULL; + Q_INT32 *bb; + double n_p[5], n_m[5]; + double d_p[5], d_m[5]; + double bd_p[5], bd_m[5]; + double *val_p = NULL; + double *val_m = NULL; + double *vp, *vm; + Q_INT32 x1, y1, x2, y2; + Q_INT32 i, j; + Q_INT32 row, col, b; + Q_INT32 terms; + double progress, max_progress; + Q_INT32 initial_p[4]; + Q_INT32 initial_m[4]; + double std_dev; + Q_INT32 pixels; + Q_INT32 total = 1; + Q_INT32 start, end; + Q_INT32 *curve; + Q_INT32 *sum = NULL; + Q_INT32 val; + Q_INT32 length; + Q_INT32 initial_pp, initial_mm; + + x1 = (Q_INT32)(rect.x() - horz); + y1 = (Q_INT32)(rect.y() - vert); + width = (Q_INT32)(rect.width() + 2 * horz); + height = (Q_INT32)(rect.height() + 2 * vert); + x2 = x1 + width; + y2 = y1 + height; + + if (width < 1 || height < 1) return; + + emit notifyProgressStage(i18n("Blur..."), 0); + + bytes = srcDev->pixelSize(); + + switch (method) + { + case BLUR_IIR: + val_p = new double[MAX (width, height) * bytes]; + val_m = new double[MAX (width, height) * bytes]; + break; + + case BLUR_RLE: + buf = new Q_INT32[MAX (width, height) * 2]; + break; + } + + src = new Q_UINT8[MAX (width, height) * bytes]; + dest = new Q_UINT8[MAX (width, height) * bytes]; + + progress = 0.0; + max_progress = (horz <= 0.0 ) ? 0 : width * height * horz; + max_progress += (vert <= 0.0 ) ? 0 : width * height * vert; + + + /* First the vertical pass */ + if (vert > 0.0) + { + vert = fabs (vert) + 1.0; + std_dev = sqrt (-(vert * vert) / (2 * log (1.0 / 255.0))); + + switch (method) + { + case BLUR_IIR: + /* derive the constants for calculating the gaussian + * from the std dev + */ + find_constants (n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev); + break; + + case BLUR_RLE: + curve = make_curve (std_dev, &length); + sum = new Q_INT32[2 * length + 1]; + + sum[0] = 0; + + for (i = 1; i <= length*2; i++) + sum[i] = curve[i-length-1] + sum[i-1]; + sum += length; + + total = sum[length] - sum[-length]; + break; + } + + for (col = 0; col < width; col++) + { + switch (method) + { + case BLUR_IIR: + memset (val_p, 0, height * bytes * sizeof (double)); + memset (val_m, 0, height * bytes * sizeof (double)); + break; + + case BLUR_RLE: + break; + } + + //gimp_pixel_rgn_get_col (&src_rgn, src, col + x1, y1, height); + srcDev->readBytes(src, col+x1, y1, 1, height); + + multiply_alpha (src, height, bytes); + + switch (method) + { + case BLUR_IIR: + sp_p = src; + sp_m = src + (height - 1) * bytes; + vp = val_p; + vm = val_m + (height - 1) * bytes; + + /* Set up the first vals */ + for (i = 0; i < bytes; i++) + { + initial_p[i] = sp_p[i]; + initial_m[i] = sp_m[i]; + } + + for (row = 0; row < height; row++) + { + double *vpptr, *vmptr; + terms = (row < 4) ? row : 4; + + for (b = 0; b < bytes; b++) + { + vpptr = vp + b; vmptr = vm + b; + for (i = 0; i <= terms; i++) + { + *vpptr += n_p[i] * sp_p[(-i * bytes) + b] - + d_p[i] * vp[(-i * bytes) + b]; + *vmptr += n_m[i] * sp_m[(i * bytes) + b] - + d_m[i] * vm[(i * bytes) + b]; + } + for (j = i; j <= 4; j++) + { + *vpptr += (n_p[j] - bd_p[j]) * initial_p[b]; + *vmptr += (n_m[j] - bd_m[j]) * initial_m[b]; + } + } + + sp_p += bytes; + sp_m -= bytes; + vp += bytes; + vm -= bytes; + } + + transfer_pixels (val_p, val_m, dest, bytes, height); + break; + + case BLUR_RLE: + sp = src; + dp = dest; + + for (b = 0; b < bytes; b++) + { + initial_pp = sp[b]; + initial_mm = sp[(height-1) * bytes + b]; + + /* Determine a run-length encoded version of the row */ + run_length_encode (sp + b, buf, bytes, height); + + for (row = 0; row < height; row++) + { + start = (row < length) ? -row : -length; + end = (height <= (row + length) ? + (height - row - 1) : length); + + val = 0; + i = start; + bb = buf + (row + i) * 2; + + if (start != -length) + val += initial_pp * (sum[start] - sum[-length]); + + while (i < end) + { + pixels = bb[0]; + i += pixels; + if (i > end) + i = end; + val += bb[1] * (sum[i] - sum[start]); + bb += (pixels * 2); + start = i; + } + + if (end != length) + val += initial_mm * (sum[length] - sum[end]); + + dp[row * bytes + b] = val / total; + } + } + break; + } + + separate_alpha (src, height, bytes); + + dstDev->writeBytes(dest, col + x1, y1, 1, height); + + progress += height * vert; + if ((col % 5) == 0) emit notifyProgress( (Q_UINT32)((progress * 100) / max_progress)); + } + } + + /* Now the horizontal pass */ + if (horz > 0.0) + { + horz = fabs (horz) + 1.0; + + if (horz != vert) + { + std_dev = sqrt (-(horz * horz) / (2 * log (1.0 / 255.0))); + + switch (method) + { + case BLUR_IIR: + /* derive the constants for calculating the gaussian + * from the std dev + */ + find_constants (n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev); + break; + + case BLUR_RLE: + curve = make_curve (std_dev, &length); + sum = new Q_INT32[2 * length + 1]; + + sum[0] = 0; + + for (i = 1; i <= length*2; i++) + sum[i] = curve[i-length-1] + sum[i-1]; + sum += length; + + total = sum[length] - sum[-length]; + break; + } + } + + for (row = 0; row < height; row++) + { + switch (method) + { + case BLUR_IIR: + memset (val_p, 0, width * bytes * sizeof (double)); + memset (val_m, 0, width * bytes * sizeof (double)); + break; + + case BLUR_RLE: + break; + } + + + //gimp_pixel_rgn_get_row (&src_rgn, src, x1, row + y1, width); + dstDev->readBytes(src, x1, row + y1, width, 1); + + multiply_alpha (dest, width, bytes); + + switch (method) + { + case BLUR_IIR: + sp_p = src; + sp_m = src + (width - 1) * bytes; + vp = val_p; + vm = val_m + (width - 1) * bytes; + + /* Set up the first vals */ + for (i = 0; i < bytes; i++) + { + initial_p[i] = sp_p[i]; + initial_m[i] = sp_m[i]; + } + + for (col = 0; col < width; col++) + { + double *vpptr, *vmptr; + terms = (col < 4) ? col : 4; + + for (b = 0; b < bytes; b++) + { + vpptr = vp + b; vmptr = vm + b; + for (i = 0; i <= terms; i++) + { + *vpptr += n_p[i] * sp_p[(-i * bytes) + b] - + d_p[i] * vp[(-i * bytes) + b]; + *vmptr += n_m[i] * sp_m[(i * bytes) + b] - + d_m[i] * vm[(i * bytes) + b]; + } + for (j = i; j <= 4; j++) + { + *vpptr += (n_p[j] - bd_p[j]) * initial_p[b]; + *vmptr += (n_m[j] - bd_m[j]) * initial_m[b]; + } + } + + sp_p += bytes; + sp_m -= bytes; + vp += bytes; + vm -= bytes; + } + + transfer_pixels (val_p, val_m, dest, bytes, width); + break; + + case BLUR_RLE: + sp = src; + dp = dest; + + for (b = 0; b < bytes; b++) + { + initial_pp = sp[b]; + initial_mm = sp[(width-1) * bytes + b]; + + /* Determine a run-length encoded version of the row */ + run_length_encode (sp + b, buf, bytes, width); + + for (col = 0; col < width; col++) + { + start = (col < length) ? -col : -length; + end = (width <= (col + length)) ? (width - col - 1) : length; + + val = 0; + i = start; + bb = buf + (col + i) * 2; + + if (start != -length) + val += initial_pp * (sum[start] - sum[-length]); + + while (i < end) + { + pixels = bb[0]; + i += pixels; + if (i > end) + i = end; + val += bb[1] * (sum[i] - sum[start]); + bb += (pixels * 2); + start = i; + } + + if (end != length) + val += initial_mm * (sum[length] - sum[end]); + + dp[col * bytes + b] = val / total; + } + } + break; + } + + separate_alpha (dest, width, bytes); + + //gimp_pixel_rgn_set_row (&dest_rgn, dest, x1, row + y1, width); + dstDev->writeBytes(dest, x1, row + y1, width, 1); + + progress += width * horz; + //if ((row % 5) == 0) gimp_progress_update (progress / max_progress); + if ((row % 5) == 0) emit notifyProgress( (Q_UINT32)((progress * 100) / max_progress )); + } + } + + /* free up buffers */ + switch (method) + { + case BLUR_IIR: + delete[] val_p; + delete[] val_m; + break; + + case BLUR_RLE: + delete[] buf; + break; + } + + delete[] src; + delete[] dest; +} + +void KisDropshadow::find_constants (double n_p[], double n_m[], double d_p[], double d_m[], double bd_p[], double bd_m[], double std_dev) +{ + Q_INT32 i; + double constants [8]; + double div; + + /* The constants used in the implemenation of a casual sequence + * using a 4th order approximation of the gaussian operator + */ + + div = sqrt(2 * M_PI) * std_dev; + constants [0] = -1.783 / std_dev; + constants [1] = -1.723 / std_dev; + constants [2] = 0.6318 / std_dev; + constants [3] = 1.997 / std_dev; + constants [4] = 1.6803 / div; + constants [5] = 3.735 / div; + constants [6] = -0.6803 / div; + constants [7] = -0.2598 / div; + + n_p [0] = constants[4] + constants[6]; + n_p [1] = exp (constants[1]) * + (constants[7] * sin (constants[3]) - + (constants[6] + 2 * constants[4]) * cos (constants[3])) + + exp (constants[0]) * + (constants[5] * sin (constants[2]) - + (2 * constants[6] + constants[4]) * cos (constants[2])); + n_p [2] = 2 * exp (constants[0] + constants[1]) * + ((constants[4] + constants[6]) * cos (constants[3]) * cos (constants[2]) - + constants[5] * cos (constants[3]) * sin (constants[2]) - + constants[7] * cos (constants[2]) * sin (constants[3])) + + constants[6] * exp (2 * constants[0]) + + constants[4] * exp (2 * constants[1]); + n_p [3] = exp (constants[1] + 2 * constants[0]) * + (constants[7] * sin (constants[3]) - constants[6] * cos (constants[3])) + + exp (constants[0] + 2 * constants[1]) * + (constants[5] * sin (constants[2]) - constants[4] * cos (constants[2])); + n_p [4] = 0.0; + + d_p [0] = 0.0; + d_p [1] = -2 * exp (constants[1]) * cos (constants[3]) - + 2 * exp (constants[0]) * cos (constants[2]); + d_p [2] = 4 * cos (constants[3]) * cos (constants[2]) * exp (constants[0] + constants[1]) + + exp (2 * constants[1]) + exp (2 * constants[0]); + d_p [3] = -2 * cos (constants[2]) * exp (constants[0] + 2 * constants[1]) - + 2 * cos (constants[3]) * exp (constants[1] + 2 * constants[0]); + d_p [4] = exp (2 * constants[0] + 2 * constants[1]); + + for (i = 0; i <= 4; i++) + d_m [i] = d_p [i]; + + n_m[0] = 0.0; + for (i = 1; i <= 4; i++) + n_m [i] = n_p[i] - d_p[i] * n_p[0]; + + { + double sum_n_p, sum_n_m, sum_d; + double a, b; + + sum_n_p = 0.0; + sum_n_m = 0.0; + sum_d = 0.0; + for (i = 0; i <= 4; i++) + { + sum_n_p += n_p[i]; + sum_n_m += n_m[i]; + sum_d += d_p[i]; + } + + a = sum_n_p / (1.0 + sum_d); + b = sum_n_m / (1.0 + sum_d); + + for (i = 0; i <= 4; i++) + { + bd_p[i] = d_p[i] * a; + bd_m[i] = d_m[i] * b; + } + } +} + + +void KisDropshadow::transfer_pixels (double *src1, double *src2, Q_UINT8 *dest, Q_INT32 bytes, Q_INT32 width) +{ + Q_INT32 b; + Q_INT32 bend = bytes * width; + double sum; + + for(b = 0; b < bend; b++) + { + sum = *src1++ + *src2++; + if (sum > 255) sum = 255; + else if(sum < 0) sum = 0; + + *dest++ = (Q_UINT8) sum; + } +} + +//The equations: g(r) = exp (- r^2 / (2 * sigma^2)), r = sqrt (x^2 + y ^2) +Q_INT32 * KisDropshadow::make_curve(double sigma, Q_INT32 *length) +{ + int *curve; + double sigma2; + double l; + int temp; + int i, n; + + sigma2 = 2 * sigma * sigma; + l = sqrt (-sigma2 * log (1.0 / 255.0)); + + n = (int)(ceil (l) * 2); + if ((n % 2) == 0) + n += 1; + + curve = new Q_INT32[n]; + + *length = n / 2; + curve += *length; + curve[0] = 255; + + for (i = 1; i <= *length; i++) + { + temp = (Q_INT32) (exp (- (i * i) / sigma2) * 255); + curve[-i] = temp; + curve[i] = temp; + } + + return curve; +} + +void KisDropshadow::run_length_encode (Q_UINT8 *src, Q_INT32 *dest, Q_INT32 bytes, Q_INT32 width) +{ + Q_INT32 start; + Q_INT32 i; + Q_INT32 j; + Q_UINT8 last; + + last = *src; + src += bytes; + start = 0; + + for (i = 1; i < width; i++) + { + if (*src != last) + { + for (j = start; j < i; j++) + { + *dest++ = (i - j); + *dest++ = last; + } + start = i; + last = *src; + } + src += bytes; + } + + for (j = start; j < i; j++) + { + *dest++ = (i - j); + *dest++ = last; + } +} + +void KisDropshadow::multiply_alpha (Q_UINT8 *buf, Q_INT32 width, Q_INT32 bytes) +{ + Q_INT32 i, j; + double alpha; + + for (i = 0; i < width * bytes; i += bytes) + { + alpha = buf[i + bytes - 1] * (1.0 / 255.0); + for (j = 0; j < bytes - 1; j++) { + double a = (double)(buf[i + j]) * alpha; + buf[i + j] = (Q_UINT8)a; + } + } +} + +void KisDropshadow::separate_alpha (Q_UINT8 *buf, Q_INT32 width, Q_INT32 bytes) +{ + Q_INT32 i, j; + Q_UINT8 alpha; + double recip_alpha; + Q_UINT32 new_val; + + for (i = 0; i < width * bytes; i += bytes) + { + alpha = buf[i + bytes - 1]; + if (alpha != 0 && alpha != 255) + { + recip_alpha = 255.0 / alpha; + for (j = 0; j < bytes - 1; j++) + { + new_val = (Q_UINT32)(buf[i + j] * recip_alpha); + buf[i + j] = MIN (255, new_val); + } + } + } +} + +#include "kis_dropshadow.moc" diff --git a/krita/plugins/viewplugins/dropshadow/kis_dropshadow.h b/krita/plugins/viewplugins/dropshadow/kis_dropshadow.h new file mode 100644 index 00000000..3aca424f --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/kis_dropshadow.h @@ -0,0 +1,71 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) Michael Thaler <michael.thaler@physik.tu-muenchen.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 of the License, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _KIS_DROPSHADOW_H_ +#define _KIS_DROPSHADOW_H_ + +#include <kis_progress_subject.h> +#include <kis_paint_device.h> + +typedef enum +{ + BLUR_IIR, + BLUR_RLE +} BlurMethod; + + +class QColor; +class KisView; +class KisProgressDisplayInterface; + +class KisDropshadow : public KisProgressSubject { + + Q_OBJECT + +public: + + KisDropshadow(KisView * view); + virtual ~KisDropshadow() {}; + + void dropshadow(KisProgressDisplayInterface * progress, Q_INT32 xoffset, Q_INT32 yoffset, Q_INT32 blurradius, QColor color, Q_UINT8 opacity, bool allowResize); + +public: // Implement KisProgressSubject + virtual void cancel() { m_cancelRequested = true; } + +private: + void gaussianblur (KisPaintDeviceSP src, KisPaintDeviceSP dst, + QRect& rect, double horz, double vert, + BlurMethod method, + KisProgressDisplayInterface * progressDisplay); + //gaussian blur helper functions + void find_constants(double n_p[], double n_m[], double d_p[], double d_m[], double bd_p[], double bd_m[], double std_dev); + void transfer_pixels(double *src1, double *src2, Q_UINT8 *dest, Q_INT32 bytes, Q_INT32 width); + Q_INT32* make_curve(double sigma, Q_INT32 *length); + void run_length_encode (Q_UINT8 *src, Q_INT32 *dest, Q_INT32 bytes, Q_INT32 width); + void multiply_alpha (Q_UINT8 *buf, Q_INT32 width, Q_INT32 bytes); + void separate_alpha (Q_UINT8 *buf, Q_INT32 width, Q_INT32 bytes); + +private: + KisView * m_view; + bool m_cancelRequested; + +}; + +#endif diff --git a/krita/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.cc b/krita/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.cc new file mode 100644 index 00000000..efe01a95 --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.cc @@ -0,0 +1,91 @@ +/* + * This file is part of the KDE project + * + * Copyright (c) 2005 Michael Thaler <michael.thaler@physik.tu-muenchen.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 of the License, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <klocale.h> +#include <kiconloader.h> +#include <kinstance.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <ktempfile.h> +#include <kdebug.h> +#include <kgenericfactory.h> + +#include <kis_view.h> +#include <kis_types.h> +#include <kis_image.h> +#include <kis_paint_device.h> +#include <kis_layer.h> + +#include "kis_dropshadow_plugin.h" +#include "kis_dropshadow.h" +#include "dlg_dropshadow.h" + +K_EXPORT_COMPONENT_FACTORY( kritadropshadow, KGenericFactory<KisDropshadowPlugin>( "krita" ) ) + +KisDropshadowPlugin::KisDropshadowPlugin(QObject *parent, const char *name, const QStringList &) + : KParts::Plugin(parent, name) +{ + if ( parent->inherits("KisView") ) { + + setInstance(KGenericFactory<KisDropshadowPlugin>::instance()); + setXMLFile(locate("data","kritaplugins/dropshadow.rc"), true); + + m_view = (KisView*) parent; + (void) new KAction(i18n("Add Drop Shadow..."), 0, 0, this, SLOT(slotDropshadow()), actionCollection(), "dropshadow"); + } +} + +KisDropshadowPlugin::~KisDropshadowPlugin() +{ +} + +void KisDropshadowPlugin::slotDropshadow() +{ + KisImageSP image = m_view->canvasSubject()->currentImg(); + if (!image) return; + + KisPaintDeviceSP dev = image->activeDevice(); + if (!dev) return; + + DlgDropshadow * dlgDropshadow = new DlgDropshadow(dev->colorSpace()->id().name(), + image->colorSpace()->id().name(), + m_view, "Dropshadow"); + Q_CHECK_PTR(dlgDropshadow); + + dlgDropshadow->setCaption(i18n("Drop Shadow")); + + if (dlgDropshadow->exec() == QDialog::Accepted) { + + KisDropshadow dropshadow(m_view); + dropshadow.dropshadow(m_view->canvasSubject()->progressDisplay(), + dlgDropshadow->getXOffset(), + dlgDropshadow->getYOffset(), + dlgDropshadow->getBlurRadius(), + dlgDropshadow->getShadowColor(), + dlgDropshadow->getShadowOpacity(), + dlgDropshadow->allowResizingChecked()); + + } + + delete dlgDropshadow; + +} + +#include "kis_dropshadow_plugin.moc" diff --git a/krita/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.h b/krita/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.h new file mode 100644 index 00000000..fd64acdb --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/kis_dropshadow_plugin.h @@ -0,0 +1,45 @@ +/* + * This file is part of Krita + * + * Copyright (c) Michael Thaler <michael.thaler@physik.tu-muenchen.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 of the License, 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _KIS_DROPSHADOW_PLUGIN_H_ +#define _KIS_DROPSHADOW_PLUGIN_H_ + +#include <kparts/plugin.h> + +class KisView; + + + +class KisDropshadowPlugin : public KParts::Plugin +{ + Q_OBJECT +public: + KisDropshadowPlugin(QObject *parent, const char *name, const QStringList &); + virtual ~KisDropshadowPlugin(); + +private slots: + + void slotDropshadow(); + +private: + + KisView * m_view; +}; + +#endif diff --git a/krita/plugins/viewplugins/dropshadow/kritadropshadow.desktop b/krita/plugins/viewplugins/dropshadow/kritadropshadow.desktop new file mode 100644 index 00000000..cec20727 --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/kritadropshadow.desktop @@ -0,0 +1,39 @@ +[Desktop Entry] +Name=Dropshadow +Name[bg]=Сянка +Name[ca]=Gota d'ombra +Name[da]=Faldskygge +Name[de]=Schattenwurf +Name[el]=Ρίψη σκιάς +Name[et]=Varju heitmine +Name[fa]=سایۀ قطره +Name[fr]=Jet d'ombre +Name[fy]=Skaad sette +Name[gl]=Sombreado +Name[hu]=Ejtett árnyék +Name[is]=Undirskuggi +Name[it]=Getta ombra +Name[ja]=影付け +Name[km]=ទម្លាក់ស្រមោល +Name[nb]=Skygge +Name[nds]=Schaddeneffekt +Name[ne]=छायाँ छोड्नुहोस् +Name[nl]=Schaduw plaatsen +Name[pl]=Dodaj cień +Name[pt]=Sombreado +Name[pt_BR]=Sombreado +Name[ru]=Тень +Name[se]=Suoivvan +Name[sk]=Tieň +Name[sl]=Senca +Name[sr]=Падајућа сенка +Name[sr@Latn]=Padajuća senka +Name[sv]=Fallskugga +Name[uk]=Тінь +Name[uz]=Soya tushirish +Name[uz@cyrillic]=Соя тушириш +Name[zh_CN]=阴影 +ServiceTypes=Krita/ViewPlugin +Type=Service +X-KDE-Library=kritadropshadow +X-Krita-Version=2 diff --git a/krita/plugins/viewplugins/dropshadow/wdg_dropshadow.ui b/krita/plugins/viewplugins/dropshadow/wdg_dropshadow.ui new file mode 100644 index 00000000..d78999c8 --- /dev/null +++ b/krita/plugins/viewplugins/dropshadow/wdg_dropshadow.ui @@ -0,0 +1,235 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>WdgDropshadow</class> +<widget class="QWidget"> + <property name="name"> + <cstring>WdgDropshadow</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>403</width> + <height>258</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Offset X:</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Offset Y:</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>Blur radius:</string> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Color:</string> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>textLabel4</cstring> + </property> + <property name="text"> + <string>Opacity:</string> + </property> + </widget> + <widget class="QSlider" row="4" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>opacitySlider</cstring> + </property> + <property name="maxValue"> + <number>100</number> + </property> + <property name="value"> + <number>80</number> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QSpinBox" row="4" column="3"> + <property name="name"> + <cstring>opacitySpinBox</cstring> + </property> + <property name="suffix"> + <string>%</string> + </property> + <property name="maxValue"> + <number>100</number> + </property> + <property name="value"> + <number>80</number> + </property> + </widget> + <widget class="QCheckBox" row="5" column="0" rowspan="1" colspan="4"> + <property name="name"> + <cstring>allowResizingCheckBox</cstring> + </property> + <property name="text"> + <string>Allow resizing</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="QSpinBox" row="0" column="1"> + <property name="name"> + <cstring>xOffsetSpinBox</cstring> + </property> + <property name="minValue"> + <number>-99</number> + </property> + <property name="value"> + <number>8</number> + </property> + </widget> + <spacer row="0" column="2" rowspan="1" colspan="2"> + <property name="name"> + <cstring>spacer7</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>200</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QSpinBox" row="1" column="1"> + <property name="name"> + <cstring>yOffsetSpinBox</cstring> + </property> + <property name="minValue"> + <number>-99</number> + </property> + <property name="value"> + <number>8</number> + </property> + </widget> + <spacer row="1" column="2" rowspan="1" colspan="2"> + <property name="name"> + <cstring>spacer8</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>200</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QSpinBox" row="2" column="1"> + <property name="name"> + <cstring>blurRadiusSpinBox</cstring> + </property> + <property name="value"> + <number>5</number> + </property> + </widget> + <spacer row="2" column="2" rowspan="1" colspan="2"> + <property name="name"> + <cstring>spacer9</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>190</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KColorButton" row="3" column="1"> + <property name="name"> + <cstring>shadowColorButton</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <spacer row="3" column="2" rowspan="1" colspan="2"> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>120</width> + <height>31</height> + </size> + </property> + </spacer> + </grid> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>opacitySpinBox</sender> + <signal>valueChanged(int)</signal> + <receiver>opacitySlider</receiver> + <slot>setValue(int)</slot> + </connection> + <connection> + <sender>opacitySlider</sender> + <signal>valueChanged(int)</signal> + <receiver>opacitySpinBox</receiver> + <slot>setValue(int)</slot> + </connection> +</connections> +<tabstops> + <tabstop>xOffsetSpinBox</tabstop> + <tabstop>yOffsetSpinBox</tabstop> + <tabstop>blurRadiusSpinBox</tabstop> + <tabstop>shadowColorButton</tabstop> + <tabstop>opacitySlider</tabstop> + <tabstop>opacitySpinBox</tabstop> + <tabstop>allowResizingCheckBox</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kcolorbutton.h</includehint> +</includehints> +</UI> |