Load PPI metadata into documents
This commit is contained in:
@@ -106,6 +106,7 @@ void print_help()
|
||||
<< " create-document --width N --height N [--layers N] [--frames N] [--frame-duration-ms N]\n"
|
||||
<< " inspect-image --path FILE\n"
|
||||
<< " inspect-project --path FILE\n"
|
||||
<< " load-project --path FILE\n"
|
||||
<< " parse-layout --path FILE\n"
|
||||
<< " simulate-stroke --x1 N --y1 N --x2 N --y2 N [--spacing N]\n"
|
||||
<< " simulate-stroke-script --path FILE\n"
|
||||
@@ -404,6 +405,134 @@ int inspect_project(int argc, char** argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
pp::foundation::Result<pp::paint::BlendMode> ppi_layer_blend_mode(std::uint32_t blend_mode) noexcept
|
||||
{
|
||||
switch (blend_mode) {
|
||||
case 0:
|
||||
return pp::foundation::Result<pp::paint::BlendMode>::success(pp::paint::BlendMode::normal);
|
||||
case 1:
|
||||
return pp::foundation::Result<pp::paint::BlendMode>::success(pp::paint::BlendMode::multiply);
|
||||
case 2:
|
||||
return pp::foundation::Result<pp::paint::BlendMode>::success(pp::paint::BlendMode::screen);
|
||||
case 3:
|
||||
return pp::foundation::Result<pp::paint::BlendMode>::success(pp::paint::BlendMode::color_dodge);
|
||||
case 4:
|
||||
return pp::foundation::Result<pp::paint::BlendMode>::success(pp::paint::BlendMode::overlay);
|
||||
default:
|
||||
return pp::foundation::Result<pp::paint::BlendMode>::failure(
|
||||
pp::foundation::Status::invalid_argument("PPI layer blend mode is not supported by pp_document"));
|
||||
}
|
||||
}
|
||||
|
||||
pp::foundation::Result<pp::document::CanvasDocument> document_from_ppi_index(
|
||||
const pp::assets::PpiProjectIndex& project)
|
||||
{
|
||||
if (project.body.layers.empty()) {
|
||||
return pp::foundation::Result<pp::document::CanvasDocument>::failure(
|
||||
pp::foundation::Status::invalid_argument("PPI project has no layers"));
|
||||
}
|
||||
|
||||
const auto& reference_frames = project.body.layers.front().frames;
|
||||
if (reference_frames.empty()) {
|
||||
return pp::foundation::Result<pp::document::CanvasDocument>::failure(
|
||||
pp::foundation::Status::invalid_argument("PPI project has no frames"));
|
||||
}
|
||||
|
||||
std::vector<pp::document::AnimationFrame> frames;
|
||||
frames.reserve(reference_frames.size());
|
||||
for (const auto& frame : reference_frames) {
|
||||
frames.push_back(pp::document::AnimationFrame { .duration_ms = frame.duration_ms });
|
||||
}
|
||||
|
||||
std::vector<pp::document::DocumentLayerConfig> layers;
|
||||
layers.reserve(project.body.layers.size());
|
||||
for (const auto& layer : project.body.layers) {
|
||||
if (layer.frames.size() != reference_frames.size()) {
|
||||
return pp::foundation::Result<pp::document::CanvasDocument>::failure(
|
||||
pp::foundation::Status::invalid_argument("PPI per-layer frame counts are not representable yet"));
|
||||
}
|
||||
|
||||
for (std::size_t frame_index = 0; frame_index < layer.frames.size(); ++frame_index) {
|
||||
if (layer.frames[frame_index].duration_ms != reference_frames[frame_index].duration_ms) {
|
||||
return pp::foundation::Result<pp::document::CanvasDocument>::failure(
|
||||
pp::foundation::Status::invalid_argument("PPI per-layer frame durations are not representable yet"));
|
||||
}
|
||||
}
|
||||
|
||||
const auto blend_mode = ppi_layer_blend_mode(layer.blend_mode);
|
||||
if (!blend_mode) {
|
||||
return pp::foundation::Result<pp::document::CanvasDocument>::failure(blend_mode.status());
|
||||
}
|
||||
|
||||
layers.push_back(pp::document::DocumentLayerConfig {
|
||||
.name = layer.name,
|
||||
.visible = layer.visible,
|
||||
.alpha_locked = layer.alpha_locked,
|
||||
.opacity = layer.opacity,
|
||||
.blend_mode = blend_mode.value(),
|
||||
});
|
||||
}
|
||||
|
||||
return pp::document::CanvasDocument::create_from_snapshot(pp::document::DocumentSnapshotConfig {
|
||||
.width = project.body.summary.width,
|
||||
.height = project.body.summary.height,
|
||||
.layers = layers,
|
||||
.frames = frames,
|
||||
});
|
||||
}
|
||||
|
||||
int load_project(int argc, char** argv)
|
||||
{
|
||||
InspectProjectArgs args;
|
||||
const auto status = parse_inspect_project_args(argc, argv, args);
|
||||
if (!status.ok()) {
|
||||
print_error("load-project", status.message);
|
||||
return 2;
|
||||
}
|
||||
|
||||
std::ifstream stream(args.path, std::ios::binary);
|
||||
if (!stream) {
|
||||
print_error("load-project", "project file could not be opened");
|
||||
return 2;
|
||||
}
|
||||
|
||||
const std::string chars {
|
||||
std::istreambuf_iterator<char>(stream),
|
||||
std::istreambuf_iterator<char>()
|
||||
};
|
||||
const auto* data = reinterpret_cast<const std::byte*>(chars.data());
|
||||
const auto project = pp::assets::parse_ppi_project_index(std::span<const std::byte>(data, chars.size()));
|
||||
if (!project) {
|
||||
print_error("load-project", project.status().message);
|
||||
return 2;
|
||||
}
|
||||
|
||||
const auto document_result = document_from_ppi_index(project.value());
|
||||
if (!document_result) {
|
||||
print_error("load-project", document_result.status().message);
|
||||
return 2;
|
||||
}
|
||||
|
||||
const auto& document = document_result.value();
|
||||
std::cout << "{\"ok\":true,\"command\":\"load-project\""
|
||||
<< ",\"source\":\"ppi\""
|
||||
<< ",\"pixelDataLoaded\":false"
|
||||
<< ",\"document\":{\"width\":" << document.width()
|
||||
<< ",\"height\":" << document.height()
|
||||
<< ",\"layers\":" << document.layers().size()
|
||||
<< ",\"frames\":" << document.frames().size()
|
||||
<< ",\"animationDurationMs\":" << document.animation_duration_ms()
|
||||
<< ",\"layerNames\":[";
|
||||
for (std::size_t layer_index = 0; layer_index < document.layers().size(); ++layer_index) {
|
||||
if (layer_index != 0U) {
|
||||
std::cout << ",";
|
||||
}
|
||||
std::cout << "\"" << json_escape(document.layers()[layer_index].name) << "\"";
|
||||
}
|
||||
std::cout << "]}}\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
pp::foundation::Status parse_simulate_stroke_args(int argc, char** argv, SimulateStrokeArgs& args)
|
||||
{
|
||||
for (int i = 2; i < argc; ++i) {
|
||||
@@ -635,6 +764,10 @@ int main(int argc, char** argv)
|
||||
return inspect_project(argc, argv);
|
||||
}
|
||||
|
||||
if (command == "load-project") {
|
||||
return load_project(argc, argv);
|
||||
}
|
||||
|
||||
if (command == "simulate-stroke") {
|
||||
return simulate_stroke(argc, argv);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user