File indexing completed on 2024-05-26 04:33:11

0001 /*
0002  * This file is part of Krita
0003  *
0004  * SPDX-FileCopyrightText: 2005 Michael Thaler <michael.thaler@physik.tu-muenchen.de>
0005  *
0006  * ported from Gimp, SPDX-FileCopyrightText: 1997 Eiichi Takamori <taka@ma1.seikyou.ne.jp>
0007  * original pixelize.c for GIMP 0.54 by Tracy Scott
0008  *
0009  *  SPDX-License-Identifier: GPL-2.0-or-later
0010  */
0011 
0012 #include "kis_round_corners_filter.h"
0013 
0014 #include <stdlib.h>
0015 #include <vector>
0016 #include <math.h>
0017 
0018 #include <QPoint>
0019 
0020 #include <klocalizedstring.h>
0021 #include <kpluginfactory.h>
0022 
0023 #include <KoUpdater.h>
0024 
0025 #include <kis_debug.h>
0026 #include <KisDocument.h>
0027 #include <filter/kis_filter_registry.h>
0028 #include <kis_global.h>
0029 #include <kis_image.h>
0030 #include <kis_layer.h>
0031 #include <widgets/kis_multi_integer_filter_widget.h>
0032 #include <kis_selection.h>
0033 #include <filter/kis_filter_category_ids.h>
0034 #include <filter/kis_filter_configuration.h>
0035 #include <kis_processing_information.h>
0036 #include <kis_types.h>
0037 #include <KisSequentialIteratorProgress.h>
0038 #include <kis_algebra_2d.h>
0039 #include <KoProgressUpdater.h>
0040 
0041 
0042 KisRoundCornersFilter::KisRoundCornersFilter() : KisFilter(id(), FiltersCategoryMapId, i18n("&Round Corners..."))
0043 {
0044     setSupportsPainting(false);
0045 
0046 }
0047 
0048 void fadeOneCorner(KisPaintDeviceSP device,
0049                    const QPoint &basePoint,
0050                    const QRect &processRect,
0051                    const qreal thresholdSq,
0052                    KoUpdater* progressUpdater)
0053 {
0054     const KoColorSpace *cs = device->colorSpace();
0055     KisSequentialIteratorProgress dstIt(device, processRect, progressUpdater);
0056 
0057     while (dstIt.nextPixel()) {
0058         const QPointF point(dstIt.x(), dstIt.y());
0059 
0060         const qreal distanceSq = kisSquareDistance(point, basePoint);
0061         if (distanceSq >= thresholdSq) {
0062             cs->setOpacity(dstIt.rawData(), OPACITY_TRANSPARENT_U8, 1);
0063         }
0064     }
0065 }
0066 
0067 
0068 void KisRoundCornersFilter::processImpl(KisPaintDeviceSP device,
0069                                         const QRect& applyRect,
0070                                         const KisFilterConfigurationSP config,
0071                                         KoUpdater* progressUpdater
0072                                         ) const
0073 {
0074     Q_UNUSED(config);
0075     Q_ASSERT(!device.isNull());
0076 
0077     if (!device || !config) {
0078         warnKrita << "Invalid parameters for round corner filter";
0079         dbgPlugins << device << " " << config;
0080         return;
0081     }
0082 
0083     const QRect bounds = device->defaultBounds()->imageBorderRect();
0084 
0085     const qint32 radius = qMin(KisAlgebra2D::minDimension(bounds) / 2, qMax(1, config->getInt("radius" , 30)));
0086     const qreal radiusSq = pow2(radius);
0087 
0088     struct CornerJob {
0089         QRect rc;
0090         QPoint pt;
0091         KoUpdater *progressUpdater;
0092     };
0093 
0094     QVector<CornerJob> jobs;
0095 
0096     KoProgressUpdater compositeUpdater(progressUpdater, KoProgressUpdater::Unthreaded);
0097 
0098     {
0099         QRect rc(bounds.x(), bounds.y(), radius, radius);
0100         QPoint pt(rc.bottomRight());
0101         jobs << CornerJob({rc, pt, compositeUpdater.startSubtask()});
0102     }
0103 
0104     {
0105         QRect rc(bounds.x() + bounds.width() - radius, bounds.y(), radius, radius);
0106         QPoint pt(rc.bottomLeft());
0107         jobs << CornerJob({rc, pt, compositeUpdater.startSubtask()});
0108     }
0109 
0110     {
0111         QRect rc(bounds.x(), bounds.y() + bounds.height() - radius, radius, radius);
0112         QPoint pt(rc.topRight());
0113         jobs << CornerJob({rc, pt, compositeUpdater.startSubtask()});
0114     }
0115 
0116     {
0117         QRect rc(bounds.x() + bounds.width() - radius, bounds.y() + bounds.height() - radius, radius, radius);
0118         QPoint pt(rc.topLeft());
0119         jobs << CornerJob({rc, pt, compositeUpdater.startSubtask()});
0120     }
0121 
0122     Q_FOREACH (const CornerJob &job, jobs) {
0123         const QRect processRect = job.rc & applyRect;
0124         if (!processRect.isEmpty()) {
0125             fadeOneCorner(device, job.pt, processRect, radiusSq, job.progressUpdater);
0126         }
0127     }
0128 }
0129 
0130 KisConfigWidget * KisRoundCornersFilter::createConfigurationWidget(QWidget* parent, const KisPaintDeviceSP, bool) const
0131 {
0132     vKisIntegerWidgetParam param;
0133     param.push_back(KisIntegerWidgetParam(2, 100, 30, i18n("Radius"), "radius"));
0134     return new KisMultiIntegerFilterWidget(id().id(), parent, id().id(), param);
0135 
0136 }
0137 
0138 KisFilterConfigurationSP KisRoundCornersFilter::defaultConfiguration(KisResourcesInterfaceSP resourcesInterface) const
0139 {
0140     KisFilterConfigurationSP config = factoryConfiguration(resourcesInterface);
0141     config->setProperty("radius", 30);
0142     return config;
0143 }