Export document frame faces as PNGs
This commit is contained in:
@@ -253,7 +253,8 @@ powershell -ExecutionPolicy Bypass -File scripts\automation\apple-remote-build.p
|
|||||||
opacity, and blend mode applied in document order, then uploading those six
|
opacity, and blend mode applied in document order, then uploading those six
|
||||||
faces through the renderer-neutral `IRenderDevice` texture API using the
|
faces through the renderer-neutral `IRenderDevice` texture API using the
|
||||||
recording backend. It also covers the shared recorded-upload report helper
|
recording backend. It also covers the shared recorded-upload report helper
|
||||||
consumed by CLI and live export-readiness bridges.
|
consumed by CLI and live export-readiness bridges, plus a pure six-face PNG
|
||||||
|
export helper that encodes composited document-frame faces through `pp_assets`.
|
||||||
- `pano_cli simulate-document-export` exposes the same pure document-to-PPI
|
- `pano_cli simulate-document-export` exposes the same pure document-to-PPI
|
||||||
export, asset-level decode, and document reimport path through JSON
|
export, asset-level decode, and document reimport path through JSON
|
||||||
automation and is covered by `pano_cli_simulate_document_export_smoke`.
|
automation and is covered by `pano_cli_simulate_document_export_smoke`.
|
||||||
@@ -273,14 +274,16 @@ powershell -ExecutionPolicy Bypass -File scripts\automation\apple-remote-build.p
|
|||||||
snapshots also feed the active frame through the `pp_paint_renderer`
|
snapshots also feed the active frame through the `pp_paint_renderer`
|
||||||
document-frame compositor and renderer-neutral recorded-upload report helper,
|
document-frame compositor and renderer-neutral recorded-upload report helper,
|
||||||
reporting texture, transition, command, byte, and active-frame payload counts
|
reporting texture, transition, command, byte, and active-frame payload counts
|
||||||
in `rendererUpload` JSON. It is covered by
|
in `rendererUpload` JSON. The same payload-complete path also reports
|
||||||
|
`facePngExport` readiness, face count, byte count, and payload count from the
|
||||||
|
pure face-PNG export helper. It is covered by
|
||||||
`pano_cli_plan_canvas_document_snapshot_smoke` plus the payload-bearing
|
`pano_cli_plan_canvas_document_snapshot_smoke` plus the payload-bearing
|
||||||
snapshot smoke.
|
snapshot smoke.
|
||||||
- Live equirectangular, layer, animation-frame, and cube-face export adapters
|
- Live equirectangular, layer, animation-frame, and cube-face export adapters
|
||||||
now prepare and log the same payload-bearing canvas document snapshot plus
|
now prepare and log the same payload-bearing canvas document snapshot plus
|
||||||
shared renderer-neutral active-frame upload report before delegating to
|
shared renderer-neutral active-frame upload and face-PNG export reports before
|
||||||
retained `Canvas` export execution. Depth and video export remain on the older
|
delegating to retained `Canvas` export execution. Depth and video export
|
||||||
retained path.
|
remain on the older retained path.
|
||||||
- `pano_cli save-document-project` writes that pure document export to a PPI
|
- `pano_cli save-document-project` writes that pure document export to a PPI
|
||||||
file and is covered by `pano_cli_save_document_project_roundtrip_smoke`,
|
file and is covered by `pano_cli_save_document_project_roundtrip_smoke`,
|
||||||
which inspects and loads the generated file.
|
which inspects and loads the generated file.
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ and validation command.
|
|||||||
| PNG/JPEG import | `Image`, `Canvas` import paths | `pp_assets`, `pp_document` | Fixture import, malformed file |
|
| PNG/JPEG import | `Image`, `Canvas` import paths | `pp_assets`, `pp_document` | Fixture import, malformed file |
|
||||||
| PNG/JPEG export | `Canvas`, `Image`, export dialogs | `pp_assets`, `pp_paint_renderer`, `pp_app_core` | Golden output tolerance, export start/target planning tests, live export-adapter document snapshot readiness |
|
| PNG/JPEG export | `Canvas`, `Image`, export dialogs | `pp_assets`, `pp_paint_renderer`, `pp_app_core` | Golden output tolerance, export start/target planning tests, live export-adapter document snapshot readiness |
|
||||||
| Equirectangular import/export | `Canvas`, shaders, RTT, export dialogs | `pp_paint_renderer`, `pp_app_core` | Tiny cube/equirect golden, app-core file target tests, live export-adapter renderer-upload readiness |
|
| Equirectangular import/export | `Canvas`, shaders, RTT, export dialogs | `pp_paint_renderer`, `pp_app_core` | Tiny cube/equirect golden, app-core file target tests, live export-adapter renderer-upload readiness |
|
||||||
| Cube face export | `Canvas` | `pp_paint_renderer` | Pure six-face document frame composite, renderer texture-upload bridge, payload-complete canvas-snapshot renderer-upload automation, live export-adapter renderer-upload readiness, OpenGL command-plan coverage, six-face golden set |
|
| Cube face export | `Canvas` | `pp_paint_renderer` | Pure six-face document frame composite, renderer texture-upload bridge, pure face-PNG export helper, payload-complete canvas-snapshot renderer-upload and face-PNG automation, live export-adapter renderer/export readiness, OpenGL command-plan coverage, six-face golden set |
|
||||||
| Depth export | `Canvas`, grid tools | `pp_paint_renderer` | Float/readback validation |
|
| Depth export | `Canvas`, grid tools | `pp_paint_renderer` | Float/readback validation |
|
||||||
|
|
||||||
## Brush And Painting
|
## Brush And Painting
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -678,13 +678,18 @@ snapshots and reports generated byte/dirty-face summaries. The same automation
|
|||||||
now feeds payload-complete snapshots through the `pp_paint_renderer`
|
now feeds payload-complete snapshots through the `pp_paint_renderer`
|
||||||
document-frame compositor and renderer-neutral recording upload path, reporting
|
document-frame compositor and renderer-neutral recording upload path, reporting
|
||||||
texture, transition, byte, payload, and command counts through the shared
|
texture, transition, byte, payload, and command counts through the shared
|
||||||
`record_document_frame_upload` report helper. Live save writer replacement,
|
`record_document_frame_upload` report helper. Payload-complete snapshot
|
||||||
export adoption, and renderer-owned readback remain under
|
automation also encodes the active document frame's six composited faces to PNG
|
||||||
|
bytes through `pp_paint_renderer::export_document_frame_face_pngs`, giving the
|
||||||
|
cube-face export path a pure renderer/document writer primitive before live
|
||||||
|
writer replacement. Live save writer replacement, export adoption, and
|
||||||
|
renderer-owned readback remain under
|
||||||
`DEBT-0010`/`DEBT-0013`/`DEBT-0036`.
|
`DEBT-0010`/`DEBT-0013`/`DEBT-0036`.
|
||||||
Live equirectangular, layer, animation-frame, and cube-face export adapters now
|
Live equirectangular, layer, animation-frame, and cube-face export adapters now
|
||||||
prepare the same payload-bearing document snapshot and renderer-neutral upload
|
prepare the same payload-bearing document snapshot and renderer-neutral upload
|
||||||
report helper before delegating to retained `Canvas` export execution, so export
|
report helper plus pure face-PNG export report before delegating to retained
|
||||||
workflows consume the shared renderer boundary without changing file output yet.
|
`Canvas` export execution, so export workflows consume the shared renderer
|
||||||
|
boundary without changing file output yet.
|
||||||
`pano_cli plan-image-import` exposes app-core planning for File > Import image
|
`pano_cli plan-image-import` exposes app-core planning for File > Import image
|
||||||
route decisions, including wide equirectangular images, legacy vertical cube
|
route decisions, including wide equirectangular images, legacy vertical cube
|
||||||
strips, regular transform-placement images, and invalid image dimensions; live
|
strips, regular transform-placement images, and invalid image dimensions; live
|
||||||
@@ -2517,12 +2522,15 @@ Results:
|
|||||||
boundary now: `pano_cli plan-canvas-document-snapshot` records the same
|
boundary now: `pano_cli plan-canvas-document-snapshot` records the same
|
||||||
snapshot through the pure document-frame compositor and renderer-neutral
|
snapshot through the pure document-frame compositor and renderer-neutral
|
||||||
texture upload stream through `pp_paint_renderer::record_document_frame_upload`,
|
texture upload stream through `pp_paint_renderer::record_document_frame_upload`,
|
||||||
so agents can validate document/canvas payloads moving into renderer commands
|
and encodes the composited active-frame cube faces as PNG bytes through
|
||||||
before live canvas export/save writer replacement.
|
`pp_paint_renderer::export_document_frame_face_pngs`, so agents can validate
|
||||||
|
document/canvas payloads moving into renderer commands and image bytes before
|
||||||
|
live canvas export/save writer replacement.
|
||||||
- Live image/collection/cube export adapters now prepare and log the same
|
- Live image/collection/cube export adapters now prepare and log the same
|
||||||
document/canvas plus shared renderer-upload readiness report before retained
|
document/canvas plus shared renderer-upload and face-PNG export readiness
|
||||||
`Canvas` export calls. Depth and video export remain on their prior retained
|
reports before retained `Canvas` export calls. Depth and video export remain
|
||||||
paths; actual image/cube writer replacement remains tracked under export debt.
|
on their prior retained paths; actual image/cube writer replacement remains
|
||||||
|
tracked under export debt.
|
||||||
- Snapshot creation now rejects invalid embedded RGBA8 face payloads before
|
- Snapshot creation now rejects invalid embedded RGBA8 face payloads before
|
||||||
document export or history can persist malformed state.
|
document export or history can persist malformed state.
|
||||||
- Package-smoke wrappers validate the Windows CMake app executable/runtime
|
- Package-smoke wrappers validate the Windows CMake app executable/runtime
|
||||||
|
|||||||
@@ -67,6 +67,25 @@ pp::foundation::Status prepare_legacy_document_export_snapshot(App& app, const c
|
|||||||
recorded_upload.value().command_count,
|
recorded_upload.value().command_count,
|
||||||
recorded_upload.value().upload_command_count,
|
recorded_upload.value().upload_command_count,
|
||||||
recorded_upload.value().transition_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(),
|
||||||
|
.clear_color = {},
|
||||||
|
});
|
||||||
|
if (!face_pngs) {
|
||||||
|
LOG("%s document export face PNG export failed: %s", context, face_pngs.status().message);
|
||||||
|
return face_pngs.status();
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(
|
||||||
|
"%s document export face PNG export: faces=%zu bytes=%llu facePayloads=%zu compositedLayerFaces=%zu",
|
||||||
|
context,
|
||||||
|
face_pngs.value().face_count,
|
||||||
|
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();
|
return pp::foundation::Status::success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "paint_renderer/compositor.h"
|
#include "paint_renderer/compositor.h"
|
||||||
|
|
||||||
|
#include "assets/image_pixels.h"
|
||||||
#include "renderer_api/recording_renderer.h"
|
#include "renderer_api/recording_renderer.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -211,6 +212,18 @@ void mark_shader_blend_fallback(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void append_rgba8_bytes(std::vector<std::uint8_t>& bytes, std::span<const pp::paint::Rgba> pixels)
|
||||||
|
{
|
||||||
|
bytes.clear();
|
||||||
|
bytes.reserve(pixels.size() * pp::document::rgba8_components);
|
||||||
|
for (const auto& pixel : pixels) {
|
||||||
|
bytes.push_back(static_cast<std::uint8_t>(rgba8_channel(pixel.r)));
|
||||||
|
bytes.push_back(static_cast<std::uint8_t>(rgba8_channel(pixel.g)));
|
||||||
|
bytes.push_back(static_cast<std::uint8_t>(rgba8_channel(pixel.b)));
|
||||||
|
bytes.push_back(static_cast<std::uint8_t>(rgba8_channel(pixel.a)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pp::foundation::Status composite_layer(
|
pp::foundation::Status composite_layer(
|
||||||
@@ -439,6 +452,35 @@ pp::foundation::Result<RecordedDocumentFrameUploadResult> record_document_frame_
|
|||||||
return pp::foundation::Result<RecordedDocumentFrameUploadResult>::success(std::move(result));
|
return pp::foundation::Result<RecordedDocumentFrameUploadResult>::success(std::move(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pp::foundation::Result<DocumentFrameFacePngExportResult> export_document_frame_face_pngs(
|
||||||
|
DocumentFrameCompositeRequest request)
|
||||||
|
{
|
||||||
|
auto composite = composite_document_frame(request);
|
||||||
|
if (!composite) {
|
||||||
|
return pp::foundation::Result<DocumentFrameFacePngExportResult>::failure(composite.status());
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentFrameFacePngExportResult result;
|
||||||
|
result.composite = std::move(composite.value());
|
||||||
|
std::vector<std::uint8_t> rgba8;
|
||||||
|
for (std::size_t face_index = 0; face_index < result.composite.faces.size(); ++face_index) {
|
||||||
|
append_rgba8_bytes(rgba8, result.composite.faces[face_index].pixels);
|
||||||
|
auto encoded = pp::assets::encode_png_rgba8(
|
||||||
|
result.composite.extent.width,
|
||||||
|
result.composite.extent.height,
|
||||||
|
rgba8);
|
||||||
|
if (!encoded) {
|
||||||
|
return pp::foundation::Result<DocumentFrameFacePngExportResult>::failure(encoded.status());
|
||||||
|
}
|
||||||
|
|
||||||
|
result.encoded_bytes += static_cast<std::uint64_t>(encoded.value().size());
|
||||||
|
result.face_pngs[face_index] = std::move(encoded.value());
|
||||||
|
++result.face_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pp::foundation::Result<DocumentFrameFacePngExportResult>::success(std::move(result));
|
||||||
|
}
|
||||||
|
|
||||||
bool stroke_composite_requires_feedback(
|
bool stroke_composite_requires_feedback(
|
||||||
pp::paint::BlendMode layer_blend_mode,
|
pp::paint::BlendMode layer_blend_mode,
|
||||||
pp::paint::StrokeBlendMode stroke_blend_mode,
|
pp::paint::StrokeBlendMode stroke_blend_mode,
|
||||||
|
|||||||
@@ -139,6 +139,13 @@ struct RecordedDocumentFrameUploadResult {
|
|||||||
std::size_t transition_command_count = 0;
|
std::size_t transition_command_count = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DocumentFrameFacePngExportResult {
|
||||||
|
DocumentFrameCompositeResult composite {};
|
||||||
|
std::array<std::vector<std::byte>, pp::document::cube_face_count> face_pngs {};
|
||||||
|
std::size_t face_count = 0;
|
||||||
|
std::uint64_t encoded_bytes = 0;
|
||||||
|
};
|
||||||
|
|
||||||
[[nodiscard]] pp::foundation::Status composite_layer(
|
[[nodiscard]] pp::foundation::Status composite_layer(
|
||||||
std::span<pp::paint::Rgba> destination,
|
std::span<pp::paint::Rgba> destination,
|
||||||
pp::renderer::Extent2D extent,
|
pp::renderer::Extent2D extent,
|
||||||
@@ -157,6 +164,9 @@ struct RecordedDocumentFrameUploadResult {
|
|||||||
[[nodiscard]] pp::foundation::Result<RecordedDocumentFrameUploadResult> record_document_frame_upload(
|
[[nodiscard]] pp::foundation::Result<RecordedDocumentFrameUploadResult> record_document_frame_upload(
|
||||||
DocumentFrameUploadRequest request);
|
DocumentFrameUploadRequest request);
|
||||||
|
|
||||||
|
[[nodiscard]] pp::foundation::Result<DocumentFrameFacePngExportResult> export_document_frame_face_pngs(
|
||||||
|
DocumentFrameCompositeRequest request);
|
||||||
|
|
||||||
[[nodiscard]] bool stroke_composite_requires_feedback(
|
[[nodiscard]] bool stroke_composite_requires_feedback(
|
||||||
pp::paint::BlendMode layer_blend_mode,
|
pp::paint::BlendMode layer_blend_mode,
|
||||||
pp::paint::StrokeBlendMode stroke_blend_mode,
|
pp::paint::StrokeBlendMode stroke_blend_mode,
|
||||||
|
|||||||
@@ -1474,13 +1474,13 @@ if(TARGET pano_cli)
|
|||||||
COMMAND pano_cli plan-canvas-document-snapshot --width 128 --height 64 --layers 3 --frames 2 --current-layer 2 --current-frame 1 --hidden-layer 0 --alpha-locked-layer 2 --opacity 0.5 --blend-mode 4 --pending-face-payloads-per-layer 6)
|
COMMAND pano_cli plan-canvas-document-snapshot --width 128 --height 64 --layers 3 --frames 2 --current-layer 2 --current-frame 1 --hidden-layer 0 --alpha-locked-layer 2 --opacity 0.5 --blend-mode 4 --pending-face-payloads-per-layer 6)
|
||||||
set_tests_properties(pano_cli_plan_canvas_document_snapshot_smoke PROPERTIES
|
set_tests_properties(pano_cli_plan_canvas_document_snapshot_smoke PROPERTIES
|
||||||
LABELS "app;document;integration;desktop-fast"
|
LABELS "app;document;integration;desktop-fast"
|
||||||
PASS_REGULAR_EXPRESSION "\"command\":\"plan-canvas-document-snapshot\".*\"width\":128.*\"height\":64.*\"layers\":3.*\"frames\":2.*\"activeLayer\":2.*\"activeFrame\":1.*\"activeLayerName\":\"Layer 3\".*\"activeLayerOpacity\":0.5.*\"activeLayerBlend\":\"overlay\".*\"activeLayerAlphaLocked\":true.*\"pendingFacePayloads\":18.*\"metadataOnly\":true.*\"requiresRendererPayloadReadback\":true.*\"documentFacePayloads\":0.*\"saveReport\":\\{\"payloadComplete\":false,\"canExportPpi\":false\\}.*\"ppiExport\":\\{\"ready\":false,\"bytes\":0,\"dirtyFaces\":0\\}.*\"rendererUpload\":\\{\"ready\":false,\"textures\":0,\"bytes\":0,\"transitions\":0,\"facePayloads\":0,\"compositedLayerFaces\":0,\"commands\":0,\"uploadCommands\":0,\"transitionCommands\":0\\}")
|
PASS_REGULAR_EXPRESSION "\"command\":\"plan-canvas-document-snapshot\".*\"width\":128.*\"height\":64.*\"layers\":3.*\"frames\":2.*\"activeLayer\":2.*\"activeFrame\":1.*\"activeLayerName\":\"Layer 3\".*\"activeLayerOpacity\":0.5.*\"activeLayerBlend\":\"overlay\".*\"activeLayerAlphaLocked\":true.*\"pendingFacePayloads\":18.*\"metadataOnly\":true.*\"requiresRendererPayloadReadback\":true.*\"documentFacePayloads\":0.*\"saveReport\":\\{\"payloadComplete\":false,\"canExportPpi\":false\\}.*\"ppiExport\":\\{\"ready\":false,\"bytes\":0,\"dirtyFaces\":0\\}.*\"rendererUpload\":\\{\"ready\":false,\"textures\":0,\"bytes\":0,\"transitions\":0,\"facePayloads\":0,\"compositedLayerFaces\":0,\"commands\":0,\"uploadCommands\":0,\"transitionCommands\":0\\}.*\"facePngExport\":\\{\"ready\":false,\"faces\":0,\"bytes\":0,\"facePayloads\":0\\}")
|
||||||
|
|
||||||
add_test(NAME pano_cli_plan_canvas_document_snapshot_payload_smoke
|
add_test(NAME pano_cli_plan_canvas_document_snapshot_payload_smoke
|
||||||
COMMAND pano_cli plan-canvas-document-snapshot --width 128 --height 64 --layers 2 --frames 2 --current-layer 1 --current-frame 1 --pending-face-payloads-per-layer 2 --captured-face-payloads-per-layer 2)
|
COMMAND pano_cli plan-canvas-document-snapshot --width 128 --height 64 --layers 2 --frames 2 --current-layer 1 --current-frame 1 --pending-face-payloads-per-layer 2 --captured-face-payloads-per-layer 2)
|
||||||
set_tests_properties(pano_cli_plan_canvas_document_snapshot_payload_smoke PROPERTIES
|
set_tests_properties(pano_cli_plan_canvas_document_snapshot_payload_smoke PROPERTIES
|
||||||
LABELS "app;document;integration;desktop-fast"
|
LABELS "app;document;integration;desktop-fast"
|
||||||
PASS_REGULAR_EXPRESSION "\"command\":\"plan-canvas-document-snapshot\".*\"layers\":2.*\"frames\":2.*\"activeLayer\":1.*\"activeFrame\":1.*\"pendingFacePayloads\":4.*\"capturedFacePayloads\":4.*\"metadataOnly\":false.*\"requiresRendererPayloadReadback\":false.*\"documentFacePayloads\":4.*\"saveReport\":\\{\"payloadComplete\":true,\"canExportPpi\":true\\}.*\"ppiExport\":\\{\"ready\":true,\"bytes\":[1-9][0-9]*,\"dirtyFaces\":4\\}.*\"rendererUpload\":\\{\"ready\":true,\"textures\":6,\"bytes\":[1-9][0-9]*,\"transitions\":6,\"facePayloads\":2,\"compositedLayerFaces\":2,\"commands\":12,\"uploadCommands\":6,\"transitionCommands\":6\\}")
|
PASS_REGULAR_EXPRESSION "\"command\":\"plan-canvas-document-snapshot\".*\"layers\":2.*\"frames\":2.*\"activeLayer\":1.*\"activeFrame\":1.*\"pendingFacePayloads\":4.*\"capturedFacePayloads\":4.*\"metadataOnly\":false.*\"requiresRendererPayloadReadback\":false.*\"documentFacePayloads\":4.*\"saveReport\":\\{\"payloadComplete\":true,\"canExportPpi\":true\\}.*\"ppiExport\":\\{\"ready\":true,\"bytes\":[1-9][0-9]*,\"dirtyFaces\":4\\}.*\"rendererUpload\":\\{\"ready\":true,\"textures\":6,\"bytes\":[1-9][0-9]*,\"transitions\":6,\"facePayloads\":2,\"compositedLayerFaces\":2,\"commands\":12,\"uploadCommands\":6,\"transitionCommands\":6\\}.*\"facePngExport\":\\{\"ready\":true,\"faces\":6,\"bytes\":[1-9][0-9]*,\"facePayloads\":2\\}")
|
||||||
|
|
||||||
add_test(NAME pano_cli_plan_canvas_document_snapshot_no_canvas
|
add_test(NAME pano_cli_plan_canvas_document_snapshot_no_canvas
|
||||||
COMMAND pano_cli plan-canvas-document-snapshot --no-canvas)
|
COMMAND pano_cli plan-canvas-document-snapshot --no-canvas)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "assets/image_pixels.h"
|
||||||
#include "paint_renderer/compositor.h"
|
#include "paint_renderer/compositor.h"
|
||||||
#include "renderer_api/recording_renderer.h"
|
#include "renderer_api/recording_renderer.h"
|
||||||
#include "test_harness.h"
|
#include "test_harness.h"
|
||||||
@@ -597,6 +598,73 @@ void records_document_frame_upload_report(pp::tests::Harness& h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void exports_document_frame_faces_as_pngs(pp::tests::Harness& h)
|
||||||
|
{
|
||||||
|
const AnimationFrame root_frames[] {
|
||||||
|
{ .duration_ms = 100, .face_pixels = {} },
|
||||||
|
};
|
||||||
|
const AnimationFrame layer_frames[] {
|
||||||
|
{
|
||||||
|
.duration_ms = 100,
|
||||||
|
.face_pixels = {
|
||||||
|
LayerFacePixels {
|
||||||
|
.face_index = 4,
|
||||||
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
.width = 1,
|
||||||
|
.height = 1,
|
||||||
|
.rgba8 = { 64, 128, 255, 255 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const DocumentLayerConfig layers[] {
|
||||||
|
{
|
||||||
|
.name = "Paint",
|
||||||
|
.frames = std::span<const AnimationFrame>(layer_frames, 1),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const auto document = CanvasDocument::create_from_snapshot(DocumentSnapshotConfig {
|
||||||
|
.width = 1,
|
||||||
|
.height = 1,
|
||||||
|
.layers = std::span<const DocumentLayerConfig>(layers, 1),
|
||||||
|
.frames = std::span<const AnimationFrame>(root_frames, 1),
|
||||||
|
.selection_masks = {},
|
||||||
|
});
|
||||||
|
PP_EXPECT(h, document);
|
||||||
|
if (!document) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto exported = pp::paint_renderer::export_document_frame_face_pngs(
|
||||||
|
pp::paint_renderer::DocumentFrameCompositeRequest {
|
||||||
|
.document = &document.value(),
|
||||||
|
.frame_index = 0,
|
||||||
|
.clear_color = {},
|
||||||
|
});
|
||||||
|
|
||||||
|
PP_EXPECT(h, exported);
|
||||||
|
if (!exported) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PP_EXPECT(h, exported.value().face_count == pp::document::cube_face_count);
|
||||||
|
PP_EXPECT(h, exported.value().encoded_bytes > 0U);
|
||||||
|
PP_EXPECT(h, exported.value().composite.face_payload_count == 1U);
|
||||||
|
|
||||||
|
const auto decoded = pp::assets::decode_png_rgba8(exported.value().face_pngs[4]);
|
||||||
|
PP_EXPECT(h, decoded);
|
||||||
|
if (decoded) {
|
||||||
|
PP_EXPECT(h, decoded.value().width == 1U);
|
||||||
|
PP_EXPECT(h, decoded.value().height == 1U);
|
||||||
|
PP_EXPECT(h, decoded.value().pixels.size() == 4U);
|
||||||
|
PP_EXPECT(h, decoded.value().pixels[0] == 64U);
|
||||||
|
PP_EXPECT(h, decoded.value().pixels[1] == 128U);
|
||||||
|
PP_EXPECT(h, decoded.value().pixels[2] == 255U);
|
||||||
|
PP_EXPECT(h, decoded.value().pixels[3] == 255U);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void document_frame_upload_rejects_invalid_requests(pp::tests::Harness& h)
|
void document_frame_upload_rejects_invalid_requests(pp::tests::Harness& h)
|
||||||
{
|
{
|
||||||
RecordingRenderDevice device;
|
RecordingRenderDevice device;
|
||||||
@@ -979,6 +1047,7 @@ int main()
|
|||||||
harness.run("document_frame_composite_rejects_invalid_requests", document_frame_composite_rejects_invalid_requests);
|
harness.run("document_frame_composite_rejects_invalid_requests", document_frame_composite_rejects_invalid_requests);
|
||||||
harness.run("uploads_document_frame_faces_to_renderer_api", uploads_document_frame_faces_to_renderer_api);
|
harness.run("uploads_document_frame_faces_to_renderer_api", uploads_document_frame_faces_to_renderer_api);
|
||||||
harness.run("records_document_frame_upload_report", records_document_frame_upload_report);
|
harness.run("records_document_frame_upload_report", records_document_frame_upload_report);
|
||||||
|
harness.run("exports_document_frame_faces_as_pngs", exports_document_frame_faces_as_pngs);
|
||||||
harness.run("document_frame_upload_rejects_invalid_requests", document_frame_upload_rejects_invalid_requests);
|
harness.run("document_frame_upload_rejects_invalid_requests", document_frame_upload_rejects_invalid_requests);
|
||||||
harness.run("detects_feedback_requirements", detects_feedback_requirements);
|
harness.run("detects_feedback_requirements", detects_feedback_requirements);
|
||||||
harness.run("plans_stroke_composite_paths", plans_stroke_composite_paths);
|
harness.run("plans_stroke_composite_paths", plans_stroke_composite_paths);
|
||||||
|
|||||||
@@ -6007,6 +6007,10 @@ int plan_canvas_document_snapshot(int argc, char** argv)
|
|||||||
std::size_t renderer_command_count = 0;
|
std::size_t renderer_command_count = 0;
|
||||||
std::size_t renderer_upload_command_count = 0;
|
std::size_t renderer_upload_command_count = 0;
|
||||||
std::size_t renderer_transition_command_count = 0;
|
std::size_t renderer_transition_command_count = 0;
|
||||||
|
bool face_png_export_ready = false;
|
||||||
|
std::size_t face_png_export_faces = 0;
|
||||||
|
std::uint64_t face_png_export_bytes = 0;
|
||||||
|
std::size_t face_png_export_payloads = 0;
|
||||||
if (save_report.can_export_ppi) {
|
if (save_report.can_export_ppi) {
|
||||||
const auto exported = pp::app::export_document_canvas_save_snapshot_to_ppi(value);
|
const auto exported = pp::app::export_document_canvas_save_snapshot_to_ppi(value);
|
||||||
if (!exported) {
|
if (!exported) {
|
||||||
@@ -6044,6 +6048,22 @@ int plan_canvas_document_snapshot(int argc, char** argv)
|
|||||||
renderer_command_count = recorded_upload.value().command_count;
|
renderer_command_count = recorded_upload.value().command_count;
|
||||||
renderer_upload_command_count = recorded_upload.value().upload_command_count;
|
renderer_upload_command_count = recorded_upload.value().upload_command_count;
|
||||||
renderer_transition_command_count = recorded_upload.value().transition_command_count;
|
renderer_transition_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 = &document,
|
||||||
|
.frame_index = document.active_frame_index(),
|
||||||
|
.clear_color = {},
|
||||||
|
});
|
||||||
|
if (!face_pngs) {
|
||||||
|
print_error("plan-canvas-document-snapshot", face_pngs.status().message);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
face_png_export_ready = true;
|
||||||
|
face_png_export_faces = face_pngs.value().face_count;
|
||||||
|
face_png_export_bytes = face_pngs.value().encoded_bytes;
|
||||||
|
face_png_export_payloads = face_pngs.value().composite.face_payload_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "{\"ok\":true,\"command\":\"plan-canvas-document-snapshot\""
|
std::cout << "{\"ok\":true,\"command\":\"plan-canvas-document-snapshot\""
|
||||||
@@ -6084,6 +6104,10 @@ int plan_canvas_document_snapshot(int argc, char** argv)
|
|||||||
<< ",\"commands\":" << renderer_command_count
|
<< ",\"commands\":" << renderer_command_count
|
||||||
<< ",\"uploadCommands\":" << renderer_upload_command_count
|
<< ",\"uploadCommands\":" << renderer_upload_command_count
|
||||||
<< ",\"transitionCommands\":" << renderer_transition_command_count
|
<< ",\"transitionCommands\":" << renderer_transition_command_count
|
||||||
|
<< "},\"facePngExport\":{\"ready\":" << json_bool(face_png_export_ready)
|
||||||
|
<< ",\"faces\":" << face_png_export_faces
|
||||||
|
<< ",\"bytes\":" << face_png_export_bytes
|
||||||
|
<< ",\"facePayloads\":" << face_png_export_payloads
|
||||||
<< "}"
|
<< "}"
|
||||||
<< "}}\n";
|
<< "}}\n";
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user