// This file is part of Desktop App Toolkit, // a set of libraries for developing nice desktop applications. // // For license and copyright information please follow this link: // https://github.com/desktop-app/legal/blob/master/LEGAL // #include "lottie/details/lottie_frame_provider_direct.h" #include "lottie/lottie_wrap.h" #include "lottie/details/lottie_frame_renderer.h" #include "ui/image/image_prepare.h" #include namespace Lottie { namespace { int GetLottieFrameRate(not_null animation, Quality quality) { const auto rate = int(qRound(animation->frameRate())); return (quality == Quality::Default && rate == 60) ? (rate / 2) : rate; } int GetLottieFramesCount(not_null animation, Quality quality) { const auto rate = int(qRound(animation->frameRate())); const auto count = int(animation->totalFrame()); return (quality == Quality::Default && rate == 60) ? ((count + 1) / 2) : count; } int GetLottieFrameIndex(not_null animation, Quality quality, int index) { const auto rate = int(qRound(animation->frameRate())); return (quality == Quality::Default && rate == 60) ? (index * 2) : index; } [[nodiscard]] rlottie::FitzModifier MapModifier(SkinModifier modifier) { using Result = rlottie::FitzModifier; switch (modifier) { case SkinModifier::None: return Result::None; case SkinModifier::Color1: return Result::Type12; case SkinModifier::Color2: return Result::Type3; case SkinModifier::Color3: return Result::Type4; case SkinModifier::Color4: return Result::Type5; case SkinModifier::Color5: return Result::Type6; } Unexpected("Unexpected modifier in MapModifier."); } } // namespace FrameProviderDirect::FrameProviderDirect(Quality quality) : _quality(quality) { } FrameProviderDirect::~FrameProviderDirect() = default; bool FrameProviderDirect::load( const QByteArray &content, const ColorReplacements *replacements) { _information = Information(); const auto string = ReadUtf8(Images::UnpackGzip(content)); if (string.size() > kMaxFileSize) { return false; } _animation = LoadAnimationFromData( string, std::string(), std::string(), false, (replacements ? replacements->replacements : std::vector>()), (replacements ? MapModifier(replacements->modifier) : rlottie::FitzModifier::None)); if (!_animation) { return false; } auto width = size_t(0); auto height = size_t(0); _animation->size(width, height); const auto rate = GetLottieFrameRate(_animation.get(), _quality); const auto count = GetLottieFramesCount(_animation.get(), _quality); return setInformation({ .size = QSize(int(width), int(height)), .frameRate = int(rate), .framesCount = int(count), }); } bool FrameProviderDirect::loaded() const { return (_animation != nullptr); } void FrameProviderDirect::unload() { _animation = nullptr; } bool FrameProviderDirect::setInformation(Information information) { if (information.size.isEmpty() || information.size.width() > kMaxSize || information.size.height() > kMaxSize || !information.frameRate || information.frameRate > kMaxFrameRate || !information.framesCount || information.framesCount > kMaxFramesCount) { return false; } _information = information; return true; } const Information &FrameProviderDirect::information() { return _information; } bool FrameProviderDirect::valid() { return _information.framesCount > 0; } QImage FrameProviderDirect::construct( std::unique_ptr &token, const FrameRequest &request) { auto cover = QImage(); render(token, cover, request, 0); return cover; } int FrameProviderDirect::sizeRounding() { return 2; } bool FrameProviderDirect::render( const std::unique_ptr &token, QImage &to, const FrameRequest &request, int index) { if (token && !token->exclusive) { token->result = FrameRenderResult::NotReady; return false; } else if (!valid()) { return false; } const auto original = information().size; const auto size = request.box.isEmpty() ? original : request.size(original, sizeRounding()); if (!GoodStorageForFrame(to, size)) { to = CreateFrameStorage(size); } renderToPrepared(to, index); return true; } void FrameProviderDirect::renderToPrepared( QImage &to, int index) const { to.fill(Qt::transparent); auto surface = rlottie::Surface( reinterpret_cast(to.bits()), to.width(), to.height(), to.bytesPerLine()); _animation->renderSync( GetLottieFrameIndex(_animation.get(), _quality, index), surface); } } // namespace Lottie