mirror of
https://github.com/vale981/tdesktop
synced 2025-03-06 02:01:40 -05:00
Fix transparent animated GIFs.
This commit is contained in:
parent
c8b61366d3
commit
556f36ba7e
4 changed files with 70 additions and 64 deletions
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "logs.h"
|
#include "logs.h"
|
||||||
|
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
#include <private/qdrawhelper_p.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <libavutil/opt.h>
|
#include <libavutil/opt.h>
|
||||||
|
@ -353,4 +354,65 @@ QImage CreateFrameStorage(QSize size) {
|
||||||
cleanupData);
|
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
|
} // namespace FFmpeg
|
||||||
|
|
|
@ -189,4 +189,7 @@ void LogError(QLatin1String method, FFmpeg::AvErrorWrap error);
|
||||||
[[nodiscard]] bool GoodStorageForFrame(const QImage &storage, QSize size);
|
[[nodiscard]] bool GoodStorageForFrame(const QImage &storage, QSize size);
|
||||||
[[nodiscard]] QImage CreateFrameStorage(QSize size);
|
[[nodiscard]] QImage CreateFrameStorage(QSize size);
|
||||||
|
|
||||||
|
void UnPremultiply(QImage &to, const QImage &from);
|
||||||
|
void PremultiplyInplace(QImage &image);
|
||||||
|
|
||||||
} // namespace FFmpeg
|
} // namespace FFmpeg
|
||||||
|
|
|
@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/bytes.h"
|
#include "base/bytes.h"
|
||||||
|
|
||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#include <private/qdrawhelper_p.h>
|
|
||||||
#include <lz4.h>
|
#include <lz4.h>
|
||||||
#include <lz4hc.h>
|
#include <lz4hc.h>
|
||||||
#include <range/v3/numeric/accumulate.hpp>
|
#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) {
|
bool UncompressToRaw(EncodedStorage &to, bytes::const_span from) {
|
||||||
if (from.empty() || from.size() > to.size()) {
|
if (from.empty() || from.size() > to.size()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -247,7 +185,7 @@ void Decode(
|
||||||
}
|
}
|
||||||
DecodeYUV2RGB(to, from, context);
|
DecodeYUV2RGB(to, from, context);
|
||||||
DecodeAlpha(to, from);
|
DecodeAlpha(to, from);
|
||||||
PremultiplyInplace(to);
|
FFmpeg::PremultiplyInplace(to);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EncodeRGB2YUV(
|
void EncodeRGB2YUV(
|
||||||
|
@ -311,7 +249,7 @@ void Encode(
|
||||||
const QImage &from,
|
const QImage &from,
|
||||||
QImage &cache,
|
QImage &cache,
|
||||||
FFmpeg::SwscalePointer &context) {
|
FFmpeg::SwscalePointer &context) {
|
||||||
UnPremultiply(cache, from);
|
FFmpeg::UnPremultiply(cache, from);
|
||||||
EncodeRGB2YUV(to, cache, context);
|
EncodeRGB2YUV(to, cache, context);
|
||||||
EncodeAlpha(to, cache);
|
EncodeAlpha(to, cache);
|
||||||
}
|
}
|
||||||
|
|
|
@ -254,6 +254,9 @@ bool FFMpegReaderImplementation::renderFrame(QImage &to, bool &hasAlpha, const Q
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (hasAlpha) {
|
||||||
|
FFmpeg::PremultiplyInplace(to);
|
||||||
|
}
|
||||||
if (_rotation != Rotation::None) {
|
if (_rotation != Rotation::None) {
|
||||||
QTransform rotationTransform;
|
QTransform rotationTransform;
|
||||||
switch (_rotation) {
|
switch (_rotation) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue