Project legacy canvas metadata into documents

This commit is contained in:
2026-06-05 17:54:45 +02:00
parent a9ef2c598c
commit d0412e3bf9
11 changed files with 580 additions and 4 deletions

View File

@@ -401,6 +401,22 @@ struct PlanCanvasClearArgs {
float a = 0.0F;
};
struct PlanCanvasDocumentSnapshotArgs {
bool has_canvas = true;
std::uint32_t width = 64;
std::uint32_t height = 32;
std::uint32_t layers = 2;
std::uint32_t frames = 2;
std::uint32_t frame_duration_ms = 100;
std::uint32_t current_layer = 1;
std::uint32_t current_frame = 0;
std::uint32_t hidden_layer = 0;
std::uint32_t alpha_locked_layer = 1;
float opacity = 0.75F;
int blend_mode = 4;
std::uint32_t pending_face_payloads_per_layer = pp::document::cube_face_count;
};
struct PlanImageImportArgs {
int width = 0;
int height = 0;
@@ -2391,6 +2407,7 @@ void print_help()
<< " plan-tools-panel --panel presets|color|color-advanced|layers|brush|grids|animation [--already-visible]\n"
<< " plan-about-menu --command help|about|news|crash|performance [--version-major N] [--version-minor N] [--version-fix N] [--no-diagnostics] [--no-canvas]\n"
<< " plan-canvas-clear [--no-canvas] [--r N] [--g N] [--b N] [--a N]\n"
<< " plan-canvas-document-snapshot [--no-canvas] [--width N] [--height N] [--layers N] [--frames N] [--frame-duration-ms N] [--current-layer N] [--current-frame N] [--hidden-layer N] [--alpha-locked-layer N] [--opacity N] [--blend-mode N] [--pending-face-payloads-per-layer N]\n"
<< " plan-image-import --width N --height N\n"
<< " plan-document-resize [--current-resolution N] [--selected-resolution-index N]\n"
<< " plan-layer-rename --old-name NAME --new-name NAME\n"
@@ -5838,6 +5855,143 @@ int plan_canvas_clear(int argc, char** argv)
return 0;
}
pp::foundation::Status parse_plan_canvas_document_snapshot_args(
int argc,
char** argv,
PlanCanvasDocumentSnapshotArgs& args)
{
for (int i = 2; i < argc; ++i) {
const std::string_view key(argv[i]);
if (key == "--no-canvas") {
args.has_canvas = false;
} else if (key == "--width" || key == "--height" || key == "--layers" || key == "--frames"
|| key == "--frame-duration-ms" || key == "--current-layer" || key == "--current-frame"
|| key == "--hidden-layer" || key == "--alpha-locked-layer"
|| key == "--pending-face-payloads-per-layer") {
if (i + 1 >= argc) {
return pp::foundation::Status::invalid_argument("missing value for option");
}
const auto value = pp::foundation::parse_u32(argv[++i]);
if (!value) {
return value.status();
}
if (key == "--width") {
args.width = value.value();
} else if (key == "--height") {
args.height = value.value();
} else if (key == "--layers") {
args.layers = value.value();
} else if (key == "--frames") {
args.frames = value.value();
} else if (key == "--frame-duration-ms") {
args.frame_duration_ms = value.value();
} else if (key == "--current-layer") {
args.current_layer = value.value();
} else if (key == "--current-frame") {
args.current_frame = value.value();
} else if (key == "--hidden-layer") {
args.hidden_layer = value.value();
} else if (key == "--alpha-locked-layer") {
args.alpha_locked_layer = value.value();
} else {
args.pending_face_payloads_per_layer = value.value();
}
} else if (key == "--opacity") {
if (i + 1 >= argc) {
return pp::foundation::Status::invalid_argument("missing value for option");
}
const auto value = parse_float_arg(argv[++i]);
if (!value) {
return value.status();
}
args.opacity = value.value();
} else if (key == "--blend-mode") {
if (i + 1 >= argc) {
return pp::foundation::Status::invalid_argument("missing value for option");
}
const auto value = parse_i32_arg(argv[++i]);
if (!value) {
return value.status();
}
args.blend_mode = value.value();
} else {
return pp::foundation::Status::invalid_argument("unknown option");
}
}
return pp::foundation::Status::success();
}
int plan_canvas_document_snapshot(int argc, char** argv)
{
PlanCanvasDocumentSnapshotArgs args;
const auto status = parse_plan_canvas_document_snapshot_args(argc, argv, args);
if (!status.ok()) {
print_error("plan-canvas-document-snapshot", status.message);
return 2;
}
std::vector<std::uint32_t> frame_durations(args.frames, args.frame_duration_ms);
std::vector<std::string> layer_names;
std::vector<pp::app::DocumentCanvasLayerSnapshotInput> layers;
layer_names.reserve(args.layers);
layers.reserve(args.layers);
for (std::uint32_t layer_index = 0; layer_index < args.layers; ++layer_index) {
layer_names.push_back("Layer " + std::to_string(layer_index + 1U));
layers.push_back(pp::app::DocumentCanvasLayerSnapshotInput {
.name = layer_names.back(),
.visible = layer_index != args.hidden_layer,
.alpha_locked = layer_index == args.alpha_locked_layer,
.opacity = layer_index == args.current_layer ? args.opacity : 1.0F,
.blend_mode = layer_index == args.current_layer ? args.blend_mode : 0,
.frame_durations_ms = std::span<const std::uint32_t>(frame_durations),
.pending_face_payloads = args.pending_face_payloads_per_layer,
});
}
const auto result = pp::app::plan_document_canvas_snapshot(pp::app::DocumentCanvasSnapshotInput {
.has_canvas = args.has_canvas,
.width = args.width,
.height = args.height,
.active_layer_index = args.current_layer,
.active_frame_index = args.current_frame,
.layers = std::span<const pp::app::DocumentCanvasLayerSnapshotInput>(layers),
});
if (!result) {
print_error("plan-canvas-document-snapshot", result.status().message);
return 2;
}
const auto& value = result.value();
const auto& document = value.document;
const auto& active_layer = document.layers()[document.active_layer_index()];
std::cout << "{\"ok\":true,\"command\":\"plan-canvas-document-snapshot\""
<< ",\"state\":{\"hasCanvas\":" << json_bool(args.has_canvas)
<< ",\"width\":" << args.width
<< ",\"height\":" << args.height
<< ",\"layers\":" << args.layers
<< ",\"frames\":" << args.frames
<< ",\"currentLayer\":" << args.current_layer
<< ",\"currentFrame\":" << args.current_frame
<< "},\"snapshot\":{\"width\":" << document.width()
<< ",\"height\":" << document.height()
<< ",\"layers\":" << value.layer_count
<< ",\"frames\":" << value.frame_count
<< ",\"activeLayer\":" << document.active_layer_index()
<< ",\"activeFrame\":" << document.active_frame_index()
<< ",\"activeLayerName\":\"" << json_escape(active_layer.name)
<< "\",\"activeLayerOpacity\":" << active_layer.opacity
<< ",\"activeLayerBlend\":\"" << pp::paint::blend_mode_name(active_layer.blend_mode)
<< "\",\"activeLayerAlphaLocked\":" << json_bool(active_layer.alpha_locked)
<< ",\"pendingFacePayloads\":" << value.pending_face_payloads
<< ",\"metadataOnly\":" << json_bool(value.metadata_only)
<< ",\"requiresRendererPayloadReadback\":"
<< json_bool(value.requires_renderer_payload_readback)
<< ",\"documentFacePayloads\":" << document.face_pixel_payload_count()
<< "}}\n";
return 0;
}
pp::foundation::Status parse_plan_image_import_args(
int argc,
char** argv,
@@ -11727,6 +11881,10 @@ int main(int argc, char** argv)
return plan_canvas_clear(argc, argv);
}
if (command == "plan-canvas-document-snapshot") {
return plan_canvas_document_snapshot(argc, argv);
}
if (command == "plan-image-import") {
return plan_image_import(argc, argv);
}