Write cube exports from document snapshots

This commit is contained in:
2026-06-05 19:48:56 +02:00
parent 6151fb7a3d
commit 27e7c60413
5 changed files with 134 additions and 28 deletions

View File

@@ -6,6 +6,10 @@
#include "legacy_document_canvas_services.h"
#include "paint_renderer/compositor.h"
#include <array>
#include <fstream>
#include <limits>
#include <span>
#include <string>
#include <thread>
@@ -21,12 +25,41 @@ void show_export_success_dialog(
}
}
pp::foundation::Status prepare_legacy_document_export_snapshot(App& app, const char* context)
struct LegacyDocumentExportSnapshotReports {
pp::app::DocumentCanvasSnapshotResult snapshot;
pp::paint_renderer::DocumentFrameFacePngExportResult face_pngs;
};
pp::foundation::Status write_binary_file(std::string_view path, std::span<const std::byte> bytes)
{
if (path.empty()) {
return pp::foundation::Status::invalid_argument("export path must not be empty");
}
if (bytes.size() > static_cast<std::size_t>(std::numeric_limits<std::streamsize>::max())) {
return pp::foundation::Status::out_of_range("export payload is too large to write");
}
std::ofstream stream(std::string(path), std::ios::binary);
if (!stream) {
return pp::foundation::Status::invalid_argument("export path could not be opened for writing");
}
stream.write(reinterpret_cast<const char*>(bytes.data()), static_cast<std::streamsize>(bytes.size()));
if (!stream) {
return pp::foundation::Status::invalid_argument("export payload could not be written");
}
return pp::foundation::Status::success();
}
pp::foundation::Result<LegacyDocumentExportSnapshotReports> prepare_legacy_document_export_snapshot(
App& app,
const char* context)
{
auto snapshot = capture_legacy_canvas_document_payload_snapshot(app);
if (!snapshot) {
LOG("%s document export snapshot failed: %s", context, snapshot.status().message);
return snapshot.status();
return pp::foundation::Result<LegacyDocumentExportSnapshotReports>::failure(snapshot.status());
}
const auto report = pp::app::make_document_canvas_save_snapshot_report(snapshot.value());
@@ -41,19 +74,22 @@ pp::foundation::Status prepare_legacy_document_export_snapshot(App& app, const c
report.pending_face_payloads,
report.can_export_ppi ? "true" : "false");
LegacyDocumentExportSnapshotReports reports {
.snapshot = std::move(snapshot.value()),
};
if (!report.can_export_ppi) {
return pp::foundation::Status::success();
return pp::foundation::Result<LegacyDocumentExportSnapshotReports>::success(std::move(reports));
}
const auto recorded_upload = pp::paint_renderer::record_document_frame_upload(
pp::paint_renderer::DocumentFrameUploadRequest {
.document = &snapshot.value().document,
.frame_index = snapshot.value().document.active_frame_index(),
.document = &reports.snapshot.document,
.frame_index = reports.snapshot.document.active_frame_index(),
.clear_color = {},
});
if (!recorded_upload) {
LOG("%s document export renderer upload failed: %s", context, recorded_upload.status().message);
return recorded_upload.status();
return pp::foundation::Result<LegacyDocumentExportSnapshotReports>::failure(recorded_upload.status());
}
const auto& uploaded = recorded_upload.value().upload;
@@ -67,16 +103,15 @@ pp::foundation::Status prepare_legacy_document_export_snapshot(App& app, const c
recorded_upload.value().command_count,
recorded_upload.value().upload_command_count,
recorded_upload.value().transition_command_count);
const auto face_pngs = pp::paint_renderer::export_document_frame_face_pngs(
pp::paint_renderer::DocumentFrameCompositeRequest {
.document = &snapshot.value().document,
.frame_index = snapshot.value().document.active_frame_index(),
.document = &reports.snapshot.document,
.frame_index = reports.snapshot.document.active_frame_index(),
.clear_color = {},
});
if (!face_pngs) {
LOG("%s document export face PNG export failed: %s", context, face_pngs.status().message);
return face_pngs.status();
return pp::foundation::Result<LegacyDocumentExportSnapshotReports>::failure(face_pngs.status());
}
LOG(
@@ -86,17 +121,56 @@ pp::foundation::Status prepare_legacy_document_export_snapshot(App& app, const c
static_cast<unsigned long long>(face_pngs.value().encoded_bytes),
face_pngs.value().composite.face_payload_count,
face_pngs.value().composite.composited_layer_face_count);
return pp::foundation::Status::success();
reports.face_pngs = std::move(face_pngs.value());
return pp::foundation::Result<LegacyDocumentExportSnapshotReports>::success(std::move(reports));
}
void prepare_legacy_document_export_snapshot_or_continue(App& app, const char* context)
{
const auto status = prepare_legacy_document_export_snapshot(app, context);
if (!status.ok()) {
LOG("%s document export snapshot bridge retained legacy export after failure: %s", context, status.message);
const auto prepared = prepare_legacy_document_export_snapshot(app, context);
if (!prepared) {
LOG(
"%s document export snapshot bridge retained legacy export after failure: %s",
context,
prepared.status().message);
}
}
pp::foundation::Status export_cube_faces_from_document_snapshot(
App& app,
std::string_view document_name,
const LegacyDocumentExportSnapshotReports& reports)
{
static constexpr std::array<std::string_view, pp::document::cube_face_count> plane_names {
"front",
"right",
"back",
"left",
"top",
"bottom",
};
if (document_name.empty()) {
return pp::foundation::Status::invalid_argument("document name must not be empty");
}
if (reports.face_pngs.face_count != pp::document::cube_face_count) {
return pp::foundation::Status::invalid_argument("document snapshot did not produce all cube face PNGs");
}
for (std::size_t face_index = 0; face_index < plane_names.size(); ++face_index) {
const std::string path = app.work_path + "/" + std::string(document_name) + "-"
+ std::string(plane_names[face_index]) + ".png";
const auto status = write_binary_file(path, reports.face_pngs.face_pngs[face_index]);
if (!status.ok()) {
return status;
}
app.publish_exported_image(path);
}
return pp::foundation::Status::success();
}
class LegacyDocumentExportServices final : public pp::app::DocumentExportServices {
public:
explicit LegacyDocumentExportServices(App& app) noexcept
@@ -200,7 +274,28 @@ public:
void export_cube_faces(std::string_view document_name) override
{
auto* app = &app_;
prepare_legacy_document_export_snapshot_or_continue(app_, "export-cube-faces");
const auto prepared = prepare_legacy_document_export_snapshot(app_, "export-cube-faces");
if (prepared) {
const auto exported = export_cube_faces_from_document_snapshot(app_, document_name, prepared.value());
if (exported.ok()) {
show_export_success_dialog(
app_,
pp::app::plan_document_export_success_dialog(
pp::app::DocumentExportSuccessKind::cube_faces,
pp::app::document_export_media_platform_destination(),
app_.work_path));
return;
}
LOG(
"export-cube-faces document export writer retained legacy export after failure: %s",
exported.message);
} else {
LOG(
"export-cube-faces document export snapshot bridge retained legacy export after failure: %s",
prepared.status().message);
}
app_.canvas->m_canvas->export_cube_faces(std::string(document_name), [app] {
show_export_success_dialog(
*app,