Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ training: release
cmake --build $(RELEASE_BUILD_DIR) --target training
$(RELEASE_BUILD_DIR)/examples/training

examples: training demo
context: release
cmake --build $(RELEASE_BUILD_DIR) --target context_demo
$(RELEASE_BUILD_DIR)/examples/context_demo

examples: training demo context

clean:
rm -rf $(BUILD_DIR)
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ For the best experience, read the docs on the [CAI Open Source SDK documentation
</div>
</div>

## Using c2pa_cpp
## Using c2pa_cpp

The recommended way to use this library in your own CMake project is with [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html):

Expand Down Expand Up @@ -112,4 +112,5 @@ Note that some components and dependent crates are licensed under different term

We welcome contributions to this project. For information on contributing, providing feedback, and about ongoing work, see [Contributing](https://github.com/contentauth/c2pa-c/blob/main/CONTRIBUTING.md).


// TODO-TMN: Add links to settings reference!
// TODO-TMN: Add example settings in tests + how to load trust
74 changes: 31 additions & 43 deletions examples/context_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// or the MIT license (http://opensource.org/licenses/MIT),
// at your option.
//
// Demonstration of the new context-based C2PA API
// Demonstration of the context-based C2PA API

#include <c2pa.hpp>
#include <iostream>
Expand All @@ -14,80 +14,68 @@ namespace fs = std::filesystem;

int main() {
try {
std::cout << "=== C2PA Context API Demo ===" << std::endl;
std::cout << "C2PA Library Version: " << c2pa::version() << std::endl << std::endl;
// 1. Create a default context
std::cout << "1. Creating default context..." << std::endl;

// 1. Example with a default context
std::cout << "Creating default context..." << std::endl;
auto context = c2pa::Context::create();
std::cout << " Context created successfully!" << std::endl;
std::cout << " Has context: " << (context->has_context() ? "yes" : "no") << std::endl << std::endl;
// 2. Create a context from JSON
std::cout << "2. Creating context from JSON configuration..." << std::endl;

// 2. Context from JSON, useful for settings direct parsing for instance
std::cout << "Creating context from JSON configuration..." << std::endl;
auto json_context = c2pa::Context::from_json(R"({
"verify": {
"verify_after_reading": true
}
})");
std::cout << " JSON context created successfully!" << std::endl << std::endl;
// 3. Create a context using Builder pattern
std::cout << "3. Creating context using Builder..." << std::endl;
auto builder_context = c2pa::Context::Builder()

// 3. Using a context creator (context builder) to create the context
std::cout << "Creating context using ContextBuilder..." << std::endl;
auto dynamic_context = c2pa::Context::ContextBuilder()
.with_json(R"({"verify": {"verify_after_sign": false}})")
.build();
std::cout << " Builder context created successfully!" << std::endl << std::endl;

// 4. Use context with Reader
std::cout << "4. Using context with Reader..." << std::endl;
.create_context();
std::cout << " Dynamic context created successfully!" << std::endl << std::endl;

// 4. Use context with the Reader API
// THis propagates settings in the context to the Reader
std::cout << "Using context with Reader..." << std::endl;
fs::path test_file = fs::path(__FILE__).parent_path().parent_path() / "tests" / "fixtures" / "C.jpg";
if (fs::exists(test_file)) {
std::cout << " Reading file: " << test_file << std::endl;
c2pa::Reader reader(context, test_file);

std::cout << " Is embedded: " << (reader.is_embedded() ? "yes" : "no") << std::endl;

// Get context from reader
auto reader_context = reader.context();
std::cout << " Reader has context: " << (reader_context ? "yes" : "no") << std::endl;
std::cout << " Same context object: " << (reader_context == context ? "yes" : "no") << std::endl;
// Get manifest

// Get manifest, with the Reader using contextual settings (eg. for trust configurations)
auto manifest_json = reader.json();
std::cout << " Manifest size: " << manifest_json.size() << " bytes" << std::endl;
} else {
std::cout << " Test file not found (expected for demo): " << test_file << std::endl;
std::cout << " Test file not found: " << test_file << std::endl;
}
std::cout << std::endl;

// 5. Demonstrate thread-safe context sharing
std::cout << "5. Context sharing demo..." << std::endl;
auto shared_context = c2pa::Context::create();
std::cout << " Context can be safely shared via shared_ptr" << std::endl;
std::cout << " Use count: " << shared_context.use_count() << std::endl;

// Make a copy
auto shared_copy = shared_context;
std::cout << " After copying, use count: " << shared_context.use_count() << std::endl;
std::cout << std::endl;

// 6. Settings example
std::cout << "6. Settings configuration demo..." << std::endl;

// Contexts are especially powerful to manage SDK settings
std::cout << "Settings configuration through context..." << std::endl;
c2pa::Settings settings;
settings.set("verify.verify_after_sign", "true")
.update(R"({"verify": {"verify_after_reading": false}})", "json");
std::cout << " Settings configured successfully!" << std::endl;
auto settings_context = c2pa::Context::Builder()

auto settings_context = c2pa::Context::ContextBuilder()
.with_settings(settings)
.build();
std::cout << " Context created from settings!" << std::endl;
.create_context();
std::cout << " Context created from settings (settings will propagate throught the context, not globally)" << std::endl;
std::cout << std::endl;

std::cout << "=== All context API demos completed successfully! ===" << std::endl;

return 0;

} catch (const c2pa::C2paException& e) {
std::cerr << "C2PA Error: " << e.what() << std::endl;
return 1;
Expand Down
55 changes: 26 additions & 29 deletions include/c2pa.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
#include <vector>
#include <optional>
#include <memory>
#include <mutex>

#include <c2pa.h>

Expand Down Expand Up @@ -75,9 +74,7 @@ namespace c2pa
};

/// @brief Interface for types that can provide C2PA context functionality.
/// @details Implement this interface to make your type usable with Reader and Builder.
/// This enables polymorphic usage where both c2pa::Context and other context
/// types (like Adobe's CaiAdobeContext) can be used interchangeably.
/// @details Implement this interface to make your own context
class C2PA_CPP_API IContextProvider {
public:
virtual ~IContextProvider() = default;
Expand Down Expand Up @@ -152,45 +149,45 @@ namespace c2pa
/// factory methods or the Builder pattern.
class C2PA_CPP_API Context : public IContextProvider {
public:
/// @brief Builder for creating customized Context instances.
class C2PA_CPP_API Builder {
/// @brief ContextBuilder for creating customized Context instances.
class C2PA_CPP_API ContextBuilder {
public:
Builder();
~Builder();
ContextBuilder();
~ContextBuilder();

// Move semantics
Builder(Builder&&) noexcept;
Builder& operator=(Builder&&) noexcept;
ContextBuilder(ContextBuilder&&) noexcept;
ContextBuilder& operator=(ContextBuilder&&) noexcept;

// Non-copyable
Builder(const Builder&) = delete;
Builder& operator=(const Builder&) = delete;
ContextBuilder(const ContextBuilder&) = delete;
ContextBuilder& operator=(const ContextBuilder&) = delete;

/// @brief Configure with Settings object.
/// @param settings Settings to use (will be copied).
/// @return Reference to this Builder for method chaining.
Builder& with_settings(const Settings& settings);
/// @return Reference to this ContextBuilder for method chaining.
ContextBuilder& with_settings(const Settings& settings);

/// @brief Configure with JSON string.
/// @param json JSON configuration string.
/// @return Reference to this Builder for method chaining.
/// @return Reference to this ContextBuilder for method chaining.
/// @throws C2paException if JSON is invalid.
Builder& with_json(const string& json);
ContextBuilder& with_json(const string& json);

/// @brief Configure with TOML string.
/// @param toml TOML configuration string.
/// @return Reference to this Builder for method chaining.
/// @return Reference to this ContextBuilder for method chaining.
/// @throws C2paException if TOML is invalid.
Builder& with_toml(const string& toml);
ContextBuilder& with_toml(const string& toml);

/// @brief Build the immutable Context.
/// @return Shared pointer to the new Context.
/// @throws C2paException if context creation fails.
/// @note This consumes the builder. After calling build(), the builder is in a moved-from state.
[[nodiscard]] ContextProviderPtr build();
/// @note This consumes the builder. After calling create_context(), the builder is in a moved-from state.
[[nodiscard]] ContextProviderPtr create_context();

private:
C2paContextBuilder* builder_;
C2paContextBuilder* context_builder_;
};

/// @brief Create a Context with default settings.
Expand Down Expand Up @@ -361,7 +358,7 @@ namespace c2pa
ContextProviderPtr context_; // Keeps context alive

public:
// ===== Context-based constructors (NEW, RECOMMENDED) =====
// ===== Context-based constructors =====

/// @brief Create a Reader from a context and stream.
/// @param context Context provider to use for this reader.
Expand Down Expand Up @@ -533,21 +530,21 @@ namespace c2pa
ContextProviderPtr context_; // Keeps context alive

public:
// ===== Context-based constructors (NEW, RECOMMENDED) =====
// ===== Context-based constructors =====

/// @brief Create a Builder from a context with an empty manifest.
/// @param context Context provider to use for this builder.
/// @throws C2pa::C2paException for errors encountered by the C2PA library.
explicit Builder(ContextProviderPtr context);

/// @brief Create a Builder from a context and manifest JSON string.
/// @param context Context provider to use for this builder.
/// @param manifest_json The manifest JSON string.
/// @throws C2pa::C2paException for errors encountered by the C2PA library.
Builder(ContextProviderPtr context, const std::string &manifest_json);

// ===== Legacy constructor (DEPRECATED) =====

/// @brief Create a Builder from a manifest JSON string (uses global settings).
/// @param manifest_json The manifest JSON string.
/// @throws C2pa::C2paException for errors encountered by the C2PA library.
Expand All @@ -574,7 +571,7 @@ namespace c2pa
}

~Builder();

/// @brief Get the context associated with this Builder.
/// @return Shared pointer to the context, or nullptr if using legacy API.
[[nodiscard]] inline ContextProviderPtr context() const noexcept {
Expand All @@ -584,7 +581,7 @@ namespace c2pa
/// @brief Get the underlying C2paBuilder pointer.
/// @return Pointer managed by this wrapper.
C2paBuilder *c2pa_builder() const noexcept;

/// @brief Set or update the manifest definition.
/// @param manifest_json The manifest JSON string.
/// @return Reference to this Builder for method chaining.
Expand Down
Loading
Loading