Load PPI metadata into documents
This commit is contained in:
@@ -46,6 +46,38 @@ namespace {
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
[[nodiscard]] pp::foundation::Status validate_layer_opacity(float opacity) noexcept
|
||||
{
|
||||
if (!std::isfinite(opacity) || opacity < 0.0F || opacity > 1.0F) {
|
||||
return pp::foundation::Status::out_of_range("layer opacity must be finite and within 0..1");
|
||||
}
|
||||
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
[[nodiscard]] pp::foundation::Status validate_blend_mode(pp::paint::BlendMode blend_mode) noexcept
|
||||
{
|
||||
switch (blend_mode) {
|
||||
case pp::paint::BlendMode::normal:
|
||||
case pp::paint::BlendMode::multiply:
|
||||
case pp::paint::BlendMode::screen:
|
||||
case pp::paint::BlendMode::color_dodge:
|
||||
case pp::paint::BlendMode::overlay:
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
return pp::foundation::Status::invalid_argument("layer blend mode is not supported");
|
||||
}
|
||||
|
||||
[[nodiscard]] pp::foundation::Status validate_frame_duration(std::uint32_t duration_ms) noexcept
|
||||
{
|
||||
if (duration_ms < min_frame_duration_ms) {
|
||||
return pp::foundation::Status::invalid_argument("frame duration must be greater than zero");
|
||||
}
|
||||
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
[[nodiscard]] pp::foundation::Status validate_layer_index(std::size_t index, std::size_t layer_count) noexcept
|
||||
{
|
||||
if (index >= layer_count) {
|
||||
@@ -85,6 +117,69 @@ pp::foundation::Result<CanvasDocument> CanvasDocument::create(DocumentConfig con
|
||||
return pp::foundation::Result<CanvasDocument>::success(document);
|
||||
}
|
||||
|
||||
pp::foundation::Result<CanvasDocument> CanvasDocument::create_from_snapshot(DocumentSnapshotConfig config)
|
||||
{
|
||||
const auto status = validate_config(DocumentConfig {
|
||||
.width = config.width,
|
||||
.height = config.height,
|
||||
.layer_count = static_cast<std::uint32_t>(config.layers.size()),
|
||||
});
|
||||
if (!status.ok()) {
|
||||
return pp::foundation::Result<CanvasDocument>::failure(status);
|
||||
}
|
||||
|
||||
if (config.frames.empty()) {
|
||||
return pp::foundation::Result<CanvasDocument>::failure(
|
||||
pp::foundation::Status::invalid_argument("document must contain at least one frame"));
|
||||
}
|
||||
|
||||
if (config.frames.size() > max_frame_count) {
|
||||
return pp::foundation::Result<CanvasDocument>::failure(
|
||||
pp::foundation::Status::out_of_range("document frame count exceeds the configured limit"));
|
||||
}
|
||||
|
||||
CanvasDocument document;
|
||||
document.width_ = config.width;
|
||||
document.height_ = config.height;
|
||||
document.layers_.reserve(config.layers.size());
|
||||
for (const auto& layer_config : config.layers) {
|
||||
const auto name_status = validate_layer_name(layer_config.name);
|
||||
if (!name_status.ok()) {
|
||||
return pp::foundation::Result<CanvasDocument>::failure(name_status);
|
||||
}
|
||||
|
||||
const auto opacity_status = validate_layer_opacity(layer_config.opacity);
|
||||
if (!opacity_status.ok()) {
|
||||
return pp::foundation::Result<CanvasDocument>::failure(opacity_status);
|
||||
}
|
||||
|
||||
const auto blend_status = validate_blend_mode(layer_config.blend_mode);
|
||||
if (!blend_status.ok()) {
|
||||
return pp::foundation::Result<CanvasDocument>::failure(blend_status);
|
||||
}
|
||||
|
||||
document.layers_.push_back(Layer {
|
||||
.name = std::string(layer_config.name),
|
||||
.visible = layer_config.visible,
|
||||
.alpha_locked = layer_config.alpha_locked,
|
||||
.opacity = layer_config.opacity,
|
||||
.blend_mode = layer_config.blend_mode,
|
||||
});
|
||||
}
|
||||
|
||||
document.frames_.reserve(config.frames.size());
|
||||
for (const auto& frame_config : config.frames) {
|
||||
const auto duration_status = validate_frame_duration(frame_config.duration_ms);
|
||||
if (!duration_status.ok()) {
|
||||
return pp::foundation::Result<CanvasDocument>::failure(duration_status);
|
||||
}
|
||||
|
||||
document.frames_.push_back(frame_config);
|
||||
}
|
||||
|
||||
return pp::foundation::Result<CanvasDocument>::success(document);
|
||||
}
|
||||
|
||||
std::uint32_t CanvasDocument::width() const noexcept
|
||||
{
|
||||
return width_;
|
||||
@@ -229,6 +324,17 @@ pp::foundation::Status CanvasDocument::set_layer_visible(std::size_t index, bool
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
pp::foundation::Status CanvasDocument::set_layer_alpha_locked(std::size_t index, bool alpha_locked) noexcept
|
||||
{
|
||||
const auto index_status = validate_layer_index(index, layers_.size());
|
||||
if (!index_status.ok()) {
|
||||
return index_status;
|
||||
}
|
||||
|
||||
layers_[index].alpha_locked = alpha_locked;
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
pp::foundation::Status CanvasDocument::set_layer_opacity(std::size_t index, float opacity) noexcept
|
||||
{
|
||||
const auto index_status = validate_layer_index(index, layers_.size());
|
||||
@@ -236,8 +342,9 @@ pp::foundation::Status CanvasDocument::set_layer_opacity(std::size_t index, floa
|
||||
return index_status;
|
||||
}
|
||||
|
||||
if (!std::isfinite(opacity) || opacity < 0.0F || opacity > 1.0F) {
|
||||
return pp::foundation::Status::out_of_range("layer opacity must be finite and within 0..1");
|
||||
const auto opacity_status = validate_layer_opacity(opacity);
|
||||
if (!opacity_status.ok()) {
|
||||
return opacity_status;
|
||||
}
|
||||
|
||||
layers_[index].opacity = opacity;
|
||||
@@ -251,17 +358,13 @@ pp::foundation::Status CanvasDocument::set_layer_blend_mode(std::size_t index, p
|
||||
return index_status;
|
||||
}
|
||||
|
||||
switch (blend_mode) {
|
||||
case pp::paint::BlendMode::normal:
|
||||
case pp::paint::BlendMode::multiply:
|
||||
case pp::paint::BlendMode::screen:
|
||||
case pp::paint::BlendMode::color_dodge:
|
||||
case pp::paint::BlendMode::overlay:
|
||||
layers_[index].blend_mode = blend_mode;
|
||||
return pp::foundation::Status::success();
|
||||
const auto blend_status = validate_blend_mode(blend_mode);
|
||||
if (!blend_status.ok()) {
|
||||
return blend_status;
|
||||
}
|
||||
|
||||
return pp::foundation::Status::invalid_argument("layer blend mode is not supported");
|
||||
layers_[index].blend_mode = blend_mode;
|
||||
return pp::foundation::Status::success();
|
||||
}
|
||||
|
||||
pp::foundation::Result<std::size_t> CanvasDocument::add_frame(std::uint32_t duration_ms)
|
||||
@@ -271,9 +374,10 @@ pp::foundation::Result<std::size_t> CanvasDocument::add_frame(std::uint32_t dura
|
||||
pp::foundation::Status::out_of_range("document frame count exceeds the configured limit"));
|
||||
}
|
||||
|
||||
if (duration_ms < min_frame_duration_ms) {
|
||||
const auto duration_status = validate_frame_duration(duration_ms);
|
||||
if (!duration_status.ok()) {
|
||||
return pp::foundation::Result<std::size_t>::failure(
|
||||
pp::foundation::Status::invalid_argument("frame duration must be greater than zero"));
|
||||
duration_status);
|
||||
}
|
||||
|
||||
frames_.push_back(AnimationFrame { .duration_ms = duration_ms });
|
||||
@@ -353,8 +457,9 @@ pp::foundation::Status CanvasDocument::set_frame_duration(std::size_t index, std
|
||||
return index_status;
|
||||
}
|
||||
|
||||
if (duration_ms < min_frame_duration_ms) {
|
||||
return pp::foundation::Status::invalid_argument("frame duration must be greater than zero");
|
||||
const auto duration_status = validate_frame_duration(duration_ms);
|
||||
if (!duration_status.ok()) {
|
||||
return duration_status;
|
||||
}
|
||||
|
||||
frames_[index].duration_ms = duration_ms;
|
||||
|
||||
@@ -28,6 +28,7 @@ struct DocumentConfig {
|
||||
struct Layer {
|
||||
std::string name;
|
||||
bool visible = true;
|
||||
bool alpha_locked = false;
|
||||
float opacity = 1.0F;
|
||||
pp::paint::BlendMode blend_mode = pp::paint::BlendMode::normal;
|
||||
};
|
||||
@@ -36,9 +37,25 @@ struct AnimationFrame {
|
||||
std::uint32_t duration_ms = 100;
|
||||
};
|
||||
|
||||
struct DocumentLayerConfig {
|
||||
std::string_view name;
|
||||
bool visible = true;
|
||||
bool alpha_locked = false;
|
||||
float opacity = 1.0F;
|
||||
pp::paint::BlendMode blend_mode = pp::paint::BlendMode::normal;
|
||||
};
|
||||
|
||||
struct DocumentSnapshotConfig {
|
||||
std::uint32_t width = 0;
|
||||
std::uint32_t height = 0;
|
||||
std::span<const DocumentLayerConfig> layers;
|
||||
std::span<const AnimationFrame> frames;
|
||||
};
|
||||
|
||||
class CanvasDocument {
|
||||
public:
|
||||
[[nodiscard]] static pp::foundation::Result<CanvasDocument> create(DocumentConfig config);
|
||||
[[nodiscard]] static pp::foundation::Result<CanvasDocument> create_from_snapshot(DocumentSnapshotConfig config);
|
||||
|
||||
[[nodiscard]] std::uint32_t width() const noexcept;
|
||||
[[nodiscard]] std::uint32_t height() const noexcept;
|
||||
@@ -54,6 +71,7 @@ public:
|
||||
[[nodiscard]] pp::foundation::Status set_active_layer(std::size_t index) noexcept;
|
||||
[[nodiscard]] pp::foundation::Status rename_layer(std::size_t index, std::string_view name);
|
||||
[[nodiscard]] pp::foundation::Status set_layer_visible(std::size_t index, bool visible) noexcept;
|
||||
[[nodiscard]] pp::foundation::Status set_layer_alpha_locked(std::size_t index, bool alpha_locked) noexcept;
|
||||
[[nodiscard]] pp::foundation::Status set_layer_opacity(std::size_t index, float opacity) noexcept;
|
||||
[[nodiscard]] pp::foundation::Status set_layer_blend_mode(std::size_t index, pp::paint::BlendMode blend_mode) noexcept;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user