mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 21:57:10 +02:00
Dither default background to avoid color banding.
This commit is contained in:
parent
8f478b86ee
commit
565877630f
6 changed files with 100 additions and 14 deletions
|
@ -239,6 +239,7 @@ void BackgroundBox::Inner::sortPapers() {
|
|||
return std::make_tuple(
|
||||
data.id() == current,
|
||||
night ? data.isDark() : !data.isDark(),
|
||||
Data::IsDefaultWallPaper(data),
|
||||
!data.isDefault() && !Data::IsLegacy1DefaultWallPaper(data),
|
||||
Data::IsLegacy2DefaultWallPaper(data),
|
||||
Data::IsLegacy1DefaultWallPaper(data));
|
||||
|
|
|
@ -622,6 +622,7 @@ void BackgroundPreviewBox::paintDate(Painter &p) {
|
|||
if (!date || !_serviceBg) {
|
||||
return;
|
||||
}
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
const auto text = date->text;
|
||||
const auto bubbleHeight = st::msgServicePadding.top() + st::msgServiceFont->height + st::msgServicePadding.bottom();
|
||||
const auto bubbleTop = st::msgServiceMargin.top();
|
||||
|
@ -758,7 +759,7 @@ void BackgroundPreviewBox::checkLoadedDocument() {
|
|||
};
|
||||
_generating = Data::ReadImageAsync(
|
||||
_media.get(),
|
||||
Window::Theme::ProcessBackgroundImage,
|
||||
Window::Theme::PreprocessBackgroundImage,
|
||||
generateCallback);
|
||||
}
|
||||
|
||||
|
|
|
@ -1265,7 +1265,7 @@ void MainWidget::checkChatBackground() {
|
|||
};
|
||||
_background->generating = Data::ReadImageAsync(
|
||||
media.get(),
|
||||
Window::Theme::ProcessBackgroundImage,
|
||||
Window::Theme::PreprocessBackgroundImage,
|
||||
generateCallback);
|
||||
}
|
||||
|
||||
|
|
|
@ -431,12 +431,89 @@ bool InitializeFromSaved(Saved &&saved) {
|
|||
return true;
|
||||
}
|
||||
|
||||
QImage validateBackgroundImage(QImage image) {
|
||||
[[nodiscard]] QImage DitherImage(QImage image) {
|
||||
Expects(image.bytesPerLine() == image.width() * 4);
|
||||
|
||||
const auto width = image.width();
|
||||
const auto height = image.height();
|
||||
|
||||
if (width < 16 || height < 16) {
|
||||
return image;
|
||||
}
|
||||
|
||||
const auto area = width * height;
|
||||
const auto shifts = std::make_unique<uchar[]>(area);
|
||||
memset_rand(shifts.get(), area);
|
||||
|
||||
// shiftx = int(shift & 0x0F) - 8; shifty = int(shift >> 4) - 8;
|
||||
// Clamp shifts close to edges.
|
||||
for (auto y = 0; y != 8; ++y) {
|
||||
const auto min = 8 - y;
|
||||
const auto shifted = (min << 4);
|
||||
auto shift = shifts.get() + y * width;
|
||||
for (const auto till = shift + width; shift != till; ++shift) {
|
||||
if ((*shift >> 4) < min) {
|
||||
*shift = shifted | (*shift & 0x0F);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto y = height - 7; y != height; ++y) {
|
||||
const auto max = 8 + (height - y - 1);
|
||||
const auto shifted = (max << 4);
|
||||
auto shift = shifts.get() + y * width;
|
||||
for (const auto till = shift + width; shift != till; ++shift) {
|
||||
if ((*shift >> 4) > max) {
|
||||
*shift = shifted | (*shift & 0x0F);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto shift = shifts.get(), ytill = shift + area
|
||||
; shift != ytill
|
||||
; shift += width - 8) {
|
||||
for (const auto till = shift + 8; shift != till; ++shift) {
|
||||
const auto min = (till - shift);
|
||||
if ((*shift & 0x0F) < min) {
|
||||
*shift = (*shift & 0xF0) | min;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto shift = shifts.get(), ytill = shift + area; shift != ytill;) {
|
||||
shift += width - 7;
|
||||
for (const auto till = shift + 7; shift != till; ++shift) {
|
||||
const auto max = 8 + (till - shift - 1);
|
||||
if ((*shift & 0x0F) > max) {
|
||||
*shift = (*shift & 0xF0) | max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto result = image;
|
||||
result.detach();
|
||||
|
||||
const auto src = reinterpret_cast<const uint32*>(image.constBits());
|
||||
const auto dst = reinterpret_cast<uint32*>(result.bits());
|
||||
for (auto index = 0; index != area; ++index) {
|
||||
const auto shift = shifts[index];
|
||||
const auto shiftx = int(shift & 0x0F) - 8;
|
||||
const auto shifty = int(shift >> 4) - 8;
|
||||
dst[index] = src[index + (shifty * width) + shiftx];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] QImage PostprocessBackgroundImage(
|
||||
QImage image,
|
||||
const Data::WallPaper &paper) {
|
||||
if (image.format() != QImage::Format_ARGB32_Premultiplied) {
|
||||
image = std::move(image).convertToFormat(
|
||||
QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
image.setDevicePixelRatio(cRetinaFactor());
|
||||
if (Data::IsDefaultWallPaper(paper)
|
||||
|| Data::details::IsTestingDefaultWallPaper(paper)) {
|
||||
return DitherImage(std::move(image));
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
|
@ -530,7 +607,9 @@ ChatBackground::ChatBackground() : _adjustableColors({
|
|||
}
|
||||
|
||||
void ChatBackground::setThemeData(QImage &&themeImage, bool themeTile) {
|
||||
_themeImage = validateBackgroundImage(std::move(themeImage));
|
||||
_themeImage = PostprocessBackgroundImage(
|
||||
std::move(themeImage),
|
||||
Data::ThemeWallPaper());
|
||||
_themeTile = themeTile;
|
||||
}
|
||||
|
||||
|
@ -627,8 +706,12 @@ void ChatBackground::checkUploadWallPaper() {
|
|||
});
|
||||
}
|
||||
|
||||
QImage ChatBackground::postprocessBackgroundImage(QImage image) {
|
||||
return PostprocessBackgroundImage(std::move(image), _paper);
|
||||
}
|
||||
|
||||
void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
||||
image = ProcessBackgroundImage(std::move(image));
|
||||
image = PreprocessBackgroundImage(std::move(image));
|
||||
|
||||
const auto needResetAdjustable = Data::IsDefaultWallPaper(paper)
|
||||
&& !Data::IsDefaultWallPaper(_paper)
|
||||
|
@ -657,7 +740,7 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
|||
image.load(qsl(":/gui/art/background.jpg"));
|
||||
setPaper(Data::details::TestingDefaultWallPaper());
|
||||
}
|
||||
image = validateBackgroundImage(std::move(image));
|
||||
image = postprocessBackgroundImage(std::move(image));
|
||||
setPreparedImage(image, image);
|
||||
} else {
|
||||
if (Data::IsLegacy1DefaultWallPaper(_paper)) {
|
||||
|
@ -681,7 +764,7 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
|||
: image));
|
||||
if (const auto fill = _paper.backgroundColor()) {
|
||||
if (_paper.isPattern() && !image.isNull()) {
|
||||
auto prepared = validateBackgroundImage(
|
||||
auto prepared = postprocessBackgroundImage(
|
||||
Data::PreparePatternImage(
|
||||
image,
|
||||
*fill,
|
||||
|
@ -697,7 +780,7 @@ void ChatBackground::set(const Data::WallPaper &paper, QImage image) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
image = validateBackgroundImage(std::move(image));
|
||||
image = postprocessBackgroundImage(std::move(image));
|
||||
setPreparedImage(image, image);
|
||||
}
|
||||
}
|
||||
|
@ -1015,7 +1098,7 @@ void ChatBackground::keepApplied(const Object &object, bool write) {
|
|||
}
|
||||
} else if (Data::details::IsTestingThemeWallPaper(_paper)) {
|
||||
setPaper(Data::ThemeWallPaper());
|
||||
_themeImage = validateBackgroundImage(base::duplicate(_original));
|
||||
_themeImage = postprocessBackgroundImage(base::duplicate(_original));
|
||||
_themeTile = tile();
|
||||
if (write) {
|
||||
writeNewBackgroundSettings();
|
||||
|
@ -1403,7 +1486,7 @@ QColor AdjustedColor(QColor original, QColor background) {
|
|||
).toRgb();
|
||||
}
|
||||
|
||||
QImage ProcessBackgroundImage(QImage image) {
|
||||
QImage PreprocessBackgroundImage(QImage image) {
|
||||
constexpr auto kMaxSize = 2960;
|
||||
|
||||
if (image.format() != QImage::Format_ARGB32_Premultiplied) {
|
||||
|
|
|
@ -98,9 +98,9 @@ bool LoadFromContent(
|
|||
const QByteArray &content,
|
||||
not_null<Instance*> out,
|
||||
Cached *outCache);
|
||||
QColor CountAverageColor(const QImage &image);
|
||||
QColor AdjustedColor(QColor original, QColor background);
|
||||
QImage ProcessBackgroundImage(QImage image);
|
||||
[[nodiscard]] QColor CountAverageColor(const QImage &image);
|
||||
[[nodiscard]] QColor AdjustedColor(QColor original, QColor background);
|
||||
[[nodiscard]] QImage PreprocessBackgroundImage(QImage image);
|
||||
|
||||
struct BackgroundUpdate {
|
||||
enum class Type {
|
||||
|
@ -215,6 +215,7 @@ private:
|
|||
[[nodiscard]] bool isNonDefaultThemeOrBackground();
|
||||
[[nodiscard]] bool isNonDefaultBackground();
|
||||
void checkUploadWallPaper();
|
||||
[[nodiscard]] QImage postprocessBackgroundImage(QImage image);
|
||||
|
||||
friend bool IsNightMode();
|
||||
friend void SetNightModeValue(bool nightMode);
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 12429c198d9176e109af282d28198ef1bd143971
|
||||
Subproject commit 1ed242718ee2dd6363ff738acb9151e649500ed7
|
Loading…
Add table
Reference in a new issue