1
0
mirror of https://github.com/telegramdesktop/tdesktop synced 2025-04-11 04:01:18 +00:00

Refactor image transformation interfaces.

This commit is contained in:
John Preston 2022-01-21 15:31:39 +03:00
parent a9a6d8a568
commit 3ff17a8789
55 changed files with 546 additions and 789 deletions

View File

@ -252,12 +252,13 @@ void ConfirmInviteBox::paintEvent(QPaintEvent *e) {
if (_photo) { if (_photo) {
if (const auto image = _photo->image(Data::PhotoSize::Small)) { if (const auto image = _photo->image(Data::PhotoSize::Small)) {
const auto size = st::confirmInvitePhotoSize;
p.drawPixmap( p.drawPixmap(
(width() - st::confirmInvitePhotoSize) / 2, (width() - size) / 2,
st::confirmInvitePhotoTop, st::confirmInvitePhotoTop,
image->pixCircled( image->pix(
st::confirmInvitePhotoSize, { size, size },
st::confirmInvitePhotoSize)); { .options = Images::Option::RoundCircle }));
} }
} else if (_photoEmpty) { } else if (_photoEmpty) {
_photoEmpty->paint( _photoEmpty->paint(

View File

@ -321,15 +321,11 @@ bool ServiceCheck::checkRippleStartPosition(QPoint position) const {
const auto takeHeight = (width > height) const auto takeHeight = (width > height)
? size ? size
: (height * size / width); : (height * size / width);
return Images::prepare( const auto ratio = style::DevicePixelRatio();
image, return Images::Prepare(image, QSize(takeWidth, takeHeight) * ratio, {
takeWidth * cIntRetinaFactor(), .options = Images::Option::TransparentBackground | blur,
takeHeight * cIntRetinaFactor(), .outer = { size, size },
Images::Option::Smooth });
| Images::Option::TransparentBackground
| blur,
size,
size);
} }
[[nodiscard]] QImage PrepareScaledFromFull( [[nodiscard]] QImage PrepareScaledFromFull(
@ -667,7 +663,7 @@ void BackgroundPreviewBox::setScaledFromThumb() {
_paper.backgroundColors(), _paper.backgroundColors(),
_paper.gradientRotation(), _paper.gradientRotation(),
_paper.patternOpacity(), _paper.patternOpacity(),
_paper.document() ? Images::Option::Blurred : Images::Option(0)); _paper.document() ? Images::Option::Blur : Images::Option());
auto blurred = (_paper.document() || _paper.isPattern()) auto blurred = (_paper.document() || _paper.isPattern())
? QImage() ? QImage()
: PrepareScaledNonPattern( : PrepareScaledNonPattern(

View File

@ -183,11 +183,10 @@ void PeerShortInfoCover::paint(QPainter &p) {
_widget->size() * style::DevicePixelRatio(), _widget->size() * style::DevicePixelRatio(),
QImage::Format_ARGB32_Premultiplied); QImage::Format_ARGB32_Premultiplied);
image.fill(Qt::black); image.fill(Qt::black);
Images::prepareRound( _userpicImage = Images::Round(
image, std::move(image),
ImageRoundRadius::Small, ImageRoundRadius::Small,
RectPart::TopLeft | RectPart::TopRight); RectPart::TopLeft | RectPart::TopRight);
_userpicImage = std::move(image);
} }
paintCoverImage(p, frame.isNull() ? _userpicImage : frame); paintCoverImage(p, frame.isNull() ? _userpicImage : frame);
@ -229,8 +228,8 @@ void PeerShortInfoCover::paintCoverImage(QPainter &p, const QImage &image) {
image, image,
QRect(0, from * factor, roundedWidth * factor, rounded * factor)); QRect(0, from * factor, roundedWidth * factor, rounded * factor));
q.end(); q.end();
Images::prepareRound( _roundedTopImage = Images::Round(
_roundedTopImage, std::move(_roundedTopImage),
ImageRoundRadius::Small, ImageRoundRadius::Small,
RectPart::TopLeft | RectPart::TopRight); RectPart::TopLeft | RectPart::TopRight);
p.drawImage( p.drawImage(
@ -244,9 +243,8 @@ void PeerShortInfoCover::paintBars(QPainter &p) {
const auto factor = style::DevicePixelRatio(); const auto factor = style::DevicePixelRatio();
if (_shadowTop.isNull()) { if (_shadowTop.isNull()) {
_shadowTop = Images::GenerateShadow(height, kShadowMaxAlpha, 0); _shadowTop = Images::GenerateShadow(height, kShadowMaxAlpha, 0);
_shadowTop = _shadowTop.scaled(QSize(_st.size, height) * factor); _shadowTop = Images::Round(
Images::prepareRound( _shadowTop.scaled(QSize(_st.size, height) * factor),
_shadowTop,
ImageRoundRadius::Small, ImageRoundRadius::Small,
RectPart::TopLeft | RectPart::TopRight); RectPart::TopLeft | RectPart::TopRight);
} }
@ -771,8 +769,8 @@ int PeerShortInfoBox::fillRoundedTopHeight() {
void PeerShortInfoBox::refreshRoundedTopImage(const QColor &color) { void PeerShortInfoBox::refreshRoundedTopImage(const QColor &color) {
_roundedTopColor = color; _roundedTopColor = color;
_roundedTop.fill(color); _roundedTop.fill(color);
Images::prepareRound( _roundedTop = Images::Round(
_roundedTop, std::move(_roundedTop),
ImageRoundRadius::Small, ImageRoundRadius::Small,
RectPart::TopLeft | RectPart::TopRight); RectPart::TopLeft | RectPart::TopRight);
} }

View File

@ -51,19 +51,15 @@ void GenerateImage(
bool blurred = false) { bool blurred = false) {
using namespace Images; using namespace Images;
const auto size = st::shortInfoWidth; const auto size = st::shortInfoWidth;
const auto factor = style::DevicePixelRatio(); const auto ratio = style::DevicePixelRatio();
const auto options = Option::Smooth const auto options = Option::RoundSmall
| Option::RoundedSmall | Option::RoundSkipBottomLeft
| Option::RoundedTopLeft | Option::RoundSkipBottomRight
| Option::RoundedTopRight | (blurred ? Option::Blur : Option());
| (blurred ? Option::Blurred : Option()); state->current.photo = Images::Prepare(
state->current.photo = Images::prepare(
std::move(image), std::move(image),
size * factor, QSize(size, size) * ratio,
size * factor, { .options = options, .outer = { size, size } });
options,
size,
size);
} }
void GenerateImage( void GenerateImage(

View File

@ -165,8 +165,12 @@ void Userpic::refreshPhoto() {
void Userpic::createCache(Image *image) { void Userpic::createCache(Image *image) {
const auto size = this->size(); const auto size = this->size();
const auto real = size * cIntRetinaFactor(); const auto real = size * cIntRetinaFactor();
auto options = Images::Option::Smooth | Images::Option::Circled; auto options = Images::Option() | Images::Option::RoundCircle;
// _useTransparency ? (Images::Option::RoundedLarge | Images::Option::RoundedTopLeft | Images::Option::RoundedTopRight | Images::Option::Smooth) : Images::Option::None; //_useTransparency
// ? (Images::Option::RoundLarge
// | Images::Option::RoundSkipBottomLeft
// | Images::Option::RoundSkipBottomRight)
// : Images::Option::None;
if (image) { if (image) {
auto width = image->width(); auto width = image->width();
auto height = image->height(); auto height = image->height();
@ -178,14 +182,16 @@ void Userpic::createCache(Image *image) {
width = real; width = real;
} }
_userPhoto = image->pixNoCache( _userPhoto = image->pixNoCache(
width, { width, height },
height, {
options, .options = Images::Option::RoundCircle,
size, .outer = { size, size },
size); });
_userPhoto.setDevicePixelRatio(cRetinaFactor()); _userPhoto.setDevicePixelRatio(cRetinaFactor());
} else { } else {
auto filled = QImage(QSize(real, real), QImage::Format_ARGB32_Premultiplied); auto filled = QImage(
QSize(real, real),
QImage::Format_ARGB32_Premultiplied);
filled.setDevicePixelRatio(cRetinaFactor()); filled.setDevicePixelRatio(cRetinaFactor());
filled.fill(Qt::transparent); filled.fill(Qt::transparent);
{ {
@ -195,7 +201,10 @@ void Userpic::createCache(Image *image) {
_peer->name _peer->name
).paint(p, 0, 0, size, size); ).paint(p, 0, 0, size, size);
} }
//Images::prepareRound(filled, ImageRoundRadius::Large, RectPart::TopLeft | RectPart::TopRight); //_userPhoto = Images::PixmapFast(Images::Round(
// std::move(filled),
// ImageRoundRadius::Large,
// RectPart::TopLeft | RectPart::TopRight));
_userPhoto = Images::PixmapFast(std::move(filled)); _userPhoto = Images::PixmapFast(std::move(filled));
} }

View File

@ -169,12 +169,12 @@ void VideoBubble::prepareFrame() {
for (; from != till; from += fromPerLine, to += toPerLine) { for (; from != till; from += fromPerLine, to += toPerLine) {
memcpy(to, from, lineSize); memcpy(to, from, lineSize);
} }
Images::prepareRound( _frame = Images::Round(
_frame, std::move(_frame),
ImageRoundRadius::Large, ImageRoundRadius::Large,
RectPart::AllCorners, RectPart::AllCorners,
QRect(QPoint(), size)); QRect(QPoint(), size)
_frame = std::move(_frame).mirrored(true, false); ).mirrored(true, false);
} }
void VideoBubble::setState(Webrtc::VideoState state) { void VideoBubble::setState(Webrtc::VideoState state) {

View File

@ -1966,12 +1966,7 @@ void StickersListWidget::paintSticker(Painter &p, Set &set, int y, int section,
const auto pixmap = !sticker.savedFrame.isNull() const auto pixmap = !sticker.savedFrame.isNull()
? sticker.savedFrame ? sticker.savedFrame
: image : image
? image->pixSingle( ? image->pixSingle(w, h, { .outer = { w, h } })
w,
h,
w,
h,
ImageRoundRadius::None)
: QPixmap(); : QPixmap();
if (!pixmap.isNull()) { if (!pixmap.isNull()) {
p.drawPixmapLeft(ppos, width(), pixmap); p.drawPixmapLeft(ppos, width(), pixmap);

View File

@ -128,9 +128,9 @@ using ItemPreviewImage = HistoryView::ItemPreviewImage;
Images::CornersMask(pxRadius)).first->second; Images::CornersMask(pxRadius)).first->second;
} }
} }
Images::prepareRound(square, *cache.lastUsed); square = Images::Round(std::move(square), *cache.lastUsed);
} else { } else {
Images::prepareRound(square, radius); square = Images::Round(std::move(square), radius);
} }
square.setDevicePixelRatio(factor); square.setDevicePixelRatio(factor);
return square; return square;

View File

@ -320,7 +320,11 @@ void PeerData::paintUserpic(
int y, int y,
int size) const { int size) const {
if (const auto userpic = currentUserpic(view)) { if (const auto userpic = currentUserpic(view)) {
p.drawPixmap(x, y, userpic->pixCircled(size, size)); const auto circled = Images::Option::RoundCircle;
p.drawPixmap(
x,
y,
userpic->pix(size, size, { .options = circled }));
} else { } else {
ensureEmptyUserpic()->paint(p, x, y, x + size + x, size); ensureEmptyUserpic()->paint(p, x, y, x + size + x, size);
} }
@ -380,10 +384,14 @@ QPixmap PeerData::genUserpic(
std::shared_ptr<Data::CloudImageView> &view, std::shared_ptr<Data::CloudImageView> &view,
int size) const { int size) const {
if (const auto userpic = currentUserpic(view)) { if (const auto userpic = currentUserpic(view)) {
return userpic->pixCircled(size, size); const auto circle = Images::Option::RoundCircle;
return userpic->pix(size, size, { .options = circle });
} }
auto result = QImage(QSize(size, size) * cIntRetinaFactor(), QImage::Format_ARGB32_Premultiplied); const auto ratio = style::DevicePixelRatio();
result.setDevicePixelRatio(cRetinaFactor()); auto result = QImage(
QSize(size, size) * ratio,
QImage::Format_ARGB32_Premultiplied);
result.setDevicePixelRatio(ratio);
result.fill(Qt::transparent); result.fill(Qt::transparent);
{ {
Painter p(&result); Painter p(&result);
@ -404,15 +412,13 @@ QImage PeerData::generateUserpicImage(
ImageRoundRadius radius) const { ImageRoundRadius radius) const {
if (const auto userpic = currentUserpic(view)) { if (const auto userpic = currentUserpic(view)) {
const auto options = (radius == ImageRoundRadius::Ellipse) const auto options = (radius == ImageRoundRadius::Ellipse)
? (Images::Option::RoundedAll | Images::Option::Circled) ? Images::Option::RoundCircle
: (radius == ImageRoundRadius::None) : (radius == ImageRoundRadius::None)
? Images::Options() ? Images::Option()
: (Images::Option::RoundedAll | Images::Option::RoundedSmall); : Images::Option::RoundSmall;
return userpic->pixNoCache( return userpic->pixNoCache(
size, { size, size },
size, { .options = options }).toImage();
Images::Option::Smooth | options
).toImage();
} }
auto result = QImage( auto result = QImage(
QSize(size, size), QSize(size, size),

View File

@ -36,7 +36,7 @@ using Data::kPhotoSizeCount;
const Data::CloudFile &file) { const Data::CloudFile &file) {
return (v::is<WebFileLocation>(file.location.file().data) return (v::is<WebFileLocation>(file.location.file().data)
&& image.format() == QImage::Format_ARGB32) && image.format() == QImage::Format_ARGB32)
? Images::prepareOpaque(std::move(image)) ? Images::Opaque(std::move(image))
: image; : image;
} }

View File

@ -41,18 +41,13 @@ void ReplyPreview::prepare(not_null<Image*> image, Images::Options options) {
st::msgReplyBarSize.height(), st::msgReplyBarSize.height(),
h * st::msgReplyBarSize.height() / w); h * st::msgReplyBarSize.height() / w);
thumbSize *= cIntRetinaFactor(); thumbSize *= cIntRetinaFactor();
const auto prepareOptions = Images::Option::Smooth options |= Images::Option::TransparentBackground;
| Images::Option::TransparentBackground
| options;
auto outerSize = st::msgReplyBarSize.height(); auto outerSize = st::msgReplyBarSize.height();
auto bitmap = image->pixNoCache( auto bitmap = image->pixNoCache(
thumbSize.width(), thumbSize,
thumbSize.height(), { .options = options, .outer = { outerSize, outerSize } });
prepareOptions,
outerSize,
outerSize);
_image = std::make_unique<Image>(bitmap.toImage()); _image = std::make_unique<Image>(bitmap.toImage());
_good = ((options & Images::Option::Blurred) == 0); _good = ((options & Images::Option::Blur) == 0);
} }
Image *ReplyPreview::image( Image *ReplyPreview::image(
@ -69,13 +64,13 @@ Image *ReplyPreview::image(
} }
const auto thumbnail = _documentMedia->thumbnail(); const auto thumbnail = _documentMedia->thumbnail();
const auto option = _document->isVideoMessage() const auto option = _document->isVideoMessage()
? Images::Option::Circled ? Images::Option::RoundCircle
: Images::Option::None; : Images::Option::None;
if (thumbnail) { if (thumbnail) {
prepare(thumbnail, option); prepare(thumbnail, option);
} else if (!_image) { } else if (!_image) {
if (const auto image = _documentMedia->thumbnailInline()) { if (const auto image = _documentMedia->thumbnailInline()) {
prepare(image, option | Images::Option::Blurred); prepare(image, option | Images::Option::Blur);
} }
} }
if (_good || !_document->hasThumbnail()) { if (_good || !_document->hasThumbnail()) {
@ -102,7 +97,7 @@ Image *ReplyPreview::image(
prepare(large, Images::Option(0)); prepare(large, Images::Option(0));
} else if (!_image) { } else if (!_image) {
if (const auto blurred = _photoMedia->thumbnailInline()) { if (const auto blurred = _photoMedia->thumbnailInline()) {
prepare(blurred, Images::Option::Blurred); prepare(blurred, Images::Option::Blur);
} }
} }
if (_good) { if (_good) {

View File

@ -90,9 +90,7 @@ PhotoEditorContent::PhotoEditorContent(
p.setTransform(_imageMatrix); p.setTransform(_imageMatrix);
p.drawPixmap( p.drawPixmap(_imageRect, _photo->pix(_imageRect.size()));
_imageRect,
_photo->pix(_imageRect.width(), _imageRect.height()));
}, lifetime()); }, lifetime());
setupDragArea(); setupDragArea();

View File

@ -90,12 +90,10 @@ QImage EdgeButton::rounded(std::optional<QColor> color) const {
result.setDevicePixelRatio(cIntRetinaFactor()); result.setDevicePixelRatio(cIntRetinaFactor());
result.fill(color.value_or(Qt::white)); result.fill(color.value_or(Qt::white));
using Option = Images::Option; const auto parts = RectPart::None
const auto options = Option::Smooth | (_left ? RectPart::TopLeft : RectPart::TopRight)
| Option::RoundedLarge | (_left ? RectPart::BottomLeft : RectPart::BottomRight);
| (_left ? Option::RoundedTopLeft : Option::RoundedTopRight) return Images::Round(std::move(result), ImageRoundRadius::Large, parts);
| (_left ? Option::RoundedBottomLeft : Option::RoundedBottomRight);
return Images::prepare(std::move(result), 0, 0, options, 0, 0);
} }
QImage EdgeButton::prepareRippleMask() const { QImage EdgeButton::prepareRippleMask() const {
@ -151,10 +149,9 @@ ButtonBar::ButtonBar(
result.setDevicePixelRatio(cIntRetinaFactor()); result.setDevicePixelRatio(cIntRetinaFactor());
result.fill(bg->c); result.fill(bg->c);
const auto options = Images::Option::Smooth _roundedBg = Images::Round(
| Images::Option::RoundedLarge std::move(result),
| Images::Option::RoundedAll; ImageRoundRadius::Large);
_roundedBg = Images::prepare(std::move(result), 0, 0, options, 0, 0);
}, lifetime()); }, lifetime());
paintRequest( paintRequest(

View File

@ -59,11 +59,9 @@ ItemSticker::ItemSticker(
if (!sticker) { if (!sticker) {
return false; return false;
} }
auto pixmap = sticker->pixNoCache( const auto ratio = style::DevicePixelRatio();
sticker->width() * cIntRetinaFactor(), auto pixmap = sticker->pixNoCache(sticker->size() * ratio);
sticker->height() * cIntRetinaFactor(), pixmap.setDevicePixelRatio(ratio);
Images::Option::Smooth);
pixmap.setDevicePixelRatio(cRetinaFactor());
updatePixmap(std::move(pixmap)); updatePixmap(std::move(pixmap));
return true; return true;
}; };

View File

@ -342,16 +342,15 @@ void HistoryMessageReply::paint(
if (hasPreview) { if (hasPreview) {
if (const auto image = replyToMsg->media()->replyPreview()) { if (const auto image = replyToMsg->media()->replyPreview()) {
auto to = style::rtlrect(x + st::msgReplyBarSkip, y + st::msgReplyPadding.top() + st::msgReplyBarPos.y(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height(), w + 2 * x); auto to = style::rtlrect(x + st::msgReplyBarSkip, y + st::msgReplyPadding.top() + st::msgReplyBarPos.y(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height(), w + 2 * x);
auto previewWidth = image->width() / cIntRetinaFactor(); const auto preview = image->pixSingle(
auto previewHeight = image->height() / cIntRetinaFactor(); image->size() / style::DevicePixelRatio(),
auto preview = image->pixSingle( {
previewWidth, .colored = (context.selected()
previewHeight, ? &st->msgStickerOverlay()
to.width(), : nullptr),
to.height(), .options = Images::Option::RoundSmall,
ImageRoundRadius::Small, .outer = to.size(),
RectPart::AllCorners, });
context.selected() ? &st->msgStickerOverlay() : nullptr);
p.drawPixmap(to.x(), to.y(), preview); p.drawPixmap(to.x(), to.y(), preview);
} }
} }

View File

@ -7139,7 +7139,12 @@ void HistoryWidget::drawField(Painter &p, const QRect &rect) {
if (drawMsgText->media() && drawMsgText->media()->hasReplyPreview()) { if (drawMsgText->media() && drawMsgText->media()->hasReplyPreview()) {
if (const auto image = drawMsgText->media()->replyPreview()) { if (const auto image = drawMsgText->media()->replyPreview()) {
auto to = QRect(replyLeft, backy + st::msgReplyPadding.top(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height()); auto to = QRect(replyLeft, backy + st::msgReplyPadding.top(), st::msgReplyBarSize.height(), st::msgReplyBarSize.height());
p.drawPixmap(to.x(), to.y(), image->pixSingle(image->width() / cIntRetinaFactor(), image->height() / cIntRetinaFactor(), to.width(), to.height(), ImageRoundRadius::Small)); p.drawPixmap(to.x(), to.y(), image->pixSingle(
image->size() / style::DevicePixelRatio(),
{
.options = Images::Option::RoundSmall,
.outer = to.size(),
}));
} }
replyLeft += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x(); replyLeft += st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x();
} }

View File

@ -1144,8 +1144,7 @@ Manager::OverlayImage Manager::validateOverlayShadow(
p.end(); p.end();
} }
_overlayShadowScaled = Images::prepareBlur( _overlayShadowScaled = Images::Blur(std::move(_overlayShadowScaled));
std::move(_overlayShadowScaled));
auto q = Painter(result.cache); auto q = Painter(result.cache);
if (result.cache != &_overlayShadowScaled) { if (result.cache != &_overlayShadowScaled) {
@ -1436,7 +1435,7 @@ QRect Manager::validateShadow(
} }
p.drawRoundedRect(big.translated(0, shift), radius, radius); p.drawRoundedRect(big.translated(0, shift), radius, radius);
p.end(); p.end();
_shadowBuffer = Images::prepareBlur(std::move(_shadowBuffer)); _shadowBuffer = Images::Blur(std::move(_shadowBuffer));
auto q = QPainter(&_cacheParts); auto q = QPainter(&_cacheParts);
q.setCompositionMode(QPainter::CompositionMode_Source); q.setCompositionMode(QPainter::CompositionMode_Source);

View File

@ -356,13 +356,18 @@ void Document::draw(
const auto inner = QRect(rthumb.x() + (rthumb.width() - innerSize) / 2, rthumb.y() + (rthumb.height() - innerSize) / 2, innerSize, innerSize); const auto inner = QRect(rthumb.x() + (rthumb.width() - innerSize) / 2, rthumb.y() + (rthumb.height() - innerSize) / 2, innerSize, innerSize);
const auto radialOpacity = radial ? _animation->radial.opacity() : 1.; const auto radialOpacity = radial ? _animation->radial.opacity() : 1.;
if (thumbed) { if (thumbed) {
auto inWebPage = (_parent->media() != this); const auto inWebPage = (_parent->media() != this);
auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large; const auto args = Images::PrepareArgs{
.options = (inWebPage
? Images::Option::RoundSmall
: Images::Option::RoundLarge),
.outer = QSize(st.thumbSize, st.thumbSize),
};
QPixmap thumb; QPixmap thumb;
if (const auto normal = _dataMedia->thumbnail()) { if (const auto normal = _dataMedia->thumbnail()) {
thumb = normal->pixSingle(thumbed->_thumbw, 0, st.thumbSize, st.thumbSize, roundRadius); thumb = normal->pixSingle(thumbed->_thumbw, args);
} else if (const auto blurred = _dataMedia->thumbnailInline()) { } else if (const auto blurred = _dataMedia->thumbnailInline()) {
thumb = blurred->pixBlurredSingle(thumbed->_thumbw, 0, st.thumbSize, st.thumbSize, roundRadius); thumb = blurred->pixSingle(thumbed->_thumbw, args.blurred());
} }
p.drawPixmap(rthumb.topLeft(), thumb); p.drawPixmap(rthumb.topLeft(), thumb);
if (context.selected()) { if (context.selected()) {
@ -1090,32 +1095,27 @@ bool DrawThumbnailAsSongCover(
return false; return false;
} }
QPixmap cover; auto cover = QPixmap();
const auto scaled = [&](not_null<Image*> image) {
const auto ow = rect.width(); const auto aspectRatio = Qt::KeepAspectRatioByExpanding;
const auto oh = rect.height(); return image->size().scaled(rect.size(), aspectRatio);
const auto r = ImageRoundRadius::Ellipse; };
const auto c = RectPart::AllCorners; const auto args = Images::PrepareArgs{
const auto aspectRatio = Qt::KeepAspectRatioByExpanding; .colored = &colored,
.options = Images::Option::RoundCircle,
const auto scaled = [&](not_null<Image*> image) -> std::pair<int, int> { .outer = rect.size(),
const auto size = image->size().scaled(ow, oh, aspectRatio);
return { size.width(), size.height() };
}; };
if (const auto normal = dataMedia->thumbnail()) { if (const auto normal = dataMedia->thumbnail()) {
const auto &[w, h] = scaled(normal); cover = normal->pixSingle(scaled(normal), args);
cover = normal->pixSingle(w, h, ow, oh, r, c, &colored);
} else if (const auto blurred = dataMedia->thumbnailInline()) { } else if (const auto blurred = dataMedia->thumbnailInline()) {
const auto &[w, h] = scaled(blurred); cover = blurred->pixSingle(scaled(blurred), args.blurred());
cover = blurred->pixBlurredSingle(w, h, ow, oh, r, c, &colored);
} else { } else {
return false; return false;
} }
if (selected) { if (selected) {
auto selectedCover = Images::prepareColored( auto selectedCover = Images::Colored(
p.textPalette().selectOverlay, cover.toImage(),
cover.toImage()); p.textPalette().selectOverlay);
cover = QPixmap::fromImage( cover = QPixmap::fromImage(
std::move(selectedCover), std::move(selectedCover),
Qt::ColorOnly); Qt::ColorOnly);

View File

@ -439,24 +439,28 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
} }
} else { } else {
ensureDataMediaCreated(); ensureDataMediaCreated();
const auto size = QSize(_thumbw, _thumbh);
const auto args = Images::PrepareArgs{
.options = Images::RoundOptions(roundRadius, roundCorners),
.outer = QSize(usew, painth),
};
if (const auto good = _dataMedia->goodThumbnail()) { if (const auto good = _dataMedia->goodThumbnail()) {
p.drawPixmap(rthumb.topLeft(), good->pixSingle(_thumbw, _thumbh, usew, painth, roundRadius, roundCorners)); p.drawPixmap(rthumb.topLeft(), good->pixSingle(size, args));
} else { } else {
const auto normal = _dataMedia->thumbnail(); const auto normal = _dataMedia->thumbnail();
if (normal) { if (normal) {
if (normal->width() >= kUseNonBlurredThreshold const auto blurred = (normal->width() < kUseNonBlurredThreshold)
|| normal->height() >= kUseNonBlurredThreshold) { || (normal->height() < kUseNonBlurredThreshold);
p.drawPixmap(rthumb.topLeft(), normal->pixSingle(_thumbw, _thumbh, usew, painth, roundRadius, roundCorners)); p.drawPixmap(
} else { rthumb.topLeft(),
p.drawPixmap(rthumb.topLeft(), normal->pixBlurredSingle(_thumbw, _thumbh, usew, painth, roundRadius, roundCorners)); normal->pixSingle(size, blurred ? args.blurred() : args));
}
} else { } else {
_data->loadThumbnail(_realParent->fullId()); _data->loadThumbnail(_realParent->fullId());
validateVideoThumbnail(); validateVideoThumbnail();
if (_videoThumbnailFrame) { if (_videoThumbnailFrame) {
p.drawPixmap(rthumb.topLeft(), _videoThumbnailFrame->pixSingle(_thumbw, _thumbh, usew, painth, roundRadius, roundCorners)); p.drawPixmap(rthumb.topLeft(), _videoThumbnailFrame->pixSingle(size, args));
} else if (const auto blurred = _dataMedia->thumbnailInline()) { } else if (const auto blurred = _dataMedia->thumbnailInline()) {
p.drawPixmap(rthumb.topLeft(), blurred->pixBlurredSingle(_thumbw, _thumbh, usew, painth, roundRadius, roundCorners)); p.drawPixmap(rthumb.topLeft(), blurred->pixSingle(size, args.blurred()));
} else if (!isRound) { } else if (!isRound) {
const auto roundTop = (roundCorners & RectPart::TopLeft); const auto roundTop = (roundCorners & RectPart::TopLeft);
const auto roundBottom = (roundCorners & RectPart::BottomLeft); const auto roundBottom = (roundCorners & RectPart::BottomLeft);
@ -1291,13 +1295,15 @@ void Gif::validateGroupedCache(
const auto loadLevel = good ? 3 : thumb ? 2 : image ? 1 : 0; const auto loadLevel = good ? 3 : thumb ? 2 : image ? 1 : 0;
const auto width = geometry.width(); const auto width = geometry.width();
const auto height = geometry.height(); const auto height = geometry.height();
const auto options = Option::Smooth const auto corner = [&](RectPart part, Option skip) {
| Option::RoundedLarge return !(corners & part) ? skip : Option();
| (blur ? Option::Blurred : Option(0)) };
| ((corners & RectPart::TopLeft) ? Option::RoundedTopLeft : Option::None) const auto options = Option::RoundLarge
| ((corners & RectPart::TopRight) ? Option::RoundedTopRight : Option::None) | (blur ? Option::Blur : Option(0))
| ((corners & RectPart::BottomLeft) ? Option::RoundedBottomLeft : Option::None) | corner(RectPart::TopLeft, Option::RoundSkipTopLeft)
| ((corners & RectPart::BottomRight) ? Option::RoundedBottomRight : Option::None); | corner(RectPart::TopRight, Option::RoundSkipTopRight)
| corner(RectPart::BottomLeft, Option::RoundSkipBottomLeft)
| corner(RectPart::BottomRight, Option::RoundSkipBottomRight);
const auto key = (uint64(width) << 48) const auto key = (uint64(width) << 48)
| (uint64(height) << 32) | (uint64(height) << 32)
| (uint64(options) << 16) | (uint64(options) << 16)
@ -1312,16 +1318,12 @@ void Gif::validateGroupedCache(
const auto pixSize = Ui::GetImageScaleSizeForGeometry( const auto pixSize = Ui::GetImageScaleSizeForGeometry(
{ originalWidth, originalHeight }, { originalWidth, originalHeight },
{ width, height }); { width, height });
const auto pixWidth = pixSize.width() * cIntRetinaFactor(); const auto ratio = style::DevicePixelRatio();
const auto pixHeight = pixSize.height() * cIntRetinaFactor();
*cacheKey = key; *cacheKey = key;
*cache = (image ? image : Image::BlankMedia().get())->pixNoCache( *cache = (image ? image : Image::BlankMedia().get())->pixNoCache(
pixWidth, pixSize * ratio,
pixHeight, { .options = options, .outer = { width, height } });
options,
width,
height);
} }
void Gif::setStatusSize(int newSize) const { void Gif::setStatusSize(int newSize) const {

View File

@ -77,17 +77,15 @@ void LargeEmoji::draw(
const auto skip = st::largeEmojiSkip - 2 * st::largeEmojiOutline; const auto skip = st::largeEmojiSkip - 2 * st::largeEmojiOutline;
const auto size = EmojiImage::Size() / cIntRetinaFactor(); const auto size = EmojiImage::Size() / cIntRetinaFactor();
for (const auto &image : images) { for (const auto &image : images) {
const auto w = size.width();
if (const auto &prepared = image->image) { if (const auto &prepared = image->image) {
const auto h = size.height(); const auto colored = context.selected()
const auto pixmap = context.selected() ? &context.st->msgStickerOverlay()
? prepared->pixColored(context.st->msgStickerOverlay(), w, h) : nullptr;
: prepared->pix(w, h); p.drawPixmap(x, y, prepared->pix(size, { .colored = colored }));
p.drawPixmap(x, y, pixmap);
} else if (image->load) { } else if (image->load) {
image->load(); image->load();
} }
x += w + skip; x += size.width() + skip;
} }
} }

View File

@ -194,8 +194,12 @@ void Location::draw(Painter &p, const PaintContext &context) const {
auto rthumb = QRect(paintx, painty, paintw, painth); auto rthumb = QRect(paintx, painty, paintw, painth);
ensureMediaCreated(); ensureMediaCreated();
if (const auto thumbnail = _media->image()) { if (const auto thumbnail = _media->image()) {
const auto &pix = thumbnail->pixSingle(paintw, painth, paintw, painth, roundRadius, roundCorners); p.drawPixmap(rthumb.topLeft(), thumbnail->pixSingle(
p.drawPixmap(rthumb.topLeft(), pix); rthumb.size(),
{
.options = Images::RoundOptions(roundRadius, roundCorners),
.outer = rthumb.size(),
}));
} else { } else {
Ui::FillComplexLocationRect(p, st, rthumb, roundRadius, roundCorners); Ui::FillComplexLocationRect(p, st, rthumb, roundRadius, roundCorners);
} }

View File

@ -265,21 +265,28 @@ void Photo::draw(Painter &p, const PaintContext &context) const {
} else { } else {
Ui::FillRoundShadow(p, 0, 0, paintw, painth, sti->msgShadow, sti->msgShadowCorners); Ui::FillRoundShadow(p, 0, 0, paintw, painth, sti->msgShadow, sti->msgShadowCorners);
} }
auto inWebPage = (_parent->media() != this); const auto inWebPage = (_parent->media() != this);
auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large; const auto roundRadius = inWebPage
auto roundCorners = inWebPage ? RectPart::AllCorners : ((isBubbleTop() ? (RectPart::TopLeft | RectPart::TopRight) : RectPart::None) ? ImageRoundRadius::Small
: ImageRoundRadius::Large;
const auto roundCorners = inWebPage ? RectPart::AllCorners : ((isBubbleTop() ? (RectPart::TopLeft | RectPart::TopRight) : RectPart::None)
| ((isRoundedInBubbleBottom() && _caption.isEmpty()) ? (RectPart::BottomLeft | RectPart::BottomRight) : RectPart::None)); | ((isRoundedInBubbleBottom() && _caption.isEmpty()) ? (RectPart::BottomLeft | RectPart::BottomRight) : RectPart::None));
const auto pix = [&] { const auto pix = [&] {
const auto size = QSize(_pixw, _pixh);
const auto args = Images::PrepareArgs{
.options = Images::RoundOptions(roundRadius, roundCorners),
.outer = QSize(paintw, painth),
};
if (const auto large = _dataMedia->image(PhotoSize::Large)) { if (const auto large = _dataMedia->image(PhotoSize::Large)) {
return large->pixSingle(_pixw, _pixh, paintw, painth, roundRadius, roundCorners); return large->pixSingle(size, args);
} else if (const auto thumbnail = _dataMedia->image( } else if (const auto thumbnail = _dataMedia->image(
PhotoSize::Thumbnail)) { PhotoSize::Thumbnail)) {
return thumbnail->pixBlurredSingle(_pixw, _pixh, paintw, painth, roundRadius, roundCorners); return thumbnail->pixSingle(size, args.blurred());
} else if (const auto small = _dataMedia->image( } else if (const auto small = _dataMedia->image(
PhotoSize::Small)) { PhotoSize::Small)) {
return small->pixBlurredSingle(_pixw, _pixh, paintw, painth, roundRadius, roundCorners); return small->pixSingle(size, args.blurred());
} else if (const auto blurred = _dataMedia->thumbnailInline()) { } else if (const auto blurred = _dataMedia->thumbnailInline()) {
return blurred->pixBlurredSingle(_pixw, _pixh, paintw, painth, roundRadius, roundCorners); return blurred->pixSingle(size, args.blurred());
} else { } else {
return QPixmap(); return QPixmap();
} }
@ -389,16 +396,20 @@ void Photo::paintUserpicFrame(
return; return;
} }
const auto pix = [&] { const auto pix = [&] {
const auto size = QSize(_pixw, _pixh);
const auto args = Images::PrepareArgs{
.options = Images::Option::RoundCircle,
};
if (const auto large = _dataMedia->image(PhotoSize::Large)) { if (const auto large = _dataMedia->image(PhotoSize::Large)) {
return large->pixCircled(_pixw, _pixh); return large->pix(size, args);
} else if (const auto thumbnail = _dataMedia->image( } else if (const auto thumbnail = _dataMedia->image(
PhotoSize::Thumbnail)) { PhotoSize::Thumbnail)) {
return thumbnail->pixBlurredCircled(_pixw, _pixh); return thumbnail->pix(size, args.blurred());
} else if (const auto small = _dataMedia->image( } else if (const auto small = _dataMedia->image(
PhotoSize::Small)) { PhotoSize::Small)) {
return small->pixBlurredCircled(_pixw, _pixh); return small->pix(size, args.blurred());
} else if (const auto blurred = _dataMedia->thumbnailInline()) { } else if (const auto blurred = _dataMedia->thumbnailInline()) {
return blurred->pixBlurredCircled(_pixw, _pixh); return blurred->pix(size, args.blurred());
} else { } else {
return QPixmap(); return QPixmap();
} }
@ -652,13 +663,15 @@ void Photo::validateGroupedCache(
: 0; : 0;
const auto width = geometry.width(); const auto width = geometry.width();
const auto height = geometry.height(); const auto height = geometry.height();
const auto options = Option::Smooth const auto corner = [&](RectPart part, Option skip) {
| Option::RoundedLarge return !(corners & part) ? skip : Option();
| (loaded ? Option::None : Option::Blurred) };
| ((corners & RectPart::TopLeft) ? Option::RoundedTopLeft : Option::None) const auto options = Option::RoundLarge
| ((corners & RectPart::TopRight) ? Option::RoundedTopRight : Option::None) | (loaded ? Option() : Option::Blur)
| ((corners & RectPart::BottomLeft) ? Option::RoundedBottomLeft : Option::None) | corner(RectPart::TopLeft, Option::RoundSkipTopLeft)
| ((corners & RectPart::BottomRight) ? Option::RoundedBottomRight : Option::None); | corner(RectPart::TopRight, Option::RoundSkipTopRight)
| corner(RectPart::BottomLeft, Option::RoundSkipBottomLeft)
| corner(RectPart::BottomRight, Option::RoundSkipBottomRight);
const auto key = (uint64(width) << 48) const auto key = (uint64(width) << 48)
| (uint64(height) << 32) | (uint64(height) << 32)
| (uint64(options) << 16) | (uint64(options) << 16)
@ -672,8 +685,7 @@ void Photo::validateGroupedCache(
const auto pixSize = Ui::GetImageScaleSizeForGeometry( const auto pixSize = Ui::GetImageScaleSizeForGeometry(
{ originalWidth, originalHeight }, { originalWidth, originalHeight },
{ width, height }); { width, height });
const auto pixWidth = pixSize.width() * cIntRetinaFactor(); const auto ratio = style::DevicePixelRatio();
const auto pixHeight = pixSize.height() * cIntRetinaFactor();
const auto image = _dataMedia->image(PhotoSize::Large) const auto image = _dataMedia->image(PhotoSize::Large)
? _dataMedia->image(PhotoSize::Large) ? _dataMedia->image(PhotoSize::Large)
: _dataMedia->image(PhotoSize::Thumbnail) : _dataMedia->image(PhotoSize::Thumbnail)
@ -685,7 +697,9 @@ void Photo::validateGroupedCache(
: Image::BlankMedia().get(); : Image::BlankMedia().get();
*cacheKey = key; *cacheKey = key;
*cache = image->pixNoCache(pixWidth, pixHeight, options, width, height); *cache = image->pixNoCache(
pixSize * ratio,
{ .options = options, .outer = { width, height } });
} }
bool Photo::createStreamingObjects() { bool Photo::createStreamingObjects() {

View File

@ -173,7 +173,9 @@ void Sticker::paintLottie(
? frame.image ? frame.image
: _lastDiceFrame; : _lastDiceFrame;
const auto prepared = (!_lastDiceFrame.isNull() && context.selected()) const auto prepared = (!_lastDiceFrame.isNull() && context.selected())
? Images::prepareColored(context.st->msgStickerOverlay()->c, image) ? Images::Colored(
base::duplicate(image),
context.st->msgStickerOverlay()->c)
: image; : image;
const auto size = prepared.size() / cIntRetinaFactor(); const auto size = prepared.size() / cIntRetinaFactor();
p.drawImage( p.drawImage(
@ -252,27 +254,25 @@ void Sticker::paintPath(
QPixmap Sticker::paintedPixmap(const PaintContext &context) const { QPixmap Sticker::paintedPixmap(const PaintContext &context) const {
const auto w = _size.width(); const auto w = _size.width();
const auto h = _size.height(); const auto h = _size.height();
const auto &c = context.st->msgStickerOverlay(); const auto colored = context.selected()
? &context.st->msgStickerOverlay()
: nullptr;
const auto good = _dataMedia->goodThumbnail(); const auto good = _dataMedia->goodThumbnail();
if (const auto image = _dataMedia->getStickerLarge()) { if (const auto image = _dataMedia->getStickerLarge()) {
return context.selected() return image->pix(_size, { .colored = colored });
? image->pixColored(c, w, h)
: image->pix(w, h);
// //
// Inline thumbnails can't have alpha channel. // Inline thumbnails can't have alpha channel.
// //
//} else if (const auto blurred = _data->thumbnailInline()) { //} else if (const auto blurred = _data->thumbnailInline()) {
// return context.selected() // return blurred->pix(
// ? blurred->pixBlurredColored(c, w, h) // _size,
// : blurred->pixBlurred(w, h); // { .colored = colored, .options = Images::Option::Blur });
} else if (good) { } else if (good) {
return context.selected() return good->pix(_size, { .colored = colored });
? good->pixColored(c, w, h)
: good->pix(w, h);
} else if (const auto thumbnail = _dataMedia->thumbnail()) { } else if (const auto thumbnail = _dataMedia->thumbnail()) {
return context.selected() return thumbnail->pix(
? thumbnail->pixBlurredColored(c, w, h) _size,
: thumbnail->pixBlurred(w, h); { .colored = colored, .options = Images::Option::Blur });
} }
return QPixmap(); return QPixmap();
} }

View File

@ -292,8 +292,7 @@ void ThemeDocument::prepareThumbnailFrom(
const auto isTheme = _data->isTheme(); const auto isTheme = _data->isTheme();
const auto isPattern = _data->isPatternWallPaper(); const auto isPattern = _data->isPatternWallPaper();
auto options = Images::Option::Smooth auto options = (good >= 0 ? Images::Option(0) : Images::Option::Blur)
| (good >= 0 ? Images::Option(0) : Images::Option::Blurred)
| (isPattern | (isPattern
? Images::Option::TransparentBackground ? Images::Option::TransparentBackground
: Images::Option(0)); : Images::Option(0));
@ -304,20 +303,18 @@ void ThemeDocument::prepareThumbnailFrom(
if (!tw || !th) { if (!tw || !th) {
tw = th = 1; tw = th = 1;
} }
original = Images::prepare( const auto ratio = style::DevicePixelRatio();
original = Images::Prepare(
std::move(original), std::move(original),
_pixw * cIntRetinaFactor(), QSize(_pixw, (_pixw * th) / tw) * ratio,
((_pixw * th) / tw) * cIntRetinaFactor(), { .options = options, .outer = { _pixw, _pixh } });
options,
_pixw,
_pixh);
if (isPattern) { if (isPattern) {
original = Ui::PreparePatternImage( original = Ui::PreparePatternImage(
std::move(original), std::move(original),
_background, _background,
_gradientRotation, _gradientRotation,
_patternOpacity); _patternOpacity);
original.setDevicePixelRatio(cRetinaFactor()); original.setDevicePixelRatio(ratio);
} }
_thumbnail = Ui::PixmapFromImage(std::move(original)); _thumbnail = Ui::PixmapFromImage(std::move(original));
_thumbnailGood = good; _thumbnailGood = good;

View File

@ -508,14 +508,19 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
pixh = qRound(pixh * coef); pixh = qRound(pixh * coef);
pixw = qRound(pixw * coef); pixw = qRound(pixw * coef);
} }
const auto size = QSize(pixw, pixh);
const auto args = Images::PrepareArgs{
.options = Images::Option::RoundSmall,
.outer = { pw, ph },
};
if (const auto thumbnail = _photoMedia->image( if (const auto thumbnail = _photoMedia->image(
Data::PhotoSize::Thumbnail)) { Data::PhotoSize::Thumbnail)) {
pix = thumbnail->pixSingle(pixw, pixh, pw, ph, ImageRoundRadius::Small); pix = thumbnail->pixSingle(size, args);
} else if (const auto small = _photoMedia->image( } else if (const auto small = _photoMedia->image(
Data::PhotoSize::Small)) { Data::PhotoSize::Small)) {
pix = small->pixBlurredSingle(pixw, pixh, pw, ph, ImageRoundRadius::Small); pix = small->pixSingle(size, args.blurred());
} else if (const auto blurred = _photoMedia->thumbnailInline()) { } else if (const auto blurred = _photoMedia->thumbnailInline()) {
pix = blurred->pixBlurredSingle(pixw, pixh, pw, ph, ImageRoundRadius::Small); pix = blurred->pixSingle(size, args.blurred());
} }
p.drawPixmapLeft(padding.left() + paintw - pw, tshift, width(), pix); p.drawPixmapLeft(padding.left() + paintw - pw, tshift, width(), pix);
if (context.selected()) { if (context.selected()) {

View File

@ -319,13 +319,12 @@ void Gif::validateThumbnail(
} }
_thumbGood = good; _thumbGood = good;
_thumb = image->pixNoCache( _thumb = image->pixNoCache(
frame.width() * cIntRetinaFactor(), frame * style::DevicePixelRatio(),
frame.height() * cIntRetinaFactor(), {
(Images::Option::Smooth .options = (Images::Option::TransparentBackground
| (good ? Images::Option::None : Images::Option::Blurred) | (good ? Images::Option() : Images::Option::Blur)),
| Images::Option::TransparentBackground), .outer = size,
size.width(), });
size.height());
} }
void Gif::prepareThumbnail(QSize size, QSize frame) const { void Gif::prepareThumbnail(QSize size, QSize frame) const {
@ -563,9 +562,7 @@ void Sticker::prepareThumbnail() const {
if (const auto sticker = _dataMedia->getStickerSmall()) { if (const auto sticker = _dataMedia->getStickerSmall()) {
if (!_lottie && !_thumbLoaded) { if (!_lottie && !_thumbLoaded) {
const auto thumbSize = getThumbSize(); const auto thumbSize = getThumbSize();
_thumb = sticker->pix( _thumb = sticker->pix(thumbSize);
thumbSize.width(),
thumbSize.height());
_thumbLoaded = true; _thumbLoaded = true;
} }
} }
@ -662,13 +659,12 @@ void Photo::validateThumbnail(
} }
const auto origin = fileOrigin(); const auto origin = fileOrigin();
_thumb = image->pixNoCache( _thumb = image->pixNoCache(
frame.width() * cIntRetinaFactor(), frame * style::DevicePixelRatio(),
frame.height() * cIntRetinaFactor(), {
(Images::Option::Smooth .options = (Images::Option::TransparentBackground
| (good ? Images::Option(0) : Images::Option::Blurred) | (good ? Images::Option() : Images::Option::Blur)),
| Images::Option::TransparentBackground), .outer = size,
size.width(), });
size.height());
_thumbGood = good; _thumbGood = good;
} }
@ -823,11 +819,11 @@ void Video::prepareThumbnail(QSize size) const {
} }
} }
_thumb = thumb->pixNoCache( _thumb = thumb->pixNoCache(
w * cIntRetinaFactor(), QSize(w, h) * style::DevicePixelRatio(),
h * cIntRetinaFactor(), {
Images::Option::Smooth | Images::Option::TransparentBackground, .options = Images::Option::TransparentBackground,
width, .outer = size,
height); });
} }
} }
@ -1162,11 +1158,11 @@ void Contact::prepareThumbnail(int width, int height) const {
} }
} }
_thumb = thumb->pixNoCache( _thumb = thumb->pixNoCache(
w * cIntRetinaFactor(), QSize(w, h) * style::DevicePixelRatio(),
h * cIntRetinaFactor(), {
Images::Option::Smooth | Images::Option::TransparentBackground, .options = Images::Option::TransparentBackground,
width, .outer = { width, height },
height); });
} }
Article::Article( Article::Article(
@ -1320,11 +1316,11 @@ void Article::prepareThumbnail(int width, int height) const {
} }
} }
_thumb = thumb->pixNoCache( _thumb = thumb->pixNoCache(
w * cIntRetinaFactor(), QSize(w, h) * style::DevicePixelRatio(),
h * cIntRetinaFactor(), {
Images::Option::Smooth | Images::Option::TransparentBackground, .options = Images::Option::TransparentBackground,
width, .outer = { width, height },
height); });
} }
Game::Game(not_null<Context*> context, not_null<Result*> result) Game::Game(not_null<Context*> context, not_null<Result*> result)
@ -1539,13 +1535,12 @@ void Game::validateThumbnail(Image *image, QSize size, bool good) const {
} }
_thumbGood = good; _thumbGood = good;
_thumb = image->pixNoCache( _thumb = image->pixNoCache(
w * cIntRetinaFactor(), QSize(w, h) * style::DevicePixelRatio(),
h * cIntRetinaFactor(), {
(Images::Option::Smooth .options = (Images::Option::TransparentBackground
| (good ? Images::Option::None : Images::Option::Blurred) | (good ? Images::Option() : Images::Option::Blur)),
| Images::Option::TransparentBackground), .outer = size,
size.width(), });
size.height());
} }
bool Game::isRadialAnimation() const { bool Game::isRadialAnimation() const {

View File

@ -79,7 +79,10 @@ QImage PrepareFrameImage(const FrameRequest &request, const QImage &original, bo
} }
} }
if (needRounding) { if (needRounding) {
Images::prepareRound(cache, request.radius, request.corners); cache = Images::Round(
std::move(cache),
request.radius,
request.corners);
} }
return cache; return cache;
} }

View File

@ -173,7 +173,7 @@ void Float::prepareShadow() {
auto extend = 2 * st::lineWidth; auto extend = 2 * st::lineWidth;
p.drawEllipse(getInnerRect().marginsAdded(QMargins(extend, extend, extend, extend))); p.drawEllipse(getInnerRect().marginsAdded(QMargins(extend, extend, extend, extend)));
} }
_shadow = Ui::PixmapFromImage(Images::prepareBlur(std::move(shadow))); _shadow = Ui::PixmapFromImage(Images::Blur(std::move(shadow)));
} }
QRect Float::getInnerRect() const { QRect Float::getInnerRect() const {

View File

@ -283,7 +283,10 @@ void ApplyFrameRounding(QImage &storage, const FrameRequest &request) {
|| (request.radius == ImageRoundRadius::None)) { || (request.radius == ImageRoundRadius::None)) {
return; return;
} }
Images::prepareRound(storage, request.radius, request.corners); storage = Images::Round(
std::move(storage),
request.radius,
request.corners);
} }
QImage PrepareByRequest( QImage PrepareByRequest(

View File

@ -300,10 +300,7 @@ void GroupThumbs::Thumb::validateImage() {
Qt::IgnoreAspectRatio, Qt::IgnoreAspectRatio,
Qt::SmoothTransformation)); Qt::SmoothTransformation));
} else { } else {
_full = _image->pixNoCache( _full = _image->pixNoCache(pixSize * style::DevicePixelRatio());
pixSize.width() * cIntRetinaFactor(),
pixSize.height() * cIntRetinaFactor(),
Images::Option::Smooth);
} }
_fullWidth = std::min( _fullWidth = std::min(
wantedPixSize().width(), wantedPixSize().width(),

View File

@ -147,9 +147,9 @@ QWidget *PipDelegate::pipParentWidget() {
} }
[[nodiscard]] Images::Options VideoThumbOptions(DocumentData *document) { [[nodiscard]] Images::Options VideoThumbOptions(DocumentData *document) {
const auto result = Images::Option::Smooth | Images::Option::Blurred; const auto result = Images::Option::Blur;
return (document && document->isVideoMessage()) return (document && document->isVideoMessage())
? (result | Images::Option::Circled) ? (result | Images::Option::RoundCircle)
: result; : result;
} }
@ -2453,9 +2453,9 @@ void OverlayWidget::displayDocument(
if (const auto image = _documentMedia->getStickerLarge()) { if (const auto image = _documentMedia->getStickerLarge()) {
setStaticContent(image->original()); setStaticContent(image->original());
} else if (const auto thumbnail = _documentMedia->thumbnail()) { } else if (const auto thumbnail = _documentMedia->thumbnail()) {
setStaticContent(thumbnail->pixBlurred( setStaticContent(thumbnail->pix(
_document->dimensions.width(), _document->dimensions,
_document->dimensions.height() { .options = Images::Option::Blur }
).toImage()); ).toImage());
} }
} else { } else {
@ -2712,10 +2712,8 @@ void OverlayWidget::initStreamingThumbnail() {
} else if (size.isEmpty()) { } else if (size.isEmpty()) {
return; return;
} }
const auto w = size.width();
const auto h = size.height();
const auto options = VideoThumbOptions(_document); const auto options = VideoThumbOptions(_document);
const auto goodOptions = (options & ~Images::Option::Blurred); const auto goodOptions = (options & ~Images::Option::Blur);
setStaticContent((good setStaticContent((good
? good ? good
: thumbnail : thumbnail
@ -2723,11 +2721,11 @@ void OverlayWidget::initStreamingThumbnail() {
: blurred : blurred
? blurred ? blurred
: Image::BlankMedia().get())->pixNoCache( : Image::BlankMedia().get())->pixNoCache(
w, size,
h, {
good ? goodOptions : options, .options = good ? goodOptions : options,
w / cIntRetinaFactor(), .outer = size / style::DevicePixelRatio(),
h / cIntRetinaFactor() }
).toImage()); ).toImage());
} }
@ -3271,10 +3269,8 @@ void OverlayWidget::validatePhotoImage(Image *image, bool blurred) {
const auto use = flipSizeByRotation({ _width, _height }) const auto use = flipSizeByRotation({ _width, _height })
* cIntRetinaFactor(); * cIntRetinaFactor();
setStaticContent(image->pixNoCache( setStaticContent(image->pixNoCache(
use.width(), use,
use.height(), { .options = (blurred ? Images::Option::Blur : Images::Option()) }
Images::Option::Smooth
| (blurred ? Images::Option::Blurred : Images::Option(0))
).toImage()); ).toImage());
_blurred = blurred; _blurred = blurred;
} }

View File

@ -1660,7 +1660,7 @@ QImage Pip::staticContent() const {
? blurred ? blurred
: Image::BlankMedia().get())->original(); : Image::BlankMedia().get())->original();
if (!good) { if (!good) {
_preparedCoverStorage = Images::prepareBlur( _preparedCoverStorage = Images::Blur(
std::move(_preparedCoverStorage)); std::move(_preparedCoverStorage));
} }
} }

View File

@ -175,27 +175,18 @@ QImage Pip::RendererSW::staticContentByRequest(
// request, // request,
// std::move(_preparedCoverStorage)); // std::move(_preparedCoverStorage));
using Option = Images::Option; using Option = Images::Option;
const auto options = Option::Smooth const auto corner = [&](RectPart part, Option skip) {
| Option::RoundedLarge return !(request.corners & part) ? skip : Option();
| ((request.corners & RectPart::TopLeft) };
? Option::RoundedTopLeft const auto options = Option::RoundLarge
: Option(0)) | corner(RectPart::TopLeft, Option::RoundSkipTopLeft)
| ((request.corners & RectPart::TopRight) | corner(RectPart::TopRight, Option::RoundSkipTopRight)
? Option::RoundedTopRight | corner(RectPart::BottomLeft, Option::RoundSkipBottomLeft)
: Option(0)) | corner(RectPart::BottomRight, Option::RoundSkipBottomRight);
| ((request.corners & RectPart::BottomRight) _preparedStaticContent = Images::Prepare(
? Option::RoundedBottomRight
: Option(0))
| ((request.corners & RectPart::BottomLeft)
? Option::RoundedBottomLeft
: Option(0));
_preparedStaticContent = Images::prepare(
image, image,
request.resize.width(), request.resize,
request.resize.height(), { .options = options, .outer = request.outer });
options,
request.outer.width(),
request.outer.height());
return _preparedStaticContent; return _preparedStaticContent;
} }

View File

@ -358,7 +358,7 @@ void Photo::setPixFrom(not_null<Image*> image) {
const auto size = _width * cIntRetinaFactor(); const auto size = _width * cIntRetinaFactor();
auto img = image->original(); auto img = image->original();
if (!_goodLoaded) { if (!_goodLoaded) {
img = Images::prepareBlur(std::move(img)); img = Images::Blur(std::move(img));
} }
if (img.width() == img.height()) { if (img.width() == img.height()) {
if (img.width() != size) { if (img.width() != size) {
@ -457,7 +457,7 @@ void Video::paint(Painter &p, const QRect &clip, TextSelection selection, const
? good->original() ? good->original()
: thumbnail : thumbnail
? thumbnail->original() ? thumbnail->original()
: Images::prepareBlur(blurred->original()); : Images::Blur(blurred->original());
if (img.width() == img.height()) { if (img.width() == img.height()) {
if (img.width() != size) { if (img.width() != size) {
img = img.scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation); img = img.scaled(size, size, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
@ -691,9 +691,11 @@ void Voice::paint(Painter &p, const QRect &clip, TextSelection selection, const
p.setPen(Qt::NoPen); p.setPen(Qt::NoPen);
if (thumbnail || blurred) { if (thumbnail || blurred) {
const auto thumb = thumbnail const auto options = Images::Option::RoundCircle
? thumbnail->pixCircled(inner.width(), inner.height()) | (blurred ? Images::Option::Blur : Images::Option());
: blurred->pixBlurredCircled(inner.width(), inner.height()); const auto thumb = (thumbnail ? thumbnail : blurred)->pix(
inner.size(),
{ .options = options });
p.drawPixmap(inner.topLeft(), thumb); p.drawPixmap(inner.topLeft(), thumb);
} else if (_data->hasThumbnail()) { } else if (_data->hasThumbnail()) {
PainterHighQualityEnabler hq(p); PainterHighQualityEnabler hq(p);
@ -1101,12 +1103,18 @@ void Document::paint(Painter &p, const QRect &clip, TextSelection selection, con
if (thumbnail || blurred) { if (thumbnail || blurred) {
if (_thumb.isNull() || (thumbnail && !_thumbLoaded)) { if (_thumb.isNull() || (thumbnail && !_thumbLoaded)) {
_thumbLoaded = (thumbnail != nullptr); _thumbLoaded = (thumbnail != nullptr);
auto options = Images::Option::Smooth const auto options = _thumbLoaded
| (_thumbLoaded ? Images::Option()
? Images::Option::None : Images::Option::Blur;
: Images::Option::Blurred);
const auto image = thumbnail ? thumbnail : blurred; const auto image = thumbnail ? thumbnail : blurred;
_thumb = image->pixNoCache(_thumbw * cIntRetinaFactor(), 0, options, _st.fileThumbSize, _st.fileThumbSize); _thumb = image->pixNoCache(
_thumbw * style::DevicePixelRatio(),
{
.options = options,
.outer = QSize(
_st.fileThumbSize,
_st.fileThumbSize),
});
} }
p.drawPixmap(rthumb.topLeft(), _thumb); p.drawPixmap(rthumb.topLeft(), _thumb);
} else { } else {
@ -1668,20 +1676,26 @@ void Link::validateThumbnail() {
if (!_thumbnail.isNull() && !_thumbnailBlurred) { if (!_thumbnail.isNull() && !_thumbnailBlurred) {
return; return;
} }
const auto size = QSize(_pixw, _pixh);
const auto outer = QSize(st::linksPhotoSize, st::linksPhotoSize);
if (_page && _page->photo) { if (_page && _page->photo) {
using Data::PhotoSize; using Data::PhotoSize;
ensurePhotoMediaCreated(); ensurePhotoMediaCreated();
const auto args = Images::PrepareArgs{
.options = Images::Option::RoundSmall,
.outer = outer,
};
if (const auto thumbnail = _photoMedia->image(PhotoSize::Thumbnail)) { if (const auto thumbnail = _photoMedia->image(PhotoSize::Thumbnail)) {
_thumbnail = thumbnail->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small); _thumbnail = thumbnail->pixSingle(size, args);
_thumbnailBlurred = false; _thumbnailBlurred = false;
} else if (const auto large = _photoMedia->image(PhotoSize::Large)) { } else if (const auto large = _photoMedia->image(PhotoSize::Large)) {
_thumbnail = large->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small); _thumbnail = large->pixSingle(size, args);
_thumbnailBlurred = false; _thumbnailBlurred = false;
} else if (const auto small = _photoMedia->image(PhotoSize::Small)) { } else if (const auto small = _photoMedia->image(PhotoSize::Small)) {
_thumbnail = small->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small); _thumbnail = small->pixSingle(size, args);
_thumbnailBlurred = false; _thumbnailBlurred = false;
} else if (const auto blurred = _photoMedia->thumbnailInline()) { } else if (const auto blurred = _photoMedia->thumbnailInline()) {
_thumbnail = blurred->pixBlurredSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, ImageRoundRadius::Small); _thumbnail = blurred->pixSingle(size, args.blurred());
return; return;
} else { } else {
return; return;
@ -1690,14 +1704,17 @@ void Link::validateThumbnail() {
delegate()->unregisterHeavyItem(this); delegate()->unregisterHeavyItem(this);
} else if (_page && _page->document && _page->document->hasThumbnail()) { } else if (_page && _page->document && _page->document->hasThumbnail()) {
ensureDocumentMediaCreated(); ensureDocumentMediaCreated();
const auto roundRadius = _page->document->isVideoMessage() const auto args = Images::PrepareArgs{
? ImageRoundRadius::Ellipse .options = (_page->document->isVideoMessage()
: ImageRoundRadius::Small; ? Images::Option::RoundCircle
: Images::Option::RoundSmall),
.outer = outer,
};
if (const auto thumbnail = _documentMedia->thumbnail()) { if (const auto thumbnail = _documentMedia->thumbnail()) {
_thumbnail = thumbnail->pixSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, roundRadius); _thumbnail = thumbnail->pixSingle(size, args);
_thumbnailBlurred = false; _thumbnailBlurred = false;
} else if (const auto blurred = _documentMedia->thumbnailInline()) { } else if (const auto blurred = _documentMedia->thumbnailInline()) {
_thumbnail = blurred->pixBlurredSingle(_pixw, _pixh, st::linksPhotoSize, st::linksPhotoSize, roundRadius); _thumbnail = blurred->pixSingle(size, args.blurred());
return; return;
} else { } else {
return; return;
@ -1930,12 +1947,11 @@ void Gif::validateThumbnail(
} }
_thumbGood = good; _thumbGood = good;
_thumb = image->pixNoCache( _thumb = image->pixNoCache(
frame.width() * cIntRetinaFactor(), frame * style::DevicePixelRatio(),
frame.height() * cIntRetinaFactor(), {
(Images::Option::Smooth .options = (good ? Images::Option() : Images::Option::Blur),
| (good ? Images::Option::None : Images::Option::Blurred)), .outer = size,
size.width(), });
size.height());
} }
void Gif::prepareThumbnail(QSize size, QSize frame) { void Gif::prepareThumbnail(QSize size, QSize frame) {

View File

@ -239,10 +239,10 @@ QImage Form::prepareThumbnail(
not_null<const Image*> image, not_null<const Image*> image,
bool blurred) const { bool blurred) const {
auto result = image->original().scaled( auto result = image->original().scaled(
st::paymentsThumbnailSize * cIntRetinaFactor(), st::paymentsThumbnailSize * style::DevicePixelRatio(),
Qt::KeepAspectRatio, Qt::KeepAspectRatio,
Qt::SmoothTransformation); Qt::SmoothTransformation);
Images::prepareRound(result, ImageRoundRadius::Large); result = Images::Round(std::move(result), ImageRoundRadius::Large);
result.setDevicePixelRatio(cRetinaFactor()); result.setDevicePixelRatio(cRetinaFactor());
return result; return result;
} }

View File

@ -106,11 +106,8 @@ struct PickerScrubberItem {
const auto size = sticker->size() const auto size = sticker->size()
.scaled(kCircleDiameter, kCircleDiameter, Qt::KeepAspectRatio); .scaled(kCircleDiameter, kCircleDiameter, Qt::KeepAspectRatio);
image = sticker->pixSingle( image = sticker->pixSingle(
size.width(), size,
size.height(), { .outer = { kCircleDiameter, kCircleDiameter } }).toImage();
kCircleDiameter,
kCircleDiameter,
ImageRoundRadius::None).toImage();
} }
bool isStickerLoaded() const { bool isStickerLoaded() const {

View File

@ -127,8 +127,13 @@ void PreviewWindowFramePaint(QImage &preview, const style::palette &palette, QRe
corners[1] = roundMask.copy(retinaRadius, 0, retinaRadius, retinaRadius); corners[1] = roundMask.copy(retinaRadius, 0, retinaRadius, retinaRadius);
corners[2] = roundMask.copy(0, retinaRadius, retinaRadius, retinaRadius); corners[2] = roundMask.copy(0, retinaRadius, retinaRadius, retinaRadius);
corners[3] = roundMask.copy(retinaRadius, retinaRadius, retinaRadius, retinaRadius); corners[3] = roundMask.copy(retinaRadius, retinaRadius, retinaRadius, retinaRadius);
auto rounded = preview.copy(inner.x() * retina, inner.y() * retina, inner.width() * retina, inner.height() * retina); auto rounded = Images::Round(
Images::prepareRound(rounded, corners); preview.copy(
inner.x() * retina,
inner.y() * retina,
inner.width() * retina,
inner.height() * retina),
corners);
rounded.setDevicePixelRatio(cRetinaFactor()); rounded.setDevicePixelRatio(cRetinaFactor());
preview.fill(st::themePreviewBg->c); preview.fill(st::themePreviewBg->c);

View File

@ -446,8 +446,9 @@ void BackgroundRow::paintEvent(QPaintEvent *e) {
if (!backThumb) { if (!backThumb) {
p.drawPixmap(0, 0, _background); p.drawPixmap(0, 0, _background);
} else { } else {
const auto &pix = backThumb->pixBlurred( const auto &pix = backThumb->pix(
st::settingsBackgroundThumb); st::settingsBackgroundThumb,
{ .options = Images::Option::Blur });
const auto factor = cIntRetinaFactor(); const auto factor = cIntRetinaFactor();
p.drawPixmap( p.drawPixmap(
0, 0,
@ -612,8 +613,8 @@ void BackgroundRow::updateImage() {
auto back = (paper.isPattern() || !background.gradientForFill().isNull()) auto back = (paper.isPattern() || !background.gradientForFill().isNull())
? preparePattern() ? preparePattern()
: prepareNormal(); : prepareNormal();
Images::prepareRound(back, ImageRoundRadius::Small); _background = Ui::PixmapFromImage(
_background = Ui::PixmapFromImage(std::move(back)); Images::Round(std::move(back), ImageRoundRadius::Small));
_background.setDevicePixelRatio(cRetinaFactor()); _background.setDevicePixelRatio(cRetinaFactor());
rtlupdate(radialRect()); rtlupdate(radialRect());

View File

@ -724,7 +724,7 @@ void FileLoadTask::process(Args &&args) {
&_information->media)) { &_information->media)) {
fullimage = base::take(image->data); fullimage = base::take(image->data);
if (!Core::IsMimeSticker(filemime)) { if (!Core::IsMimeSticker(filemime)) {
fullimage = Images::prepareOpaque(std::move(fullimage)); fullimage = Images::Opaque(std::move(fullimage));
} }
isAnimation = image->animated; isAnimation = image->animated;
} }
@ -743,7 +743,7 @@ void FileLoadTask::process(Args &&args) {
const auto mimeType = Core::MimeTypeForData(_content); const auto mimeType = Core::MimeTypeForData(_content);
filemime = mimeType.name(); filemime = mimeType.name();
if (!Core::IsMimeSticker(filemime)) { if (!Core::IsMimeSticker(filemime)) {
fullimage = Images::prepareOpaque(std::move(fullimage)); fullimage = Images::Opaque(std::move(fullimage));
} }
if (filemime == "image/jpeg") { if (filemime == "image/jpeg") {
filename = filedialogDefaultName(qsl("photo"), qsl(".jpg"), QString(), true); filename = filedialogDefaultName(qsl("photo"), qsl(".jpg"), QString(), true);
@ -784,7 +784,7 @@ void FileLoadTask::process(Args &&args) {
} }
filesize = _content.size(); filesize = _content.size();
} }
fullimage = Images::prepareOpaque(std::move(fullimage)); fullimage = Images::Opaque(std::move(fullimage));
} }
} }
_result->filesize = (int32)qMin(filesize, qint64(INT_MAX)); _result->filesize = (int32)qMin(filesize, qint64(INT_MAX));

View File

@ -304,7 +304,8 @@ void PrepareDetails(PreparedFile &file, int previewWidth) {
} else if (const auto video = std::get_if<Video>( } else if (const auto video = std::get_if<Video>(
&file.information->media)) { &file.information->media)) {
if (ValidVideoForAlbum(*video)) { if (ValidVideoForAlbum(*video)) {
auto blurred = Images::prepareBlur(Images::prepareOpaque(video->thumbnail)); auto blurred = Images::Blur(
Images::Opaque(base::duplicate(video->thumbnail)));
file.shownDimensions = PrepareShownDimensions(video->thumbnail); file.shownDimensions = PrepareShownDimensions(video->thumbnail);
file.preview = std::move(blurred).scaledToWidth( file.preview = std::move(blurred).scaledToWidth(
previewWidth * cIntRetinaFactor(), previewWidth * cIntRetinaFactor(),
@ -333,7 +334,7 @@ void UpdateImageDetails(PreparedFile &file, int previewWidth) {
previewWidth, previewWidth,
style::ConvertScale(preview.width()) style::ConvertScale(preview.width())
) * cIntRetinaFactor(); ) * cIntRetinaFactor();
const auto scaled = preview.scaledToWidth( auto scaled = preview.scaledToWidth(
toWidth, toWidth,
Qt::SmoothTransformation); Qt::SmoothTransformation);
if (scaled.isNull()) { if (scaled.isNull()) {
@ -345,7 +346,7 @@ void UpdateImageDetails(PreparedFile &file, int previewWidth) {
Unexpected("Scaled is null."); Unexpected("Scaled is null.");
} }
Assert(!scaled.isNull()); Assert(!scaled.isNull());
file.preview = Images::prepareOpaque(scaled); file.preview = Images::Opaque(std::move(scaled));
Assert(!file.preview.isNull()); Assert(!file.preview.isNull());
file.preview.setDevicePixelRatio(cRetinaFactor()); file.preview.setDevicePixelRatio(cRetinaFactor());
} }

View File

@ -69,19 +69,11 @@ void AbstractSingleFilePreview::prepareThumbFor(
if (originalWidth > originalHeight) { if (originalWidth > originalHeight) {
thumbWidth = (originalWidth * st.thumbSize) / originalHeight; thumbWidth = (originalWidth * st.thumbSize) / originalHeight;
} }
auto options = Images::Option::Smooth const auto options = Images::Option::RoundSmall;
| Images::Option::RoundedSmall data.fileThumb = PixmapFromImage(Images::Prepare(
| Images::Option::RoundedTopLeft
| Images::Option::RoundedTopRight
| Images::Option::RoundedBottomLeft
| Images::Option::RoundedBottomRight;
data.fileThumb = PixmapFromImage(Images::prepare(
preview, preview,
thumbWidth * style::DevicePixelRatio(), thumbWidth * style::DevicePixelRatio(),
0, { .options = options, .outer = { st.thumbSize, st.thumbSize } }));
options,
st.thumbSize,
st.thumbSize));
} }
void AbstractSingleFilePreview::paintEvent(QPaintEvent *e) { void AbstractSingleFilePreview::paintEvent(QPaintEvent *e) {

View File

@ -65,13 +65,11 @@ void AbstractSingleMediaPreview::preparePreview(QImage preview) {
maxH = limitH; maxH = limitH;
} }
} }
preview = Images::prepare( const auto ratio = style::DevicePixelRatio();
preview, preview = Images::Prepare(
maxW * style::DevicePixelRatio(), std::move(preview),
maxH * style::DevicePixelRatio(), QSize(maxW, maxH) * ratio,
Images::Option::Smooth | Images::Option::Blurred, { .options = Images::Option::Blur, .outer = { maxW, maxH } });
maxW,
maxH);
} }
auto originalWidth = preview.width(); auto originalWidth = preview.width();
auto originalHeight = preview.height(); auto originalHeight = preview.height();
@ -103,7 +101,7 @@ void AbstractSingleMediaPreview::preparePreview(QImage preview) {
_previewHeight * style::DevicePixelRatio(), _previewHeight * style::DevicePixelRatio(),
Qt::IgnoreAspectRatio, Qt::IgnoreAspectRatio,
Qt::SmoothTransformation); Qt::SmoothTransformation);
preview = Images::prepareOpaque(std::move(preview)); preview = Images::Opaque(std::move(preview));
_preview = PixmapFromImage(std::move(preview)); _preview = PixmapFromImage(std::move(preview));
_preview.setDevicePixelRatio(style::DevicePixelRatio()); _preview.setDevicePixelRatio(style::DevicePixelRatio());

View File

@ -44,27 +44,26 @@ AlbumThumbnail::AlbumThumbnail(
const auto imageHeight = std::max( const auto imageHeight = std::max(
previewHeight / style::DevicePixelRatio(), previewHeight / style::DevicePixelRatio(),
st::minPhotoSize); st::minPhotoSize);
_photo = PixmapFromImage(Images::prepare( _photo = PixmapFromImage(Images::Prepare(
_fullPreview, _fullPreview,
previewWidth, QSize(previewWidth, previewHeight),
previewHeight, {
Option::RoundedLarge | Option::RoundedAll, .options = Option::RoundLarge,
imageWidth, .outer = { imageWidth, imageHeight },
imageHeight)); }));
const auto &st = st::attachPreviewThumbLayout; const auto &st = st::attachPreviewThumbLayout;
const auto idealSize = st.thumbSize * style::DevicePixelRatio(); const auto idealSize = st.thumbSize * style::DevicePixelRatio();
const auto fileThumbSize = (previewWidth > previewHeight) const auto fileThumbSize = (previewWidth > previewHeight)
? QSize(previewWidth * idealSize / previewHeight, idealSize) ? QSize(previewWidth * idealSize / previewHeight, idealSize)
: QSize(idealSize, previewHeight * idealSize / previewWidth); : QSize(idealSize, previewHeight * idealSize / previewWidth);
_fileThumb = PixmapFromImage(Images::prepare( _fileThumb = PixmapFromImage(Images::Prepare(
_fullPreview, _fullPreview,
fileThumbSize.width(), fileThumbSize,
fileThumbSize.height(), {
Option::RoundedSmall | Option::RoundedAll, .options = Option::RoundSmall,
st.thumbSize, .outer = { st.thumbSize, st.thumbSize },
st.thumbSize }));
));
const auto availableFileWidth = st::sendMediaPreviewSize const auto availableFileWidth = st::sendMediaPreviewSize
- st.thumbSize - st.thumbSize
@ -138,40 +137,35 @@ void AlbumThumbnail::animateLayoutToInitial() {
} }
void AlbumThumbnail::moveToLayout(const GroupMediaLayout &layout) { void AlbumThumbnail::moveToLayout(const GroupMediaLayout &layout) {
using Option = Images::Option;
animateLayoutToInitial(); animateLayoutToInitial();
_layout = layout; _layout = layout;
const auto width = _layout.geometry.width(); const auto width = _layout.geometry.width();
const auto height = _layout.geometry.height(); const auto height = _layout.geometry.height();
_albumCorners = GetCornersFromSides(_layout.sides); _albumCorners = GetCornersFromSides(_layout.sides);
using Option = Images::Option; const auto corner = [&](RectPart part, Option skip) {
const auto options = Option::Smooth return !(_albumCorners & part) ? skip : Option();
| Option::RoundedLarge };
| ((_albumCorners & RectPart::TopLeft) const auto options = Option::RoundLarge
? Option::RoundedTopLeft | corner(RectPart::TopLeft, Option::RoundSkipTopLeft)
: Option::None) | corner(RectPart::TopRight, Option::RoundSkipTopRight)
| ((_albumCorners & RectPart::TopRight) | corner(RectPart::BottomLeft, Option::RoundSkipBottomLeft)
? Option::RoundedTopRight | corner(RectPart::BottomRight, Option::RoundSkipBottomRight);
: Option::None)
| ((_albumCorners & RectPart::BottomLeft)
? Option::RoundedBottomLeft
: Option::None)
| ((_albumCorners & RectPart::BottomRight)
? Option::RoundedBottomRight
: Option::None);
const auto pixSize = GetImageScaleSizeForGeometry( const auto pixSize = GetImageScaleSizeForGeometry(
{ _fullPreview.width(), _fullPreview.height() }, { _fullPreview.width(), _fullPreview.height() },
{ width, height }); { width, height });
const auto pixWidth = pixSize.width() * style::DevicePixelRatio(); const auto pixWidth = pixSize.width() * style::DevicePixelRatio();
const auto pixHeight = pixSize.height() * style::DevicePixelRatio(); const auto pixHeight = pixSize.height() * style::DevicePixelRatio();
_albumImage = PixmapFromImage(Images::prepare( _albumImage = PixmapFromImage(Images::Prepare(
_fullPreview, _fullPreview,
pixWidth, QSize(pixWidth, pixHeight),
pixHeight, {
options, .options = options,
width, .outer = { width, height },
height)); }));
} }
int AlbumThumbnail::photoHeight() const { int AlbumThumbnail::photoHeight() const {
@ -250,8 +244,8 @@ void AlbumThumbnail::prepareCache(QSize size, int shrink) {
); );
drawSimpleFrame(p, to, size); drawSimpleFrame(p, to, size);
} }
Images::prepareRound( _albumCache = Images::Round(
_albumCache, std::move(_albumCache),
ImageRoundRadius::Large, ImageRoundRadius::Large,
_albumCorners, _albumCorners,
QRect(QPoint(), size * style::DevicePixelRatio())); QRect(QPoint(), size * style::DevicePixelRatio()));

View File

@ -266,14 +266,15 @@ QPixmap PrepareSongCoverForThumbnail(QImage image, int size) {
size, size,
Qt::KeepAspectRatioByExpanding); Qt::KeepAspectRatioByExpanding);
using Option = Images::Option; using Option = Images::Option;
return PixmapFromImage(Images::prepare( const auto ratio = style::DevicePixelRatio();
return PixmapFromImage(Images::Prepare(
std::move(image), std::move(image),
scaledSize.width() * style::DevicePixelRatio(), scaledSize * ratio,
scaledSize.height() * style::DevicePixelRatio(), {
Option::Circled | Option::Colored | Option::Smooth, .colored = &st::songCoverOverlayFg,
size, .options = Option::RoundCircle,
size, .outer = { size, size },
&st::songCoverOverlayFg)); }));
} }
} // namespace Ui } // namespace Ui

View File

@ -994,7 +994,7 @@ QImage PrepareBlurredBackground(QImage image) {
Qt::KeepAspectRatio, Qt::KeepAspectRatio,
Qt::SmoothTransformation); Qt::SmoothTransformation);
} }
return Images::BlurLargeImage(image, kRadius); return Images::BlurLargeImage(std::move(image), kRadius);
} }
QImage GenerateDitheredGradient( QImage GenerateDitheredGradient(

View File

@ -109,8 +109,7 @@ constexpr auto kDisableElement = "disable"_cs;
Qt::SmoothTransformation Qt::SmoothTransformation
).convertToFormat(QImage::Format_ARGB32_Premultiplied); ).convertToFormat(QImage::Format_ARGB32_Premultiplied);
const auto corners = Images::CornersMask(radius); const auto corners = Images::CornersMask(radius);
Images::prepareRound(bubble, corners); p.drawImage(sent, Images::Round(std::move(bubble), corners));
p.drawImage(sent, bubble);
} else { } else {
p.setBrush(theme->palette()->msgOutBg()->c); p.setBrush(theme->palette()->msgOutBg()->c);
p.drawRoundedRect(sent, radius, radius); p.drawRoundedRect(sent, radius, radius);
@ -118,8 +117,7 @@ constexpr auto kDisableElement = "disable"_cs;
p.setBrush(theme->palette()->msgInBg()->c); p.setBrush(theme->palette()->msgInBg()->c);
p.drawRoundedRect(received, radius, radius); p.drawRoundedRect(received, radius, radius);
} }
Images::prepareRound(result, ImageRoundRadius::Large); return Images::Round(std::move(result), ImageRoundRadius::Large);
return result;
} }
[[nodiscard]] QImage GenerateEmptyPreview() { [[nodiscard]] QImage GenerateEmptyPreview() {
@ -140,8 +138,7 @@ constexpr auto kDisableElement = "disable"_cs;
tr::lng_chat_theme_none(tr::now), tr::lng_chat_theme_none(tr::now),
style::al_top); style::al_top);
} }
Images::prepareRound(result, ImageRoundRadius::Large); return Images::Round(std::move(result), ImageRoundRadius::Large);
return result;
} }
} // namespace } // namespace

View File

@ -27,6 +27,18 @@ namespace {
return PixKey(0, 0, options); return PixKey(0, 0, options);
} }
[[nodiscard]] Options OptionsByArgs(const PrepareArgs &args) {
return args.options | (args.colored ? Option::Colorize : Option::None);
}
[[nodiscard]] uint64 PixKey(int width, int height, const PrepareArgs &args) {
return PixKey(width, height, OptionsByArgs(args));
}
[[nodiscard]] uint64 SinglePixKey(const PrepareArgs &args) {
return SinglePixKey(OptionsByArgs(args));
}
} // namespace } // namespace
QByteArray ExpandInlineBytes(const QByteArray &bytes) { QByteArray ExpandInlineBytes(const QByteArray &bytes) {
@ -330,336 +342,66 @@ QImage Image::original() const {
return _data; return _data;
} }
const QPixmap &Image::pix(int w, int h) const { const QPixmap &Image::cached(
if (w <= 0 || !width() || !height()) {
w = width();
} else {
w *= cIntRetinaFactor();
h *= cIntRetinaFactor();
}
auto options = Option::Smooth | Option::None;
auto k = PixKey(w, h, options);
auto i = _cache.find(k);
if (i == _cache.cend()) {
auto p = pixNoCache(w, h, options);
p.setDevicePixelRatio(cRetinaFactor());
i = _cache.emplace_or_assign(k, p).first;
}
return i->second;
}
const QPixmap &Image::pixRounded(
int w, int w,
int h, int h,
ImageRoundRadius radius, const Images::PrepareArgs &args,
RectParts corners) const { bool single) const {
const auto ratio = style::DevicePixelRatio();
if (w <= 0 || !width() || !height()) { if (w <= 0 || !width() || !height()) {
w = width(); w = width() * ratio;
} else if (h <= 0) {
h = std::max(int(int64(height()) * w / width()), 1) * ratio;
} else { } else {
w *= cIntRetinaFactor(); w *= ratio;
h *= cIntRetinaFactor(); h *= ratio;
} }
auto options = Option::Smooth | Option::None; const auto outer = args.outer;
auto cornerOptions = [](RectParts corners) { const auto size = outer.isEmpty() ? QSize(w, h) : outer * ratio;
return (corners & RectPart::TopLeft ? Option::RoundedTopLeft : Option::None) const auto k = single ? SinglePixKey(args) : PixKey(w, h, args);
| (corners & RectPart::TopRight ? Option::RoundedTopRight : Option::None) const auto i = _cache.find(k);
| (corners & RectPart::BottomLeft ? Option::RoundedBottomLeft : Option::None) return (i != _cache.cend() && i->second.size() == size)
| (corners & RectPart::BottomRight ? Option::RoundedBottomRight : Option::None); ? i->second
}; : _cache.emplace_or_assign(k, prepare(w, h, args)).first->second;
if (radius == ImageRoundRadius::Large) {
options |= Option::RoundedLarge | cornerOptions(corners);
} else if (radius == ImageRoundRadius::Small) {
options |= Option::RoundedSmall | cornerOptions(corners);
} else if (radius == ImageRoundRadius::Ellipse) {
options |= Option::Circled | cornerOptions(corners);
}
auto k = PixKey(w, h, options);
auto i = _cache.find(k);
if (i == _cache.cend()) {
auto p = pixNoCache(w, h, options);
p.setDevicePixelRatio(cRetinaFactor());
i = _cache.emplace_or_assign(k, p).first;
}
return i->second;
} }
const QPixmap &Image::pixCircled(int w, int h) const { QPixmap Image::prepare(int w, int h, const Images::PrepareArgs &args) const {
if (w <= 0 || !width() || !height()) {
w = width();
} else {
w *= cIntRetinaFactor();
h *= cIntRetinaFactor();
}
auto options = Option::Smooth | Option::Circled;
auto k = PixKey(w, h, options);
auto i = _cache.find(k);
if (i == _cache.cend()) {
auto p = pixNoCache(w, h, options);
p.setDevicePixelRatio(cRetinaFactor());
i = _cache.emplace_or_assign(k, p).first;
}
return i->second;
}
const QPixmap &Image::pixBlurredCircled(int w, int h) const {
if (w <= 0 || !width() || !height()) {
w = width();
} else {
w *= cIntRetinaFactor();
h *= cIntRetinaFactor();
}
auto options = Option::Smooth | Option::Circled | Option::Blurred;
auto k = PixKey(w, h, options);
auto i = _cache.find(k);
if (i == _cache.cend()) {
auto p = pixNoCache(w, h, options);
p.setDevicePixelRatio(cRetinaFactor());
i = _cache.emplace_or_assign(k, p).first;
}
return i->second;
}
const QPixmap &Image::pixBlurred(int w, int h) const {
if (w <= 0 || !width() || !height()) {
w = width() * cIntRetinaFactor();
} else {
w *= cIntRetinaFactor();
h *= cIntRetinaFactor();
}
auto options = Option::Smooth | Option::Blurred;
auto k = PixKey(w, h, options);
auto i = _cache.find(k);
if (i == _cache.cend()) {
auto p = pixNoCache(w, h, options);
p.setDevicePixelRatio(cRetinaFactor());
i = _cache.emplace_or_assign(k, p).first;
}
return i->second;
}
const QPixmap &Image::pixColored(style::color add, int w, int h) const {
if (w <= 0 || !width() || !height()) {
w = width() * cIntRetinaFactor();
} else {
w *= cIntRetinaFactor();
h *= cIntRetinaFactor();
}
auto options = Option::Smooth | Option::Colored;
auto k = PixKey(w, h, options);
auto i = _cache.find(k);
if (i == _cache.cend()) {
auto p = pixColoredNoCache(add, w, h, true);
p.setDevicePixelRatio(cRetinaFactor());
i = _cache.emplace_or_assign(k, p).first;
}
return i->second;
}
const QPixmap &Image::pixBlurredColored(
style::color add,
int w,
int h) const {
if (w <= 0 || !width() || !height()) {
w = width() * cIntRetinaFactor();
} else {
w *= cIntRetinaFactor();
h *= cIntRetinaFactor();
}
auto options = Option::Blurred | Option::Smooth | Option::Colored;
auto k = PixKey(w, h, options);
auto i = _cache.find(k);
if (i == _cache.cend()) {
auto p = pixBlurredColoredNoCache(add, w, h);
p.setDevicePixelRatio(cRetinaFactor());
i = _cache.emplace_or_assign(k, p).first;
}
return i->second;
}
const QPixmap &Image::pixSingle(
int w,
int h,
int outerw,
int outerh,
ImageRoundRadius radius,
RectParts corners,
const style::color *colored) const {
if (w <= 0 || !width() || !height()) {
w = width() * cIntRetinaFactor();
} else {
w *= cIntRetinaFactor();
h *= cIntRetinaFactor();
}
auto options = Option::Smooth | Option::None;
auto cornerOptions = [](RectParts corners) {
return (corners & RectPart::TopLeft ? Option::RoundedTopLeft : Option::None)
| (corners & RectPart::TopRight ? Option::RoundedTopRight : Option::None)
| (corners & RectPart::BottomLeft ? Option::RoundedBottomLeft : Option::None)
| (corners & RectPart::BottomRight ? Option::RoundedBottomRight : Option::None);
};
if (radius == ImageRoundRadius::Large) {
options |= Option::RoundedLarge | cornerOptions(corners);
} else if (radius == ImageRoundRadius::Small) {
options |= Option::RoundedSmall | cornerOptions(corners);
} else if (radius == ImageRoundRadius::Ellipse) {
options |= Option::Circled | cornerOptions(corners);
}
if (colored) {
options |= Option::Colored;
}
auto k = SinglePixKey(options);
auto i = _cache.find(k);
if (i == _cache.cend() || i->second.width() != (outerw * cIntRetinaFactor()) || i->second.height() != (outerh * cIntRetinaFactor())) {
auto p = pixNoCache(w, h, options, outerw, outerh, colored);
p.setDevicePixelRatio(cRetinaFactor());
i = _cache.emplace_or_assign(k, p).first;
}
return i->second;
}
const QPixmap &Image::pixBlurredSingle(
int w,
int h,
int outerw,
int outerh,
ImageRoundRadius radius,
RectParts corners,
const style::color *colored) const {
if (w <= 0 || !width() || !height()) {
w = width() * cIntRetinaFactor();
} else {
w *= cIntRetinaFactor();
h *= cIntRetinaFactor();
}
auto options = Option::Smooth | Option::Blurred;
auto cornerOptions = [](RectParts corners) {
return (corners & RectPart::TopLeft ? Option::RoundedTopLeft : Option::None)
| (corners & RectPart::TopRight ? Option::RoundedTopRight : Option::None)
| (corners & RectPart::BottomLeft ? Option::RoundedBottomLeft : Option::None)
| (corners & RectPart::BottomRight ? Option::RoundedBottomRight : Option::None);
};
if (radius == ImageRoundRadius::Large) {
options |= Option::RoundedLarge | cornerOptions(corners);
} else if (radius == ImageRoundRadius::Small) {
options |= Option::RoundedSmall | cornerOptions(corners);
} else if (radius == ImageRoundRadius::Ellipse) {
options |= Option::Circled | cornerOptions(corners);
}
if (colored) {
options |= Option::Colored;
}
auto k = SinglePixKey(options);
auto i = _cache.find(k);
if (i == _cache.cend() || i->second.width() != (outerw * cIntRetinaFactor()) || i->second.height() != (outerh * cIntRetinaFactor())) {
auto p = pixNoCache(w, h, options, outerw, outerh, colored);
p.setDevicePixelRatio(cRetinaFactor());
i = _cache.emplace_or_assign(k, p).first;
}
return i->second;
}
QPixmap Image::pixNoCache(
int w,
int h,
Options options,
int outerw,
int outerh,
const style::color *colored) const {
if (_data.isNull()) { if (_data.isNull()) {
if (h <= 0 && height() > 0) { if (h <= 0 && height() > 0) {
h = qRound(width() * w / float64(height())); h = qRound(width() * w / float64(height()));
} }
return Empty()->pixNoCache(w, h, options, outerw, outerh); return Empty()->prepare(w, h, args);
} }
if (isNull() && outerw > 0 && outerh > 0) { auto outer = args.outer;
outerw *= cIntRetinaFactor(); if (!isNull() || outer.isEmpty()) {
outerh *= cIntRetinaFactor(); return Ui::PixmapFromImage(Prepare(_data, w, h, args));
QImage result(outerw, outerh, QImage::Format_ARGB32_Premultiplied);
result.setDevicePixelRatio(style::DevicePixelRatio());
{
QPainter p(&result);
if (w < outerw) {
p.fillRect(0, 0, (outerw - w) / 2, result.height(), st::imageBg);
p.fillRect(((outerw - w) / 2) + w, 0, result.width() - (((outerw - w) / 2) + w), result.height(), st::imageBg);
}
if (h < outerh) {
p.fillRect(qMax(0, (outerw - w) / 2), 0, qMin(result.width(), w), (outerh - h) / 2, st::imageBg);
p.fillRect(qMax(0, (outerw - w) / 2), ((outerh - h) / 2) + h, qMin(result.width(), w), result.height() - (((outerh - h) / 2) + h), st::imageBg);
}
p.fillRect(qMax(0, (outerw - w) / 2), qMax(0, (outerh - h) / 2), qMin(result.width(), w), qMin(result.height(), h), st::imageBgTransparent);
}
auto corners = [](Options options) {
return ((options & Option::RoundedTopLeft) ? RectPart::TopLeft : RectPart::None)
| ((options & Option::RoundedTopRight) ? RectPart::TopRight : RectPart::None)
| ((options & Option::RoundedBottomLeft) ? RectPart::BottomLeft : RectPart::None)
| ((options & Option::RoundedBottomRight) ? RectPart::BottomRight : RectPart::None);
};
if (options & Option::Circled) {
prepareCircle(result);
} else if (options & Option::RoundedLarge) {
prepareRound(result, ImageRoundRadius::Large, corners(options));
} else if (options & Option::RoundedSmall) {
prepareRound(result, ImageRoundRadius::Small, corners(options));
}
if (options & Option::Colored) {
Assert(colored != nullptr);
result = prepareColored(*colored, std::move(result));
}
return Ui::PixmapFromImage(std::move(result));
} }
return Ui::PixmapFromImage( const auto ratio = style::DevicePixelRatio();
prepare(_data, w, h, options, outerw, outerh, colored)); const auto outerw = outer.width() * ratio;
} const auto outerh = outer.height() * ratio;
QPixmap Image::pixColoredNoCache( auto result = QImage(
style::color add, QSize(outerw, outerh),
int w, QImage::Format_ARGB32_Premultiplied);
int h, result.setDevicePixelRatio(ratio);
bool smooth) const {
if (_data.isNull()) { auto p = QPainter(&result);
return Empty()->pix(); if (w < outerw) {
} p.fillRect(0, 0, (outerw - w) / 2, result.height(), Qt::black);
p.fillRect(((outerw - w) / 2) + w, 0, result.width() - (((outerw - w) / 2) + w), result.height(), Qt::black);
auto img = _data; }
if (w <= 0 || !width() || !height() || (w == width() && (h <= 0 || h == height()))) { if (h < outerh) {
return Ui::PixmapFromImage(prepareColored(add, std::move(img))); p.fillRect(qMax(0, (outerw - w) / 2), 0, qMin(result.width(), w), (outerh - h) / 2, Qt::black);
} p.fillRect(qMax(0, (outerw - w) / 2), ((outerh - h) / 2) + h, qMin(result.width(), w), result.height() - (((outerh - h) / 2) + h), Qt::black);
const auto transformation = smooth }
? Qt::SmoothTransformation p.fillRect(qMax(0, (outerw - w) / 2), qMax(0, (outerh - h) / 2), qMin(result.width(), w), qMin(result.height(), h), Qt::white);
: Qt::FastTransformation; p.end();
if (h <= 0) {
return Ui::PixmapFromImage( result = Round(std::move(result), args.options);
prepareColored(add, img.scaledToWidth(w, transformation))); if (args.colored) {
} result = Colored(std::move(result), *args.colored);
return Ui::PixmapFromImage( }
prepareColored( return Ui::PixmapFromImage(std::move(result));
add,
img.scaled(w, h, Qt::IgnoreAspectRatio, transformation)));
}
QPixmap Image::pixBlurredColoredNoCache(
style::color add,
int w,
int h) const {
if (_data.isNull()) {
return Empty()->pix();
}
auto img = prepareBlur(_data);
if (h <= 0) {
img = img.scaledToWidth(w, Qt::SmoothTransformation);
} else {
img = img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
return Ui::PixmapFromImage(prepareColored(add, img));
} }

View File

@ -44,54 +44,68 @@ public:
[[nodiscard]] QImage original() const; [[nodiscard]] QImage original() const;
[[nodiscard]] const QPixmap &pix(int w = 0, int h = 0) const; [[nodiscard]] const QPixmap &pix(
[[nodiscard]] const QPixmap &pixRounded( QSize size,
int w = 0, const Images::PrepareArgs &args = {}) const {
int h = 0, return cached(size.width(), size.height(), args, false);
ImageRoundRadius radius = ImageRoundRadius::None, }
RectParts corners = RectPart::AllCorners) const; [[nodiscard]] const QPixmap &pix(
[[nodiscard]] const QPixmap &pixBlurred(int w = 0, int h = 0) const; int w,
[[nodiscard]] const QPixmap &pixColored(style::color add, int w = 0, int h = 0) const; int h,
[[nodiscard]] const QPixmap &pixBlurredColored( const Images::PrepareArgs &args = {}) const {
style::color add, return cached(w, h, args, false);
int w = 0, }
int h = 0) const; [[nodiscard]] const QPixmap &pix(
int w = 0,
const Images::PrepareArgs &args = {}) const {
return cached(w, 0, args, false);
}
[[nodiscard]] const QPixmap &pixSingle( [[nodiscard]] const QPixmap &pixSingle(
int w, QSize size,
int h, const Images::PrepareArgs &args = {}) const {
int outerw, return cached(size.width(), size.height(), args, true);
int outerh, }
ImageRoundRadius radius, [[nodiscard]] const QPixmap &pixSingle(
RectParts corners = RectPart::AllCorners, int w,
const style::color *colored = nullptr) const; int h,
[[nodiscard]] const QPixmap &pixBlurredSingle( const Images::PrepareArgs &args = {}) const {
int w, return cached(w, h, args, true);
int h, }
int outerw, [[nodiscard]] const QPixmap &pixSingle(
int outerh, int w = 0,
ImageRoundRadius radius, const Images::PrepareArgs &args = {}) const {
RectParts corners = RectPart::AllCorners, return cached(w, 0, args, true);
const style::color *colored = nullptr) const; }
[[nodiscard]] const QPixmap &pixCircled(int w = 0, int h = 0) const;
[[nodiscard]] const QPixmap &pixBlurredCircled(int w = 0, int h = 0) const;
[[nodiscard]] QPixmap pixNoCache( [[nodiscard]] QPixmap pixNoCache(
int w = 0, QSize size,
int h = 0, const Images::PrepareArgs &args = {}) const {
Images::Options options = 0, return prepare(size.width(), size.height(), args);
int outerw = -1, }
int outerh = -1, [[nodiscard]] QPixmap pixNoCache(
const style::color *colored = nullptr) const; int w,
[[nodiscard]] QPixmap pixColoredNoCache( int h,
style::color add, const Images::PrepareArgs &args = {}) const {
int w = 0, return prepare(w, h, args);
int h = 0, }
bool smooth = false) const; [[nodiscard]] QPixmap pixNoCache(
[[nodiscard]] QPixmap pixBlurredColoredNoCache( int w = 0,
style::color add, const Images::PrepareArgs &args = {}) const {
int w, return prepare(w, 0, args);
int h = 0) const; }
private: private:
[[nodiscard]] QPixmap prepare(
int w,
int h,
const Images::PrepareArgs &args) const;
[[nodiscard]] const QPixmap &cached(
int w,
int h,
const Images::PrepareArgs &args,
bool single) const;
const QImage _data; const QImage _data;
mutable base::flat_map<uint64, QPixmap> _cache; mutable base::flat_map<uint64, QPixmap> _cache;

View File

@ -696,8 +696,7 @@ void UserpicButton::setImage(QImage &&image) {
size * cIntRetinaFactor(), size * cIntRetinaFactor(),
Qt::IgnoreAspectRatio, Qt::IgnoreAspectRatio,
Qt::SmoothTransformation); Qt::SmoothTransformation);
Images::prepareCircle(small); _userpic = Ui::PixmapFromImage(Images::Circle(std::move(small)));
_userpic = Ui::PixmapFromImage(std::move(small));
_userpic.setDevicePixelRatio(cRetinaFactor()); _userpic.setDevicePixelRatio(cRetinaFactor());
_userpicCustom = _userpicHasImage = true; _userpicCustom = _userpicHasImage = true;
_result = std::move(image); _result = std::move(image);

View File

@ -169,8 +169,8 @@ void BackgroundSelector::updateThumbnail() {
int s = (pix.width() > pix.height()) ? pix.height() : pix.width(); int s = (pix.width() > pix.height()) ? pix.height() : pix.width();
p.drawImage(QRect(0, 0, size, size), pix, QRect(sx, sy, s, s)); p.drawImage(QRect(0, 0, size, size), pix, QRect(sx, sy, s, s));
} }
Images::prepareRound(back, ImageRoundRadius::Small); _thumbnail = Ui::PixmapFromImage(
_thumbnail = Ui::PixmapFromImage(std::move(back)); Images::Round(std::move(back), ImageRoundRadius::Small));
_thumbnail.setDevicePixelRatio(cRetinaFactor()); _thumbnail.setDevicePixelRatio(cRetinaFactor());
update(); update();
} }

View File

@ -968,7 +968,7 @@ void Generator::paintUserpic(int x, int y, Row::Type type, int index, QString le
p.setPen(st::historyPeerUserpicFg[_palette]); p.setPen(st::historyPeerUserpicFg[_palette]);
p.drawText(QRect(0, 0, st::dialogsPhotoSize, st::dialogsPhotoSize), letters, QTextOption(style::al_center)); p.drawText(QRect(0, 0, st::dialogsPhotoSize, st::dialogsPhotoSize), letters, QTextOption(style::al_center));
} }
Images::prepareCircle(image); image = Images::Circle(std::move(image));
_p->drawImage(rtl() ? (_rect.width() - x - st::dialogsPhotoSize) : x, y, image); _p->drawImage(rtl() ? (_rect.width() - x - st::dialogsPhotoSize) : x, y, image);
} }

View File

@ -214,7 +214,9 @@ void CloudListCheck::validateBackgroundCache(int width) {
0, 0,
imageWidth, imageWidth,
_backgroundFull.height()); _backgroundFull.height());
Images::prepareRound(_backgroundCache, ImageRoundRadius::Large); _backgroundCache = Images::Round(
std::move(_backgroundCache),
ImageRoundRadius::Large);
_backgroundCache.setDevicePixelRatio(cRetinaFactor()); _backgroundCache.setDevicePixelRatio(cRetinaFactor());
} }

View File

@ -258,6 +258,7 @@ void MediaPreviewWidget::setupLottie() {
} }
QPixmap MediaPreviewWidget::currentImage() const { QPixmap MediaPreviewWidget::currentImage() const {
const auto blur = Images::PrepareArgs{ .options = Images::Option::Blur };
if (_document) { if (_document) {
if (const auto sticker = _document->sticker()) { if (const auto sticker = _document->sticker()) {
if (_cacheStatus != CacheLoaded) { if (_cacheStatus != CacheLoaded) {
@ -268,13 +269,13 @@ QPixmap MediaPreviewWidget::currentImage() const {
return QPixmap(); return QPixmap();
} else if (const auto image = _documentMedia->getStickerLarge()) { } else if (const auto image = _documentMedia->getStickerLarge()) {
QSize s = currentDimensions(); QSize s = currentDimensions();
_cache = image->pix(s.width(), s.height()); _cache = image->pix(s);
_cacheStatus = CacheLoaded; _cacheStatus = CacheLoaded;
} else if (_cacheStatus != CacheThumbLoaded } else if (_cacheStatus != CacheThumbLoaded
&& _document->hasThumbnail() && _document->hasThumbnail()
&& _documentMedia->thumbnail()) { && _documentMedia->thumbnail()) {
QSize s = currentDimensions(); QSize s = currentDimensions();
_cache = _documentMedia->thumbnail()->pixBlurred(s.width(), s.height()); _cache = _documentMedia->thumbnail()->pix(s, blur);
_cacheStatus = CacheThumbLoaded; _cacheStatus = CacheThumbLoaded;
} }
} }
@ -293,10 +294,10 @@ QPixmap MediaPreviewWidget::currentImage() const {
QSize s = currentDimensions(); QSize s = currentDimensions();
const auto thumbnail = _documentMedia->thumbnail(); const auto thumbnail = _documentMedia->thumbnail();
if (thumbnail) { if (thumbnail) {
_cache = thumbnail->pixBlurred(s.width(), s.height()); _cache = thumbnail->pix(s, blur);
_cacheStatus = CacheThumbLoaded; _cacheStatus = CacheThumbLoaded;
} else if (const auto blurred = _documentMedia->thumbnailInline()) { } else if (const auto blurred = _documentMedia->thumbnailInline()) {
_cache = blurred->pixBlurred(s.width(), s.height()); _cache = blurred->pix(s, blur);
_cacheStatus = CacheThumbLoaded; _cacheStatus = CacheThumbLoaded;
} }
} }
@ -305,7 +306,7 @@ QPixmap MediaPreviewWidget::currentImage() const {
if (_cacheStatus != CacheLoaded) { if (_cacheStatus != CacheLoaded) {
if (_photoMedia->loaded()) { if (_photoMedia->loaded()) {
QSize s = currentDimensions(); QSize s = currentDimensions();
_cache = _photoMedia->image(Data::PhotoSize::Large)->pix(s.width(), s.height()); _cache = _photoMedia->image(Data::PhotoSize::Large)->pix(s);
_cacheStatus = CacheLoaded; _cacheStatus = CacheLoaded;
} else { } else {
_photo->load(_origin); _photo->load(_origin);
@ -313,14 +314,14 @@ QPixmap MediaPreviewWidget::currentImage() const {
QSize s = currentDimensions(); QSize s = currentDimensions();
if (const auto thumbnail = _photoMedia->image( if (const auto thumbnail = _photoMedia->image(
Data::PhotoSize::Thumbnail)) { Data::PhotoSize::Thumbnail)) {
_cache = thumbnail->pixBlurred(s.width(), s.height()); _cache = thumbnail->pix(s, blur);
_cacheStatus = CacheThumbLoaded; _cacheStatus = CacheThumbLoaded;
} else if (const auto small = _photoMedia->image( } else if (const auto small = _photoMedia->image(
Data::PhotoSize::Small)) { Data::PhotoSize::Small)) {
_cache = small->pixBlurred(s.width(), s.height()); _cache = small->pix(s, blur);
_cacheStatus = CacheThumbLoaded; _cacheStatus = CacheThumbLoaded;
} else if (const auto blurred = _photoMedia->thumbnailInline()) { } else if (const auto blurred = _photoMedia->thumbnailInline()) {
_cache = blurred->pixBlurred(s.width(), s.height()); _cache = blurred->pix(s, blur);
_cacheStatus = CacheThumbLoaded; _cacheStatus = CacheThumbLoaded;
} else { } else {
_photoMedia->wanted(Data::PhotoSize::Small, _origin); _photoMedia->wanted(Data::PhotoSize::Small, _origin);

@ -1 +1 @@
Subproject commit 17fbf3dec42290ed0c00c2458be82f6e8bdd47e9 Subproject commit f20776cf6541342c88e540b96e843cadb27016e0

@ -1 +1 @@
Subproject commit 04886885929086dea6fa80c038efc6f372d6996a Subproject commit 87e62b7737a68e9293e29f6467ca145a781ac9e6