11#include <kpluginfactory.h>
49 const QRect &applyRect,
60 const QString mode = filterConfig->
mode();
105 processMask(device, applyRect, filterConfig, progressUpdater);
108 processAlpha(device, applyRect, filterConfig, progressUpdater);
117 for (
int i = 0; i < 256; ++i) {
118 hardnessLut[i] = i < 128 ? 0 : 255;
121 qreal m = 1.0 / (1.0 - hardness);
122 qreal b = -m * (hardness / 2.0);
123 for (
int i = 0; i < 256; ++i) {
124 hardnessLut[i] = qBound(0,
static_cast<int>(qRound((m * (i / 255.0) + b) * 255.0)), 255);
134 for (
int i = 0; i < 256; ++i) {
135 qreal iNorm = i / 255.0;
136 qreal weight = (2.0 - std::abs(4.0 * iNorm - 2.0)) + hardness;
137 noiseWeightLut[i] = qBound(0,
static_cast<int>(qRound(weight * 255.0)), 255);
139 return noiseWeightLut;
143 const QString & prefix,
144 const QRect &applyRect,
148 const QString generatorId = config->
generatorId(prefix);
149 if (generatorId.isEmpty()) {
166 generatorConfiguration,
170 return generatorDevice;
177 if (!progressUpdater) {
190 const QRect &applyRect,
194 const QString prefix =
"intensity_";
202 if (!generatorDevice) {
210 const qreal hardness = config->
hardness(prefix) / 100.0;
218 const bool invert = config->
invert(prefix);
227 int srcGray = srcIterator.
rawData()[0];
228 int srcAlpha = srcIterator.
rawData()[1];
231 int result = qBound(0, dstGray + (srcGray - 128) * noiseWeightLut[dstGray] * srcAlpha / 0xFE01, 255);
234 result = hardnessLut[result];
236 *maskIterator.
rawData() = 255 - result;
241 int srcGray = srcIterator.
rawData()[0];
242 int srcAlpha = srcIterator.
rawData()[1];
245 int result = qBound(0, dstGray + (srcGray - 128) * noiseWeightLut[dstGray] * srcAlpha / 0xFE01, 255);
248 result = hardnessLut[result];
250 *maskIterator.
rawData() = result;
276 foregroundColor.
setOpacity(foregroundOpacity);
277 backgroundColor.
setOpacity(backgroundOpacity);
279 foregroundDevice->
fill(applyRect, foregroundColor);
280 halftoneDevice->
fill(applyRect, backgroundColor);
282 KisPainter painter(halftoneDevice, maskDevice);
284 painter.
bitBlt(applyRect.topLeft(), foregroundDevice, applyRect);
297 painter.
bitBlt(applyRect.topLeft(), device, applyRect);
302 painter.
bitBlt(applyRect.topLeft(), halftoneDevice, applyRect);
311template <
typename ChannelType>
314 const QRect &applyRect,
316 const QString & prefix,
319 const int channelPos = channelInfo->
pos() /
sizeof(ChannelType);
321 const qreal hardness = config->
hardness(prefix) / 100.0;
326 const bool invert = config->
invert(prefix);
336 int src = srcIterator.
rawData()[0];
337 int srcAlpha = srcIterator.
rawData()[1];
343 int result = qBound(0, dst + (src - 128) * noiseWeightLut[dst] * srcAlpha / 0xFE01, 255);
346 result = hardnessLut[result];
348 ChannelType *dstPixel =
reinterpret_cast<ChannelType*
>(dstIterator.
rawData());
349 ChannelType channelMin =
static_cast<ChannelType
>(channelInfo->
getUIMin());
350 ChannelType channelMax =
static_cast<ChannelType
>(channelInfo->
getUIMax());
351 dstPixel[channelPos] =
static_cast<ChannelType
>(
mapU8ToRange(255 - result, channelMin, channelMax));
356 int src = srcIterator.
rawData()[0];
357 int srcAlpha = srcIterator.
rawData()[1];
363 int result = qBound(0, dst + (src - 128) * noiseWeightLut[dst] * srcAlpha / 0xFE01, 255);
366 result = hardnessLut[result];
368 ChannelType *dstPixel =
reinterpret_cast<ChannelType*
>(dstIterator.
rawData());
369 ChannelType channelMin =
static_cast<ChannelType
>(channelInfo->
getUIMin());
370 ChannelType channelMax =
static_cast<ChannelType
>(channelInfo->
getUIMax());
371 dstPixel[channelPos] =
static_cast<ChannelType
>(
mapU8ToRange(result, channelMin, channelMax));
378 int src = srcIterator.
rawData()[0];
379 int srcAlpha = srcIterator.
rawData()[1];
382 int result = qBound(0, dst + (src - 128) * noiseWeightLut[dst] * srcAlpha / 0xFE01, 255);
385 result = hardnessLut[result];
387 ChannelType *dstPixel =
reinterpret_cast<ChannelType*
>(dstIterator.
rawData());
388 ChannelType channelMin =
static_cast<ChannelType
>(channelInfo->
getUIMin());
389 ChannelType channelMax =
static_cast<ChannelType
>(channelInfo->
getUIMax());
390 dstPixel[channelPos] =
static_cast<ChannelType
>(
mapU8ToRange(255 - result, channelMin, channelMax));
395 int src = srcIterator.
rawData()[0];
396 int srcAlpha = srcIterator.
rawData()[1];
399 int result = qBound(0, dst + (src - 128) * noiseWeightLut[dst] * srcAlpha / 0xFE01, 255);
402 result = hardnessLut[result];
404 ChannelType *dstPixel =
reinterpret_cast<ChannelType*
>(dstIterator.
rawData());
405 ChannelType channelMin =
static_cast<ChannelType
>(channelInfo->
getUIMin());
406 ChannelType channelMax =
static_cast<ChannelType
>(channelInfo->
getUIMax());
407 dstPixel[channelPos] =
static_cast<ChannelType
>(
mapU8ToRange(result, channelMin, channelMax));
414 const QRect &applyRect,
419 const int progressStep = 100 / (channels.count() * 2);
427 for (
int i = 0; i < channels.count(); ++i) {
429 generatorDevices[i] =
nullptr;
431 const QString prefix =
434 if (generatorDevice) {
435 generatorDevices[i] = generatorDevice;
437 generatorDevices[i] =
nullptr;
446 for (
int i = 0; i < channels.count(); ++i) {
447 if (!generatorDevices[i]) {
454 switch (channels.at(i)->channelValueType()) {
456 processChannel<quint8>(device, generatorDevices[i], applyRect, config, prefix, channels.at(i));
459 processChannel<quint16>(device, generatorDevices[i], applyRect, config, prefix, channels.at(i));
462 processChannel<quint32>(device, generatorDevices[i], applyRect, config, prefix, channels.at(i));
466 processChannel<half>(device, generatorDevices[i], applyRect, config, prefix, channels.at(i));
470 processChannel<float>(device, generatorDevices[i], applyRect, config, prefix, channels.at(i));
473 processChannel<double>(device, generatorDevices[i], applyRect, config, prefix, channels.at(i));
476 processChannel<qint8>(device, generatorDevices[i], applyRect, config, prefix, channels.at(i));
479 processChannel<qint16>(device, generatorDevices[i], applyRect, config, prefix, channels.at(i));
499 const QRect& applyRect,
503 const QString prefix =
"alpha_";
511 if (!generatorDevice) {
519 const qreal hardness = config->
hardness(prefix) / 100.0;
524 const bool invert = config->
invert(prefix);
531 int src = srcIterator.
rawData()[0];
532 int srcAlpha = srcIterator.
rawData()[1];
535 int result = qBound(0, dst + (src - 128) * noiseWeightLut[dst] * srcAlpha / 0xFE01, 255);
538 result = hardnessLut[result];
545 int src = srcIterator.
rawData()[0];
546 int srcAlpha = srcIterator.
rawData()[1];
549 int result = qBound(0, dst + (src - 128) * noiseWeightLut[dst] * srcAlpha / 0xFE01, 255);
552 result = hardnessLut[result];
565 const QRect& applyRect,
569 const QString prefix =
"alpha_";
577 if (!generatorDevice) {
585 const qreal hardness = config->
hardness(prefix) / 100.0;
590 const bool invert = config->
invert(prefix);
596 int dst = 255 - *dstIterator.
rawData();
597 int src = *srcIterator.
rawData();
600 int result = qBound(0, dst + (src - 128) * noiseWeightLut[dst] / 0xFF, 255);
603 result = hardnessLut[result];
605 *dstIterator.
rawData() =
static_cast<quint8
>(255 - result);
609 int dst = *dstIterator.
rawData();
610 int src = *srcIterator.
rawData();
613 int result = qBound(0, dst + (src - 128) * noiseWeightLut[dst] / 0xFF, 255);
616 result = hardnessLut[result];
618 *dstIterator.
rawData() =
static_cast<quint8
>(result);
639 filterConfig->setGeneratorId(
"intensity_", defaultGeneratorId);
640 if (defaultGenerator) {
643 if (defaultGeneratorId ==
"screentone") {
644 defaultGeneratorConfiguration->setProperty(
"rotation", 45.0);
645 defaultGeneratorConfiguration->setProperty(
"contrast", 50.0);
647 filterConfig->setGeneratorConfiguration(
"intensity_", defaultGeneratorConfiguration);
657 filterConfig->setGeneratorId(
"alpha_", defaultGeneratorId);
658 if (defaultGenerator) {
661 if (defaultGeneratorId ==
"screentone") {
662 defaultGeneratorConfiguration->setProperty(
"rotation", 45.0);
663 defaultGeneratorConfiguration->setProperty(
"contrast", 50.0);
665 filterConfig->setGeneratorConfiguration(
"alpha_", defaultGeneratorConfiguration);
674 QHash<QString, qreal> channelDict;
675 channelDict.insert(
"RGBA_channel0_", 15.0);
676 channelDict.insert(
"RGBA_channel1_", 45.0);
677 channelDict.insert(
"RGBA_channel2_", 75.0);
678 channelDict.insert(
"CMYKA_channel0_", 15.0);
679 channelDict.insert(
"CMYKA_channel1_", 75.0);
680 channelDict.insert(
"CMYKA_channel2_", 0.0);
681 channelDict.insert(
"CMYKA_channel3_", 45.0);
683 for (
auto i = channelDict.constBegin(); i != channelDict.constEnd(); ++i) {
684 if (defaultGenerator && defaultGeneratorId ==
"screentone") {
685 filterConfig->setGeneratorId(i.key(),
"screentone");
688 defaultGeneratorConfiguration->setProperty(
"rotation", i.value());
689 defaultGeneratorConfiguration->setProperty(
"contrast", 50.0);
690 filterConfig->setGeneratorConfiguration(i.key(), defaultGeneratorConfiguration);
692 filterConfig->setGeneratorId(i.key(),
"");
708 Q_UNUSED(useForMasks);
712#include "KisHalftoneFilter.moc"
const KoID YCbCrAColorModelID("YCbCrA", ki18n("YCbCr/Alpha"))
const KoID GrayAColorModelID("GRAYA", ki18n("Grayscale/Alpha"))
const KoID XYZAColorModelID("XYZA", ki18n("XYZ/Alpha"))
const KoID AlphaColorModelID("A", ki18n("Alpha mask"))
const KoID CMYKAColorModelID("CMYKA", ki18n("CMYK/Alpha"))
const KoID LABAColorModelID("LABA", ki18n("L*a*b*/Alpha"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
const KoID GrayColorModelID("GRAY", ki18n("Grayscale (without transparency)"))
const QString COMPOSITE_OVER
const QString COMPOSITE_COPY
const QString COMPOSITE_DESTINATION_IN
KisPaintDeviceSP getDevice(KisPaintDeviceSP prototype)
void putDevice(KisPaintDeviceSP device)
void putSelection(KisSelectionSP selection)
KisSelectionSP getSelection()
void add(KisFilterSP item)
static KisFilterRegistry * instance()
static KisGeneratorRegistry * instance()
virtual void generate(KisProcessingInformation dst, const QSize &size, const KisFilterConfigurationSP config, KoUpdater *progressUpdater) const =0
static constexpr qreal defaultHardness()
static constexpr int defaultBackgroundOpacity()
static const KoColor & defaultBackgroundColor()
static constexpr const char * HalftoneMode_Alpha
static constexpr int defaultForegroundOpacity()
static const KoColor & defaultForegroundColor()
static constexpr bool defaultInvert()
static QString defaultGeneratorId()
static constexpr const char * HalftoneMode_IndependentChannels
static constexpr const char * HalftoneMode_Intensity
KoColor backgroundColor(const QString &prefix) const
QString generatorId(const QString &prefix) const
int backgroundOpacity(const QString &prefix) const
int foregroundOpacity(const QString &prefix) const
QString colorModelId() const
KisFilterConfigurationSP generatorConfiguration(const QString &prefix) const
qreal hardness(const QString &prefix) const
KoColor foregroundColor(const QString &prefix) const
bool invert(const QString &prefix) const
static QString defaultMode()
void processIntensity(KisPaintDeviceSP device, const QRect &applyRect, const KisHalftoneFilterConfiguration *config, KoUpdater *progressUpdater) const
KisCachedPaintDevice m_grayDevicesCache
static QVector< quint8 > makeHardnessLut(qreal hardness)
void processImpl(KisPaintDeviceSP device, const QRect &applyRect, const KisFilterConfigurationSP config, KoUpdater *progressUpdater) const override
KisFilterConfigurationSP factoryConfiguration(KisResourcesInterfaceSP resourcesInterface) const override
void processChannels(KisPaintDeviceSP device, const QRect &applyRect, const KisHalftoneFilterConfiguration *config, KoUpdater *progressUpdater) const
KisCachedPaintDevice m_genericDevicesCache
KisCachedSelection m_selectionsCache
void processMask(KisPaintDeviceSP device, const QRect &applyRect, const KisHalftoneFilterConfiguration *config, KoUpdater *progressUpdater) const
void processChannel(KisPaintDeviceSP device, KisPaintDeviceSP generatorDevice, const QRect &applyRect, const KisHalftoneFilterConfiguration *config, const QString &prefix, KoChannelInfo *channelInfo) const
void processAlpha(KisPaintDeviceSP device, const QRect &applyRect, const KisHalftoneFilterConfiguration *config, KoUpdater *progressUpdater) const
KisConfigWidget * createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev, bool useForMasks) const override
static quint8 mapU8ToRange(quint8 value, quint8 new_min, quint8 new_max)
KisPaintDeviceSP makeGeneratorPaintDevice(KisPaintDeviceSP prototype, const QString &prefix, const QRect &applyRect, const KisHalftoneFilterConfiguration *config, KoUpdater *progressUpdater) const
bool checkUpdaterInterruptedAndSetPercent(KoUpdater *progressUpdater, int percent) const
static QVector< quint8 > makeNoiseWeightLut(qreal hardness)
KisFilterConfigurationSP defaultConfiguration(KisResourcesInterfaceSP resourcesInterface) const override
void fill(const QRect &rc, const KoColor &color)
const KoColorSpace * colorSpace() const
void bitBlt(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight)
void setCompositeOpId(const KoCompositeOp *op)
ALWAYS_INLINE quint8 * rawData()
@ ALPHA
The channel represents the opacity of a pixel.
@ UINT8
use this for an unsigned integer 8bits channel
@ UINT16
use this for an integer 16bits channel
@ INT16
use this for an integer 16bits channel
@ INT8
use this for an integer 8bits channel
@ FLOAT32
use this for a float 32bits channel
@ FLOAT16
use this for a float 16bits channel
@ UINT32
use this for an unsigned integer 21bits channel
@ FLOAT64
use this for a float 64bits channel
double getUIMin(void) const
double getUIMax(void) const
virtual quint32 alphaPos() const =0
virtual quint8 intensity8(const quint8 *src) const =0
virtual void setOpacity(quint8 *pixels, quint8 alpha, qint32 nPixels) const =0
QList< KoChannelInfo * > channels
virtual quint8 scaleToU8(const quint8 *srcPixel, qint32 channelPos) const =0
virtual KoID colorModelId() const =0
virtual quint8 opacityU8(const quint8 *pixel) const =0
virtual const KoColorProfile * profile() const =0
void convertTo(const KoColorSpace *cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
void setOpacity(quint8 alpha)
T get(const QString &id) const
void setProgress(int percent)
~KritaHalftone() override
KritaHalftone(QObject *parent, const QVariantList &)
static bool qFuzzyCompare(half p1, half p2)
K_PLUGIN_FACTORY_WITH_JSON(KritaASCCDLFactory, "kritaasccdl.json", registerPlugin< KritaASCCDL >();) KritaASCCDL
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
const KoID FiltersCategoryArtisticId("artistic_filters", ki18nc("The category of artistic filters, like raindrops. Adjective.", "Artistic"))
virtual KisFilterConfigurationSP defaultConfiguration(KisResourcesInterfaceSP resourcesInterface) const
void setSupportsPainting(bool v)
bool hasLocalResourcesSnapshot() const
KisPixelSelectionSP pixelSelection
virtual bool isLinear() const =0
static KoColorSpaceRegistry * instance()
const KoColorSpace * rgb8(const QString &profileName=QString())