mirror of
https://github.com/darlinghq/xcbuild.git
synced 2025-02-22 09:22:34 +00:00
Support compiling app icon sets. (#94)
* Pass through info and dependency info options to asset compile output. Fixes writing out additional info plist and dependency info. * Add initial implementation of compiling app icons. Supports copying the images and writing the icon metadata to info plist additions. Current implementation has two limitations: - All idioms are copied for all target platforms. For example, watch images are copied for asset compilation targeting a phone. - The size of images is not verified against the specified dimensions.
This commit is contained in:
parent
b9aae64b4e
commit
f7dc2741e2
@ -10,6 +10,10 @@
|
||||
#include <acdriver/Compile/AppIconSet.h>
|
||||
#include <acdriver/CompileOutput.h>
|
||||
#include <acdriver/Result.h>
|
||||
#include <plist/Array.h>
|
||||
#include <plist/Boolean.h>
|
||||
#include <plist/Dictionary.h>
|
||||
#include <plist/String.h>
|
||||
#include <libutil/Filesystem.h>
|
||||
|
||||
using acdriver::Compile::AppIconSet;
|
||||
@ -17,6 +21,50 @@ using acdriver::CompileOutput;
|
||||
using acdriver::Result;
|
||||
using libutil::Filesystem;
|
||||
|
||||
static plist::Dictionary *
|
||||
IconsDictionary(plist::Dictionary *info, std::string const &key)
|
||||
{
|
||||
if (auto existing = info->value<plist::Dictionary>(key)) {
|
||||
return existing;
|
||||
} else {
|
||||
auto icons = plist::Dictionary::New();
|
||||
info->set(key, std::move(icons));
|
||||
return info->value<plist::Dictionary>(key);
|
||||
}
|
||||
}
|
||||
|
||||
static std::string
|
||||
IdiomSuffix(xcassets::Slot::Idiom idiom)
|
||||
{
|
||||
switch (idiom) {
|
||||
case xcassets::Slot::Idiom::Universal:
|
||||
return std::string();
|
||||
case xcassets::Slot::Idiom::Phone:
|
||||
return std::string();
|
||||
case xcassets::Slot::Idiom::Pad:
|
||||
return "~ipad";
|
||||
case xcassets::Slot::Idiom::Desktop:
|
||||
// TODO: no idiom suffix for desktop
|
||||
return std::string();
|
||||
case xcassets::Slot::Idiom::TV:
|
||||
return "~tv";
|
||||
case xcassets::Slot::Idiom::Watch:
|
||||
return "~watch";
|
||||
case xcassets::Slot::Idiom::Car:
|
||||
return "~car";
|
||||
}
|
||||
|
||||
abort();
|
||||
}
|
||||
|
||||
struct IdiomHash
|
||||
{
|
||||
std::size_t operator()(xcassets::Slot::Idiom idiom) const
|
||||
{
|
||||
return static_cast<std::size_t>(idiom);
|
||||
}
|
||||
};
|
||||
|
||||
bool AppIconSet::
|
||||
Compile(
|
||||
std::shared_ptr<xcassets::Asset::AppIconSet> const &appIconSet,
|
||||
@ -24,12 +72,85 @@ Compile(
|
||||
CompileOutput *compileOutput,
|
||||
Result *result)
|
||||
{
|
||||
result->document(
|
||||
Result::Severity::Warning,
|
||||
appIconSet->path(),
|
||||
{ CompileOutput::AssetReference(appIconSet) },
|
||||
"Not Implemented",
|
||||
"app icon set not yet supported");
|
||||
/*
|
||||
* Copy the app icon images into the output.
|
||||
*/
|
||||
auto files = std::unordered_map<xcassets::Slot::Idiom, std::vector<std::string>, IdiomHash>();
|
||||
if (appIconSet->images()) {
|
||||
for (xcassets::Asset::AppIconSet::Image const &image : *appIconSet->images()) {
|
||||
/*
|
||||
* Verify the image has the required information.
|
||||
*/
|
||||
if (image.unassigned() || !image.fileName() || !image.imageSize() || !image.scale()) {
|
||||
result->document(
|
||||
Result::Severity::Warning,
|
||||
appIconSet->path(),
|
||||
{ CompileOutput::AssetReference(appIconSet) },
|
||||
"Ambiguous Content",
|
||||
"an icon in \"" + appIconSet->name().name() + "\" is unassigned");
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
/*
|
||||
* Determine information about the icon image.
|
||||
*/
|
||||
xcassets::Slot::ImageSize const &size = *image.imageSize();
|
||||
// TODO: verify the dimensions of the image are correct
|
||||
std::string sizeSuffix = xcassets::Slot::ImageSize::String(size);
|
||||
|
||||
xcassets::Slot::Scale const &scale = *image.scale();
|
||||
std::string scaleSuffix = std::string();
|
||||
if (scale.value() != 1.0) {
|
||||
scaleSuffix = "@" + xcassets::Slot::Scale::String(scale);
|
||||
}
|
||||
|
||||
xcassets::Slot::Idiom idiom = image.idiom().value_or(xcassets::Slot::Idiom::Universal);
|
||||
// TODO: skip images with idioms inappropriate for target platform
|
||||
std::string idiomSuffix = IdiomSuffix(idiom);
|
||||
|
||||
/*
|
||||
* Copy the icon image into the output.
|
||||
*/
|
||||
std::string source = appIconSet->path() + "/" + *image.fileName();
|
||||
std::string destination = compileOutput->root() + "/" + appIconSet->name().name() + sizeSuffix + scaleSuffix + idiomSuffix + ".png";
|
||||
compileOutput->copies().push_back({ source, destination });
|
||||
|
||||
/*
|
||||
* Add the file to the output info.
|
||||
*/
|
||||
std::string name = appIconSet->name().name() + sizeSuffix;
|
||||
files[idiom].push_back(name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Build up the info about the icons.
|
||||
*/
|
||||
for (auto const &pair : files) {
|
||||
/*
|
||||
* Record details about the icon itself.
|
||||
*/
|
||||
auto primary = plist::Dictionary::New();
|
||||
|
||||
/* List the files for the icon. */
|
||||
auto files = plist::Array::New();
|
||||
for (std::string const &file : pair.second) {
|
||||
files->append(plist::String::New(file));
|
||||
}
|
||||
primary->set("CFBundleIconFiles", std::move(files));
|
||||
|
||||
/* Record if the icon is pre-rendered. */
|
||||
if (appIconSet->preRendered()) {
|
||||
primary->set("UIPrerenderedIcon", plist::Boolean::New(true));
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the icon in the additional info.
|
||||
*/
|
||||
std::string idiomSuffix = IdiomSuffix(pair.first);
|
||||
plist::Dictionary *icons = IconsDictionary(compileOutput->additionalInfo(), "CFBundleIcons" + idiomSuffix);
|
||||
icons->set("CFBundlePrimaryIcon", std::move(primary));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -302,7 +302,9 @@ run(Filesystem *filesystem, Options const &options, Output *output, Result *resu
|
||||
/*
|
||||
* Write out the output.
|
||||
*/
|
||||
if (!compileOutput.write(filesystem, ext::nullopt, ext::nullopt, result)) {
|
||||
ext::optional<std::string> partialInfoPlist = (!options.outputPartialInfoPlist().empty() ? ext::optional<std::string>(options.outputPartialInfoPlist()) : ext::nullopt);
|
||||
ext::optional<std::string> dependencyInfo = (!options.exportDependencyInfo().empty() ? ext::optional<std::string>(options.exportDependencyInfo()) : ext::nullopt);
|
||||
if (!compileOutput.write(filesystem, partialInfoPlist, dependencyInfo, result)) {
|
||||
/* Error already reported. */
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user