Add file-driven image import automation
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user