Add metadata-only PPI save automation

This commit is contained in:
2026-06-02 10:10:30 +02:00
parent b0445382dd
commit 374cb5b075
8 changed files with 345 additions and 0 deletions

View File

@@ -5,6 +5,7 @@
#include <bit>
#include <limits>
#include <string_view>
#include <utility>
namespace pp::assets {
@@ -43,6 +44,26 @@ namespace {
return pp::foundation::Result<float>::success(std::bit_cast<float>(bits.value()));
}
void append_u32(std::vector<std::byte>& bytes, std::uint32_t value)
{
bytes.push_back(static_cast<std::byte>(value & 0xffU));
bytes.push_back(static_cast<std::byte>((value >> 8U) & 0xffU));
bytes.push_back(static_cast<std::byte>((value >> 16U) & 0xffU));
bytes.push_back(static_cast<std::byte>((value >> 24U) & 0xffU));
}
void append_f32(std::vector<std::byte>& bytes, float value)
{
append_u32(bytes, std::bit_cast<std::uint32_t>(value));
}
void append_ascii(std::vector<std::byte>& bytes, std::string_view value)
{
for (const auto ch : value) {
bytes.push_back(static_cast<std::byte>(ch));
}
}
[[nodiscard]] pp::foundation::Status skip_bytes(
pp::foundation::ByteReader& reader,
std::size_t bytes) noexcept
@@ -616,4 +637,66 @@ pp::foundation::Result<PpiDecodedProjectImages> decode_ppi_project_images(std::s
return pp::foundation::Result<PpiDecodedProjectImages>::success(std::move(decoded));
}
pp::foundation::Result<std::vector<std::byte>> create_minimal_ppi_project(PpiMinimalProjectConfig config)
{
const auto canvas_status = validate_canvas_size(config.width, config.height);
if (!canvas_status.ok()) {
return pp::foundation::Result<std::vector<std::byte>>::failure(canvas_status);
}
if (config.layer_name.empty()) {
return pp::foundation::Result<std::vector<std::byte>>::failure(
pp::foundation::Status::invalid_argument("PPI layer name must not be empty"));
}
if (config.layer_name.size() > max_ppi_layer_name_length) {
return pp::foundation::Result<std::vector<std::byte>>::failure(
pp::foundation::Status::out_of_range("PPI layer name exceeds the configured limit"));
}
if (config.frame_duration_ms == 0) {
return pp::foundation::Result<std::vector<std::byte>>::failure(
pp::foundation::Status::invalid_argument("PPI frame duration must be greater than zero"));
}
std::vector<std::byte> bytes {
std::byte { 'P' },
std::byte { 'P' },
std::byte { 'I' },
std::byte { 0 },
};
append_u32(bytes, 0);
append_u32(bytes, 4);
append_u32(bytes, 0);
append_u32(bytes, 0);
append_u32(bytes, 0);
append_u32(bytes, 0);
append_u32(bytes, 128);
append_u32(bytes, 128);
append_u32(bytes, 4);
constexpr std::size_t thumbnail_bytes = 128U * 128U * 4U;
bytes.resize(ppi_header_size + thumbnail_bytes, std::byte { 0 });
append_u32(bytes, config.width);
append_u32(bytes, config.height);
append_u32(bytes, 1);
append_u32(bytes, 1);
append_u32(bytes, 0);
append_f32(bytes, 1.0F);
append_u32(bytes, static_cast<std::uint32_t>(config.layer_name.size()));
append_ascii(bytes, config.layer_name);
append_u32(bytes, 0);
bytes.push_back(std::byte { 0 });
bytes.push_back(std::byte { 1 });
append_u32(bytes, 1);
append_u32(bytes, config.frame_duration_ms);
for (std::uint32_t face = 0; face < 6U; ++face) {
append_u32(bytes, 0);
}
append_u32(bytes, 0);
return pp::foundation::Result<std::vector<std::byte>>::success(std::move(bytes));
}
}