13#include "kiconeffect.h"
16#include <KColorScheme>
17#include <KConfigGroup>
18#include <KSharedConfig>
19#include <kicontheme.h>
25#include <qplatformdefs.h>
29class KIconEffectPrivate
53 : d(new KIconEffectPrivate)
58KIconEffect::~KIconEffect() =
default;
70 groups += QStringLiteral(
"Desktop");
71 groups += QStringLiteral(
"Toolbar");
72 groups += QStringLiteral(
"MainToolbar");
73 groups += QStringLiteral(
"Small");
74 groups += QStringLiteral(
"Panel");
75 groups += QStringLiteral(
"Dialog");
78 states += QStringLiteral(
"Default");
79 states += QStringLiteral(
"Active");
80 states += QStringLiteral(
"Disabled");
84 QString _togray(QStringLiteral(
"togray"));
85 QString _colorize(QStringLiteral(
"colorize"));
86 QString _desaturate(QStringLiteral(
"desaturate"));
87 QString _togamma(QStringLiteral(
"togamma"));
88 QString _none(QStringLiteral(
"none"));
89 QString _tomonochrome(QStringLiteral(
"tomonochrome"));
93 d->effect[i][0] = NoEffect;
94 d->effect[i][1] = ((i == 0) || (i == 4)) ? ToGamma : NoEffect;
95 d->effect[i][2] = ToGray;
97 d->trans[i][0] =
false;
98 d->trans[i][1] =
false;
99 d->trans[i][2] =
true;
100 d->value[i][0] = 1.0;
101 d->value[i][1] = ((i == 0) || (i == 4)) ? 0.7 : 1.0;
102 d->value[i][2] = 1.0;
103 d->color[i][0] =
QColor(144, 128, 248);
104 d->color[i][1] =
QColor(169, 156, 255);
105 d->color[i][2] =
QColor(34, 202, 0);
106 d->color2[i][0] =
QColor(0, 0, 0);
107 d->color2[i][1] =
QColor(0, 0, 0);
108 d->color2[i][2] =
QColor(0, 0, 0);
113 if (tmp == _togray) {
115 }
else if (tmp == _colorize) {
117 }
else if (tmp == _desaturate) {
119 }
else if (tmp == _togamma) {
121 }
else if (tmp == _tomonochrome) {
122 effect = ToMonochrome;
123 }
else if (tmp == _none) {
129 d->effect[i][j] = effect;
131 d->value[i][j] = cg.
readEntry(*it2 + QStringLiteral(
"Value"), 0.0);
132 d->color[i][j] = cg.
readEntry(*it2 + QStringLiteral(
"Color"),
QColor());
133 d->color2[i][j] = cg.
readEntry(*it2 + QStringLiteral(
"Color2"),
QColor());
134 d->trans[i][j] = cg.
readEntry(*it2 + QStringLiteral(
"SemiTransparent"),
false);
146 return d->effect[group][state] != NoEffect;
156 QString cached = d->key[group][state];
159 cached = tmp.
setNum(d->effect[group][state]);
161 cached += tmp.
setNum(d->value[group][state]);
164 if (d->effect[group][state] == Colorize || d->effect[group][state] == ToMonochrome) {
166 cached += d->color[group][state].name();
168 if (d->effect[group][state] == ToMonochrome) {
170 cached += d->color2[group][state].name();
173 d->key[group][state] = cached;
182 qCWarning(KICONTHEMES) <<
"Invalid icon state:" << state <<
", should be one of KIconLoader::States";
186 qCWarning(KICONTHEMES) <<
"Invalid icon group:" << group <<
", should be one of KIconLoader::Group";
189 return apply(image, d->effect[group][state], d->value[group][state], d->color[group][state], d->color2[group][state], d->trans[group][state]);
200 if (effect >= LastEffect) {
201 qCWarning(KICONTHEMES) <<
"Invalid icon effect:" << effect <<
", should be one of KIconLoader::Effects";
206 }
else if (value < 0.0) {
235 qCWarning(KICONTHEMES) <<
"Invalid icon state:" << state <<
", should be one of KIconLoader::States";
239 qCWarning(KICONTHEMES) <<
"Invalid icon group:" << group <<
", should be one of KIconLoader::Group";
242 return apply(pixmap, d->effect[group][state], d->value[group][state], d->color[group][state], d->color2[group][state], d->trans[group][state]);
254 if (effect >= LastEffect) {
255 qCWarning(KICONTHEMES) <<
"Invalid icon effect:" << effect <<
", should be one of KIconLoader::Effects";
259 if ((trans ==
true) && (effect == NoEffect)) {
262 }
else if (effect != NoEffect) {
264 tmpImg =
apply(tmpImg, effect, value, col, col2, trans);
282 if (img.
depth() > 8) {
289 data = (
unsigned int *)img.
bits();
294 data = (
unsigned int *)colors.
data();
300 if (img.
depth() <= 8) {
305 KIEImgEdit(
const KIEImgEdit &) =
delete;
306 KIEImgEdit &operator=(
const KIEImgEdit &) =
delete;
319 QRgb *data = ii.data;
320 QRgb *end = data + ii.pixels;
324 while (data != end) {
326 *data = qRgba(gray, gray, gray, qAlpha(*data));
330 unsigned char val = (
unsigned char)(255.0 * value);
331 while (data != end) {
333 *data = qRgba((val * gray + (0xFF - val) * qRed(*data)) >> 8,
334 (val * gray + (0xFF - val) * qGreen(*data)) >> 8,
335 (val * gray + (0xFF - val) * qBlue(*data)) >> 8,
349 QRgb *data = ii.data;
350 QRgb *end = data + ii.pixels;
352 float rcol = col.
red();
353 float gcol = col.
green();
354 float bcol = col.
blue();
359 unsigned char val = (
unsigned char)(255.0 * value);
360 while (data != end) {
363 red =
static_cast<unsigned char>(rcol / 128 * gray);
364 green =
static_cast<unsigned char>(gcol / 128 * gray);
365 blue =
static_cast<unsigned char>(bcol / 128 * gray);
366 }
else if (gray > 128) {
367 red =
static_cast<unsigned char>((gray - 128) * (2 - rcol / 128) + rcol - 1);
368 green =
static_cast<unsigned char>((gray - 128) * (2 - gcol / 128) + gcol - 1);
369 blue =
static_cast<unsigned char>((gray - 128) * (2 - bcol / 128) + bcol - 1);
371 red =
static_cast<unsigned char>(rcol);
372 green =
static_cast<unsigned char>(gcol);
373 blue =
static_cast<unsigned char>(bcol);
376 *data = qRgba((val * red + (0xFF - val) * qRed(*data)) >> 8,
377 (val * green + (0xFF - val) * qGreen(*data)) >> 8,
378 (val * blue + (0xFF - val) * qBlue(*data)) >> 8,
391 QRgb *data = ii.data;
392 QRgb *end = data + ii.pixels;
397 bool grayscale =
true;
398 while (data != end) {
399 sum += qGray(*data) * qAlpha(*data) + 255 * (255 - qAlpha(*data));
401 if ((qRed(*data) != qGreen(*data)) || (qGreen(*data) != qBlue(*data))) {
406 double medium = sum / values;
409 unsigned char val = (
unsigned char)(255.0 * value);
410 int rw = white.red();
411 int gw = white.green();
412 int bw = white.blue();
413 int rb = black.red();
414 int gb = black.green();
415 int bb = black.blue();
419 while (data != end) {
420 if (qRed(*data) <= medium) {
421 *data = qRgba((val * rb + (0xFF - val) * qRed(*data)) >> 8,
422 (val * gb + (0xFF - val) * qGreen(*data)) >> 8,
423 (val * bb + (0xFF - val) * qBlue(*data)) >> 8,
426 *data = qRgba((val * rw + (0xFF - val) * qRed(*data)) >> 8,
427 (val * gw + (0xFF - val) * qGreen(*data)) >> 8,
428 (val * bw + (0xFF - val) * qBlue(*data)) >> 8,
434 while (data != end) {
435 if (qGray(*data) <= medium) {
436 *data = qRgba((val * rb + (0xFF - val) * qRed(*data)) >> 8,
437 (val * gb + (0xFF - val) * qGreen(*data)) >> 8,
438 (val * bb + (0xFF - val) * qBlue(*data)) >> 8,
441 *data = qRgba((val * rw + (0xFF - val) * qRed(*data)) >> 8,
442 (val * gw + (0xFF - val) * qGreen(*data)) >> 8,
443 (val * bw + (0xFF - val) * qBlue(*data)) >> 8,
458 QRgb *data = ii.data;
459 QRgb *end = data + ii.pixels;
465 while (data != end) {
468 color.
setHsv(h, (
int)(s * (1.0 - value) + 0.5), v);
469 *data = qRgba(color.
red(), color.
green(), color.
blue(), qAlpha(*data));
477 QRgb *data = ii.data;
478 QRgb *end = data + ii.pixels;
480 float gamma = 1 / (2 * value + 0.5);
481 while (data != end) {
482 *data = qRgba(
static_cast<unsigned char>(pow(
static_cast<float>(qRed(*data)) / 255, gamma) * 255),
483 static_cast<unsigned char>(pow(
static_cast<float>(qGreen(*data)) / 255, gamma) * 255),
484 static_cast<unsigned char>(pow(
static_cast<float>(qBlue(*data)) / 255, gamma) * 255),
492 if (img.
depth() == 32) {
496 int width = img.
width();
497 int height = img.
height();
500 for (
int y = 0; y < height; ++y) {
506 for (
int x = 0; x < width; ++x) {
511 }
else if (img.
depth() == 8) {
514 for (
int i = 0; i < colorTable.
size(); ++i) {
515 colorTable[i] = (colorTable[i] & 0x00ffffff) | ((colorTable[i] & 0xfe000000) >> 1);
525 if (qAlpha(img.
color(x)) < 127) {
532 if (transColor < 0 || transColor >= img.
colorCount()) {
538 if (img.
depth() == 8) {
539 for (
int y = 0; y < img.
height(); ++y) {
541 for (
int x = (y % 2); x < img.
width(); x += 2) {
542 line[x] = transColor;
546 const bool setOn = (transColor != 0);
548 for (
int y = 0; y < img.
height(); ++y) {
550 for (
int x = (y % 2); x < img.
width(); x += 2) {
552 *(line + (x >> 3)) &= ~(1 << (x & 7));
554 *(line + (x >> 3)) |= (1 << (x & 7));
559 for (
int y = 0; y < img.
height(); ++y) {
561 for (
int x = (y % 2); x < img.
width(); x += 2) {
563 *(line + (x >> 3)) &= ~(1 << (7 - (x & 7)));
565 *(line + (x >> 3)) |= (1 << (7 - (x & 7)));
588 if (src.
depth() == 1) {
589 qWarning() <<
"image depth 1 not supported";
595 if (src.
depth() == 32) {
598 for (y = 0; y < h; ++y) {
601 for (x = 0; x < w; ++x) {
602 l2[x * 2] = l2[x * 2 + 1] = l1[x];
611 const unsigned char *l1;
613 for (y = 0; y < h; ++y) {
616 for (x = 0; x < w; ++x) {
618 l2[x * 2 + 1] = l1[x];
629 qWarning() <<
"Image depth src (" << src.
depth() <<
") != overlay "
630 <<
"(" <<
overlay.depth() <<
")!";
634 qWarning() <<
"Image size src != overlay";
642 qWarning() <<
"Overlay doesn't have alpha buffer!";
653 if (src.
depth() == 1) {
654 qWarning() <<
"1bpp not supported!";
660 if (src.
depth() == 8) {
662 qWarning() <<
"Too many colors in src + overlay!";
668 for (trans = 0; trans <
overlay.colorCount(); trans++) {
669 if (qAlpha(
overlay.color(trans)) == 0) {
670 qWarning() <<
"transparent pixel found at " << trans;
674 if (trans ==
overlay.colorCount()) {
675 qWarning() <<
"transparent pixel not found!";
682 for (i = 0; i <
overlay.colorCount(); ++i) {
687 unsigned char *oline;
688 unsigned char *sline;
689 for (i = 0; i < src.
height(); ++i) {
692 for (j = 0; j < src.
width(); ++j) {
693 if (oline[j] != trans) {
694 sline[j] = oline[j] + nc;
702 if (src.
depth() == 32) {
714 for (i = 0; i < src.
height(); ++i) {
715 oline = (QRgb *)
overlay.scanLine(i);
718 for (j = 0; j < src.
width(); ++j) {
720 g1 = qGreen(oline[j]);
721 b1 = qBlue(oline[j]);
722 a1 = qAlpha(oline[j]);
725 g2 = qGreen(sline[j]);
726 b2 = qBlue(sline[j]);
727 a2 = qAlpha(sline[j]);
729 r2 = (a1 * r1 + (0xff - a1) * r2) >> 8;
730 g2 = (a1 * g1 + (0xff - a1) * g2) >> 8;
731 b2 = (a1 * b1 + (0xff - a1) * b2) >> 8;
734 sline[j] = qRgba(r2, g2, b2, a2);
QString readEntry(const char *key, const char *aDefault=nullptr) const
QString fingerprint(int group, int state) const
Returns a fingerprint for the effect by encoding the given group and state into a QString.
static void overlay(QImage &src, QImage &overlay)
Overlays an image with an other image.
QImage doublePixels(const QImage &src) const
Returns an image twice as large, consisting of 2x2 pixels.
static void toGray(QImage &image, float value)
Tints an image gray.
static void colorize(QImage &image, const QColor &col, float value)
Colorizes an image with a specific color.
void init()
Rereads configuration.
static void semiTransparent(QImage &image)
Renders an image semi-transparent.
KIconEffect()
Create a new KIconEffect.
static void toGamma(QImage &image, float value)
Changes the gamma value of an image.
static void toMonochrome(QImage &image, const QColor &black, const QColor &white, float value)
Produces a monochrome icon with a given foreground and background color.
bool hasEffect(int group, int state) const
Tests whether an effect has been configured for the given icon group.
QImage apply(const QImage &src, int group, int state) const
Applies an effect to an image.
static void deSaturate(QImage &image, float value)
Desaturates an image.
@ LastState
Last state (last constant)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
void getHsv(int *h, int *s, int *v, int *a) const const
void setHsv(int h, int s, int v, int a)
qsizetype bytesPerLine() const const
QRgb color(int i) const const
int colorCount() const const
QList< QRgb > colorTable() const const
void convertTo(Format format, Qt::ImageConversionFlags flags)
void setColor(int index, QRgb colorValue)
void setColorCount(int colorCount)
void setColorTable(const QList< QRgb > &colors)
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype size() const const
QPixmap fromImage(QImage &&image, Qt::ImageConversionFlags flags)
QImage toImage() const const
bool isEmpty() const const
QString & setNum(double n, char format, int precision)