[skottie] Add DataURI image support in utils/tools
BodyMovin can export inline (dataURI) images. Change-Id: I821a2e225359f8ac37d4d2c9479d4ff5d78f924e Reviewed-on: https://skia-review.googlesource.com/c/skia/+/249516 Reviewed-by: Kevin Lubick <kjlubick@google.com> Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Florin Malita <fmalita@chromium.org>
This commit is contained in:
parent
7333ed23d3
commit
cfbc4d496d
@ -1117,7 +1117,10 @@ SkottieSrc::SkottieSrc(Path path) : fPath(std::move(path)) {}
|
||||
Error SkottieSrc::draw(SkCanvas* canvas) const {
|
||||
auto animation = skottie::Animation::Builder()
|
||||
.setResourceProvider(
|
||||
skottie_utils::FileResourceProvider::Make(SkOSPath::Dirname(fPath.c_str())))
|
||||
skottie_utils::DataURIResourceProviderProxy::Make(
|
||||
skottie_utils::FileResourceProvider::Make(SkOSPath::Dirname(fPath.c_str()),
|
||||
/*predecode=*/true),
|
||||
/*predecode=*/true))
|
||||
.makeFromFile(fPath.c_str());
|
||||
if (!animation) {
|
||||
return SkStringPrintf("Unable to parse file: %s", fPath.c_str());
|
||||
|
@ -21,6 +21,7 @@ public:
|
||||
SkBase64();
|
||||
Error decode(const char* src, size_t length);
|
||||
char* getData() { return fData; }
|
||||
size_t getDataSize() { return fLength; }
|
||||
/**
|
||||
Base64 encodes src into dst. encode is a pointer to at least 65 chars.
|
||||
encode[64] will be used as the pad character. Encodings other than the
|
||||
|
@ -83,12 +83,13 @@ private:
|
||||
|
||||
class ManagedAnimation final : public SkRefCnt {
|
||||
public:
|
||||
static sk_sp<ManagedAnimation> Make(const std::string& json, sk_sp<SkottieAssetProvider> ap) {
|
||||
static sk_sp<ManagedAnimation> Make(const std::string& json,
|
||||
sk_sp<skottie::ResourceProvider> rp) {
|
||||
auto mgr = skstd::make_unique<skottie_utils::CustomPropertyManager>();
|
||||
auto animation = skottie::Animation::Builder()
|
||||
.setMarkerObserver(mgr->getMarkerObserver())
|
||||
.setPropertyObserver(mgr->getPropertyObserver())
|
||||
.setResourceProvider(ap)
|
||||
.setResourceProvider(rp)
|
||||
.make(json.c_str(), json.size());
|
||||
|
||||
return animation
|
||||
@ -231,7 +232,10 @@ EMSCRIPTEN_BINDINGS(Skottie) {
|
||||
assets.push_back(std::make_pair(std::move(name), std::move(bytes)));
|
||||
}
|
||||
|
||||
return ManagedAnimation::Make(json, SkottieAssetProvider::Make(std::move(assets)));
|
||||
return ManagedAnimation::Make(json,
|
||||
skottie_utils::DataURIResourceProviderProxy::Make(
|
||||
SkottieAssetProvider::Make(std::move(assets)),
|
||||
/*predecode=*/true));
|
||||
}));
|
||||
constant("managed_skottie", true);
|
||||
#endif // SK_INCLUDE_MANAGED_SKOTTIE
|
||||
|
@ -261,8 +261,10 @@ int main(int argc, char** argv) {
|
||||
|
||||
auto logger = sk_make_sp<Logger>();
|
||||
auto rp = skottie_utils::CachingResourceProvider::Make(
|
||||
skottie_utils::DataURIResourceProviderProxy::Make(
|
||||
skottie_utils::FileResourceProvider::Make(SkOSPath::Dirname(FLAGS_input[0]),
|
||||
/*predecode=*/true));
|
||||
/*predecode=*/true),
|
||||
/*predecode=*/true));
|
||||
auto data = SkData::MakeFromFileName(FLAGS_input[0]);
|
||||
|
||||
if (!data) {
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "include/core/SkData.h"
|
||||
#include "include/core/SkImage.h"
|
||||
#include "include/utils/SkAnimCodecPlayer.h"
|
||||
#include "include/utils/SkBase64.h"
|
||||
#include "src/core/SkMakeUnique.h"
|
||||
#include "src/core/SkOSFile.h"
|
||||
#include "src/utils/SkOSPath.h"
|
||||
@ -100,9 +101,30 @@ sk_sp<skottie::ImageAsset> FileResourceProvider::loadImageAsset(const char resou
|
||||
return MultiFrameImageAsset::Make(this->load(resource_path, resource_name), fPredecode);
|
||||
}
|
||||
|
||||
CachingResourceProvider::CachingResourceProvider(sk_sp<ResourceProvider> rp)
|
||||
ResourceProviderProxyBase::ResourceProviderProxyBase(sk_sp<ResourceProvider> rp)
|
||||
: fProxy(std::move(rp)) {}
|
||||
|
||||
sk_sp<SkData> ResourceProviderProxyBase::load(const char resource_path[],
|
||||
const char resource_name[]) const {
|
||||
return fProxy ? fProxy->load(resource_path, resource_name)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
sk_sp<skottie::ImageAsset> ResourceProviderProxyBase::loadImageAsset(const char rpath[],
|
||||
const char rname[],
|
||||
const char rid[]) const {
|
||||
return fProxy ? fProxy->loadImageAsset(rpath, rname, rid)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
sk_sp<SkData> ResourceProviderProxyBase::loadFont(const char name[], const char url[]) const {
|
||||
return fProxy ? fProxy->loadFont(name, url)
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
CachingResourceProvider::CachingResourceProvider(sk_sp<ResourceProvider> rp)
|
||||
: INHERITED(std::move(rp)) {}
|
||||
|
||||
sk_sp<skottie::ImageAsset> CachingResourceProvider::loadImageAsset(const char resource_path[],
|
||||
const char resource_name[],
|
||||
const char resource_id[]) const {
|
||||
@ -113,12 +135,53 @@ sk_sp<skottie::ImageAsset> CachingResourceProvider::loadImageAsset(const char re
|
||||
return *asset;
|
||||
}
|
||||
|
||||
auto asset = fProxy->loadImageAsset(resource_path, resource_name, resource_id);
|
||||
auto asset = this->INHERITED::loadImageAsset(resource_path, resource_name, resource_id);
|
||||
fImageCache.set(key, asset);
|
||||
|
||||
return asset;
|
||||
}
|
||||
|
||||
sk_sp<DataURIResourceProviderProxy> DataURIResourceProviderProxy::Make(sk_sp<ResourceProvider> rp,
|
||||
bool predecode) {
|
||||
return sk_sp<DataURIResourceProviderProxy>(
|
||||
new DataURIResourceProviderProxy(std::move(rp), predecode));
|
||||
}
|
||||
|
||||
DataURIResourceProviderProxy::DataURIResourceProviderProxy(sk_sp<ResourceProvider> rp,
|
||||
bool predecode)
|
||||
: INHERITED(std::move(rp))
|
||||
, fPredecode(predecode) {}
|
||||
|
||||
sk_sp<skottie::ImageAsset> DataURIResourceProviderProxy::loadImageAsset(const char rpath[],
|
||||
const char rname[],
|
||||
const char rid[]) const {
|
||||
// We only handle B64 encoded image dataURIs: data:image/<type>;base64,<data>
|
||||
// (https://en.wikipedia.org/wiki/Data_URI_scheme)
|
||||
static constexpr char kDataURIImagePrefix[] = "data:image/",
|
||||
kDataURIEncodingStr[] = ";base64,";
|
||||
|
||||
if (!strncmp(rname, kDataURIImagePrefix, SK_ARRAY_COUNT(kDataURIImagePrefix) - 1)) {
|
||||
const char* encoding_start = strstr(rname + SK_ARRAY_COUNT(kDataURIImagePrefix) - 1,
|
||||
kDataURIEncodingStr);
|
||||
if (encoding_start) {
|
||||
const char* data_start = encoding_start + SK_ARRAY_COUNT(kDataURIEncodingStr) - 1;
|
||||
|
||||
// TODO: SkBase64::decode ergonomics are... interesting.
|
||||
SkBase64 b64;
|
||||
if (SkBase64::kNoError == b64.decode(data_start, strlen(data_start))) {
|
||||
return MultiFrameImageAsset::Make(SkData::MakeWithProc(b64.getData(),
|
||||
b64.getDataSize(),
|
||||
[](const void* ptr, void*) {
|
||||
delete[] static_cast<const char*>(ptr);
|
||||
}, /*context=*/nullptr),
|
||||
fPredecode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this->INHERITED::loadImageAsset(rpath, rname, rid);
|
||||
}
|
||||
|
||||
class CustomPropertyManager::PropertyInterceptor final : public skottie::PropertyObserver {
|
||||
public:
|
||||
explicit PropertyInterceptor(CustomPropertyManager* mgr) : fMgr(mgr) {}
|
||||
|
@ -68,7 +68,20 @@ private:
|
||||
using INHERITED = skottie::ResourceProvider;
|
||||
};
|
||||
|
||||
class CachingResourceProvider final : public skottie::ResourceProvider {
|
||||
class ResourceProviderProxyBase : public skottie::ResourceProvider {
|
||||
protected:
|
||||
explicit ResourceProviderProxyBase(sk_sp<ResourceProvider>);
|
||||
|
||||
sk_sp<SkData> load(const char[], const char[]) const override;
|
||||
sk_sp<skottie::ImageAsset> loadImageAsset(const char[], const char[],
|
||||
const char[]) const override;
|
||||
sk_sp<SkData> loadFont(const char[], const char[]) const override;
|
||||
|
||||
private:
|
||||
const sk_sp<ResourceProvider> fProxy;
|
||||
};
|
||||
|
||||
class CachingResourceProvider final : public ResourceProviderProxyBase {
|
||||
public:
|
||||
static sk_sp<CachingResourceProvider> Make(sk_sp<ResourceProvider> rp) {
|
||||
return rp ? sk_sp<CachingResourceProvider>(new CachingResourceProvider(std::move(rp)))
|
||||
@ -81,12 +94,26 @@ private:
|
||||
sk_sp<skottie::ImageAsset> loadImageAsset(const char[], const char[],
|
||||
const char[]) const override;
|
||||
|
||||
const sk_sp<ResourceProvider> fProxy;
|
||||
|
||||
mutable SkMutex fMutex;
|
||||
mutable SkTHashMap<SkString, sk_sp<skottie::ImageAsset>> fImageCache;
|
||||
|
||||
using INHERITED = skottie::ResourceProvider;
|
||||
using INHERITED = ResourceProviderProxyBase;
|
||||
};
|
||||
|
||||
class DataURIResourceProviderProxy final : public ResourceProviderProxyBase {
|
||||
public:
|
||||
static sk_sp<DataURIResourceProviderProxy> Make(sk_sp<ResourceProvider> rp,
|
||||
bool predecode = false);
|
||||
|
||||
private:
|
||||
DataURIResourceProviderProxy(sk_sp<ResourceProvider>, bool);
|
||||
|
||||
sk_sp<skottie::ImageAsset> loadImageAsset(const char[], const char[],
|
||||
const char[]) const override;
|
||||
|
||||
const bool fPredecode;
|
||||
|
||||
using INHERITED = ResourceProviderProxyBase;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -97,7 +97,10 @@ void SkottieSlide::load(SkScalar w, SkScalar h) {
|
||||
fAnimation = builder
|
||||
.setLogger(logger)
|
||||
.setResourceProvider(
|
||||
skottie_utils::FileResourceProvider::Make(SkOSPath::Dirname(fPath.c_str())))
|
||||
skottie_utils::DataURIResourceProviderProxy::Make(
|
||||
skottie_utils::FileResourceProvider::Make(SkOSPath::Dirname(fPath.c_str()),
|
||||
/*predecode=*/true),
|
||||
/*predecode=*/true))
|
||||
.makeFromFile(fPath.c_str());
|
||||
fAnimationStats = builder.getStats();
|
||||
fWinSize = SkSize::Make(w, h);
|
||||
|
Loading…
Reference in New Issue
Block a user