Export equirectangular JPEGs through paint renderer

This commit is contained in:
2026-06-05 21:22:06 +02:00
parent 875a0127d9
commit bd416f8473
11 changed files with 604 additions and 96 deletions

View File

@@ -38,6 +38,40 @@ bool is_png_export_target(std::string_view path) noexcept
&& (extension[3] == 'g' || extension[3] == 'G');
}
bool ascii_iequals(std::string_view left, std::string_view right) noexcept
{
if (left.size() != right.size()) {
return false;
}
for (std::size_t i = 0; i < left.size(); ++i) {
auto lhs = left[i];
if (lhs >= 'A' && lhs <= 'Z') {
lhs = static_cast<char>(lhs - 'A' + 'a');
}
auto rhs = right[i];
if (rhs >= 'A' && rhs <= 'Z') {
rhs = static_cast<char>(rhs - 'A' + 'a');
}
if (lhs != rhs) {
return false;
}
}
return true;
}
bool has_extension(std::string_view path, std::string_view extension) noexcept
{
return path.size() >= extension.size()
&& ascii_iequals(path.substr(path.size() - extension.size()), extension);
}
bool is_jpeg_export_target(std::string_view path) noexcept
{
return has_extension(path, ".jpg") || has_extension(path, ".jpeg");
}
struct LegacyDocumentExportSnapshotReports {
pp::app::DocumentCanvasSnapshotResult snapshot;
pp::paint_renderer::DocumentFrameFacePngExportResult face_pngs;
@@ -270,32 +304,52 @@ pp::foundation::Status export_animation_frames_from_document_snapshot(
return pp::app::execute_document_export_collection_write(target, payloads, services);
}
pp::foundation::Status export_equirectangular_png_from_document_snapshot(
pp::foundation::Status export_equirectangular_from_document_snapshot(
App& app,
const pp::app::DocumentExportFileTarget& target,
const LegacyDocumentExportSnapshotReports& reports)
{
if (!is_png_export_target(target.path)) {
std::span<const std::byte> bytes;
pp::paint_renderer::DocumentFrameEquirectangularPngExportResult png_export;
pp::paint_renderer::DocumentFrameEquirectangularJpegExportResult jpeg_export;
if (is_png_export_target(target.path)) {
auto exported = pp::paint_renderer::export_document_frame_equirectangular_png(reports.face_pngs.composite);
if (!exported) {
return exported.status();
}
png_export = std::move(exported.value());
LOG(
"export-equirectangular document export PNG writer: %ux%u bytes=%llu facePayloads=%zu compositedLayerFaces=%zu",
png_export.equirectangular_extent.width,
png_export.equirectangular_extent.height,
static_cast<unsigned long long>(png_export.encoded_bytes),
png_export.face_payload_count,
png_export.composited_layer_face_count);
bytes = std::span<const std::byte>(png_export.png.data(), png_export.png.size());
} else if (is_jpeg_export_target(target.path)) {
auto exported = pp::paint_renderer::export_document_frame_equirectangular_jpeg(reports.face_pngs.composite);
if (!exported) {
return exported.status();
}
jpeg_export = std::move(exported.value());
LOG(
"export-equirectangular document export JPEG writer: %ux%u bytes=%llu facePayloads=%zu compositedLayerFaces=%zu xmp=%s",
jpeg_export.equirectangular_extent.width,
jpeg_export.equirectangular_extent.height,
static_cast<unsigned long long>(jpeg_export.encoded_bytes),
jpeg_export.face_payload_count,
jpeg_export.composited_layer_face_count,
jpeg_export.xmp_injected ? "true" : "false");
bytes = std::span<const std::byte>(jpeg_export.jpeg.data(), jpeg_export.jpeg.size());
} else {
return pp::foundation::Status::invalid_argument(
"document snapshot equirectangular export currently supports PNG targets only");
"document snapshot equirectangular export currently supports PNG and JPEG targets only");
}
auto exported = pp::paint_renderer::export_document_frame_equirectangular_png(reports.face_pngs.composite);
if (!exported) {
return exported.status();
}
auto exported_value = std::move(exported.value());
LOG(
"export-equirectangular document export PNG writer: %ux%u bytes=%llu facePayloads=%zu compositedLayerFaces=%zu",
exported_value.equirectangular_extent.width,
exported_value.equirectangular_extent.height,
static_cast<unsigned long long>(exported_value.encoded_bytes),
exported_value.face_payload_count,
exported_value.composited_layer_face_count);
const auto write_status = write_export_binary_file(
target.path,
std::span<const std::byte>(exported_value.png.data(), exported_value.png.size()));
const auto write_status = write_export_binary_file(target.path, bytes);
if (!write_status.ok()) {
return write_status;
}
@@ -320,10 +374,10 @@ public:
{
auto* app = &app_;
#if !__WEB__
if (is_png_export_target(target.path)) {
if (is_png_export_target(target.path) || is_jpeg_export_target(target.path)) {
const auto prepared = prepare_legacy_document_export_snapshot(app_, "export-equirectangular");
if (prepared) {
const auto exported = export_equirectangular_png_from_document_snapshot(app_, target, prepared.value());
const auto exported = export_equirectangular_from_document_snapshot(app_, target, prepared.value());
if (exported.ok()) {
show_export_success_dialog(
app_,