> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/web/get-started/samples/showcase-demo-pdf-stamps.md).

# PDF Stamps Showcase Demo Code Sample

Add stamps to your documents. The viewer includes several sample stamps, and you can also create custom ones using text or images.

{% hint style="info" %}
**Requirements**

*These packages are required to use these features in production. Trial keys have unlimited access to all features*

<a href="/web/get-started/readme.md" class="button primary">Web SDK</a><a href="https://showcase.apryse.com/pdf-stamps" class="button primary">Live demo</a>
{% endhint %}

Easily add stamps to your documents. The viewer includes several sample stamps, and you can also create custom stamps using text or images.

This demo allows you to:

* Load default stamps and add them to a document.
* Create custom stamps:
  * Text
  * Image
* Resize stamps.
* Download an edited document with annotated stamps.

**Implementation steps** To add stamping capability with WebViewer:

Step 1: Choose your [preferred web stack](/web/get-started/readme.md). Step 2: Add the ES6 JavaScript sample code provided in this guide.

Once you generate your license key, it will automatically be included in your sample code below.

{% @apryse-license-key/apryse-license-key platform="WEB\_VIEWER" variant="compact" %}

{% tabs %}
{% tab title="index.js" %}

<pre class="language-js" data-line-numbers><code class="lang-js">// ES6 Compliant Syntax
// Copilot name: GitHub Copilot, version: 1.0.0, model: GPT-4, version: 2024-06, date: 2025-10-23
// File: showcase-demos/edit-table-of-contents/index.js

import WebViewer from '@pdftron/webviewer';

const licenseKey = '<code class="expression">visitor.claims.wvKey || "YOUR_WEBVIEWER_LICENSE_KEY"</code>';

// State variables for demo
const dropPoint = {};
const customStampDemoFile = 'https://apryse.s3.us-west-1.amazonaws.com/public/files/samples/sales-invoice.pdf';

function initializeWebViewer() {
  WebViewer(
    {
      path: '/lib',
      initialDoc: customStampDemoFile,
      enableFilePicker: true, // Enable file picker to open files. In WebViewer -> menu icon -> Open File
      licenseKey: licenseKey, // Replace with your license key
    },
    document.getElementById('viewer')
  ).then((instance) => {

    createUIElements();

    // Set toolbar group immediately after WebViewer loads
    instance.UI.setToolbarGroup(['toolbarGroup-Insert']);

    // Wait for document to load before setting tool mode (more reliable)
    instance.Core.documentViewer.addEventListener('documentLoaded', () => {

      // Set the rubber stamp tool mode
      instance.UI.setToolMode('AnnotationCreateRubberStamp');

      // Add a small delay before opening the panel
      setTimeout(() => {
        instance.UI.openElements(['rubberStampPanel']);
      }, 150);

      // Register events after the page is loaded
      demoComplete();
      registerDragEvents();
    });
  });
};

const getIframeWindow = () => {
  return (
    document.getElementById('viewer')?.getElementsByTagName('iframe')?.[0]?.contentWindow || window
  );
};

const getIframeContext = () => {
  return (
    document.getElementById('viewer')?.getElementsByTagName('iframe')?.[0]?.contentWindow
      .instance || window.WebViewer.getInstance()
  );
};

// Drag and drop handlers
const dragOver = (e) => {
  e.preventDefault();
  //const imgData = e.dataTransfer.getData('text/plain');
  e.target.style.opacity = 1;
  e.preventDefault();
};

// Update drop event to adjust dropPoint to fit document coordinates
const drop = (e) => {
  console.log('File dropped:', e);
  e.preventDefault();
  e.stopPropagation();
  const documentViewer = getIframeContext().Core.documentViewer;
  const scrollElement = documentViewer.getScrollViewElement();
  const scrollLeft = scrollElement.scrollLeft || 0;
  const scrollTop = scrollElement.scrollTop || 0;
  const zoomLevel = documentViewer.getZoomLevel();
  dropPoint.current = { x: (e.pageX + scrollLeft), y: (e.pageY + scrollTop) };
  const displayMode = documentViewer.getDisplayModeManager().getDisplayMode();
  const doc = documentViewer.getDocument();

  const documentWidth = doc.getPageInfo(1).width;
  const documentHeight = doc.getPageInfo(1).height;
  dropPoint.current.x = Math.min(Math.max(dropPoint.current.x, 0), documentWidth);
  dropPoint.current.y = Math.min(Math.max(dropPoint.current.y, 0), documentHeight);
  const page = displayMode.getSelectedPages(dropPoint.current, dropPoint.current);

  if (!page.first) {
    console.error('128 Invalid page location for point:', dropPoint.current);

    // Log dimensions of all pages for debugging
    const pageCount = doc.getPageCount();
    for (let i = 1; i &#x3C;= pageCount; i++) {
      const pageInfo = doc.getPageInfo(i);
      console.log(`Page ${i} bounds:`, pageInfo);
    }

    return;
  }

  const pageInfo = doc.getPageInfo(page.first);
  console.log('Selected page bounds:', pageInfo);

  let pagePoint = displayMode.windowToPage(dropPoint.current, page.first);
  console.log('Mapped pagePoint before clamping:', pagePoint);

  if (!pagePoint || pagePoint.x &#x3C; 0 || pagePoint.y &#x3C; 0 || pagePoint.x > pageInfo.width || pagePoint.y > pageInfo.height) {
    console.error('Invalid page coordinates after mapping:', pagePoint);
    pagePoint = {
      x: Math.min(Math.max(pagePoint.x || 0, 0), pageInfo.width),
      y: Math.min(Math.max(pagePoint.y || 0, 0), pageInfo.height),
    };
  }

  const imgData = e.dataTransfer.getData('text/plain');
  if (!imgData) {
    console.error('No imgData found in dataTransfer');
    return;
  }

  console.log('Dimensions of image dataTransfer:', e.dataTransfer);
  let stampSize = { width: 100, height: 25 }; //Default size
  let img = new Image();
  img.src = imgData; // Set the base64 string as the source

  img.onload = () => {
    document.body.appendChild(img); // Append the image to the DOM temporarily
    const renderedWidth = img.offsetWidth; // Rendered width of the image
    const renderedHeight = img.offsetHeight; // Rendered height of the image
    document.body.removeChild(img); // Remove the image from the DOM

    // You can now use these dimensions to set the stamp size
    stampSize.width = renderedWidth;
    stampSize.height = renderedHeight;

    //find slider and get the value for width of image
    const widthSlider = document.getElementById('width-slider');
    if (widthSlider) {
      const sliderValue = parseFloat(widthSlider.value);
      if (!isNaN(sliderValue) &#x26;&#x26; sliderValue > 0) {
        stampSize.width = sliderValue;
        const aspectRatio = renderedWidth / renderedHeight;
        stampSize.height = sliderValue / aspectRatio;
      }
    }

    const viewFactor = 0.66; // Adjust this factor as needed, used to scale the stamp appropriately
    let stampRect = { width: stampSize.width * zoomLevel * viewFactor, height: stampSize.height * zoomLevel * viewFactor };

    try {
      addStamp(imgData, pagePoint, stampRect, page.first);
      console.log('Stamp added at point:', pagePoint, 'with rect:', stampRect);
    } catch (error) {
      console.error('Error while adding stamp:', error);
      console.error('Parameters passed to addStamp:', {
        imgData,
        point: pagePoint,
        rect: stampRect,
        pageNumber: page.first,
      });
    }
  };

  img.onerror = () => {
    console.error('Failed to load image from data URL');
  };
};

function demoComplete() {
  //let defaultDocument = customStampDemoFile;
  //console.log('Demo initialization complete');
  const documentViewer = getIframeContext().Core.documentViewer;
  documentViewer.addEventListener('toolModeUpdated', toolModeUpdated);
  const iframeDoc = getIframeWindow().document.body;
  iframeDoc.addEventListener('dragover', dragOver);
  iframeDoc.addEventListener('drop', drop);

  // Allow annotations outside page bounds
  getIframeContext().Core.Tools.Tool.ALLOW_ANNOTS_OUTSIDE_PAGE = true;
};

const toolModeUpdated = (type) => {
  const { id } = type;
  if (id) {
    // Check if stamps object exists and has the id
    if (window.stamps &#x26;&#x26; window.stamps[id]) {
      data = window.stamps[id];
      name = id;
    } else {
      data = null;
    }
  }
};

const stampPanelWidthOffset = 146;

const addStamp = (
  imgData,
  point = {},
  rect = { height: undefined, width: undefined }
) => {
  const { Annotations } = getIframeContext().Core;
  const { documentViewer, annotationManager } = getIframeContext().Core;
  const doc = documentViewer.getDocument();
  const displayMode = documentViewer.getDisplayModeManager().getDisplayMode();

  console.log('Adding stamp at point:', point, 'with rect:', rect);

  //if stamp panel is open add points to x coordinate
  if (getIframeContext().UI.isElementOpen('rubberStampPanel')) {
    point.x += stampPanelWidthOffset + (rect.width &#x3C; 50 ? rect.width + 50 : rect.width); // add width of stamp panel + width
    console.log('326 Adjusted point for open stamp panel:', point);
  }

  const page = displayMode.getSelectedPages(point, point);
  const page_num = page.first || documentViewer.getCurrentPage();
  if (!page_num || typeof page_num !== 'number') {
    console.error('Invalid page number:', page_num);
    return;
  }

  const page_info = doc.getPageInfo(page_num);
  const page_point = displayMode.windowToPage(point, page_num);
  const zoom = documentViewer.getZoomLevel();
  const stampAnnot = new Annotations.StampAnnotation();
  stampAnnot.PageNumber = page_num;
  const rotation = documentViewer.getCompleteRotation(page_num) * 90;
  stampAnnot.Rotation = rotation;
  if (rotation === 270 || rotation === 90) {
    stampAnnot.Width = rect.height / zoom;
    stampAnnot.Height = rect.width / zoom;
  } else {
    stampAnnot.Width = rect.width / zoom;
    stampAnnot.Height = rect.height / zoom;
  }

  stampAnnot.X = (page_point.x || page_info.width / 2) - stampAnnot.Width / 2;
  stampAnnot.X += (rect.width &#x3C; 50 ? rect.width + 50 : rect.width); // Shift right by rect width to account for drag offset, stamp is shifted to the right
  stampAnnot.Y = (page_point.y || page_info.height / 2) - stampAnnot.Height / 2;
  stampAnnot.setImageData(imgData);
  stampAnnot.Author = annotationManager.getCurrentUser();
  annotationManager.deselectAllAnnotations();
  annotationManager.addAnnotation(stampAnnot, true);
  annotationManager.redrawAnnotation(stampAnnot);
  annotationManager.selectAnnotation(stampAnnot);
};

// Register drag and drop events
function registerDragEvents() {
  // Required: 
  // target is 'viewer'
  const dropTarget = document.getElementById('viewer');

  // Just adds the '+' to show while dragging to the drop target
  dropTarget.addEventListener('dragover', (e) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = 'copy'; // with copy, shows '+' symbol during drag
  });

  dropTarget.addEventListener('drop', (e) => {
    const imgData = e.dataTransfer.getData('text/plain'); // Retrieve using custom data type
    if (!imgData) {
      console.error('No imgData found in dataTransfer');
      return;
    }

    const documentViewer = getIframeContext().Core.documentViewer;
    const scrollElement = documentViewer.getScrollViewElement();
    const scrollLeft = scrollElement.scrollLeft || 0;
    const scrollTop = scrollElement.scrollTop || 0;
    dropPoint.current = { x: e.pageX + scrollLeft, y: e.pageY + scrollTop };
    const displayMode = documentViewer.getDisplayModeManager().getDisplayMode();
    const page = displayMode.getSelectedPages(dropPoint.current, dropPoint.current);
    if (!page.first) {
      return;
    }
  });

  // Custom annotation behavior checkbox handler
  const setCustomAnnotationBehavior = () => {
    const isChecked = document.getElementById('custom-annotation-behavior').checked;
    getIframeContext().Core.Tools.Tool.ALLOW_ANNOTS_OUTSIDE_PAGE = isChecked;
  };

  // Register event listener for custom annotation behavior checkbox
  const customAnnotationCheckbox = document.getElementById('custom-annotation-behavior');
  if (customAnnotationCheckbox) {
    customAnnotationCheckbox.addEventListener('click', setCustomAnnotationBehavior);
  }

  // Open custom stamp modal on button click
  const setTextStamp = () => {
    getIframeContext().UI.openElements(['customStampModal']);
  };

  // Register event listener for custom annotation behavior checkbox
  const onClickCreateTextStamp = document.getElementById('choose-file-button-text');
  if (onClickCreateTextStamp) {
    onClickCreateTextStamp.addEventListener('click', setTextStamp);
  }
}

function createUIElements() {
  // Create a container for all controls (label, dropdown, and buttons)
  // Dynamically load ui-elements.js if not already loaded
  if (!window.SidePanel) {
    const script = document.createElement('script');
    script.src = '/showcase-demos/pdf-stamps/ui-elements.js';
    script.onload = () => {
      UIElements.init('viewer');

    };
    document.head.appendChild(script);
  }
}

function loadObservableUtils() {
  if (!window.registerObservable) {
    const script = document.createElement('script');
    script.src = '/showcase-demos/pdf-stamps/observable-utils.js';
    script.onload = () => {
      registerObservable();
    };
    document.head.appendChild(script);
  } else {
    registerObservable();
  }
}

initializeWebViewer();
loadObservableUtils();

</code></pre>

{% endtab %}

{% tab title="index.css" %}
{% code title="index.css" lineNumbers="true" %}

```css
/* Main layout - side by side containers within #viewer */
#viewer {
  display: flex;
  height: 100%;
  width: 100%;
}

/* Side Panel Styles */
.viewer-wrapper {
  display: flex;
  height: 100vh;
  width: 100%;
}

.side-panel {
  width: 300px;
  min-width: 250px;
  max-width: 400px;
  background-color: #f5f5f5;
  border-right: 1px solid #ddd;
  box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
  transition: transform 0.3s ease;
  z-index: 1000;
  display: flex;
  flex-direction: column;
}

.stamp-image {
  margin: 10px auto;
  max-width: 40%;
  height: 25px;
}

.stamp-image:hover {
  cursor: pointer;
  transform: scale(1.05);
  transition: transform 0.2s;
}

#stamp-images {
  text-align: center;
  margin-bottom: 20px;
}

.button-container {
  text-align: center;
  margin-bottom: 20px;
  font-weight: 200;
}

.butoon-header {
  font-size: 16px;
  margin-bottom: 8px;
  color: #333;
  font-weight: 500;
}

.side-panel-content {
  flex: 1;
  padding: 20px;
  overflow-y: auto;
}

.panel-section {
  margin-bottom: 25px;
}

.panel-section h4 {
  margin: 0 0 12px 0;
  font-size: 14px;
  font-weight: 600;
  color: #555;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}



/* Choose File Button Styles */
#choose-file {
  display: block;
  width: 100%;
  padding: 12px 20px;
  margin: 10px 0;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  font-size: 16px;
  font-weight: 500;
  text-align: center;
  transition: all 0.3s ease;
  box-shadow: 0 2px 4px rgba(0, 123, 255, 0.2);
}

#choose-file:hover {
  background-color: #0056b3;
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(0, 123, 255, 0.3);
}

#choose-file:active {
  background-color: #004085;
  transform: translateY(0);
  box-shadow: 0 2px 4px rgba(0, 123, 255, 0.2);
}

#choose-file:focus {
  outline: none;
  box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
}




/* Choose File Button Styles */
.choose-file-button {
  display: block;
  width: 100%;
  padding: 12px 20px;
  margin: 10px 0;
  background-color: #eff2f5;
  color: #007bff;
  border: #007bff 2px solid;
  border-radius: 8px;
  cursor: pointer;
  font-size: 16px;
  font-weight: 500;
  text-align: center;
  transition: all 0.3s ease;
  box-shadow: 0 2px 4px rgba(0, 123, 255, 0.2);
}

.choose-file-button:hover {
  background-color: rgb(0,226,234);
  transform: translateY(-1px);
  box-shadow: 0 4px 8px rgba(0, 123, 255, 0.3);
}

.choose-file-button:active {
  background-color: #004085;
  transform: translateY(0);
  box-shadow: 0 2px 4px rgba(0, 123, 255, 0.2);
}

.choose-file-button:focus {
  outline: none;
  box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25);
}




.viewer-with-panel {
  flex: 1;
  height: 100vh;
}





/* Text color changes */
#dark-mode:checked ~ .switch-option.left {
  color: white;
}

#light-mode:checked ~ .switch-option.right {
  color: white;
}

.switch-option {
  color: #6c757d;
}

/* Dark mode theme styles */
@media (prefers-color-scheme: dark) {
  .theme-switch {
    background-color: #4a5568;
    border-color: #718096;
  }
  
  .switch-option {
    color: #a0aec0;
  }
  
  #dark-mode:checked ~ .switch-option.left {
    color: white;
  }
  
  #light-mode:checked ~ .switch-option.right {
    color: white;
  }
}

/* Styles for the stamp slider */
#stamp-slider {
  position: absolute;
  top: 80px;
  left: 0px;
  width: 300px;
  min-height: 550px;
  max-height: 550px;
  overflow-y: auto;
  background-color: #ffffff;
  border: 1px solid #ddd;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
  border-radius: 8px;
  padding: 16px;
  z-index: 2000;
}

#stamp-slider .image-container {
  text-align: center;
  margin-bottom: 16px;
}

#stamp-slider #preview-stamp-image {
  max-width: 100%;
  height: auto;
  border: 1px solid #ccc;
  border-radius: 4px;
}

#stamp-slider .slider-container {
  display: flex;
  align-items: center;
  margin-bottom: 16px;
}

#stamp-slider .slider-container label {
  margin-right: 8px;
  font-weight: bold;
}

#stamp-slider .slider-container input[type="range"] {
  flex: 1;
}

#stamp-slider .slider-container span {
  margin-left: 8px;
  font-size: 14px;
}

#stamp-slider .btn-style, #add-more-stamps-button {
  display: block;
  width: 100%;
  padding: 10px;
  background-color: #007bff;
  color: #ffffff;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  text-align: center;
  font-size: 14px;
}

#stamp-slider .btn-style:hover {
  background-color: #0056b3;
}

#controls-container {
  bottom: 10px;
  left: 10px;
  right: 10px;
  position: absolute;
  flex-direction: column;
  gap: 12px;
}

.button-header {
  font-size: 14px;
  margin-bottom: 8px;
  color: #333;
  font-weight: bolder;
}

```

{% endcode %}
{% endtab %}

{% tab title="ui-elements.js" %}
{% code title="ui-elements.js" lineNumbers="true" %}

```js
// ES6 Compliant Syntax
// GitHub Copilot, version: 1.0.0, model: GPT-4, version: 2024-06, date: 2025-10-23
// File: showcase-demos/pdf-stamps/ui-elements.js


class UIElements {

    static init(viewerId) {
        this.createSidePanel(viewerId);
    }

    // Function to create a side panel that sits on the left side of the viewer
    static createSidePanel(viewerId) {
        const viewerElement = document.getElementById(viewerId);
        if (!viewerElement) {
            console.error(`Viewer element with id '${viewerId}' not found.`);
            return;
        }

        // Create the side panel container
        const sidePanel = document.createElement('div');
        sidePanel.id = 'side-panel';
        sidePanel.className = 'side-panel';

        // Create side panel content
        const content = document.createElement('div');
        content.className = 'side-panel-content';

        // Add the text extraction content
        const sampleContent = document.createElement('div');
        sampleContent.innerHTML = `
      <div class="panel-section">
        <h4>JS PDF Stamps Creation Demo</h4>
        <p>A demo of the document stamping capability in WebViewer, a JavaScript-based PDF SDK for web apps. By default WebViewer includes several standard stamps that are part of the PDF specification, but it also supports the creation of custom stamps with custom text and colors.</p>

        <div class="button-container">
          <button id="choose-file" class="btn-style">Choose File</button>
        </div>
        <p class="button-header">Select a Sample Image</p>
        <div id="stamp-images" class="stamp-images">
          <img class="stamp-image draggable-image" width="100px" src="data:image/png;base64,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" class="chakra-image css-el3l7b">
          <img class="stamp-image draggable-image" width="100px" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAbEAAABaCAMAAAAB+ph2AAADAFBMVEVHcEydDgSdDwWcDgSdDgScDgScDgScDgScDgScDgScDgSdDgSeDgayISGfDw+cDgScDgShGA+rLSS1Qjq9VU29WFC9V0+9Vk69Uky9UUq+T0m+Tki+TUe4RT2vMyymIhmgDwfFa2Xksaz66OX66ef66eb66Ob66ef76eb65+X76Ob65+P75+X75+P65eL75uL75uP65eH75eH75eL64+H74+H74+H64uD74uD74uD64eD74eD74d/64d/84d/74N/74N784N/739774N384N3739z839373tz73tv83dz73Nv83Nv73Nr729r83Nv829r729n829n72tn829r82tn72tj82tj72dj82tn82dj82df82Nf92dj82db819X82NX92Nb81dT91tX91dT81NP81NT91dT91NP91NP809P809L909P909L909P80tL90tL909L90tH90dH90c/90tD90ND/0M/9z8/9z87/z8/9zs790M/9zs3/zs79zc3/zs3/zcz9zcz/zs39zMz/zMv9zMv/zMz9y8v/y8v/y8v9ysr/ysrztbTQcm2xOzOeDgWcEASiGxLOgHr34+D66Ob75+P75uL83tz82Nb919X80dH/zMv/y8r/ycnmmpawNy/Ag4O3SED129j66uj56ef65+XTeHSeEgj/y8n9ysj/yMj839z9yMjoo6CgFQudEAb66+fahoLBVU7HY13srKqqKiHCXFWtMSn34Nz33drswr7UjYfIb2i/XFW7UUm2RTzBYlzJcmzemZX009H32tj32NX62NXjrKfnq6j509L50dD5z876zczusrDGZ2HCWFK7S0PJa2Xcj4v2xMP5ysn7xsXOe3XZlpHEZl/strPNd3GzPTXNc2yfEwmkHhXkn5zNcGm5TkXzysjpsa7ai4fpqKXyu7nNa2b2v73eop7qu7fjm5fFX1nzzsviqKOoKB/uyMXltbDdnJizPzfxwL6oJR3flJH3vLzRg33Yko3UhoHYgX354d/wuLbKaWPVfXlwOlItAAABAHRSTlMAMoSwzuX+/+/WvZhMBxD3cPz49PDw8PDw8PDw8PP3+h/t4dnZ2dnY2NnY2djY2djZ2djZ2dnY2dnY2dnZ2djZ2djZ2NjZ2NnZ2NnZ2dnY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" alt="Approved Stamp" />
          </div>
        <div id="added-stamps-container" class="added-stamps-container">
        <!-- Added stamps will be displayed here -->
        </div>
        <p class="button-header">Or create a custom image</p>
        <div class="button-container">
          <button id="choose-file-button-image" class="choose-file-button">Choose Image to stamp</button>
        </div>

        <p class="button-header">Or create a text-based stamp</p>
        <div class="button-container">
          <button id="choose-file-button-text" class="choose-file-button">Create text-based stamp</button>
        </div>

        <p class="button-header">Set custom annotations behaviour</p>
        <div class="custom-container">
          <input type="checkbox" id="custom-annotation-behavior" name="custom-annotation-behavior" checked>
          <label for="custom-annotation-behavior">Move off page to delete</label><br>
        </div>
        
      </div>
    `;

        content.appendChild(sampleContent);
        sidePanel.appendChild(content);

        // Create a wrapper to contain both the side panel and viewer
        const wrapper = document.createElement('div');
        wrapper.id = 'viewer-wrapper';
        wrapper.className = 'viewer-wrapper';

        // Insert the wrapper before the viewer element
        viewerElement.parentNode.insertBefore(wrapper, viewerElement);

        // Move the viewer element into the wrapper and add the side panel
        wrapper.appendChild(sidePanel);
        wrapper.appendChild(viewerElement);

        // Add the viewer-with-panel class to the viewer element
        viewerElement.classList.add('viewer-with-panel');

        // Add event handler for the choose-file button
        const chooseFileButton = document.getElementById('choose-file');
        if (chooseFileButton) {
            chooseFileButton.addEventListener('click', () => {
                // Get the WebViewer instance and document viewer
                const instance = window.WebViewer ? window.WebViewer.getInstance() : null;
                if (instance && instance.Core && instance.Core.documentViewer) {
                    const documentViewer = instance.Core.documentViewer;
                    const loadingMessage = document.createElement('div');
                    loadingMessage.id = 'loading-message';
                    loadingMessage.style.marginTop = '10px';

                    // Add loading message to the panel if it doesn't exist
                    if (!document.getElementById('loading-message')) {
                        chooseFileButton.parentNode.appendChild(loadingMessage);
                    } else {
                        loadingMessage = document.getElementById('loading-message');
                    }

                    // Create and trigger the file picker
                    const filePickerButton = UIElements.createFilePickerButton(documentViewer, loadingMessage);
                    filePickerButton.click();
                } else {
                    console.error('WebViewer instance not found');
                }
            });
        }

        // Add event handler for the choose-file-button-image
        const chooseImageButton = document.getElementById('choose-file-button-image');
        if (chooseImageButton) {
            chooseImageButton.addEventListener('click', () => {
                // Create hidden file input element
                const fileInput = document.createElement('input');
                fileInput.type = 'file';
                fileInput.accept = 'image/*';
                fileInput.style.display = 'none';

                // Add event handler for file selection
                fileInput.addEventListener('change', (event) => {
                    const file = event.target.files[0];
                    if (file && file.type.startsWith('image/')) {
                        const reader = new FileReader();
                        reader.onload = function (e) {
                            // Show the stamp slider instead of directly adding the image
                            UIElements.showStampSlider(e.target.result);

                            // Clean up
                            document.body.removeChild(fileInput);
                        };
                        reader.readAsDataURL(file);
                    } else {
                        alert('Please select a valid image file.');
                        document.body.removeChild(fileInput);
                    }
                });

                // Add file input to DOM and trigger click
                document.body.appendChild(fileInput);
                fileInput.click();
            });
        }

        // Add click event listeners to the two images on lines 41 and 42
        const stampImages = document.querySelectorAll('#stamp-images .stamp-image');
        stampImages.forEach((image) => {
            image.addEventListener('click', () => {

                // Ensure the added stamps container exists
                let addedStampsContainer = document.getElementById('added-stamps-container');
                if (!addedStampsContainer) {
                    addedStampsContainer = document.createElement('div');
                    addedStampsContainer.id = 'added-stamps-container';
                    addedStampsContainer.style.display = 'flex';
                    addedStampsContainer.style.flexWrap = 'wrap';
                    addedStampsContainer.style.gap = '10px';
                    addedStampsContainer.style.marginTop = '20px';

                    // Append the container to the panel section or body as a fallback
                    const panelSection = document.querySelector('.panel-section');
                    if (panelSection) {
                        panelSection.appendChild(addedStampsContainer);
                    } else {
                        document.body.appendChild(addedStampsContainer);
                    }
                }

                // Call UIElements.showStampSlider with the image source
                UIElements.showStampSlider(image.src);
            });
        });

        console.log('Side panel created successfully');
    }

    // Function to add content to the side panel
    addPanelContent(content) {
        const panelContent = document.querySelector('.side-panel-content');
        if (panelContent) {
            const contentDiv = document.createElement('div');
            contentDiv.className = 'panel-section';
            contentDiv.innerHTML = content;
            panelContent.appendChild(contentDiv);
        }
    }

    // Setup event handlers for the UI elements
    static updateUIElements() {
        const pageInput = document.getElementById('input-page-number');
        const pageCountLabel = document.getElementById('page-count-label');
        const pageTextContent = document.getElementById('page-text-content');
        const pageAnnotationsContent = document.getElementById('page-annotations-content');
        const annotationsLabel = document.getElementById('annotations-label');

        // Function to update page count display
        const updatePageCount = () => {
            const totalPages = window.pageCount || 0;
            pageCountLabel.textContent = `of ${totalPages} full page text`;
        };
        // Function to update content displays
        const updateContent = (pageNumber) => {
            // Update annotations label
            annotationsLabel.textContent = `Page ${pageNumber} text under annotations:`;

            // Call the global function to get text
            if (window.getAllTextFromDocument) {
                window.getAllTextFromDocument(pageNumber);
            }
        };

        // Function to immediately update UI content from global variables
        const updateUIContent = () => {
            if (window.textContent !== undefined) {
                pageTextContent.value = window.textContent || 'No text found on this page.';
            }
            if (window.annotTextContent !== undefined) {
                pageAnnotationsContent.value = window.annotTextContent || 'No annotation text found on this page.';
            }
        };

        // Expose the UI update function globally
        window.updateUIContent = updateUIContent;

        // Function to update page input from window.currentPage
        const updatePageInput = () => {
            console.log('Updating page input. Current page:', window.currentPage);
            if (window.currentPage !== undefined && pageInput.value != window.currentPage) {
                console.log('Page input changed, updating to:', window.currentPage);
                pageInput.value = window.currentPage;
                updateContent(window.currentPage);
            }
        };

        // Monitor for page count updates and current page changes
        const checkPageCount = () => {
            updatePageCount();
            updatePageInput();
            if (window.pageCount > 0) {
                pageInput.max = window.pageCount;
            }
        };

        // Update content for the current page
        updatePageCount();
        updatePageInput();
        updateContent(window.currentPage);
    }

    static createFilePickerButton(documentViewer, loadingMessage) {
        const filePickerButton = document.createElement('button');
        filePickerButton.className = 'btn-style';
        filePickerButton.id = 'file-picker';
        filePickerButton.innerHTML = 'Pick File';
        filePickerButton.onclick = () => {
            // Open file picker dialog
            const fileInput = document.createElement('input');
            fileInput.type = 'file';
            fileInput.accept = '.pdf,.doc,.docx,.ppt,.pptx';// Accept Office file formats
            fileInput.onchange = async (event) => {
                const file = event.target.files[0];
                if (file) {
                    try {
                        const url = URL.createObjectURL(file);

                        // Extract file extension from filename
                        const fileName = file.name;
                        const extension = fileName.split('.').pop().toLowerCase();

                        console.log(`Loading file: ${file.name} (extension: ${extension}) blob URL: ${url}`);

                        // Add loading feedback
                        loadingMessage.innerHTML = `Loading ${fileName}...`;
                        loadingMessage.style.color = '#666';

                        // Load document with explicit extension and error handling
                        await documentViewer.loadDocument(url, {
                            extension: extension,
                            // Add additional options for better compatibility
                            withCredentials: false,
                            customHeaders: {}
                        });

                    } catch (error) {
                        console.error('Error loading file:', error);
                        loadingMessage.innerHTML = `Error loading file: ${error.message || 'Network failure'}. Please try again.`;
                        loadingMessage.style.color = 'red';

                        // Clean up blob URL on error
                        if (url) {
                            URL.revokeObjectURL(url);
                        }
                    }
                }
            };
            fileInput.click();
        };

        return filePickerButton;
    }


    static imageSizeAdjuster(imageBlob, maxWidth, maxHeight) {
        return new Promise((resolve) => {
            const img = new Image();
            img.src = URL.createObjectURL(imageBlob);
            img.onload = () => {
                const aspectRatio = img.naturalWidth / img.naturalHeight;
                //const maxWidth =  maxWidth //300; // Set your desired max width
                //const maxHeight = // 300; // Set your desired max height
                let width = maxWidth;
                let height = maxHeight;

                if (aspectRatio > 1) {
                    // Landscape orientation
                    height = maxHeight / aspectRatio;
                } else {
                    // Portrait orientation
                    width = maxWidth * aspectRatio;
                }

                resolve({ width, height });
            };
        });
    }


    static sliderValueDisplay() {
        // Create the stamp slider container
        const stampSlider = document.createElement('div');
        stampSlider.id = 'stamp-slider';

        // Create container for the image preview
        const imageContainer = document.createElement('div');
        imageContainer.className = 'image-container';

        // Create controls section for the slider
        const controlsContainer = document.createElement('div');
        controlsContainer.id = 'controls-container';


        // Create the preview image element
        const previewImage = document.createElement('img');
        previewImage.id = 'preview-stamp-image';

        // Create slider container
        const sliderContainer = document.createElement('div');
        sliderContainer.className = 'slider-container';


        // Create slider label
        const sliderLabel = document.createElement('label');
        sliderLabel.textContent = 'Width: ';

        // Create the range slider
        const widthSlider = document.createElement('input');
        widthSlider.type = 'range';
        widthSlider.min = '10';
        widthSlider.max = '300';
        widthSlider.value = '150';
        widthSlider.id = 'width-slider';
        
        // Create value display
        const valueDisplay = document.createElement('span');
        valueDisplay.id = 'width-value';
        valueDisplay.textContent = '150px';

        // Create info paragraph
        const infoParagraph = document.createElement('p');
        infoParagraph.textContent = 'Click the stamp above to add it or select the button below to return to adding more stamps. This stamp is also selectable from the toolbar now.';

        // Create Add More Stamps button
        const addMoreButton = document.createElement('button');
        addMoreButton.className = 'add-more-stamps-button';
        addMoreButton.textContent = 'Add More Stamps';
        addMoreButton.id = 'add-more-stamps-button';

        // Assemble the slider components
        sliderContainer.appendChild(sliderLabel);
        sliderContainer.appendChild(widthSlider);
        sliderContainer.appendChild(valueDisplay);

        // Append to .panel-section
        const panelSection = document.querySelector('.panel-section');
        if (panelSection) {
            panelSection.appendChild(stampSlider);
        } else {
            console.error('Panel section not found');
        }

        // Slider event handler
        widthSlider.addEventListener('input', function () {
            const width = this.value;
            valueDisplay.textContent = width + 'px';
            previewImage.style.width = width + 'px';
        });

        // Preview image click handler - adds stamp and closes slider
        previewImage.addEventListener('click', function () {
            UIElements.addStampFromSlider(previewImage.src, widthSlider.value);
            UIElements.closeStampSlider();
        });

        // Add More Stamps button handler - clones the image with the current width
        addMoreButton.addEventListener('click', function () {
            const clonedImage = previewImage.cloneNode(true);
            clonedImage.style.width = widthSlider.value + 'px';
            clonedImage.className = 'draggable-image';

            // Append the cloned image to a designated container
            const addedStampsContainer = document.getElementById('added-stamps-container');
            if (addedStampsContainer) {
                addedStampsContainer.appendChild(clonedImage);
            } else {
                console.error('Added stamps container not found');
            }

            // Close the slider
            UIElements.closeStampSlider();
        });

        stampSlider.appendChild(imageContainer);
        imageContainer.appendChild(previewImage);
        controlsContainer.appendChild(sliderLabel);
        controlsContainer.appendChild(sliderContainer);
        controlsContainer.appendChild(infoParagraph);
        controlsContainer.appendChild(addMoreButton);
        stampSlider.appendChild(controlsContainer);
        console.log('Stamp slider created: ', stampSlider);

        return stampSlider;
    }

    // Helper method to show the stamp slider
    static showStampSlider(imageSrc) {
        let stampSlider = document.getElementById('stamp-slider');
        if (!stampSlider) {
            stampSlider = UIElements.sliderValueDisplay();
        }

        const previewImage = stampSlider.querySelector('#preview-stamp-image');
        if (previewImage) {
            console.log('Setting preview image source');
            previewImage.src = imageSrc;
            previewImage.style.width = '150px'; // Reset to default width
        }

        const panelSection = document.querySelector('.panel-section');
        if (panelSection) {
            console.log('Appending stamp slider to panel section');
            panelSection.appendChild(stampSlider);
        }
    }

    static closeStampSlider() {
        const stampSlider = document.getElementById('stamp-slider');
        if (stampSlider) {
            stampSlider.remove();
        }
    }

    static addStampFromSlider(imageSrc, width) {
        console.log(`Adding stamp with width: ${width}`);
        // Implementation for adding the stamp
    }
}




```

{% endcode %}
{% endtab %}

{% tab title="observable-utils.js" %}
{% code title="observable-utils.js" lineNumbers="true" %}

```js
// ES6 Compliant Syntax
// GitHub Copilot, version: 1.0.0, model: GPT-4, version: 2024-06, date: 2025-10-23
// File: showcase-demos/pdf-stamps/observableUtils.js

function registerObservable() {
  const sidePanel = document.getElementById('side-panel');
  if (!sidePanel) {
    console.error('Side panel not found. Observable not registered.');
    return;
  }

  // Register existing elements with the 'draggable-image' class
  sidePanel.querySelectorAll('.draggable-image').forEach((img) => {
    img.setAttribute('draggable', true);
  });

  // Set up the MutationObserver for dynamically added elements
  const observer = new MutationObserver((mutationsList) => {
    mutationsList.forEach((mutation) => {
      if (mutation.type === 'childList') {
        mutation.addedNodes.forEach((node) => {
          if (node.nodeType === Node.ELEMENT_NODE && node.classList.contains('draggable-image')) {
            node.setAttribute('draggable', true);
          }
        });
      }
    });
  });

  observer.observe(sidePanel, { childList: true, subtree: true });
}
```

{% endcode %}
{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/web/get-started/samples/showcase-demo-pdf-stamps.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
