Export layer collections through paint renderer

This commit is contained in:
2026-06-05 20:48:16 +02:00
parent 77268a28fb
commit 3c36be4b43
10 changed files with 815 additions and 21 deletions

View File

@@ -65,9 +65,11 @@ pp::foundation::Status write_export_binary_file(std::string_view path, std::span
return pp::foundation::Status::success();
}
class LegacyCubeFaceExportWriteServices final : public pp::app::DocumentCubeFaceExportWriteServices {
class LegacyExportWriteServices final
: public pp::app::DocumentCubeFaceExportWriteServices
, public pp::app::DocumentExportCollectionWriteServices {
public:
explicit LegacyCubeFaceExportWriteServices(App& app) noexcept
explicit LegacyExportWriteServices(App& app) noexcept
: app_(app)
{
}
@@ -183,10 +185,90 @@ pp::foundation::Status export_cube_faces_from_document_snapshot(
payloads[face_index].bytes = std::span<const std::byte>(reports.face_pngs.face_pngs[face_index]);
}
LegacyCubeFaceExportWriteServices services(app);
LegacyExportWriteServices services(app);
return pp::app::execute_document_cube_face_export_write(target.value(), payloads, services);
}
pp::foundation::Status export_layers_from_document_snapshot(
App& app,
const pp::app::DocumentExportCollectionTarget& target,
const LegacyDocumentExportSnapshotReports& reports)
{
const auto report = pp::app::make_document_canvas_save_snapshot_report(reports.snapshot);
if (!report.payload_complete) {
return pp::foundation::Status::invalid_argument(
"document snapshot layer export still requires renderer payload readback");
}
auto exported = pp::paint_renderer::export_document_layers_equirectangular_pngs(
pp::paint_renderer::DocumentLayerEquirectangularPngExportRequest {
.document = &reports.snapshot.document,
.frame_index = reports.snapshot.document.active_frame_index(),
.clear_color = {},
});
if (!exported) {
return exported.status();
}
auto exported_value = std::move(exported.value());
LOG(
"export-layers document export PNG writer: layers=%zu bytes=%llu activeFrame=%zu",
exported_value.layer_count,
static_cast<unsigned long long>(exported_value.encoded_bytes),
reports.snapshot.document.active_frame_index());
std::vector<pp::app::DocumentExportCollectionPngPayload> payloads;
payloads.reserve(exported_value.layers.size());
for (const auto& layer : exported_value.layers) {
payloads.push_back(pp::app::DocumentExportCollectionPngPayload {
.path_suffix = pp::app::make_document_layer_export_path_suffix(layer.layer_index, layer.layer_name),
.bytes = std::span<const std::byte>(layer.png.data(), layer.png.size()),
});
}
LegacyExportWriteServices services(app);
return pp::app::execute_document_export_collection_write(target, payloads, services);
}
pp::foundation::Status export_animation_frames_from_document_snapshot(
App& app,
const pp::app::DocumentExportCollectionTarget& target,
const LegacyDocumentExportSnapshotReports& reports)
{
const auto report = pp::app::make_document_canvas_save_snapshot_report(reports.snapshot);
if (!report.payload_complete) {
return pp::foundation::Status::invalid_argument(
"document snapshot animation-frame export still requires renderer payload readback");
}
auto exported = pp::paint_renderer::export_document_animation_frames_equirectangular_pngs(
pp::paint_renderer::DocumentAnimationFrameEquirectangularPngExportRequest {
.document = &reports.snapshot.document,
.clear_color = {},
});
if (!exported) {
return exported.status();
}
auto exported_value = std::move(exported.value());
LOG(
"export-animation-frames document export PNG writer: frames=%zu bytes=%llu",
exported_value.frame_count,
static_cast<unsigned long long>(exported_value.encoded_bytes));
std::vector<pp::app::DocumentExportCollectionPngPayload> payloads;
payloads.reserve(exported_value.frames.size());
for (const auto& frame : exported_value.frames) {
payloads.push_back(pp::app::DocumentExportCollectionPngPayload {
.path_suffix = pp::app::make_document_animation_frame_export_path_suffix(frame.frame_index),
.bytes = std::span<const std::byte>(frame.png.data(), frame.png.size()),
});
}
LegacyExportWriteServices services(app);
return pp::app::execute_document_export_collection_write(target, payloads, services);
}
pp::foundation::Status export_equirectangular_png_from_document_snapshot(
App& app,
const pp::app::DocumentExportFileTarget& target,
@@ -284,7 +366,32 @@ public:
void export_layers_to_stem(const pp::app::DocumentExportStemTarget& target) override
{
auto* app = &app_;
#if !__WEB__
const auto prepared = prepare_legacy_document_export_snapshot(app_, "export-layers");
if (prepared) {
const auto collection_target = pp::app::DocumentExportCollectionTarget {
.stem_path = target.stem_path,
};
const auto exported = export_layers_from_document_snapshot(app_, collection_target, prepared.value());
if (exported.ok()) {
show_export_success_dialog(
app_,
pp::app::plan_document_export_success_dialog(
pp::app::DocumentExportSuccessKind::layers,
pp::app::DocumentExportSuccessDestination::path,
target.stem_path));
return;
}
LOG("export-layers document export writer retained legacy export after failure: %s", exported.message);
} else {
LOG(
"export-layers document export snapshot bridge retained legacy export after failure: %s",
prepared.status().message);
}
#else
prepare_legacy_document_export_snapshot_or_continue(app_, "export-layers");
#endif
app_.canvas->m_canvas->export_layers(target.stem_path, [app, target] {
show_export_success_dialog(
*app,
@@ -298,7 +405,28 @@ public:
void export_layers_to_collection(const pp::app::DocumentExportCollectionTarget& target) override
{
auto* app = &app_;
#if !__WEB__
const auto prepared = prepare_legacy_document_export_snapshot(app_, "export-layers");
if (prepared) {
const auto exported = export_layers_from_document_snapshot(app_, target, prepared.value());
if (exported.ok()) {
show_export_success_dialog(
app_,
pp::app::plan_document_export_success_dialog(
pp::app::DocumentExportSuccessKind::layers,
pp::app::DocumentExportSuccessDestination::files_panopainter));
return;
}
LOG("export-layers document export writer retained legacy export after failure: %s", exported.message);
} else {
LOG(
"export-layers document export snapshot bridge retained legacy export after failure: %s",
prepared.status().message);
}
#else
prepare_legacy_document_export_snapshot_or_continue(app_, "export-layers");
#endif
app_.canvas->m_canvas->export_layers(target.stem_path, [app] {
show_export_success_dialog(
*app,
@@ -311,7 +439,37 @@ public:
void export_animation_frames_to_stem(const pp::app::DocumentExportStemTarget& target) override
{
auto* app = &app_;
#if !__WEB__
const auto prepared = prepare_legacy_document_export_snapshot(app_, "export-animation-frames");
if (prepared) {
const auto collection_target = pp::app::DocumentExportCollectionTarget {
.stem_path = target.stem_path,
};
const auto exported = export_animation_frames_from_document_snapshot(
app_,
collection_target,
prepared.value());
if (exported.ok()) {
show_export_success_dialog(
app_,
pp::app::plan_document_export_success_dialog(
pp::app::DocumentExportSuccessKind::animation_frames,
pp::app::DocumentExportSuccessDestination::path,
target.stem_path));
return;
}
LOG(
"export-animation-frames document export writer retained legacy export after failure: %s",
exported.message);
} else {
LOG(
"export-animation-frames document export snapshot bridge retained legacy export after failure: %s",
prepared.status().message);
}
#else
prepare_legacy_document_export_snapshot_or_continue(app_, "export-animation-frames");
#endif
app_.canvas->m_canvas->export_anim_frames(target.stem_path, [app, target] {
show_export_success_dialog(
*app,
@@ -325,7 +483,30 @@ public:
void export_animation_frames_to_collection(const pp::app::DocumentExportCollectionTarget& target) override
{
auto* app = &app_;
#if !__WEB__
const auto prepared = prepare_legacy_document_export_snapshot(app_, "export-animation-frames");
if (prepared) {
const auto exported = export_animation_frames_from_document_snapshot(app_, target, prepared.value());
if (exported.ok()) {
show_export_success_dialog(
app_,
pp::app::plan_document_export_success_dialog(
pp::app::DocumentExportSuccessKind::animation_frames,
pp::app::DocumentExportSuccessDestination::files_panopainter));
return;
}
LOG(
"export-animation-frames document export writer retained legacy export after failure: %s",
exported.message);
} else {
LOG(
"export-animation-frames document export snapshot bridge retained legacy export after failure: %s",
prepared.status().message);
}
#else
prepare_legacy_document_export_snapshot_or_continue(app_, "export-animation-frames");
#endif
app_.canvas->m_canvas->export_anim_frames(target.stem_path, [app] {
show_export_success_dialog(
*app,