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 (const auto image = _photo->image(Data::PhotoSize::Small)) {
const auto size = st::confirmInvitePhotoSize;
p.drawPixmap(
(width() - st::confirmInvitePhotoSize) / 2,
(width() - size) / 2,
st::confirmInvitePhotoTop,
image->pixCircled(
st::confirmInvitePhotoSize,
st::confirmInvitePhotoSize));
image->pix(
{ size, size },
{ .options = Images::Option::RoundCircle }));
}
} else if (_photoEmpty) {
_photoEmpty->paint(

View File

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

View File

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

View File

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

View File

@ -165,8 +165,12 @@ void Userpic::refreshPhoto() {
void Userpic::createCache(Image *image) {
const auto size = this->size();
const auto real = size * cIntRetinaFactor();
auto options = Images::Option::Smooth | Images::Option::Circled;
// _useTransparency ? (Images::Option::RoundedLarge | Images::Option::RoundedTopLeft | Images::Option::RoundedTopRight | Images::Option::Smooth) : Images::Option::None;
auto options = Images::Option() | Images::Option::RoundCircle;
//_useTransparency
// ? (Images::Option::RoundLarge
// | Images::Option::RoundSkipBottomLeft
// | Images::Option::RoundSkipBottomRight)
// : Images::Option::None;
if (image) {
auto width = image->width();
auto height = image->height();
@ -178,14 +182,16 @@ void Userpic::createCache(Image *image) {
width = real;
}
_userPhoto = image->pixNoCache(
width,
height,
options,
size,
size);
{ width, height },
{
.options = Images::Option::RoundCircle,
.outer = { size, size },
});
_userPhoto.setDevicePixelRatio(cRetinaFactor());
} 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.fill(Qt::transparent);
{
@ -195,7 +201,10 @@ void Userpic::createCache(Image *image) {
_peer->name
).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));
}

View File

@ -169,12 +169,12 @@ void VideoBubble::prepareFrame() {
for (; from != till; from += fromPerLine, to += toPerLine) {
memcpy(to, from, lineSize);
}
Images::prepareRound(
_frame,
_frame = Images::Round(
std::move(_frame),
ImageRoundRadius::Large,
RectPart::AllCorners,
QRect(QPoint(), size));
_frame = std::move(_frame).mirrored(true, false);
QRect(QPoint(), size)
).mirrored(true, false);
}
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()
? sticker.savedFrame
: image
? image->pixSingle(
w,
h,
w,
h,
ImageRoundRadius::None)
? image->pixSingle(w, h, { .outer = { w, h } })
: QPixmap();
if (!pixmap.isNull()) {
p.drawPixmapLeft(ppos, width(), pixmap);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -342,16 +342,15 @@ void HistoryMessageReply::paint(
if (hasPreview) {
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 previewWidth = image->width() / cIntRetinaFactor();
auto previewHeight = image->height() / cIntRetinaFactor();
auto preview = image->pixSingle(
previewWidth,
previewHeight,
to.width(),
to.height(),
ImageRoundRadius::Small,
RectPart::AllCorners,
context.selected() ? &st->msgStickerOverlay() : nullptr);
const auto preview = image->pixSingle(
image->size() / style::DevicePixelRatio(),
{
.colored = (context.selected()
? &st->msgStickerOverlay()
: nullptr),
.options = Images::Option::RoundSmall,
.outer = to.size(),
});
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 (const auto image = drawMsgText->media()->replyPreview()) {
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();
}

View File

@ -1144,8 +1144,7 @@ Manager::OverlayImage Manager::validateOverlayShadow(
p.end();
}
_overlayShadowScaled = Images::prepareBlur(
std::move(_overlayShadowScaled));
_overlayShadowScaled = Images::Blur(std::move(_overlayShadowScaled));
auto q = Painter(result.cache);
if (result.cache != &_overlayShadowScaled) {
@ -1436,7 +1435,7 @@ QRect Manager::validateShadow(
}
p.drawRoundedRect(big.translated(0, shift), radius, radius);
p.end();
_shadowBuffer = Images::prepareBlur(std::move(_shadowBuffer));
_shadowBuffer = Images::Blur(std::move(_shadowBuffer));
auto q = QPainter(&_cacheParts);
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 radialOpacity = radial ? _animation->radial.opacity() : 1.;
if (thumbed) {
auto inWebPage = (_parent->media() != this);
auto roundRadius = inWebPage ? ImageRoundRadius::Small : ImageRoundRadius::Large;
const auto inWebPage = (_parent->media() != this);
const auto args = Images::PrepareArgs{
.options = (inWebPage
? Images::Option::RoundSmall
: Images::Option::RoundLarge),
.outer = QSize(st.thumbSize, st.thumbSize),
};
QPixmap thumb;
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()) {
thumb = blurred->pixBlurredSingle(thumbed->_thumbw, 0, st.thumbSize, st.thumbSize, roundRadius);
thumb = blurred->pixSingle(thumbed->_thumbw, args.blurred());
}
p.drawPixmap(rthumb.topLeft(), thumb);
if (context.selected()) {
@ -1090,32 +1095,27 @@ bool DrawThumbnailAsSongCover(
return false;
}
QPixmap cover;
const auto ow = rect.width();
const auto oh = rect.height();
const auto r = ImageRoundRadius::Ellipse;
const auto c = RectPart::AllCorners;
const auto aspectRatio = Qt::KeepAspectRatioByExpanding;
const auto scaled = [&](not_null<Image*> image) -> std::pair<int, int> {
const auto size = image->size().scaled(ow, oh, aspectRatio);
return { size.width(), size.height() };
auto cover = QPixmap();
const auto scaled = [&](not_null<Image*> image) {
const auto aspectRatio = Qt::KeepAspectRatioByExpanding;
return image->size().scaled(rect.size(), aspectRatio);
};
const auto args = Images::PrepareArgs{
.colored = &colored,
.options = Images::Option::RoundCircle,
.outer = rect.size(),
};
if (const auto normal = dataMedia->thumbnail()) {
const auto &[w, h] = scaled(normal);
cover = normal->pixSingle(w, h, ow, oh, r, c, &colored);
cover = normal->pixSingle(scaled(normal), args);
} else if (const auto blurred = dataMedia->thumbnailInline()) {
const auto &[w, h] = scaled(blurred);
cover = blurred->pixBlurredSingle(w, h, ow, oh, r, c, &colored);
cover = blurred->pixSingle(scaled(blurred), args.blurred());
} else {
return false;
}
if (selected) {
auto selectedCover = Images::prepareColored(
p.textPalette().selectOverlay,
cover.toImage());
auto selectedCover = Images::Colored(
cover.toImage(),
p.textPalette().selectOverlay);
cover = QPixmap::fromImage(
std::move(selectedCover),
Qt::ColorOnly);

View File

@ -439,24 +439,28 @@ void Gif::draw(Painter &p, const PaintContext &context) const {
}
} else {
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()) {
p.drawPixmap(rthumb.topLeft(), good->pixSingle(_thumbw, _thumbh, usew, painth, roundRadius, roundCorners));
p.drawPixmap(rthumb.topLeft(), good->pixSingle(size, args));
} else {
const auto normal = _dataMedia->thumbnail();
if (normal) {
if (normal->width() >= kUseNonBlurredThreshold
|| normal->height() >= kUseNonBlurredThreshold) {
p.drawPixmap(rthumb.topLeft(), normal->pixSingle(_thumbw, _thumbh, usew, painth, roundRadius, roundCorners));
} else {
p.drawPixmap(rthumb.topLeft(), normal->pixBlurredSingle(_thumbw, _thumbh, usew, painth, roundRadius, roundCorners));
}
const auto blurred = (normal->width() < kUseNonBlurredThreshold)
|| (normal->height() < kUseNonBlurredThreshold);
p.drawPixmap(
rthumb.topLeft(),
normal->pixSingle(size, blurred ? args.blurred() : args));
} else {
_data->loadThumbnail(_realParent->fullId());
validateVideoThumbnail();
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()) {
p.drawPixmap(rthumb.topLeft(), blurred->pixBlurredSingle(_thumbw, _thumbh, usew, painth, roundRadius, roundCorners));
p.drawPixmap(rthumb.topLeft(), blurred->pixSingle(size, args.blurred()));
} else if (!isRound) {
const auto roundTop = (roundCorners & RectPart::TopLeft);
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 width = geometry.width();
const auto height = geometry.height();
const auto options = Option::Smooth
| Option::RoundedLarge
| (blur ? Option::Blurred : Option(0))
| ((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);
const auto corner = [&](RectPart part, Option skip) {
return !(corners & part) ? skip : Option();
};
const auto options = Option::RoundLarge
| (blur ? Option::Blur : Option(0))
| corner(RectPart::TopLeft, Option::RoundSkipTopLeft)
| corner(RectPart::TopRight, Option::RoundSkipTopRight)
| corner(RectPart::BottomLeft, Option::RoundSkipBottomLeft)
| corner(RectPart::BottomRight, Option::RoundSkipBottomRight);
const auto key = (uint64(width) << 48)
| (uint64(height) << 32)
| (uint64(options) << 16)
@ -1312,16 +1318,12 @@ void Gif::validateGroupedCache(
const auto pixSize = Ui::GetImageScaleSizeForGeometry(
{ originalWidth, originalHeight },
{ width, height });
const auto pixWidth = pixSize.width() * cIntRetinaFactor();
const auto pixHeight = pixSize.height() * cIntRetinaFactor();
const auto ratio = style::DevicePixelRatio();
*cacheKey = key;
*cache = (image ? image : Image::BlankMedia().get())->pixNoCache(
pixWidth,
pixHeight,
options,
width,
height);
pixSize * ratio,
{ .options = options, .outer = { width, height } });
}
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 size = EmojiImage::Size() / cIntRetinaFactor();
for (const auto &image : images) {
const auto w = size.width();
if (const auto &prepared = image->image) {
const auto h = size.height();
const auto pixmap = context.selected()
? prepared->pixColored(context.st->msgStickerOverlay(), w, h)
: prepared->pix(w, h);
p.drawPixmap(x, y, pixmap);
const auto colored = context.selected()
? &context.st->msgStickerOverlay()
: nullptr;
p.drawPixmap(x, y, prepared->pix(size, { .colored = colored }));
} else if (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);
ensureMediaCreated();
if (const auto thumbnail = _media->image()) {
const auto &pix = thumbnail->pixSingle(paintw, painth, paintw, painth, roundRadius, roundCorners);
p.drawPixmap(rthumb.topLeft(), pix);
p.drawPixmap(rthumb.topLeft(), thumbnail->pixSingle(
rthumb.size(),
{
.options = Images::RoundOptions(roundRadius, roundCorners),
.outer = rthumb.size(),
}));
} else {
Ui::FillComplexLocationRect(p, st, rthumb, roundRadius, roundCorners);
}

View File

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

View File

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

View File

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

View File

@ -508,14 +508,19 @@ void WebPage::draw(Painter &p, const PaintContext &context) const {
pixh = qRound(pixh * 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(
Data::PhotoSize::Thumbnail)) {
pix = thumbnail->pixSingle(pixw, pixh, pw, ph, ImageRoundRadius::Small);
pix = thumbnail->pixSingle(size, args);
} else if (const auto small = _photoMedia->image(
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()) {
pix = blurred->pixBlurredSingle(pixw, pixh, pw, ph, ImageRoundRadius::Small);
pix = blurred->pixSingle(size, args.blurred());
}
p.drawPixmapLeft(padding.left() + paintw - pw, tshift, width(), pix);
if (context.selected()) {

View File

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

View File

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

View File

@ -173,7 +173,7 @@ void Float::prepareShadow() {
auto extend = 2 * st::lineWidth;
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 {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -106,11 +106,8 @@ struct PickerScrubberItem {
const auto size = sticker->size()
.scaled(kCircleDiameter, kCircleDiameter, Qt::KeepAspectRatio);
image = sticker->pixSingle(
size.width(),
size.height(),
kCircleDiameter,
kCircleDiameter,
ImageRoundRadius::None).toImage();
size,
{ .outer = { kCircleDiameter, kCircleDiameter } }).toImage();
}
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[2] = roundMask.copy(0, 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);
Images::prepareRound(rounded, corners);
auto rounded = Images::Round(
preview.copy(
inner.x() * retina,
inner.y() * retina,
inner.width() * retina,
inner.height() * retina),
corners);
rounded.setDevicePixelRatio(cRetinaFactor());
preview.fill(st::themePreviewBg->c);

View File

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

View File

@ -724,7 +724,7 @@ void FileLoadTask::process(Args &&args) {
&_information->media)) {
fullimage = base::take(image->data);
if (!Core::IsMimeSticker(filemime)) {
fullimage = Images::prepareOpaque(std::move(fullimage));
fullimage = Images::Opaque(std::move(fullimage));
}
isAnimation = image->animated;
}
@ -743,7 +743,7 @@ void FileLoadTask::process(Args &&args) {
const auto mimeType = Core::MimeTypeForData(_content);
filemime = mimeType.name();
if (!Core::IsMimeSticker(filemime)) {
fullimage = Images::prepareOpaque(std::move(fullimage));
fullimage = Images::Opaque(std::move(fullimage));
}
if (filemime == "image/jpeg") {
filename = filedialogDefaultName(qsl("photo"), qsl(".jpg"), QString(), true);
@ -784,7 +784,7 @@ void FileLoadTask::process(Args &&args) {
}
filesize = _content.size();
}
fullimage = Images::prepareOpaque(std::move(fullimage));
fullimage = Images::Opaque(std::move(fullimage));
}
}
_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>(
&file.information->media)) {
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.preview = std::move(blurred).scaledToWidth(
previewWidth * cIntRetinaFactor(),
@ -333,7 +334,7 @@ void UpdateImageDetails(PreparedFile &file, int previewWidth) {
previewWidth,
style::ConvertScale(preview.width())
) * cIntRetinaFactor();
const auto scaled = preview.scaledToWidth(
auto scaled = preview.scaledToWidth(
toWidth,
Qt::SmoothTransformation);
if (scaled.isNull()) {
@ -345,7 +346,7 @@ void UpdateImageDetails(PreparedFile &file, int previewWidth) {
Unexpected("Scaled is null.");
}
Assert(!scaled.isNull());
file.preview = Images::prepareOpaque(scaled);
file.preview = Images::Opaque(std::move(scaled));
Assert(!file.preview.isNull());
file.preview.setDevicePixelRatio(cRetinaFactor());
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,6 +27,18 @@ namespace {
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
QByteArray ExpandInlineBytes(const QByteArray &bytes) {
@ -330,336 +342,66 @@ QImage Image::original() const {
return _data;
}
const QPixmap &Image::pix(int w, int h) const {
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(
const QPixmap &Image::cached(
int w,
int h,
ImageRoundRadius radius,
RectParts corners) const {
const Images::PrepareArgs &args,
bool single) const {
const auto ratio = style::DevicePixelRatio();
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 {
w *= cIntRetinaFactor();
h *= cIntRetinaFactor();
w *= ratio;
h *= ratio;
}
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);
}
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 auto outer = args.outer;
const auto size = outer.isEmpty() ? QSize(w, h) : outer * ratio;
const auto k = single ? SinglePixKey(args) : PixKey(w, h, args);
const auto i = _cache.find(k);
return (i != _cache.cend() && i->second.size() == size)
? i->second
: _cache.emplace_or_assign(k, prepare(w, h, args)).first->second;
}
const QPixmap &Image::pixCircled(int w, int h) 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 {
QPixmap Image::prepare(int w, int h, const Images::PrepareArgs &args) const {
if (_data.isNull()) {
if (h <= 0 && height() > 0) {
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) {
outerw *= cIntRetinaFactor();
outerh *= cIntRetinaFactor();
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));
auto outer = args.outer;
if (!isNull() || outer.isEmpty()) {
return Ui::PixmapFromImage(Prepare(_data, w, h, args));
}
return Ui::PixmapFromImage(
prepare(_data, w, h, options, outerw, outerh, colored));
}
QPixmap Image::pixColoredNoCache(
style::color add,
int w,
int h,
bool smooth) const {
if (_data.isNull()) {
return Empty()->pix();
}
auto img = _data;
if (w <= 0 || !width() || !height() || (w == width() && (h <= 0 || h == height()))) {
return Ui::PixmapFromImage(prepareColored(add, std::move(img)));
}
const auto transformation = smooth
? Qt::SmoothTransformation
: Qt::FastTransformation;
if (h <= 0) {
return Ui::PixmapFromImage(
prepareColored(add, img.scaledToWidth(w, transformation)));
}
return Ui::PixmapFromImage(
prepareColored(
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));
const auto ratio = style::DevicePixelRatio();
const auto outerw = outer.width() * ratio;
const auto outerh = outer.height() * ratio;
auto result = QImage(
QSize(outerw, outerh),
QImage::Format_ARGB32_Premultiplied);
result.setDevicePixelRatio(ratio);
auto p = QPainter(&result);
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);
}
if (h < outerh) {
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);
}
p.fillRect(qMax(0, (outerw - w) / 2), qMax(0, (outerh - h) / 2), qMin(result.width(), w), qMin(result.height(), h), Qt::white);
p.end();
result = Round(std::move(result), args.options);
if (args.colored) {
result = Colored(std::move(result), *args.colored);
}
return Ui::PixmapFromImage(std::move(result));
}

View File

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

View File

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

View File

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

View File

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

View File

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

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

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