[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:
Florin Malita 2019-10-18 13:13:40 -04:00 committed by Skia Commit-Bot
parent 7333ed23d3
commit cfbc4d496d
7 changed files with 115 additions and 12 deletions

View File

@ -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());

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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) {}

View File

@ -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;
};
/**

View File

@ -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);