Add file-driven image import automation

This commit is contained in:
2026-06-02 10:04:48 +02:00
parent 3701fd2a71
commit b0445382dd
5 changed files with 196 additions and 3 deletions

View File

@@ -35,6 +35,15 @@ struct InspectImageArgs {
std::string path;
};
struct ImportImageArgs {
std::string path;
std::uint32_t document_width = 0;
std::uint32_t document_height = 0;
std::uint32_t face = 0;
std::uint32_t x = 0;
std::uint32_t y = 0;
};
struct ParseLayoutArgs {
std::string path;
};
@@ -130,6 +139,7 @@ void print_help()
<< "pano_cli commands:\n"
<< " create-document --width N --height N [--layers N] [--frames N] [--frame-duration-ms N]\n"
<< " inspect-image --path FILE\n"
<< " import-image --path FILE [--document-width N] [--document-height N] [--face N] [--x N] [--y N]\n"
<< " inspect-project --path FILE\n"
<< " load-project --path FILE\n"
<< " parse-layout --path FILE\n"
@@ -317,6 +327,132 @@ int inspect_image(int argc, char** argv)
return 0;
}
pp::foundation::Status parse_import_image_args(int argc, char** argv, ImportImageArgs& args)
{
for (int i = 2; i < argc; ++i) {
const std::string_view key(argv[i]);
if (key == "--path") {
if (i + 1 >= argc) {
return pp::foundation::Status::invalid_argument("missing value for option");
}
args.path = argv[++i];
} else if (key == "--document-width" || key == "--document-height"
|| key == "--face" || key == "--x" || key == "--y") {
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 == "--document-width") {
args.document_width = value.value();
} else if (key == "--document-height") {
args.document_height = value.value();
} else if (key == "--face") {
args.face = value.value();
} else if (key == "--x") {
args.x = value.value();
} else {
args.y = value.value();
}
} else {
return pp::foundation::Status::invalid_argument("unknown option");
}
}
if (args.path.empty()) {
return pp::foundation::Status::invalid_argument("path must not be empty");
}
if ((args.document_width == 0) != (args.document_height == 0)) {
return pp::foundation::Status::invalid_argument(
"document width and height must both be omitted or both be greater than zero");
}
return pp::foundation::Status::success();
}
int import_image(int argc, char** argv)
{
ImportImageArgs args;
const auto status = parse_import_image_args(argc, argv, args);
if (!status.ok()) {
print_error("import-image", status.message);
return 2;
}
std::ifstream stream(args.path, std::ios::binary);
if (!stream) {
print_error("import-image", "image file could not be opened");
return 2;
}
const std::vector<char> chars {
std::istreambuf_iterator<char>(stream),
std::istreambuf_iterator<char>()
};
const auto* data = reinterpret_cast<const std::byte*>(chars.data());
const auto image_result = pp::assets::decode_png_rgba8(std::span<const std::byte>(data, chars.size()));
if (!image_result) {
print_error("import-image", image_result.status().message);
return 2;
}
const auto& image = image_result.value();
const std::uint32_t document_width = args.document_width == 0 ? image.width : args.document_width;
const std::uint32_t document_height = args.document_height == 0 ? image.height : args.document_height;
const auto document_result = pp::document::CanvasDocument::create(
pp::document::DocumentConfig {
.width = document_width,
.height = document_height,
.layer_count = 1,
});
if (!document_result) {
print_error("import-image", document_result.status().message);
return 2;
}
auto document = document_result.value();
const auto import_status = document.set_layer_frame_face_pixels(
0,
0,
pp::document::LayerFacePixels {
.face_index = args.face,
.x = args.x,
.y = args.y,
.width = image.width,
.height = image.height,
.rgba8 = image.pixels,
});
if (!import_status.ok()) {
print_error("import-image", import_status.message);
return 2;
}
std::cout << "{\"ok\":true,\"command\":\"import-image\""
<< ",\"source\":\"" << json_escape(args.path) << "\""
<< ",\"image\":{\"format\":\"png\",\"width\":" << image.width
<< ",\"height\":" << image.height
<< ",\"bytes\":" << image.pixels.size()
<< "},\"document\":{\"width\":" << document.width()
<< ",\"height\":" << document.height()
<< ",\"layers\":" << document.layers().size()
<< ",\"frames\":" << document.frames().size()
<< ",\"facePayloads\":" << document.face_pixel_payload_count()
<< "},\"payload\":{\"face\":" << args.face
<< ",\"x\":" << args.x
<< ",\"y\":" << args.y
<< ",\"width\":" << image.width
<< ",\"height\":" << image.height
<< ",\"bytes\":" << image.pixels.size()
<< "}}\n";
return 0;
}
pp::foundation::Status parse_inspect_project_args(int argc, char** argv, InspectProjectArgs& args)
{
for (int i = 2; i < argc; ++i) {
@@ -1268,6 +1404,10 @@ int main(int argc, char** argv)
return inspect_image(argc, argv);
}
if (command == "import-image") {
return import_image(argc, argv);
}
if (command == "inspect-project") {
return inspect_project(argc, argv);
}