mirror of
https://github.com/telegramdesktop/tdesktop
synced 2025-01-25 16:54:25 +00:00
Fix transparent animated GIFs.
This commit is contained in:
parent
c8b61366d3
commit
556f36ba7e
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "logs.h"
|
||||
|
||||
#include <QImage>
|
||||
#include <private/qdrawhelper_p.h>
|
||||
|
||||
extern "C" {
|
||||
#include <libavutil/opt.h>
|
||||
@ -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<uint*>(toBytes),
|
||||
reinterpret_cast<const uint*>(fromBytes),
|
||||
width,
|
||||
layout,
|
||||
nullptr);
|
||||
fromBytes += fromPerLine;
|
||||
toBytes += toPerLine;
|
||||
}
|
||||
} else {
|
||||
convert(
|
||||
reinterpret_cast<uint*>(to.bits()),
|
||||
reinterpret_cast<const uint*>(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<uint*>(bytes),
|
||||
reinterpret_cast<const uint*>(bytes),
|
||||
width,
|
||||
layout,
|
||||
nullptr);
|
||||
bytes += perLine;
|
||||
}
|
||||
} else {
|
||||
convert(
|
||||
reinterpret_cast<uint*>(image.bits()),
|
||||
reinterpret_cast<const uint*>(image.bits()),
|
||||
image.width() * image.height(),
|
||||
layout,
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace FFmpeg
|
||||
|
@ -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
|
||||
|
@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
#include "base/bytes.h"
|
||||
|
||||
#include <QDataStream>
|
||||
#include <private/qdrawhelper_p.h>
|
||||
#include <lz4.h>
|
||||
#include <lz4hc.h>
|
||||
#include <range/v3/numeric/accumulate.hpp>
|
||||
@ -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<uint*>(toBytes),
|
||||
reinterpret_cast<const uint*>(fromBytes),
|
||||
width,
|
||||
layout,
|
||||
nullptr);
|
||||
fromBytes += fromPerLine;
|
||||
toBytes += toPerLine;
|
||||
}
|
||||
} else {
|
||||
convert(
|
||||
reinterpret_cast<uint*>(to.bits()),
|
||||
reinterpret_cast<const uint*>(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<uint*>(bytes),
|
||||
reinterpret_cast<const uint*>(bytes),
|
||||
width,
|
||||
layout,
|
||||
nullptr);
|
||||
bytes += perLine;
|
||||
}
|
||||
} else {
|
||||
convert(
|
||||
reinterpret_cast<uint*>(image.bits()),
|
||||
reinterpret_cast<const uint*>(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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user