#include "document/ppi_export.h" #include "assets/image_pixels.h" #include "assets/ppi_header.h" #include #include #include namespace pp::document { namespace { [[nodiscard]] pp::foundation::Result ppi_blend_mode( pp::paint::BlendMode blend_mode) noexcept { switch (blend_mode) { case pp::paint::BlendMode::normal: return pp::foundation::Result::success(0); case pp::paint::BlendMode::multiply: return pp::foundation::Result::success(1); case pp::paint::BlendMode::screen: return pp::foundation::Result::success(2); case pp::paint::BlendMode::color_dodge: return pp::foundation::Result::success(3); case pp::paint::BlendMode::overlay: return pp::foundation::Result::success(4); } return pp::foundation::Result::failure( pp::foundation::Status::invalid_argument("document layer blend mode cannot be exported to PPI")); } } pp::foundation::Result> export_ppi_project_document( const CanvasDocument& document) { std::vector> frame_configs; frame_configs.reserve(document.layers().size()); std::vector layer_configs; layer_configs.reserve(document.layers().size()); std::vector> payloads; payloads.reserve(document.face_pixel_payload_count()); std::vector dirty_faces; dirty_faces.reserve(document.face_pixel_payload_count()); for (std::size_t layer_index = 0; layer_index < document.layers().size(); ++layer_index) { const auto& layer = document.layers()[layer_index]; const auto blend_mode = ppi_blend_mode(layer.blend_mode); if (!blend_mode) { return pp::foundation::Result>::failure(blend_mode.status()); } auto& frames = frame_configs.emplace_back(); frames.reserve(layer.frames.size()); for (std::size_t frame_index = 0; frame_index < layer.frames.size(); ++frame_index) { const auto& frame = layer.frames[frame_index]; frames.push_back(pp::assets::PpiFrameConfig { .duration_ms = frame.duration_ms, }); for (const auto& face : frame.face_pixels) { const auto encoded = pp::assets::encode_png_rgba8( face.width, face.height, face.rgba8); if (!encoded) { return pp::foundation::Result>::failure(encoded.status()); } payloads.push_back(encoded.value()); const auto& payload = payloads.back(); dirty_faces.push_back(pp::assets::PpiDirtyFacePayloadConfig { .layer_index = static_cast(layer_index), .frame_index = static_cast(frame_index), .face_index = face.face_index, .x = face.x, .y = face.y, .width = face.width, .height = face.height, .png_rgba8 = std::span(payload.data(), payload.size()), }); } } layer_configs.push_back(pp::assets::PpiLayerConfig { .name = layer.name, .metadata = pp::assets::PpiLayerMetadataConfig { .opacity = layer.opacity, .blend_mode = blend_mode.value(), .alpha_locked = layer.alpha_locked, .visible = layer.visible, }, .frames = std::span(frames.data(), frames.size()), }); } return pp::assets::create_ppi_project(pp::assets::PpiProjectConfig { .width = document.width(), .height = document.height(), .layers = std::span(layer_configs.data(), layer_configs.size()), .dirty_faces = std::span(dirty_faces.data(), dirty_faces.size()), }); } }