PageSourceSearch

https://opensource.contentauthenticity.org/assets/js/891107e5.b4101025.js

js contentauthenticity.org collected 2026-09-24 08:25:09 UTC 15,597 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkopensource_contentauth_org=globalThis.webpackChunkopensource_contentauth_org||[]).push([[2653],{6130:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>c,contentTitle:()=>a,default:()=>h,frontMatter:()=>r,metadata:()=>i,toc:()=>o});const i=JSON.parse('{"id":"sdk-repos/c2pa-cpp/readme","title":"CAI SDK C++ library","description":"The c2pa-cpp repository implements C++ APIs that:","source":"@site/docs/sdk-repos/c2pa-cpp/readme.md","sourceDirName":"sdk-repos/c2pa-cpp","slug":"/sdk-repos/c2pa-cpp/","permalink":"/docs/sdk-repos/c2pa-cpp/","draft":false,"unlisted":false,"editUrl":"https://github.com/contentauth/c2pa-cpp/edit/main/README.md","tags":[],"version":"current","frontMatter":{},"sidebar":"docs","previous":{"title":"C2PA Python example","permalink":"/docs/sdk-repos/c2pa-python-example/"},"next":{"title":"Using the C++ library","permalink":"/docs/sdk-repos/c2pa-cpp/docs/usage"}}');var t=s(4848),l=s(8453);const r={},a="CAI SDK C++ library",c={},o=[{value:"Using c2pa_cpp",id:"using-c2pa_cpp",level:2},{value:"Example usage",id:"example-usage",level:3},{value:"Development",id:"development",level:2},{value:"Building using pre-built C FFI libraries",id:"building-using-pre-built-c-ffi-libraries",level:3},{value:"Building using local sources",id:"building-using-local-sources",level:3},{value:"Building the Emscripten/WebAssembly example",id:"building-the-emscriptenwebassembly-example",level:3},{value:"Testing",id:"testing",level:3},{value:"Troubleshooting",id:"troubleshooting",level:3},{value:"Sanitizer test builds fail on macOS",id:"sanitizer-test-builds-fail-on-macos",level:4},{value:"Building API documentation",id:"building-api-documentation",level:3},{value:"License",id:"license",level:2},{value:"Contributions and feedback",id:"contributions-and-feedback",level:3}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",li:"li",p:"p",pre:"pre",ul:"ul",...(0,l.R)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(n.header,{children:(0,t.jsx)(n.h1,{id:"cai-sdk-c-library",children:"CAI SDK C++ library"})}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.a,{href:"https://github.com/contentauth/c2pa-cpp",children:"c2pa-cpp repository"})," implements C++ APIs that:"]}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Read and validate C2PA data from media files in supported formats."}),"\n",(0,t.jsx)(n.li,{children:"Add signed manifests to media files in supported formats."}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"Although this library works for plain C applications, the documentation assumes you're using C++, since that's most common for modern applications."}),"\n",(0,t.jsx)("div",{class:"hide-doxygen",children:(0,t.jsxs)("div",{class:"github-only",children:[(0,t.jsxs)(n.p,{children:["For the best experience, read the docs on the ","CAI Open Source SDK documentation website","."]}),(0,t.jsx)(n.p,{children:"If you want to view the documentation in GitHub, see:"}),(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsx)(n.li,{children:"Using the C++ library"}),"\n",(0,t.jsx)(n.li,{children:"Supported formats"}),"\n",(0,t.jsxs)(n.li,{children:["Configuring the SDK using ",(0,t.jsx)(n.code,{children:"Context"})," and ",(0,t.jsx)(n.code,{children:"Settings"})]}),"\n",(0,t.jsxs)(n.li,{children:["Using Builder intents"," to ensure spec-compliant manifests"]}),"\n",(0,t.jsxs)(n.li,{children:["Using ","working stores and archives"]}),"\n",(0,t.jsxs)(n.li,{children:["Selectively constructing manifests by ","filtering actions and ingredients"]}),"\n",(0,t.jsxs)(n.li,{children:["Using the ","embeddable API for low-level control over embedding manifests"]}),"\n",(0,t.jsx)(n.li,{children:"Frequently asked questions (FAQs)"}),"\n",(0,t.jsx)(n.li,{children:"Release notes"}),"\n"]})]})}),"\n",(0,t.jsx)(n.h2,{id:"using-c2pa_cpp",children:"Using c2pa_cpp"}),"\n",(0,t.jsxs)(n.p,{children:["The recommended way to use this library in your own CMake project is with ",(0,t.jsx)(n.a,{href:"https://cmake.org/cmake/help/latest/module/FetchContent.html",children:"FetchContent"}),":"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-cmake",children:"include(FetchContent)\n\nFetchContent_Declare(\n    c2pa_cpp\n    GIT_REPOSITORY https://github.com/contentauth/c2pa-cpp.git\n    GIT_TAG main  # Or use a specific release tag\n)\nFetchContent_MakeAvailable(c2pa_cpp)\n\nadd_executable(myapp main.cpp)\ntarget_link_libraries(myapp PRIVATE c2pa_cpp)\n"})}),"\n",(0,t.jsxs)(n.p,{children:["This will automatically fetch, build, and link the ",(0,t.jsx)(n.code,{children:"c2pa_cpp"})," library and its dependencies."]}),"\n",(0,t.jsx)(n.admonition,{type:"note",children:(0,t.jsxs)(n.p,{children:["This project uses pre-built dynamic libraries from the ",(0,t.jsx)(n.a,{href:"https://github.com/contentauth/c2pa-rs",children:"c2pa-rs"})," repository. It should select the correct library for your platform. If your platform is not supported, you can build your own library using the c2pa_rs repo."]})}),"\n",(0,t.jsx)(n.h3,{id:"example-usage",children:"Example usage"}),"\n",(0,t.jsxs)(n.p,{children:["See the ",(0,t.jsx)(n.a,{href:"https://github.com/contentauth/c2pa-cpp/tree/main/examples",children:(0,t.jsx)(n.code,{children:"examples/"})})," directory for sample applications that demonstrate how to use the library in practice."]}),"\n",(0,t.jsx)(n.h2,{id:"development",children:"Development"}),"\n",(0,t.jsx)(n.p,{children:"This project has been tested on macOS and should also work on common Linux distributions."}),"\n",(0,t.jsxs)(n.p,{children:["You must install the ",(0,t.jsx)(n.a,{href:"https://github.com/ninja-build/ninja/wiki/Pre-built-Ninja-packages",children:"Ninja"})," build system to run the unit tests."]}),"\n",(0,t.jsx)(n.h3,{id:"building-using-pre-built-c-ffi-libraries",children:"Building using pre-built C FFI libraries"}),"\n",(0,t.jsxs)(n.p,{children:["Building the library holding the C++ SDK requires ",(0,t.jsx)(n.a,{href:"https://www.gnu.org/software/make/",children:"GNU make"}),", which is installed on most macOS systems."]}),"\n",(0,t.jsx)(n.p,{children:"Enter this command to build the SDK:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:"make release\n"})}),"\n",(0,t.jsxs)(n.p,{children:["This will download the ",(0,t.jsx)(n.a,{href:"https://github.com/contentauth/c2pa-rs/releases",children:"prebuilt libraries published with c2pa releases"}),", build and link the C++ code."]}),"\n",(0,t.jsx)(n.p,{children:"The Makefile has a number of other targets; for example:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"test"})," to run unit tests"]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"examples"})," to build and run the C++ examples."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"emscripten-example"})," to build the Emscripten/WebAssembly example (see below)."]}),"\n",(0,t.jsxs)(n.li,{children:[(0,t.jsx)(n.code,{children:"all"})," to build and run everything."]}),"\n"]}),"\n",(0,t.jsxs)(n.p,{children:["Results are saved in the ",(0,t.jsx)(n.code,{children:"build"})," directory."]}),"\n",(0,t.jsx)(n.h3,{id:"building-using-local-sources",children:"Building using local sources"}),"\n",(0,t.jsxs)(n.p,{children:["This project can also be built entirely from source (without pre-built library download), with the prerequisite that you will also need ",(0,t.jsx)(n.a,{href:"https://github.com/contentauth/c2pa-rs",children:"c2pa-rs"})," on the local machine, as well as the ",(0,t.jsx)(n.a,{href:"https://rust-lang.org/tools/install/",children:"Rust toolchain"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["To build in this case, the build scripts need to be able to locate the ",(0,t.jsx)(n.code,{children:"c2pa-rs"})," sources as well as the library this builds for linking. This is done by setting environment variables in the terminal where the builds will run."]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'# Enable local c2pa-rs build\nexport C2PA_BUILD_FROM_SOURCE=ON\n\n# If local build is enabled, set this environment variable to contain the path to c2pa-rs sources\nexport C2PA_RS_PATH=path_to_c2pa_rs_sources\n\n# Since this is going to build Rust code, the build system needs to locate cargo, the tool to build Rust code\n# Add Rust cargo to PATH if not already there\nexport PATH="$HOME/.cargo/bin:$PATH"\n\n# macOs: Set built library path for running tests\nexport DYLD_LIBRARY_PATH="$(pwd)/build/release/tests:$DYLD_LIBRARY_PATH"\n\n# Linux: Set built library path for running tests\nexport LD_LIBRARY_PATH="$(pwd)/build/release/tests:$LD_LIBRARY_PATH"\n'})}),"\n",(0,t.jsx)(n.h3,{id:"building-the-emscriptenwebassembly-example",children:"Building the Emscripten/WebAssembly example"}),"\n",(0,t.jsxs)(n.p,{children:["The ",(0,t.jsx)(n.a,{href:"https://github.com/contentauth/c2pa-cpp/blob/main/examples/emscripten_example.cpp",children:(0,t.jsx)(n.code,{children:"examples/emscripten_example.cpp"})})," file demonstrates using the c2pa C++ library compiled to WebAssembly via Emscripten. It includes reading manifests from files, streams, and using a custom HTTP resolver with ",(0,t.jsx)(n.code,{children:"emscripten_fetch"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["Prerequisites: Install the ",(0,t.jsx)(n.a,{href:"https://emscripten.org/docs/getting_started/downloads.html",children:"Emscripten SDK"})," (4.x or later recommended) and activate it in your shell:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:"source /path/to/emsdk/emsdk_env.sh\n"})}),"\n",(0,t.jsx)(n.p,{children:"Build and run:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:"make emscripten-example\nnode build/emscripten-example/c2pa_example.js path/to/image.jpg\n"})}),"\n",(0,t.jsxs)(n.p,{children:["This downloads prebuilt wasm libraries from the c2pa-rs release, compiles the C++ sources with ",(0,t.jsx)(n.code,{children:"emcc"}),", and produces a Node.js-runnable output. The HTTP resolver example requires a Web Worker in the browser but works without restriction under Node.js."]}),"\n",(0,t.jsx)(n.h3,{id:"testing",children:"Testing"}),"\n",(0,t.jsxs)(n.p,{children:["Build the ",(0,t.jsx)(n.a,{href:"https://github.com/contentauth/c2pa-cpp/tree/main/tests",children:"unit tests"})," by entering this ",(0,t.jsx)(n.code,{children:"make"})," command:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{children:"make test\n"})}),"\n",(0,t.jsxs)(n.p,{children:["The Rust ",(0,t.jsx)(n.code,{children:"c2pa_c"})," library does not need to be sanitizer-instrumented for this to work."]}),"\n",(0,t.jsx)(n.h3,{id:"troubleshooting",children:"Troubleshooting"}),"\n",(0,t.jsx)(n.h4,{id:"sanitizer-test-builds-fail-on-macos",children:"Sanitizer test builds fail on macOS"}),"\n",(0,t.jsxs)(n.p,{children:[(0,t.jsx)(n.code,{children:"make test-san"})," builds the tests with AddressSanitizer/UBSan. On some recent macOS versions the\nAddressSanitizer runtime shipped with Xcode's AppleClang can abort at process start with a message like:"]}
1),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'AddressSanitizer: CHECK failed: sanitizer_malloc_mac.inc:189 "((!asan_init_is_running)) != (0)"\n'})}),"\n",(0,t.jsxs)(n.p,{children:["This is an incompatibility between an older AppleClang sanitizer runtime and the host\nmalloc. The fix is to build the sanitizer target with a newer LLVM/Clang (for example, Homebrew's ",(0,t.jsx)(n.code,{children:"llvm"}),")."]}),"\n",(0,t.jsxs)(n.p,{children:["To do so, install (or update) an ",(0,t.jsx)(n.code,{children:"llvm"})," version. For instance, using homebrew:"]}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:"brew install llvm\n"})}),"\n",(0,t.jsx)(n.p,{children:"Then, build and run the tests with the sanitizers activated. First, configure the build:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:'cmake -S . -B build/debug -G Ninja -DCMAKE_BUILD_TYPE=Debug -DENABLE_SANITIZERS=ON \\\n  -DCMAKE_C_COMPILER="$(brew --prefix llvm)/bin/clang" \\\n  -DCMAKE_CXX_COMPILER="$(brew --prefix llvm)/bin/clang++"\n'})}),"\n",(0,t.jsxs)(n.p,{children:["Note that the llvm compiler from ",(0,t.jsx)(n.code,{children:"brew --prefix llvm"})," must properly resolve for this command to work."]}),"\n",(0,t.jsx)(n.p,{children:"Then run the build scripts:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:"cmake --build build/debug\n"})}),"\n",(0,t.jsx)(n.p,{children:"And finally run the test executable:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:"ctest --test-dir build/debug --output-on-failure\n"})}),"\n",(0,t.jsx)(n.h3,{id:"building-api-documentation",children:"Building API documentation"}),"\n",(0,t.jsx)(n.p,{children:"Doxygen automatically builds API documentation on each PR."}),"\n",(0,t.jsx)(n.p,{children:"To generate API docs locally, these are the main files:"}),"\n",(0,t.jsxs)(n.ul,{children:["\n",(0,t.jsxs)(n.li,{children:["Configuration file: ",(0,t.jsx)(n.code,{children:"c2pa-cpp/Doxyfile"})]}),"\n",(0,t.jsxs)(n.li,{children:["Script: ",(0,t.jsx)(n.code,{children:"c2pa-cpp/scripts/generate_api_docs.sh"})]}),"\n",(0,t.jsxs)(n.li,{children:["Output directory: ",(0,t.jsx)(n.code,{children:"docs/_build/html"})]}),"\n"]}),"\n",(0,t.jsx)(n.p,{children:"Install Doxygen if needed:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:"macOS: brew install doxygen\nUbuntu/Debian: sudo apt-get install doxygen\n"})}),"\n",(0,t.jsx)(n.p,{children:"To generate docs, enter the command:"}),"\n",(0,t.jsx)(n.pre,{children:(0,t.jsx)(n.code,{className:"language-sh",children:"./scripts/generate_api_docs.sh\n"})}),"\n",(0,t.jsxs)(n.p,{children:["Or run ",(0,t.jsx)(n.code,{children:"make -C docs"}),"."]}),"\n",(0,t.jsxs)(n.p,{children:["Open ",(0,t.jsx)(n.code,{children:"_build/html/index.html"})," to see the results."]}),"\n",(0,t.jsx)(n.h2,{id:"license",children:"License"}),"\n",(0,t.jsxs)(n.p,{children:["This package is distributed under the terms of both the ",(0,t.jsx)(n.a,{href:"https://github.com/contentauth/c2pa-cpp/blob/main/LICENSE-MIT",children:"MIT license"})," and the ",(0,t.jsx)(n.a,{href:"https://github.com/contentauth/c2pa-cpp/blob/main/LICENSE-APACHE",children:"Apache License (Version 2.0)"}),"."]}),"\n",(0,t.jsx)(n.p,{children:"Note that some components and dependent crates are licensed under different terms; please check the license terms for each crate and component for details."}),"\n",(0,t.jsx)(n.h3,{id:"contributions-and-feedback",children:"Contributions and feedback"}),"\n",(0,t.jsxs)(n.p,{children:["We welcome contributions to this project.  For information on contributing, providing feedback, and about ongoing work, see ",(0,t.jsx)(n.a,{href:"https://github.com/contentauth/c2pa-cpp/blob/main/CONTRIBUTING.md",children:"Contributing"}),"."]})]})}function h(e={}){const{wrapper:n}={...(0,l.R)(),...e.components};return n?(0,t.jsx)(n,{...e,children:(0,t.jsx)(d,{...e})}):d(e)}},8453:(e,n,s)=>{s.d(n,{R:()=>r,x:()=>a});var i=s(6540);const t={},l=i.createContext(t);function r(e){const n=i.useContext(l);return i.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function a(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:r(e.components),i.createElement(l.Provider,{value:n},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.