Add support for SVG patterns in wallpapers.

This commit is contained in:
John Preston 2021-08-11 19:56:12 +03:00
parent e8fc874456
commit 6cadf54874
7 changed files with 62 additions and 29 deletions

View file

@ -411,7 +411,7 @@ void DocumentData::setattributes(
void DocumentData::validateLottieSticker() { void DocumentData::validateLottieSticker() {
if (type == FileDocument if (type == FileDocument
&& _mimeString == qstr("application/x-tgsticker")) { && hasMimeType(qstr("application/x-tgsticker"))) {
type = StickerDocument; type = StickerDocument;
_additional = std::make_unique<StickerData>(); _additional = std::make_unique<StickerData>();
sticker()->animated = true; sticker()->animated = true;
@ -442,9 +442,8 @@ bool DocumentData::checkWallPaperProperties() {
|| !dimensions.height() || !dimensions.height()
|| dimensions.width() > Storage::kMaxWallPaperDimension || dimensions.width() > Storage::kMaxWallPaperDimension
|| dimensions.height() > Storage::kMaxWallPaperDimension || dimensions.height() > Storage::kMaxWallPaperDimension
|| size > Storage::kMaxWallPaperInMemory || size > Storage::kMaxWallPaperInMemory) {
|| mimeString() == qstr("application/x-tgwallpattern")) { return false;
return false; // #TODO themes support svg patterns
} }
type = WallPaperDocument; type = WallPaperDocument;
return true; return true;
@ -487,9 +486,18 @@ bool DocumentData::isWallPaper() const {
} }
bool DocumentData::isPatternWallPaper() const { bool DocumentData::isPatternWallPaper() const {
return isWallPaper()
&& (isPatternWallPaperPNG() || isPatternWallPaperSVG());
}
bool DocumentData::isPatternWallPaperPNG() const {
return isWallPaper() && hasMimeType(qstr("image/png")); return isWallPaper() && hasMimeType(qstr("image/png"));
} }
bool DocumentData::isPatternWallPaperSVG() const {
return isWallPaper() && hasMimeType(qstr("application/x-tgwallpattern"));
}
bool DocumentData::hasThumbnail() const { bool DocumentData::hasThumbnail() const {
return _thumbnail.location.valid(); return _thumbnail.location.valid();
} }
@ -661,9 +669,9 @@ bool DocumentData::saveToCache() const {
&& ((type == StickerDocument) && ((type == StickerDocument)
|| isAnimation() || isAnimation()
|| isVoiceMessage() || isVoiceMessage()
|| (type == WallPaperDocument) || isWallPaper()
|| isTheme() || isTheme()
|| (mimeString() == qstr("image/png") || (hasMimeType(qstr("image/png"))
&& _filename.startsWith("image_"))); && _filename.startsWith("image_")));
} }
@ -1233,11 +1241,12 @@ QString DocumentData::mimeString() const {
} }
bool DocumentData::hasMimeType(QLatin1String mime) const { bool DocumentData::hasMimeType(QLatin1String mime) const {
return !_mimeString.compare(mime, Qt::CaseInsensitive); return (_mimeString == mime);
} }
void DocumentData::setMimeString(const QString &mime) { void DocumentData::setMimeString(const QString &mime) {
_mimeString = mime; _mimeString = mime;
_mimeString = std::move(_mimeString).toLower();
} }
MediaKey DocumentData::mediaKey() const { MediaKey DocumentData::mediaKey() const {
@ -1263,7 +1272,7 @@ uint8 DocumentData::cacheTag() const {
return Data::kVideoMessageCacheTag; return Data::kVideoMessageCacheTag;
} else if (isAnimation()) { } else if (isAnimation()) {
return Data::kAnimationCacheTag; return Data::kAnimationCacheTag;
} else if (type == WallPaperDocument) { } else if (isWallPaper()) {
return Data::kImageCacheTag; return Data::kImageCacheTag;
} }
return 0; return 0;
@ -1298,14 +1307,9 @@ bool DocumentData::isGifv() const {
} }
bool DocumentData::isTheme() const { bool DocumentData::isTheme() const {
return return hasMimeType(qstr("application/x-tgtheme-tdesktop"))
_mimeString == qstr("application/x-tgtheme-tdesktop") || _filename.endsWith(qstr(".tdesktop-theme"), Qt::CaseInsensitive)
|| _filename.endsWith( || _filename.endsWith(qstr(".tdesktop-palette"), Qt::CaseInsensitive);
qstr(".tdesktop-theme"),
Qt::CaseInsensitive)
|| _filename.endsWith(
qstr(".tdesktop-palette"),
Qt::CaseInsensitive);
} }
bool DocumentData::isSong() const { bool DocumentData::isSong() const {

View file

@ -155,6 +155,8 @@ public:
bool checkWallPaperProperties(); bool checkWallPaperProperties();
[[nodiscard]] bool isWallPaper() const; [[nodiscard]] bool isWallPaper() const;
[[nodiscard]] bool isPatternWallPaper() const; [[nodiscard]] bool isPatternWallPaper() const;
[[nodiscard]] bool isPatternWallPaperPNG() const;
[[nodiscard]] bool isPatternWallPaperSVG() const;
[[nodiscard]] bool hasThumbnail() const; [[nodiscard]] bool hasThumbnail() const;
[[nodiscard]] bool thumbnailLoading() const; [[nodiscard]] bool thumbnailLoading() const;

View file

@ -39,6 +39,8 @@ enum class FileType {
Video, Video,
AnimatedSticker, AnimatedSticker,
WallPaper, WallPaper,
WallPatternPNG,
WallPatternSVG,
Theme, Theme,
}; };
@ -60,6 +62,15 @@ enum class FileType {
return Lottie::ReadThumbnail(Lottie::ReadContent(data, path)); return Lottie::ReadThumbnail(Lottie::ReadContent(data, path));
} else if (type == FileType::Theme) { } else if (type == FileType::Theme) {
return Window::Theme::GeneratePreview(data, path); return Window::Theme::GeneratePreview(data, path);
} else if (type == FileType::WallPatternSVG) {
return Images::Read({
.path = path,
.content = std::move(data),
.maxSize = QSize(
kWallPaperThumbnailLimit,
kWallPaperThumbnailLimit),
.gzipSvg = true,
}).image;
} }
auto buffer = QBuffer(&data); auto buffer = QBuffer(&data);
auto file = QFile(path); auto file = QFile(path);
@ -390,7 +401,11 @@ void DocumentMedia::checkStickerLarge(not_null<FileLoader*> loader) {
void DocumentMedia::GenerateGoodThumbnail( void DocumentMedia::GenerateGoodThumbnail(
not_null<DocumentData*> document, not_null<DocumentData*> document,
QByteArray data) { QByteArray data) {
const auto type = document->isWallPaper() const auto type = document->isPatternWallPaperSVG()
? FileType::WallPatternSVG
: document->isPatternWallPaperPNG()
? FileType::WallPatternPNG
: document->isWallPaper()
? FileType::WallPaper ? FileType::WallPaper
: document->isTheme() : document->isTheme()
? FileType::Theme ? FileType::Theme
@ -415,7 +430,8 @@ void DocumentMedia::GenerateGoodThumbnail(
auto buffer = QBuffer(&bytes); auto buffer = QBuffer(&bytes);
const auto format = (type == FileType::AnimatedSticker) const auto format = (type == FileType::AnimatedSticker)
? "WEBP" ? "WEBP"
: (type == FileType::WallPaper && result.hasAlphaChannel()) : (type == FileType::WallPatternPNG
|| type == FileType::WallPatternSVG)
? "PNG" ? "PNG"
: "JPG"; : "JPG";
result.save(&buffer, format, kGoodThumbQuality); result.save(&buffer, format, kGoodThumbQuality);

View file

@ -33,6 +33,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Data { namespace Data {
namespace { namespace {
constexpr auto kMaxWallpaperSize = 3072;
void LaunchWithWarning( void LaunchWithWarning(
// not_null<Window::Controller*> controller, // not_null<Window::Controller*> controller,
const QString &name, const QString &name,
@ -173,27 +175,38 @@ bool IsIpRevealingName(const QString &filepath) {
); );
} }
[[nodiscard]] QImage ReadImage(
const QString &path,
const QByteArray &content,
bool gzipSvg) {
return Images::Read({
.path = path,
.content = content,
.maxSize = QSize(kMaxWallpaperSize, kMaxWallpaperSize),
.gzipSvg = gzipSvg,
}).image;
}
base::binary_guard ReadImageAsync( base::binary_guard ReadImageAsync(
not_null<Data::DocumentMedia*> media, not_null<Data::DocumentMedia*> media,
FnMut<QImage(QImage)> postprocess, FnMut<QImage(QImage)> postprocess,
FnMut<void(QImage&&)> done) { FnMut<void(QImage&&)> done) {
auto result = base::binary_guard(); auto result = base::binary_guard();
const auto gzipSvg = media->owner()->isPatternWallPaperSVG();
crl::async([ crl::async([
gzipSvg,
bytes = media->bytes(), bytes = media->bytes(),
path = media->owner()->filepath(), path = media->owner()->filepath(),
postprocess = std::move(postprocess), postprocess = std::move(postprocess),
guard = result.make_guard(), guard = result.make_guard(),
callback = std::move(done) callback = std::move(done)
]() mutable { ]() mutable {
auto read = Images::Read({ auto image = ReadImage(path, bytes, gzipSvg);
.path = path,
.content = bytes,
});
if (postprocess) { if (postprocess) {
read.image = postprocess(std::move(read.image)); image = postprocess(std::move(image));
} }
crl::on_main(std::move(guard), [ crl::on_main(std::move(guard), [
image = std::move(read.image), image = std::move(image),
callback = std::move(callback) callback = std::move(callback)
]() mutable { ]() mutable {
callback(std::move(image)); callback(std::move(image));

View file

@ -35,9 +35,7 @@ DocumentGenericPreview DocumentGenericPreview::Create(
: document->filename()) : document->filename())
: tr::lng_message_empty(tr::now)).toLower(); : tr::lng_message_empty(tr::now)).toLower();
auto lastDot = name.lastIndexOf('.'); auto lastDot = name.lastIndexOf('.');
const auto mime = document const auto mime = document ? document->mimeString() : QString();
? document->mimeString().toLower()
: QString();
if (name.endsWith(qstr(".doc")) || if (name.endsWith(qstr(".doc")) ||
name.endsWith(qstr(".docx")) || name.endsWith(qstr(".docx")) ||
name.endsWith(qstr(".txt")) || name.endsWith(qstr(".txt")) ||

@ -1 +1 @@
Subproject commit 2f9bda2cc7b8c94abe34f501b270df8533a7b141 Subproject commit 06960b493d58d7c4e642dc38384d5f0db5340f1c

@ -1 +1 @@
Subproject commit 2bd63281b58d54aa129da78f05f0e6e73e5d63c9 Subproject commit dd88f8fa41a06bdf3128276d8084cfa4f087dee7