trustmark.js / docs /index.html
pdbq's picture
Perceptual model added
ecbc109 verified
<!DOCTYPE html><html class="default" lang="en" data-base="."><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>TrustMark.js</title><link rel="icon" href="assets/favicon.svg" type="image/svg+xml"/><meta name="description" content="Documentation for TrustMark.js"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="assets/style.css"/><link rel="stylesheet" href="assets/highlight.css"/><script defer src="assets/main.js"></script><script async src="assets/icons.js" id="tsd-icons-script"></script><script async src="assets/search.js" id="tsd-search-script"></script><script async src="assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><div class="table-cell" id="tsd-search"><div class="field"><label for="tsd-search-field" class="tsd-widget tsd-toolbar-icon search no-caption"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-search"></use></svg></label><input type="text" id="tsd-search-field" aria-label="Search"/></div><div class="field"><div id="tsd-toolbar-links"></div></div><ul class="results"><li class="state loading">Preparing search index...</li><li class="state failure">The search index is not available</li></ul><a href="index.html" class="title">TrustMark.js</a></div><div class="table-cell" id="tsd-widgets"><a href="#" class="tsd-widget tsd-toolbar-icon menu no-caption" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-menu"></use></svg></a></div></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><h1>TrustMark.js</h1></div><div class="tsd-panel tsd-typography"><a id="trustmarkjs" class="tsd-anchor"></a><h1 class="tsd-anchor-link">TrustMark.js<a href="#trustmarkjs" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h1><p>Javascript implementation of TrustMark watermarking as described in <a href="https://arxiv.org/abs/2311.18297">TrustMark - Universal Watermarking for Arbitrary Resolution Images</a> for encoding &amp; decoding TrustMark watermarks in modern browsers as well as Node.js.</p>
<a id="important" class="tsd-anchor"></a><h1 class="tsd-anchor-link">Important!<a href="#important" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h1><p>TrustMark.js <strong>is not suitable</strong> for production environments. Handling large image files significantly increases memory allocation, which can cause browser tab crashes or memory errors in a Node.js environment.</p>
<a id="usage-browser" class="tsd-anchor"></a><h1 class="tsd-anchor-link">Usage Browser<a href="#usage-browser" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h1><p>Add the <code>onnxruntime-web</code> and <code>@tensorflow/tfjs</code> dependencies to your main HTML file:</p>
<pre><code class="html"><span class="hl-0">&lt;</span><span class="hl-1">script</span><span class="hl-2"> </span><span class="hl-3">src</span><span class="hl-2">=</span><span class="hl-4">&quot;https://cdn.jsdelivr.net/npm/onnxruntime-web@latest/dist/ort.min.js&quot;</span><span class="hl-0">&gt;&lt;/</span><span class="hl-1">script</span><span class="hl-0">&gt;</span><br/><span class="hl-0">&lt;</span><span class="hl-1">script</span><span class="hl-2"> </span><span class="hl-3">src</span><span class="hl-2">=</span><span class="hl-4">&quot;https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest/dist/tf.min.js&quot;</span><span class="hl-0">&gt;&lt;/</span><span class="hl-1">script</span><span class="hl-0">&gt;</span>
</code><button type="button">Copy</button></pre>
<pre><code class="javascript"><span class="hl-5">import</span><span class="hl-6"> { </span><span class="hl-7">TrustMark</span><span class="hl-6"> } </span><span class="hl-5">from</span><span class="hl-6"> </span><span class="hl-8">&#39;./dist/index.js&#39;</span><span class="hl-6">;</span><br/><span class="hl-9">//Instanciate Trustmark</span><br/><span class="hl-10">const</span><span class="hl-6"> </span><span class="hl-11">tm</span><span class="hl-6"> = </span><span class="hl-10">new</span><span class="hl-6"> </span><span class="hl-12">TrustMark</span><span class="hl-6">()</span><br/><br/><span class="hl-9">// Load the models</span><br/><span class="hl-5">await</span><span class="hl-6"> </span><span class="hl-7">tm</span><span class="hl-6">.</span><span class="hl-12">load_models</span><span class="hl-6">()</span><br/><span class="hl-9">// Decode an Image</span><br/><span class="hl-10">let</span><span class="hl-6"> </span><span class="hl-7">decoded</span><span class="hl-6"> = </span><span class="hl-5">await</span><span class="hl-6"> </span><span class="hl-7">tm</span><span class="hl-6">.</span><span class="hl-12">decode</span><span class="hl-6">(</span><span class="hl-8">&quot;tests/fixtures/Django_Reinhardt_(Gottlieb_07301)_watermarked.jpeg&quot;</span><span class="hl-6">);</span>
</code><button type="button">Copy</button></pre>
<p>Note: CPU and WebGL backends are included by default in <code>@tensorflow/tfjs</code>.</p>
<a id="usage-nodejs" class="tsd-anchor"></a><h1 class="tsd-anchor-link">Usage Node.js<a href="#usage-nodejs" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h1><pre><code class="javascript"><span class="hl-5">import</span><span class="hl-6"> { </span><span class="hl-7">TrustMark</span><span class="hl-6"> } </span><span class="hl-5">from</span><span class="hl-6"> </span><span class="hl-8">&#39;./dist/index.cjs&#39;</span><span class="hl-6">;</span><br/><span class="hl-9">//Instanciate Trustmark</span><br/><span class="hl-10">const</span><span class="hl-6"> </span><span class="hl-11">tm</span><span class="hl-6"> = </span><span class="hl-10">new</span><span class="hl-6"> </span><span class="hl-12">TrustMark</span><span class="hl-6">()</span><br/><br/><span class="hl-9">// Load the models</span><br/><span class="hl-5">await</span><span class="hl-6"> </span><span class="hl-7">tm</span><span class="hl-6">.</span><span class="hl-12">load_models</span><span class="hl-6">()</span><br/><span class="hl-9">// Decode an Image</span><br/><span class="hl-10">let</span><span class="hl-6"> </span><span class="hl-7">decoded</span><span class="hl-6"> = </span><span class="hl-5">await</span><span class="hl-6"> </span><span class="hl-7">tm</span><span class="hl-6">.</span><span class="hl-12">decode</span><span class="hl-6">(</span><span class="hl-8">&quot;tests/fixtures/CLIC_watermarked.jpeg&quot;</span><span class="hl-6">);</span>
</code><button type="button">Copy</button></pre>
<p><a href="https://github.com/tensorflow/tfjs/blob/master/tfjs-node/README.md">tfjs-node-gpu</a> is recommended for Node.js if you need to watermark large image files.</p>
<a id="models" class="tsd-anchor"></a><h1 class="tsd-anchor-link">Models<a href="#models" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h1><p>TrustMark.js is using the Q (quality) and P (perceptual) model variants, trained to encode a payload of 100 bits. Models are fetched and cached on first use into <code>models</code> directory on Node.js, and into the <a href="https://developer.mozilla.org/en-US/docs/Web/API/CacheStorage">CacheStorage</a> in a browser environment.</p>
<a id="trustmark-q-quality-default" class="tsd-anchor"></a><h2 class="tsd-anchor-link">TrustMark-Q (Quality) (default)<a href="#trustmark-q-quality-default" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Offers a good balance between robustness and quality</p>
<a id="trustmark-p-perceptual" class="tsd-anchor"></a><h2 class="tsd-anchor-link">TrustMark-P (Perceptual)<a href="#trustmark-p-perceptual" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Gives high visual quality with PSNR exceeding 50db but less robustness to more severe noise degradations, yet it will survive most content distribution platforms.</p>
<a id="supported-data-schema-modes" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Supported data schema modes<a href="#supported-data-schema-modes" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><ul>
<li><code>Encoding.BCH_5</code> - Protected payload of 61 bits (+ 35 ECC bits) - allows for 5 bit flips.</li>
<li><code>Encoding.BCH_4</code> - Protected payload of 68 bits (+ 28 ECC bits) - allows for 4 bit flips. (default)</li>
<li><code>Encoding.BCH_3</code> - Protected payload of 75 bits (+ 21 ECC bits) - allows for 3 bit flips.</li>
<li><code>Encoding.BCH_SUPER</code> - Protected payload of 40 bits (+ 56 ECC bits) - allows for 8 bit flips.</li>
</ul>
<a id="preprocessing-model" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Preprocessing model<a href="#preprocessing-model" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><p>The models <code>models/preprocess_224.onnx</code> and <code>models/preprocess_256.onnx</code> are used to resize images to the format expected as input for the Trustmark models. It is mandatory to get the same inference results as the original Python implementation.</p>
<a id="decode" class="tsd-anchor"></a><h1 class="tsd-anchor-link">Decode<a href="#decode" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h1><pre><code class="javascript"><span class="hl-9">// Decode the watermark of an image</span><br/><span class="hl-10">let</span><span class="hl-6"> </span><span class="hl-7">decoded</span><span class="hl-6"> = </span><span class="hl-5">await</span><span class="hl-6"> </span><span class="hl-7">tm</span><span class="hl-6">.</span><span class="hl-12">decode</span><span class="hl-6">(</span><span class="hl-8">&quot;tests/fixtures/Django_Reinhardt_(Gottlieb_07301)_watermarked.jpeg&quot;</span><span class="hl-6">);</span><br/><span class="hl-9">/*</span><br/><span class="hl-9">return:</span><br/><span class="hl-9">{</span><br/><span class="hl-9">bitflips, (number) - corrected bits</span><br/><span class="hl-9">valid, (boolean) - validity of the decoded watermark</span><br/><span class="hl-9">binary, (string) - string representation of decoded bits</span><br/><span class="hl-9">hex,(string) - string representation of decoded bits as hexadecimal</span><br/><span class="hl-9">ascii (string) - string representation of decoded bits as 7-bit ASCII</span><br/><span class="hl-9">}</span><br/><span class="hl-9">*/</span>
</code><button type="button">Copy</button></pre>
<a id="encode" class="tsd-anchor"></a><h1 class="tsd-anchor-link">Encode<a href="#encode" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h1><a id="text-mode" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Text mode<a href="#text-mode" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><p>The payload is encoded as ASCII 7 bits. The 68 bits give you 9 characters.</p>
<a id="binary-mode" class="tsd-anchor"></a><h2 class="tsd-anchor-link">Binary mode<a href="#binary-mode" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h2><p>The 68 bits give you 8 bytes.</p>
<pre><code class="javascript"><span class="hl-9">// text mode, 0.4 strenght, no erase</span><br/><span class="hl-5">await</span><span class="hl-6"> </span><span class="hl-7">tm</span><span class="hl-6">.</span><span class="hl-12">encode</span><span class="hl-6">(</span><span class="hl-8">&quot;tests/fixtures/Django_Reinhardt_(Gottlieb_07301).jpeg&quot;</span><span class="hl-6">, </span><span class="hl-8">&#39;Marzipan&#39;</span><span class="hl-6">, </span><span class="hl-13">0.4</span><span class="hl-6">, </span><span class="hl-10">false</span><span class="hl-6">);</span><br/><br/><span class="hl-9">// binary mode 0.4 strenght, no erase</span><br/><span class="hl-5">await</span><span class="hl-6"> </span><span class="hl-7">tm</span><span class="hl-6">.</span><span class="hl-12">encode</span><span class="hl-6">(</span><span class="hl-8">&quot;tests/fixtures/Django_Reinhardt_(Gottlieb_07301).jpeg&quot;</span><span class="hl-6">, </span><span class="hl-8">&#39;11011011110100011110010101000111000100110101010010101110101011011011&#39;</span><span class="hl-6">, </span><span class="hl-13">0.4</span><span class="hl-6">, </span><span class="hl-10">false</span><span class="hl-6">);</span><br/><br/><span class="hl-9">// text mode, 0.4 strenght, no erase as a png encoded file</span><br/><span class="hl-10">let</span><span class="hl-6"> </span><span class="hl-7">encoded</span><span class="hl-6"> = </span><span class="hl-5">await</span><span class="hl-6"> </span><span class="hl-7">tm</span><span class="hl-6">.</span><span class="hl-12">encode</span><span class="hl-6">(</span><span class="hl-8">&quot;tests/fixtures/Django_Reinhardt_(Gottlieb_07301).jpeg&quot;</span><span class="hl-6">, </span><span class="hl-8">&#39;Marzipan&#39;</span><span class="hl-6">, </span><span class="hl-13">0.4</span><span class="hl-6">, </span><span class="hl-10">false</span><span class="hl-6">, </span><span class="hl-8">&#39;png&#39;</span><span class="hl-6">)</span><br/><br/><br/><span class="hl-9">/*</span><br/><span class="hl-9">return:</span><br/><span class="hl-9">{</span><br/><span class="hl-9">stego, (Uint8ClampedArray | PNG data) - the watermaked image data</span><br/><span class="hl-9">residual, (Uint8ClampedArray | PNG data) - the residual image data</span><br/><span class="hl-9">width, (number) - width of the watermaked image</span><br/><span class="hl-9">height,(number) - height of the watermaked image</span><br/><span class="hl-9">}</span><br/><span class="hl-9">*/</span>
</code><button type="button">Copy</button></pre>
<a id="erase" class="tsd-anchor"></a><h1 class="tsd-anchor-link">Erase<a href="#erase" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="assets/icons.svg#icon-anchor"></use></svg></a></h1><p>Overwrite an existing watermark with random values.</p>
<pre><code class="javascript"><span class="hl-9">// erase, 0.4 strenght</span><br/><span class="hl-5">await</span><span class="hl-6"> </span><span class="hl-7">tm</span><span class="hl-6">.</span><span class="hl-12">encode</span><span class="hl-6">(</span><span class="hl-8">&quot;tests/fixtures/Django_Reinhardt_(Gottlieb_07301)_watermarked.jpeg&quot;</span><span class="hl-6">, </span><span class="hl-8">&#39;&#39;</span><span class="hl-6">, </span><span class="hl-13">0.4</span><span class="hl-6">, </span><span class="hl-10">true</span><span class="hl-6">);</span><br/><br/><span class="hl-9">/*</span><br/><span class="hl-9">return:</span><br/><span class="hl-9">{</span><br/><span class="hl-9">stego, (Uint8ClampedArray | PNG data) - the image data with the watermark erased.</span><br/><span class="hl-9">residual, (Uint8ClampedArray | PNG data) - the residual image data</span><br/><span class="hl-9">width, (number) - width of the image</span><br/><span class="hl-9">height,(number) - height of the image</span><br/><span class="hl-9">}</span><br/><span class="hl-9">*/</span>
</code><button type="button">Copy</button></pre>
</div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-chevronDown"></use></svg>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="assets/icons.svg#icon-chevronDown"></use></svg>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#trustmarkjs"><span>Trust<wbr/>Mark.js</span></a><a href="#important"><span>Important!</span></a><a href="#usage-browser"><span>Usage <wbr/>Browser</span></a><a href="#usage-nodejs"><span>Usage <wbr/>Node.js</span></a><a href="#models"><span>Models</span></a><ul><li><a href="#trustmark-q-quality-default"><span>Trust<wbr/>Mark-<wbr/>Q (<wbr/>Quality) (default)</span></a></li><li><a href="#trustmark-p-perceptual"><span>Trust<wbr/>Mark-<wbr/>P (<wbr/>Perceptual)</span></a></li><li><a href="#supported-data-schema-modes"><span>Supported data schema modes</span></a></li><li><a href="#preprocessing-model"><span>Preprocessing model</span></a></li></ul><a href="#decode"><span>Decode</span></a><a href="#encode"><span>Encode</span></a><ul><li><a href="#text-mode"><span>Text mode</span></a></li><li><a href="#binary-mode"><span>Binary mode</span></a></li></ul><a href="#erase"><span>Erase</span></a></div></details></div><div class="site-menu"><nav class="tsd-navigation"><a href="modules.html">TrustMark.js</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html>