mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Fix showing static content in OpenGL media viewer.
This commit is contained in:
parent
23c2bce1bb
commit
71ddfacfaa
4 changed files with 113 additions and 60 deletions
|
@ -264,6 +264,14 @@ void OverlayWidget::RendererGL::paintTransformedStaticContent(
|
||||||
const QImage &image,
|
const QImage &image,
|
||||||
ContentGeometry geometry,
|
ContentGeometry geometry,
|
||||||
bool fillTransparentBackground) {
|
bool fillTransparentBackground) {
|
||||||
|
Expects(image.isNull()
|
||||||
|
|| image.format() == QImage::Format_RGB32
|
||||||
|
|| image.format() == QImage::Format_ARGB32_Premultiplied);
|
||||||
|
|
||||||
|
if (geometry.rect.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto &program = fillTransparentBackground
|
auto &program = fillTransparentBackground
|
||||||
? _withTransparencyProgram
|
? _withTransparencyProgram
|
||||||
: _imageProgram;
|
: _imageProgram;
|
||||||
|
@ -282,20 +290,33 @@ void OverlayWidget::RendererGL::paintTransformedStaticContent(
|
||||||
|
|
||||||
_f->glActiveTexture(GL_TEXTURE0);
|
_f->glActiveTexture(GL_TEXTURE0);
|
||||||
_textures.bind(*_f, 0);
|
_textures.bind(*_f, 0);
|
||||||
const auto cacheKey = image.cacheKey();
|
const auto cacheKey = image.isNull() ? qint64(-1) : image.cacheKey();
|
||||||
const auto upload = (_cacheKey != cacheKey);
|
const auto upload = (_cacheKey != cacheKey);
|
||||||
if (upload) {
|
if (upload) {
|
||||||
_cacheKey = cacheKey;
|
_cacheKey = cacheKey;
|
||||||
const auto stride = image.bytesPerLine() / 4;
|
if (image.isNull()) {
|
||||||
const auto data = image.constBits();
|
// Upload transparent 2x2 texture.
|
||||||
uploadTexture(
|
const auto stride = 2;
|
||||||
GL_RGBA,
|
const uint32_t data[4] = { 0 };
|
||||||
GL_RGBA,
|
uploadTexture(
|
||||||
image.size(),
|
GL_RGBA,
|
||||||
_rgbaSize,
|
GL_RGBA,
|
||||||
stride,
|
QSize(2, 2),
|
||||||
data);
|
_rgbaSize,
|
||||||
_rgbaSize = image.size();
|
stride,
|
||||||
|
data);
|
||||||
|
} else {
|
||||||
|
const auto stride = image.bytesPerLine() / 4;
|
||||||
|
const auto data = image.constBits();
|
||||||
|
uploadTexture(
|
||||||
|
GL_RGBA,
|
||||||
|
GL_RGBA,
|
||||||
|
image.size(),
|
||||||
|
_rgbaSize,
|
||||||
|
stride,
|
||||||
|
data);
|
||||||
|
_rgbaSize = image.size();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
paintTransformedContent(&*program, geometry);
|
paintTransformedContent(&*program, geometry);
|
||||||
|
|
|
@ -119,7 +119,7 @@ private:
|
||||||
QSize _rgbaSize;
|
QSize _rgbaSize;
|
||||||
QSize _lumaSize;
|
QSize _lumaSize;
|
||||||
QSize _chromaSize;
|
QSize _chromaSize;
|
||||||
quint64 _cacheKey = 0;
|
qint64 _cacheKey = 0;
|
||||||
int _trackFrameIndex = 0;
|
int _trackFrameIndex = 0;
|
||||||
int _streamedIndex = 0;
|
int _streamedIndex = 0;
|
||||||
|
|
||||||
|
|
|
@ -139,14 +139,14 @@ QWidget *PipDelegate::pipParentWidget() {
|
||||||
return _parent;
|
return _parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
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::Smooth | Images::Option::Blurred;
|
||||||
return (document && document->isVideoMessage())
|
return (document && document->isVideoMessage())
|
||||||
? (result | Images::Option::Circled)
|
? (result | Images::Option::Circled)
|
||||||
: result;
|
: result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage PrepareStaticImage(QImage image) {
|
[[nodiscard]] QImage PrepareStaticImage(QImage image) {
|
||||||
if (image.width() > kMaxDisplayImageSize
|
if (image.width() > kMaxDisplayImageSize
|
||||||
|| image.height() > kMaxDisplayImageSize) {
|
|| image.height() > kMaxDisplayImageSize) {
|
||||||
image = image.scaled(
|
image = image.scaled(
|
||||||
|
@ -158,14 +158,35 @@ QImage PrepareStaticImage(QImage image) {
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage PrepareStaticImage(const QString &path) {
|
[[nodiscard]] QImage PrepareStaticImage(const QString &path) {
|
||||||
return PrepareStaticImage(App::readImage(path, nullptr, false));
|
return PrepareStaticImage(App::readImage(path, nullptr, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage PrepareStaticImage(const QByteArray &bytes) {
|
[[nodiscard]] QImage PrepareStaticImage(const QByteArray &bytes) {
|
||||||
return PrepareStaticImage(App::readImage(bytes, nullptr, false));
|
return PrepareStaticImage(App::readImage(bytes, nullptr, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool IsSemitransparent(const QImage &image) {
|
||||||
|
if (image.isNull()) {
|
||||||
|
return true;
|
||||||
|
} else if (!image.hasAlphaChannel()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Assert(image.format() == QImage::Format_ARGB32_Premultiplied);
|
||||||
|
constexpr auto kAlphaMask = 0xFF000000;
|
||||||
|
auto ints = reinterpret_cast<const uint32*>(image.bits());
|
||||||
|
const auto add = (image.bytesPerLine() / 4) - image.width();
|
||||||
|
for (auto y = 0; y != image.height(); ++y) {
|
||||||
|
for (auto till = ints + image.width(); ints != till; ++ints) {
|
||||||
|
if ((*ints & kAlphaMask) != kAlphaMask) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ints += add;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
struct OverlayWidget::SharedMedia {
|
struct OverlayWidget::SharedMedia {
|
||||||
|
@ -589,6 +610,18 @@ bool OverlayWidget::documentBubbleShown() const {
|
||||||
&& _staticContent.isNull());
|
&& _staticContent.isNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OverlayWidget::setStaticContent(QImage image) {
|
||||||
|
constexpr auto kGood = QImage::Format_ARGB32_Premultiplied;
|
||||||
|
if (!image.isNull()
|
||||||
|
&& image.format() != kGood
|
||||||
|
&& image.format() != QImage::Format_RGB32) {
|
||||||
|
image = std::move(image).convertToFormat(kGood);
|
||||||
|
}
|
||||||
|
image.setDevicePixelRatio(cRetinaFactor());
|
||||||
|
_staticContent = std::move(image);
|
||||||
|
_staticContentTransparent = IsSemitransparent(_staticContent);
|
||||||
|
}
|
||||||
|
|
||||||
bool OverlayWidget::contentShown() const {
|
bool OverlayWidget::contentShown() const {
|
||||||
return _photo || documentContentShown();
|
return _photo || documentContentShown();
|
||||||
}
|
}
|
||||||
|
@ -2362,43 +2395,44 @@ void OverlayWidget::displayDocument(
|
||||||
|
|
||||||
refreshMediaViewer();
|
refreshMediaViewer();
|
||||||
if (_document) {
|
if (_document) {
|
||||||
if (_document->sticker()) {
|
if (_document->sticker()) {
|
||||||
if (const auto image = _documentMedia->getStickerLarge()) {
|
if (const auto image = _documentMedia->getStickerLarge()) {
|
||||||
_staticContent = image->original();
|
setStaticContent(image->original());
|
||||||
} else if (const auto thumbnail = _documentMedia->thumbnail()) {
|
} else if (const auto thumbnail = _documentMedia->thumbnail()) {
|
||||||
_staticContent = thumbnail->pixBlurred(
|
setStaticContent(thumbnail->pixBlurred(
|
||||||
_document->dimensions.width(),
|
_document->dimensions.width(),
|
||||||
_document->dimensions.height()
|
_document->dimensions.height()
|
||||||
).toImage();
|
).toImage());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_documentMedia->canBePlayed()
|
||||||
|
&& initStreaming(continueStreaming)) {
|
||||||
|
} else if (_document->isVideoFile()) {
|
||||||
|
_documentMedia->automaticLoad(fileOrigin(), item);
|
||||||
|
initStreamingThumbnail();
|
||||||
|
} else if (_document->isTheme()) {
|
||||||
|
_documentMedia->automaticLoad(fileOrigin(), item);
|
||||||
|
initThemePreview();
|
||||||
|
} else {
|
||||||
|
_documentMedia->automaticLoad(fileOrigin(), item);
|
||||||
|
_document->saveFromDataSilent();
|
||||||
|
auto &location = _document->location(true);
|
||||||
|
if (location.accessEnable()) {
|
||||||
|
const auto &path = location.name();
|
||||||
|
if (QImageReader(path).canRead()) {
|
||||||
|
setStaticContent(PrepareStaticImage(path));
|
||||||
|
_touchbarDisplay.fire(TouchBarItemType::Photo);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!_documentMedia->bytes().isEmpty()) {
|
||||||
if (_documentMedia->canBePlayed()
|
setStaticContent(
|
||||||
&& initStreaming(continueStreaming)) {
|
PrepareStaticImage(_documentMedia->bytes()));
|
||||||
} else if (_document->isVideoFile()) {
|
if (!_staticContent.isNull()) {
|
||||||
_documentMedia->automaticLoad(fileOrigin(), item);
|
_touchbarDisplay.fire(TouchBarItemType::Photo);
|
||||||
initStreamingThumbnail();
|
|
||||||
} else if (_document->isTheme()) {
|
|
||||||
_documentMedia->automaticLoad(fileOrigin(), item);
|
|
||||||
initThemePreview();
|
|
||||||
} else {
|
|
||||||
_documentMedia->automaticLoad(fileOrigin(), item);
|
|
||||||
_document->saveFromDataSilent();
|
|
||||||
auto &location = _document->location(true);
|
|
||||||
if (location.accessEnable()) {
|
|
||||||
const auto &path = location.name();
|
|
||||||
if (QImageReader(path).canRead()) {
|
|
||||||
_staticContent = PrepareStaticImage(path);
|
|
||||||
_touchbarDisplay.fire(TouchBarItemType::Photo);
|
|
||||||
}
|
|
||||||
} else if (!_documentMedia->bytes().isEmpty()) {
|
|
||||||
_staticContent = PrepareStaticImage(_documentMedia->bytes());
|
|
||||||
if (!_staticContent.isNull()) {
|
|
||||||
_touchbarDisplay.fire(TouchBarItemType::Photo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
location.accessDisable();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
location.accessDisable();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
refreshCaption(item);
|
refreshCaption(item);
|
||||||
|
|
||||||
|
@ -2459,7 +2493,6 @@ void OverlayWidget::displayDocument(
|
||||||
} else if (_themePreviewShown) {
|
} else if (_themePreviewShown) {
|
||||||
updateThemePreviewGeometry();
|
updateThemePreviewGeometry();
|
||||||
} else if (!_staticContent.isNull()) {
|
} else if (!_staticContent.isNull()) {
|
||||||
_staticContent.setDevicePixelRatio(cRetinaFactor());
|
|
||||||
const auto size = style::ConvertScale(
|
const auto size = style::ConvertScale(
|
||||||
flipSizeByRotation(_staticContent.size()));
|
flipSizeByRotation(_staticContent.size()));
|
||||||
_w = size.width();
|
_w = size.width();
|
||||||
|
@ -2631,7 +2664,7 @@ void OverlayWidget::initStreamingThumbnail() {
|
||||||
const auto h = size.height();
|
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::Blurred);
|
||||||
_staticContent = (good
|
setStaticContent((good
|
||||||
? good
|
? good
|
||||||
: thumbnail
|
: thumbnail
|
||||||
? thumbnail
|
? thumbnail
|
||||||
|
@ -2643,8 +2676,7 @@ void OverlayWidget::initStreamingThumbnail() {
|
||||||
good ? goodOptions : options,
|
good ? goodOptions : options,
|
||||||
w / cIntRetinaFactor(),
|
w / cIntRetinaFactor(),
|
||||||
h / cIntRetinaFactor()
|
h / cIntRetinaFactor()
|
||||||
).toImage();
|
).toImage());
|
||||||
_staticContent.setDevicePixelRatio(cRetinaFactor());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverlayWidget::streamingReady(Streaming::Information &&info) {
|
void OverlayWidget::streamingReady(Streaming::Information &&info) {
|
||||||
|
@ -2970,7 +3002,7 @@ void OverlayWidget::restartAtSeekPosition(crl::time position) {
|
||||||
if (videoShown()) {
|
if (videoShown()) {
|
||||||
_streamed->instance.saveFrameToCover();
|
_streamed->instance.saveFrameToCover();
|
||||||
const auto saved = base::take(_rotation);
|
const auto saved = base::take(_rotation);
|
||||||
_staticContent = transformedShownContent();
|
setStaticContent(transformedShownContent());
|
||||||
_rotation = saved;
|
_rotation = saved;
|
||||||
updateContentRect();
|
updateContentRect();
|
||||||
}
|
}
|
||||||
|
@ -3163,13 +3195,12 @@ void OverlayWidget::validatePhotoImage(Image *image, bool blurred) {
|
||||||
}
|
}
|
||||||
const auto use = flipSizeByRotation({ _width, _height })
|
const auto use = flipSizeByRotation({ _width, _height })
|
||||||
* cIntRetinaFactor();
|
* cIntRetinaFactor();
|
||||||
_staticContent = image->pixNoCache(
|
setStaticContent(image->pixNoCache(
|
||||||
use.width(),
|
use.width(),
|
||||||
use.height(),
|
use.height(),
|
||||||
Images::Option::Smooth
|
Images::Option::Smooth
|
||||||
| (blurred ? Images::Option::Blurred : Images::Option(0))
|
| (blurred ? Images::Option::Blurred : Images::Option(0))
|
||||||
).toImage();
|
).toImage());
|
||||||
_staticContent.setDevicePixelRatio(cRetinaFactor());
|
|
||||||
_blurred = blurred;
|
_blurred = blurred;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3226,8 +3257,7 @@ void OverlayWidget::paint(not_null<Renderer*> renderer) {
|
||||||
validatePhotoCurrentImage();
|
validatePhotoCurrentImage();
|
||||||
const auto fillTransparentBackground = (!_document
|
const auto fillTransparentBackground = (!_document
|
||||||
|| (!_document->sticker() && !_document->isVideoMessage()))
|
|| (!_document->sticker() && !_document->isVideoMessage()))
|
||||||
&& (_staticContent.isNull()
|
&& _staticContentTransparent;
|
||||||
|| _staticContent.hasAlphaChannel());
|
|
||||||
renderer->paintTransformedStaticContent(
|
renderer->paintTransformedStaticContent(
|
||||||
_staticContent,
|
_staticContent,
|
||||||
contentGeometry(),
|
contentGeometry(),
|
||||||
|
|
|
@ -413,6 +413,7 @@ private:
|
||||||
int rotation) const;
|
int rotation) const;
|
||||||
[[nodiscard]] bool documentContentShown() const;
|
[[nodiscard]] bool documentContentShown() const;
|
||||||
[[nodiscard]] bool documentBubbleShown() const;
|
[[nodiscard]] bool documentBubbleShown() const;
|
||||||
|
void setStaticContent(QImage image);
|
||||||
[[nodiscard]] bool contentShown() const;
|
[[nodiscard]] bool contentShown() const;
|
||||||
[[nodiscard]] bool opaqueContentShown() const;
|
[[nodiscard]] bool opaqueContentShown() const;
|
||||||
void clearStreaming(bool savePosition = true);
|
void clearStreaming(bool savePosition = true);
|
||||||
|
@ -477,6 +478,7 @@ private:
|
||||||
bool _pressed = false;
|
bool _pressed = false;
|
||||||
int32 _dragging = 0;
|
int32 _dragging = 0;
|
||||||
QImage _staticContent;
|
QImage _staticContent;
|
||||||
|
bool _staticContentTransparent = false;
|
||||||
bool _blurred = true;
|
bool _blurred = true;
|
||||||
|
|
||||||
ContentGeometry _oldGeometry;
|
ContentGeometry _oldGeometry;
|
||||||
|
|
Loading…
Add table
Reference in a new issue