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]); 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) { QColor ThemeAdjustedColor(QColor original, QColor background) {
return QColor::fromHslF( return QColor::fromHslF(
background.hslHueF(), background.hslHueF(),
@ -747,7 +754,7 @@ QImage GenerateBackgroundImage(
const std::vector<QColor> &bg, const std::vector<QColor> &bg,
int gradientRotation, int gradientRotation,
float64 patternOpacity, float64 patternOpacity,
Fn<void(QPainter&)> drawPattern) { Fn<void(QPainter&,bool)> drawPattern) {
auto result = bg.empty() auto result = bg.empty()
? Images::GenerateGradient(size, { DefaultBackgroundColor() }) ? Images::GenerateGradient(size, { DefaultBackgroundColor() })
: Images::GenerateGradient(size, bg, gradientRotation); : Images::GenerateGradient(size, bg, gradientRotation);
@ -762,7 +769,7 @@ QImage GenerateBackgroundImage(
} else { } else {
p.setCompositionMode(QPainter::CompositionMode_DestinationIn); p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
} }
drawPattern(p); drawPattern(p, IsPatternInverted(bg, patternOpacity));
if (patternOpacity < 0. && patternOpacity > -1.) { if (patternOpacity < 0. && patternOpacity > -1.) {
p.setCompositionMode(QPainter::CompositionMode_SourceOver); p.setCompositionMode(QPainter::CompositionMode_SourceOver);
p.setOpacity(1. + patternOpacity); p.setOpacity(1. + patternOpacity);
@ -784,7 +791,10 @@ QImage PreparePatternImage(
bg, bg,
gradientRotation, gradientRotation,
patternOpacity, patternOpacity,
[&](QPainter &p) { [&](QPainter &p, bool inverted) {
if (inverted) {
pattern = InvertPatternImage(std::move(pattern));
}
p.drawImage(QRect(QPoint(), pattern.size()), pattern); p.drawImage(QRect(QPoint(), pattern.size()), pattern);
}); });
@ -792,6 +802,23 @@ QImage PreparePatternImage(
return result; 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) { QImage PrepareBlurredBackground(QImage image) {
constexpr auto kSize = 900; constexpr auto kSize = 900;
constexpr auto kRadius = 24; constexpr auto kRadius = 24;
@ -834,6 +861,8 @@ ChatThemeBackground PrepareBackgroundImage(
data.colors, data.colors,
data.gradientRotation, data.gradientRotation,
data.patternOpacity); data.patternOpacity);
} else if (IsPatternInverted(data.colors, data.patternOpacity)) {
prepared = InvertPatternImage(std::move(prepared));
} }
prepared.setDevicePixelRatio(style::DevicePixelRatio()); prepared.setDevicePixelRatio(style::DevicePixelRatio());
} else if (data.colors.empty()) { } else if (data.colors.empty()) {

View file

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

View file

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

View file

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