#pragma once #include "Document/Guides.h" #include "Document/LayerAdjustment.h" #include "Document/LayerAppearance.h" #include "Document/LayerEffects.h" #include "Document/LayerTransform.h" #include "Document/ShapeTool.h" #include "Document/TypeTool.h" #include "IO/ImageImporter.h" #include #include #include #include #include #include #include #include struct LayerMask; // Absent optionals stay out of the manifest. struct ProjectLayerRecord { QUuid id; QString name; bool isVisible; LayerTransform transform; std::optional imageFile; std::optional parentID = std::nullopt; std::optional isGroup = std::nullopt; std::optional opacity = std::nullopt; std::optional blendMode = std::nullopt; std::optional maskFile = std::nullopt; std::optional maskEnabled = std::nullopt; std::optional maskSourceID = std::nullopt; std::optional adjustment = std::nullopt; std::optional maskPlacement = std::nullopt; // Absent in older projects, which means linked. std::optional maskLinked = std::nullopt; // A shape layer's shape; older versions keep the pixels alone. std::optional shape = std::nullopt; // What the layer draws round itself; its pixels stay. std::optional effects = std::nullopt; std::optional text = std::nullopt; // Drawn opacity, folders included; defined in LayerGroups.cpp. double effectiveOpacity(const std::map &byID) const; }; // A UUID as Swift writes it: upper case, no braces. QString uuidString(const QUuid &id); struct ProjectManifest { // Swift's current and supported: what saves write, what loads accept. static constexpr qint64 current = 10; static constexpr std::pair supported{1, current}; static bool supports(qint64 version) { return version >= supported.first && version <= supported.second; } QString format = QStringLiteral("com.compositor.project"); // Swift's Int: a wild number must reach validation whole. qint64 version = current; QString colorSpace = QStringLiteral("sRGB"); // Version-1 projects carry none: 72 pixels per inch. std::optional resolution = std::nullopt; QUuid documentID; qint64 width; qint64 height; std::optional activeLayerID; std::vector layers; // Alignment guides; versions 1 to 7 carry none. std::optional> guides = std::nullopt; // Pretty JSON with sorted keys; absent optionals are left out. QByteArray encoded() const; // Throws ProjectError(invalid) on anything Swift's decoder refuses. static ProjectManifest decoded(const QByteArray &data); // Format and version alone: newer files may not decode. static std::pair header(const QByteArray &data); }; struct ProjectSnapshot { ProjectManifest manifest; std::map images; std::map masks = {}; // A record's mask, from its mask file and fields. std::optional mask(const ProjectLayerRecord &layer) const; }; class ProjectError : public std::runtime_error { public: enum class Kind { invalid, version, missingImage, tooLarge, encode }; explicit ProjectError(Kind kind); static ProjectError unsupportedVersion(qint64 version); const Kind kind; // Set only for Kind::version. const std::optional version; private: ProjectError(Kind kind, std::optional version, const QString &description); }; // A .comp project: a directory holding manifest.json and images/. namespace ProjectStore { // Replaces the project in one step or leaves it untouched. void save(const ProjectSnapshot &snapshot, const QString &path); ProjectSnapshot load(const QString &path); }