2
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-09-05 08:55:59 +00:00

Add support for pattern wallpapers.

This commit is contained in:
John Preston
2019-01-29 10:29:38 +03:00
parent c2744700c0
commit b6edf4561d
13 changed files with 401 additions and 107 deletions

View File

@@ -74,9 +74,9 @@ AdminLog::OwnedItem GenerateTextItem(
return AdminLog::OwnedItem(delegate, item);
}
QImage PrepareScaledFromFull(
QImage PrepareScaledNonPattern(
const QImage &image,
Images::Option blur = Images::Option(0)) {
Images::Option blur) {
const auto size = st::boxWideWidth;
const auto width = std::max(image.width(), 1);
const auto height = std::max(image.height(), 1);
@@ -90,17 +90,71 @@ QImage PrepareScaledFromFull(
image,
takeWidth,
takeHeight,
Images::Option::Smooth | blur,
Images::Option::Smooth
| Images::Option::TransparentBackground
| blur,
size,
size);
}
QPixmap PrepareScaledFromThumb(not_null<Image*> thumb, bool good) {
return thumb->loaded()
? App::pixmapFromImageInPlace(PrepareScaledFromFull(
thumb->original(),
good ? Images::Option(0) : Images::Option::Blurred))
: QPixmap();
QImage ColorizePattern(QImage image, QColor color) {
if (image.format() != QImage::Format_ARGB32_Premultiplied) {
image = std::move(image).convertToFormat(
QImage::Format_ARGB32_Premultiplied);
}
// Similar to style::colorizeImage.
// But style::colorizeImage takes pattern with all pixels having the
// same components value, from (0, 0, 0, 0) to (255, 255, 255, 255).
//
// While in patterns we have different value ranges, usually they are
// from (0, 0, 0, 0) to (0, 0, 0, 255), so we should use only 'alpha'.
const auto width = image.width();
const auto height = image.height();
const auto pattern = anim::shifted(color);
const auto resultBytesPerPixel = (image.depth() >> 3);
constexpr auto resultIntsPerPixel = 1;
const auto resultIntsPerLine = (image.bytesPerLine() >> 2);
const auto resultIntsAdded = resultIntsPerLine - width * resultIntsPerPixel;
auto resultInts = reinterpret_cast<uint32*>(image.bits());
Assert(resultIntsAdded >= 0);
Assert(image.depth() == static_cast<int>((resultIntsPerPixel * sizeof(uint32)) << 3));
Assert(image.bytesPerLine() == (resultIntsPerLine << 2));
const auto maskBytesPerPixel = (image.depth() >> 3);
const auto maskBytesPerLine = image.bytesPerLine();
const auto maskBytesAdded = maskBytesPerLine - width * maskBytesPerPixel;
// We want to read the last byte of four available.
// This is the difference with style::colorizeImage.
auto maskBytes = image.constBits() + (maskBytesPerPixel - 1);
Assert(maskBytesAdded >= 0);
Assert(image.depth() == (maskBytesPerPixel << 3));
for (auto y = 0; y != height; ++y) {
for (auto x = 0; x != width; ++x) {
auto maskOpacity = static_cast<anim::ShiftedMultiplier>(*maskBytes) + 1;
*resultInts = anim::unshifted(pattern * maskOpacity);
maskBytes += maskBytesPerPixel;
resultInts += resultIntsPerPixel;
}
maskBytes += maskBytesAdded;
resultInts += resultIntsAdded;
}
return std::move(image);
}
QImage PrepareScaledFromFull(
const QImage &image,
std::optional<QColor> patternBackground,
Images::Option blur = Images::Option(0)) {
auto result = PrepareScaledNonPattern(image, blur);
if (patternBackground) {
result = ColorizePattern(
std::move(result),
Window::Theme::PatternColor(*patternBackground));
}
return result;
}
} // namespace
@@ -358,10 +412,11 @@ void BackgroundPreviewBox::paintEvent(QPaintEvent *e) {
Painter p(this);
const auto ms = getms();
if (const auto color = _paper.backgroundColor()) {
const auto color = _paper.backgroundColor();
if (color) {
p.fillRect(e->rect(), *color);
} else {
}
if (!color || _paper.isPattern()) {
if (_scaled.isNull() && !setScaledFromThumb()) {
p.fillRect(e->rect(), st::boxBg);
return;
@@ -375,6 +430,11 @@ void BackgroundPreviewBox::paintEvent(QPaintEvent *e) {
void BackgroundPreviewBox::paintImage(Painter &p) {
Expects(!_scaled.isNull());
p.setOpacity(_paper.isPattern()
? std::clamp(_paper.patternIntensity() / 100., 0., 1.)
: 1.);
const auto guard = gsl::finally([&] { p.setOpacity(1.); });
const auto factor = cIntRetinaFactor();
const auto size = st::boxWideWidth;
const auto from = QRect(
@@ -457,10 +517,25 @@ void BackgroundPreviewBox::step_radial(TimeMs ms, bool timer) {
}
bool BackgroundPreviewBox::setScaledFromThumb() {
_scaled = PrepareScaledFromThumb(
_paper.thumbnail(),
!_paper.document());
return !_scaled.isNull();
Expects(_paper.thumbnail() != nullptr);
const auto thumbnail = _paper.thumbnail();
if (!thumbnail->loaded()) {
return false;
}
setScaledFromImage(PrepareScaledFromFull(
thumbnail->original(),
patternBackgroundColor(),
_paper.document() ? Images::Option::Blurred : Images::Option(0)));
return true;
}
void BackgroundPreviewBox::setScaledFromImage(QImage &&image) {
_scaled = App::pixmapFromImageInPlace(std::move(image));
}
std::optional<QColor> BackgroundPreviewBox::patternBackgroundColor() const {
return _paper.isPattern() ? _paper.backgroundColor() : std::nullopt;
}
void BackgroundPreviewBox::checkLoadedDocument() {
@@ -477,9 +552,10 @@ void BackgroundPreviewBox::checkLoadedDocument() {
crl::async([
this,
image = std::move(image),
patternBackground = patternBackgroundColor(),
guard = std::move(right)
]() mutable {
auto scaled = PrepareScaledFromFull(image);
auto scaled = PrepareScaledFromFull(image, patternBackground);
crl::on_main([
this,
image = std::move(image),
@@ -489,7 +565,7 @@ void BackgroundPreviewBox::checkLoadedDocument() {
if (!guard) {
return;
}
_scaled = App::pixmapFromImageInPlace(std::move(scaled));
setScaledFromImage(std::move(scaled));
_full = std::move(image);
update();
});
@@ -497,17 +573,19 @@ void BackgroundPreviewBox::checkLoadedDocument() {
});
}
bool BackgroundPreviewBox::Start(const QString &slug, const QString &mode) {
bool BackgroundPreviewBox::Start(
const QString &slug,
const QMap<QString, QString> &params) {
if (const auto paper = Data::WallPaper::FromColorSlug(slug)) {
Ui::show(Box<BackgroundPreviewBox>(*paper));
Ui::show(Box<BackgroundPreviewBox>(paper->withUrlParams(params)));
return true;
}
if (!IsValidWallPaperSlug(slug)) {
Ui::show(Box<InformBox>(lang(lng_background_bad_link)));
return false;
}
Auth().api().requestWallPaper(slug, [](const Data::WallPaper &result) {
Ui::show(Box<BackgroundPreviewBox>(result));
Auth().api().requestWallPaper(slug, [=](const Data::WallPaper &result) {
Ui::show(Box<BackgroundPreviewBox>(result.withUrlParams(params)));
}, [](const RPCError &error) {
Ui::show(Box<InformBox>(lang(lng_background_bad_link)));
});