Invert patter image to white for dark colors.

This commit is contained in:
John Preston 2021-09-07 00:15:38 +03:00
parent 4273167aa2
commit b6cd9c2911
4 changed files with 56 additions and 17 deletions

View File

@ -647,6 +647,13 @@ QColor CountAverageColor(const std::vector<QColor> &colors) {
return QColor(components[0], components[1], components[2]);
}
bool IsPatternInverted(
const std::vector<QColor> &background,
float64 patternOpacity) {
return (patternOpacity > 0.)
&& (CountAverageColor(background).toHsv().valueF() <= 0.3);
}
QColor ThemeAdjustedColor(QColor original, QColor background) {
return QColor::fromHslF(
background.hslHueF(),
@ -747,7 +754,7 @@ QImage GenerateBackgroundImage(
const std::vector<QColor> &bg,
int gradientRotation,
float64 patternOpacity,
Fn<void(QPainter&)> drawPattern) {
Fn<void(QPainter&,bool)> drawPattern) {
auto result = bg.empty()
? Images::GenerateGradient(size, { DefaultBackgroundColor() })
: Images::GenerateGradient(size, bg, gradientRotation);
@ -762,7 +769,7 @@ QImage GenerateBackgroundImage(
} else {
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
}
drawPattern(p);
drawPattern(p, IsPatternInverted(bg, patternOpacity));
if (patternOpacity < 0. && patternOpacity > -1.) {
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
p.setOpacity(1. + patternOpacity);
@ -784,7 +791,10 @@ QImage PreparePatternImage(
bg,
gradientRotation,
patternOpacity,
[&](QPainter &p) {
[&](QPainter &p, bool inverted) {
if (inverted) {
pattern = InvertPatternImage(std::move(pattern));
}
p.drawImage(QRect(QPoint(), pattern.size()), pattern);
});
@ -792,6 +802,23 @@ QImage PreparePatternImage(
return result;
}
QImage InvertPatternImage(QImage pattern) {
pattern = std::move(pattern).convertToFormat(
QImage::Format_ARGB32_Premultiplied);
const auto w = pattern.bytesPerLine() / 4;
auto ints = reinterpret_cast<uint32*>(pattern.bits());
for (auto y = 0, h = pattern.height(); y != h; ++y) {
for (auto x = 0; x != w; ++x) {
const auto value = (*ints >> 24);
*ints++ = (value << 24)
| (value << 16)
| (value << 8)
| value;
}
}
return pattern;
}
QImage PrepareBlurredBackground(QImage image) {
constexpr auto kSize = 900;
constexpr auto kRadius = 24;
@ -834,6 +861,8 @@ ChatThemeBackground PrepareBackgroundImage(
data.colors,
data.gradientRotation,
data.patternOpacity);
} else if (IsPatternInverted(data.colors, data.patternOpacity)) {
prepared = InvertPatternImage(std::move(prepared));
}
prepared.setDevicePixelRatio(style::DevicePixelRatio());
} else if (data.colors.empty()) {

View File

@ -184,6 +184,9 @@ struct ChatBackgroundRects {
[[nodiscard]] QColor CountAverageColor(const QImage &image);
[[nodiscard]] QColor CountAverageColor(const std::vector<QColor> &colors);
[[nodiscard]] bool IsPatternInverted(
const std::vector<QColor> &background,
float64 patternOpacity);
[[nodiscard]] QColor ThemeAdjustedColor(QColor original, QColor background);
[[nodiscard]] QImage PreprocessBackgroundImage(QImage image);
[[nodiscard]] std::optional<QColor> CalculateImageMonoColor(
@ -199,7 +202,8 @@ struct ChatBackgroundRects {
const std::vector<QColor> &bg,
int gradientRotation,
float64 patternOpacity = 1.,
Fn<void(QPainter&)> drawPattern = nullptr);
Fn<void(QPainter&,bool)> drawPattern = nullptr);
[[nodiscard]] QImage InvertPatternImage(QImage pattern);
[[nodiscard]] QImage PreparePatternImage(
QImage pattern,
const std::vector<QColor> &bg,

View File

@ -722,6 +722,9 @@ void ChatBackground::setPreparedAfterPaper(QImage image) {
QImage());
} else {
image = postprocessBackgroundImage(std::move(image));
if (Ui::IsPatternInverted(bgColors, _paper.patternOpacity())) {
image = Ui::InvertPatternImage(std::move(image));
}
setPrepared(
image,
image,

View File

@ -985,6 +985,9 @@ void MainMenu::refreshMenu() {
}
void MainMenu::refreshBackground() {
if (IsFilledCover()) {
return;
}
const auto fill = QSize(st::mainMenuWidth, st::mainMenuCoverHeight);
const auto intensityText = IntensityOfColor(st::mainMenuCoverFg->c);
const auto background = Window::Theme::Background();
@ -995,14 +998,14 @@ void MainMenu::refreshBackground() {
fill,
prepared.size());
auto backgroundImage = paper.isPattern()
auto backgroundImage = /*paper.isPattern()
? Ui::GenerateBackgroundImage(
fill * cIntRetinaFactor(),
paper.backgroundColors(),
paper.gradientRotation(),
paper.patternOpacity(),
[&](QPainter &p) { p.drawImage(rects.to, prepared, rects.from); })
: QImage(
: */QImage(
fill * cIntRetinaFactor(),
QImage::Format_ARGB32_Premultiplied);
QPainter p(&backgroundImage);
@ -1019,20 +1022,20 @@ void MainMenu::refreshBackground() {
};
// Solid color.
if (const auto color = background->colorForFill()) {
const auto intensity = IntensityOfColor(*color);
p.fillRect(QRect(QPoint(), fill), *color);
if (std::abs(intensity - intensityText) < kMinDiffIntensity) {
drawShadow(p);
}
_background = backgroundImage;
return;
}
//if (const auto color = background->colorForFill()) {
// const auto intensity = IntensityOfColor(*color);
// p.fillRect(QRect(QPoint(), fill), *color);
// if (std::abs(intensity - intensityText) < kMinDiffIntensity) {
// drawShadow(p);
// }
// _background = backgroundImage;
// return;
//}
// Background image.
if (!paper.isPattern()) {
//if (!paper.isPattern()) {
p.drawImage(rects.to, prepared, rects.from);
}
//}
// Cut off the part of the background that is under text.
const QRect underText(