diff --git a/ui/image/image_prepare.cpp b/ui/image/image_prepare.cpp index f4c7408..d60194f 100644 --- a/ui/image/image_prepare.cpp +++ b/ui/image/image_prepare.cpp @@ -583,57 +583,58 @@ QImage BlurLargeImage(QImage image, int radius) { return image; } -[[nodiscard]] QImage DitherImage(QImage image) { - Expects(image.bytesPerLine() == image.width() * 4); +template // 4 means 16x16, 3 means 8x8 +[[nodiscard]] QImage DitherGeneric(const QImage &image) { + static_assert(kBits >= 1 && kBits <= 4); + + constexpr auto kSquareSide = (1 << kBits); + constexpr auto kShift = kSquareSide / 2; + constexpr auto kMask = (kSquareSide - 1); 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(area); bytes::set_random(bytes::make_span(shifts.get(), area)); - // shiftx = int(shift & 0x0F) - 8; shifty = int(shift >> 4) - 8; + // shiftx = int(shift & kMask) - kShift; + // shifty = int((shift >> 4) & kMask) - kShift; // Clamp shifts close to edges. - for (auto y = 0; y != 8; ++y) { - const auto min = 8 - y; + for (auto y = 0; y != kShift; ++y) { + const auto min = kShift - 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) { + if (((*shift >> 4) & kMask) < min) { *shift = shifted | (*shift & 0x0F); } } } - for (auto y = height - 7; y != height; ++y) { - const auto max = 8 + (height - y - 1); + for (auto y = height - (kShift - 1); y != height; ++y) { + const auto max = kShift + (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) { + if (((*shift >> 4) & kMask) > 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) { + ; shift += width - kShift) { + for (const auto till = shift + kShift; shift != till; ++shift) { const auto min = (till - shift); - if ((*shift & 0x0F) < min) { + if ((*shift & kMask) < 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 += width - (kShift - 1); + for (const auto till = shift + (kShift - 1); shift != till; ++shift) { + const auto max = kShift + (till - shift - 1); + if ((*shift & kMask) > max) { *shift = (*shift & 0xF0) | max; } } @@ -646,14 +647,33 @@ QImage BlurLargeImage(QImage image, int radius) { const auto dst = reinterpret_cast(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; + const auto shiftx = int(shift & kMask) - kShift; + const auto shifty = int((shift >> 4) & kMask) - kShift; dst[index] = src[index + (shifty * width) + shiftx]; } return result; } +[[nodiscard]] QImage DitherImage(QImage image) { + Expects(image.bytesPerLine() == image.width() * 4); + + const auto width = image.width(); + const auto height = image.height(); + const auto min = std::min(width, height); + const auto max = std::max(width, height); + if (max >= 1024 && min >= 512) { + return DitherGeneric<4>(image); + } else if (max >= 512 && min >= 256) { + return DitherGeneric<3>(image); + } else if (max >= 256 && min >= 128) { + return DitherGeneric<2>(image); + } else if (min >= 32) { + return DitherGeneric<1>(image); + } + return image; +} + void prepareCircle(QImage &img) { Assert(!img.isNull());