diff --git a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp index 6aea0c7ab9..5d0e50926e 100644 --- a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp +++ b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.cpp @@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "logs.h" #include +#include extern "C" { #include @@ -353,4 +354,65 @@ QImage CreateFrameStorage(QSize size) { cleanupData); } +void UnPremultiply(QImage &to, const QImage &from) { + // This creates QImage::Format_ARGB32_Premultiplied, but we use it + // as an image in QImage::Format_ARGB32 format. + if (!GoodStorageForFrame(to, from.size())) { + to = CreateFrameStorage(from.size()); + } + + const auto layout = &qPixelLayouts[QImage::Format_ARGB32]; + const auto convert = layout->convertFromARGB32PM; + const auto fromPerLine = from.bytesPerLine(); + const auto toPerLine = to.bytesPerLine(); + const auto width = from.width(); + if (fromPerLine != width * 4 || toPerLine != width * 4) { + auto fromBytes = from.bits(); + auto toBytes = to.bits(); + for (auto i = 0; i != to.height(); ++i) { + convert( + reinterpret_cast(toBytes), + reinterpret_cast(fromBytes), + width, + layout, + nullptr); + fromBytes += fromPerLine; + toBytes += toPerLine; + } + } else { + convert( + reinterpret_cast(to.bits()), + reinterpret_cast(from.bits()), + from.width() * from.height(), + layout, + nullptr); + } +} + +void PremultiplyInplace(QImage &image) { + const auto layout = &qPixelLayouts[QImage::Format_ARGB32]; + const auto convert = layout->convertToARGB32PM; + const auto perLine = image.bytesPerLine(); + const auto width = image.width(); + if (perLine != width * 4) { + auto bytes = image.bits(); + for (auto i = 0; i != image.height(); ++i) { + convert( + reinterpret_cast(bytes), + reinterpret_cast(bytes), + width, + layout, + nullptr); + bytes += perLine; + } + } else { + convert( + reinterpret_cast(image.bits()), + reinterpret_cast(image.bits()), + image.width() * image.height(), + layout, + nullptr); + } +} + } // namespace FFmpeg diff --git a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.h b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.h index 6d75dde527..c30663f501 100644 --- a/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.h +++ b/Telegram/SourceFiles/ffmpeg/ffmpeg_utility.h @@ -189,4 +189,7 @@ void LogError(QLatin1String method, FFmpeg::AvErrorWrap error); [[nodiscard]] bool GoodStorageForFrame(const QImage &storage, QSize size); [[nodiscard]] QImage CreateFrameStorage(QSize size); +void UnPremultiply(QImage &to, const QImage &from); +void PremultiplyInplace(QImage &image); + } // namespace FFmpeg diff --git a/Telegram/SourceFiles/lottie/lottie_cache.cpp b/Telegram/SourceFiles/lottie/lottie_cache.cpp index 93a4a48fdb..b34eaf77aa 100644 --- a/Telegram/SourceFiles/lottie/lottie_cache.cpp +++ b/Telegram/SourceFiles/lottie/lottie_cache.cpp @@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "base/bytes.h" #include -#include #include #include #include @@ -48,67 +47,6 @@ void Xor(EncodedStorage &to, const EncodedStorage &from) { } } -void UnPremultiply(QImage &to, const QImage &from) { - // This creates QImage::Format_ARGB32_Premultiplied, but we use it - // as an image in QImage::Format_ARGB32 format. - if (!FFmpeg::GoodStorageForFrame(to, from.size())) { - to = FFmpeg::CreateFrameStorage(from.size()); - } - - const auto layout = &qPixelLayouts[QImage::Format_ARGB32]; - const auto convert = layout->convertFromARGB32PM; - const auto fromPerLine = from.bytesPerLine(); - const auto toPerLine = to.bytesPerLine(); - const auto width = from.width(); - if (fromPerLine != width * 4 || toPerLine != width * 4) { - auto fromBytes = from.bits(); - auto toBytes = to.bits(); - for (auto i = 0; i != to.height(); ++i) { - convert( - reinterpret_cast(toBytes), - reinterpret_cast(fromBytes), - width, - layout, - nullptr); - fromBytes += fromPerLine; - toBytes += toPerLine; - } - } else { - convert( - reinterpret_cast(to.bits()), - reinterpret_cast(from.bits()), - from.width() * from.height(), - layout, - nullptr); - } -} - -void PremultiplyInplace(QImage &image) { - const auto layout = &qPixelLayouts[QImage::Format_ARGB32]; - const auto convert = layout->convertToARGB32PM; - const auto perLine = image.bytesPerLine(); - const auto width = image.width(); - if (perLine != width * 4) { - auto bytes = image.bits(); - for (auto i = 0; i != image.height(); ++i) { - convert( - reinterpret_cast(bytes), - reinterpret_cast(bytes), - width, - layout, - nullptr); - bytes += perLine; - } - } else { - convert( - reinterpret_cast(image.bits()), - reinterpret_cast(image.bits()), - image.width() * image.height(), - layout, - nullptr); - } -} - bool UncompressToRaw(EncodedStorage &to, bytes::const_span from) { if (from.empty() || from.size() > to.size()) { return false; @@ -247,7 +185,7 @@ void Decode( } DecodeYUV2RGB(to, from, context); DecodeAlpha(to, from); - PremultiplyInplace(to); + FFmpeg::PremultiplyInplace(to); } void EncodeRGB2YUV( @@ -311,7 +249,7 @@ void Encode( const QImage &from, QImage &cache, FFmpeg::SwscalePointer &context) { - UnPremultiply(cache, from); + FFmpeg::UnPremultiply(cache, from); EncodeRGB2YUV(to, cache, context); EncodeAlpha(to, cache); } diff --git a/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp b/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp index 9ef76638a8..e4dfbe18ec 100644 --- a/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp +++ b/Telegram/SourceFiles/media/clip/media_clip_ffmpeg.cpp @@ -254,6 +254,9 @@ bool FFMpegReaderImplementation::renderFrame(QImage &to, bool &hasAlpha, const Q return false; } } + if (hasAlpha) { + FFmpeg::PremultiplyInplace(to); + } if (_rotation != Rotation::None) { QTransform rotationTransform; switch (_rotation) {