How can i get the same custom annotation font when downloading the document?

Hello.

I want to put a free text annotation on my documents (programatically) but i want to use another font (Great Vibes), I’m getting the result on WebViewer but when I download file, I’m getting the default font.

I’m making these steps:

1.- I paste the importation from Google Fonts on my CSS file,

@import url(‘https://fonts.googleapis.com/css2?family=Great+Vibes&display=swap’);

2.- Setup my instance options to use my CSS file:

{
path: ‘/lib/webviewer’,
initialDoc:
https://pdftron.s3.amazonaws.com/downloads/pl/PDFTRON_about.pdf’,
disabledElements: […],
css: ‘/assets/css/webViewerStyles.css’,
}.

3.- And my annotation is using: annotationToCreate.Font = ‘Great Vibes’;

I attach my webviewer and the exported file, i don’t know if i have to do something more.


WebViewer Version: 8.0.0
Are you using the WebViewer server?
No, I’m just using WebViewer on Frontend

Hi,

Thanks for contacting, we’re still investigating and thanks for your patience.

Wanbo

Hi,

It seems working for me, please check the attached PDF file. And for your step 3, may I know how exactly are doing it? Maybe show me your code?

Wanbo
blank (1).pdf (20.4 KB)

Hi, Thanks for your answer.

I’m following your sign app example
But, i don’t want to make the same thing… I want to put annotation styled (With Great Vibes font). So, My code base is similar to that example (I copied and pasted), This my first time using your solution.

By the way, I’m using NextJS (I don’t know if it’s useful to know it)

This is my code. I modified some handler as uploadForSigning, applyFields and i’m harcording my name on annotation content.

imports...

interface IContentModalLocaleSignatureProps {
  onCloseModal: () => void;
}

interface ICoodirnates {
  x: number;
  y: number;
}

const ContentModalLocaleSignature: FunctionComponent<IContentModalLocaleSignatureProps> =
  ({ onCloseModal }) => {
    const viewerRef = useRef<HTMLDivElement>(null);
    const [webViewerInstance, setWebViewerInstance] =
      useState<WebViewerInstance | null>(null);
    const [dropPoint, setDropPoint] = useState<ICoodirnates | null>(null);

    useEffect(() => {
      let instance: WebViewerInstance;
      if (!webViewerInstance) {
        const runWebViewer = async () => {
          instance = await WebViewer(
            {
              path: '/lib/webviewer',
              initialDoc:
                'https://pdftron.s3.amazonaws.com/downloads/pl/PDFTRON_about.pdf',
              disabledElements: [
                'leftPanelButton',
                'printButton',
                'ribbons',
                'toggleNotesButton',
                'downloadButton',
                'searchButton',
                'annotationCommentButton',
                'linkButton',
                'menuButton',
                'highlightToolButton',
                'freeHandToolButton',
                'freeHandHighlightToolButton',
                'freeTextToolButton',
                'annotationStylePopup',
                'annotationGroupButton',
                'rotateHeader',
                'rotateClockwiseButton',
                'rotateCounterClockwiseButton',
                'viewControlsDivider2',
              ],
              css: '/assets/css/webViewerStyles.css',
            },
            viewerRef.current as HTMLDivElement,
          );
          const { documentViewer, Annotations, annotationManager } =
            instance.Core;
          const { setZoomLevel, iframeWindow } = instance.UI;

          documentViewer.addEventListener('documentLoaded', async () => {
            if (!isProduction) {
              console.log(`WebViewer is running and showing`);
            }
            setZoomLevel('100%');
          });

          setWebViewerInstance(instance);

          const iframeDoc = iframeWindow.document.body;
          iframeDoc.addEventListener('dragover', (e) => {
            e.preventDefault();
            return false;
          });
          iframeDoc.addEventListener('drop', (e) => {
            const eventInherited = e as unknown;
            drop(eventInherited as DragEvent<HTMLDivElement>, instance);
          });
        };
        runWebViewer();
      }
      return () => {
        if (webViewerInstance && instance) {
          webViewerInstance.Core.dispose();
        }
      };
    }, []);

    const uploadForSigning = async () => {
      if (webViewerInstance) {
        const { documentViewer, AnnotationManager } = webViewerInstance.Core;
        const annotManager = documentViewer.getAnnotationManager();
        const xfdfString = await annotManager.exportAnnotations({
          widgets: true,
          fields: true,
        });
        console.log('XFDF Result', xfdfString);
      }
    };

    const applyFields = async () => {
      if (webViewerInstance) {
        const { documentViewer } = webViewerInstance.Core;
        const annotManager = documentViewer.getAnnotationManager();
        const xfdfString = await annotManager.exportAnnotations({
          fields: true,
          links: false,
        });
        console.log('XFDF Result', xfdfString);
        webViewerInstance.UI.downloadPdf({
          flatten: false,
        });
      }
    };

    const addField = (
      type: string,
      point: ICoodirnates,
      name = '',
      value = '',
      flag = {},
    ) => {
      if (webViewerInstance) {
        const { documentViewer, Annotations, Math } = webViewerInstance.Core;
        const annotManager = documentViewer.getAnnotationManager();
        const doc = documentViewer.getDocument();
        const displayMode = documentViewer
          .getDisplayModeManager()
          .getDisplayMode();
        const page = displayMode.getSelectedPages(point, point);
        if (!!point.x && page.first == null) {
          return; //don't add field to an invalid page location
        }
        const page_idx =
          page.first !== null ? page.first : documentViewer.getCurrentPage();
        const page_info = doc.getPageInfo(page_idx);
        const page_point = displayMode.windowToPage(point, page_idx);
        const zoom = documentViewer.getZoom();

        const textAnnot = new Annotations.FreeTextAnnotation();
        textAnnot.PageNumber = page_idx;
        const rotation = documentViewer.getCompleteRotation(page_idx) * 90;
        textAnnot.Rotation = rotation;
        if (rotation === 270 || rotation === 90) {
          textAnnot.Width = 50.0 / zoom;
          textAnnot.Height = 250.0 / zoom;
        } else {
          textAnnot.Width = 250.0 / zoom;
          textAnnot.Height = 50.0 / zoom;
        }
        textAnnot.X =
          (page_point.x || page_info.width / 2) - textAnnot.Width / 2;
        textAnnot.Y =
          (page_point.y || page_info.height / 2) - textAnnot.Height / 2;

        textAnnot.setCustomData('type', type);
        textAnnot.setCustomData('name', 'Alejandro Parra');

        // set the type of annot
        textAnnot.setContents('Alejandro ParraT');
        textAnnot.setPadding(new Math.Rect(0, 0, 0, 0));
        textAnnot.disableRotationControl();
        textAnnot.LockedContents = true;
        textAnnot.FontSize = `${25.0 / zoom}px`;
        textAnnot.TextColor = new Annotations.Color(0, 0, 0);
        textAnnot.StrokeThickness = 0; // Remove border
        textAnnot.Author = annotManager.getCurrentUser();
        textAnnot.Font = 'Great Vibes';

        annotManager.deselectAllAnnotations();
        annotManager.addAnnotation(textAnnot, {
          imported: true,
          autoFocus: true,
        });
        annotManager.redrawAnnotation(textAnnot);
        annotManager.selectAnnotation(textAnnot);
      }
    };

    const drop = (
      e: DragEvent<HTMLDivElement>,
      instance: WebViewerInstance,
    ) => {
      const { documentViewer } = instance.Core;
      const scrollElement = documentViewer.getScrollViewElement();
      const scrollLeft = scrollElement.scrollLeft || 0;
      const scrollTop = scrollElement.scrollTop || 0;
      setDropPoint({ x: e.pageX + scrollLeft, y: e.pageY + scrollTop });
      e.preventDefault();
      return false;
    };

    const dragStart = (e: DragEvent<HTMLDivElement>) => {
      e.currentTarget.style.opacity = '0.5';
      const copy = e.currentTarget.cloneNode(true) as HTMLDivElement;
      copy.id = 'form-build-drag-image-copy';
      copy.style.width = '250px';
      document.body.appendChild(copy);
      e.dataTransfer.setDragImage(copy, 125, 25);
      e.dataTransfer.setData('text', '');
    };

    const dragEnd = (e: DragEvent<HTMLDivElement>, type: string) => {
      addField(type, dropPoint as ICoodirnates);
      e.currentTarget.style.opacity = '1';
      document.body.removeChild(
        document.getElementById('form-build-drag-image-copy') as Node,
      );
      e.preventDefault();
    };

    return (
      <>
        <div className="flex ml-7 mt-7 mb-4">
          <h2>
            Header
          </h2>
        </div>
        <div className="flex max-h-screen ">
          <div className="flex flex-col w-1/4 min-h-full max-h-175 overflow-y-auto bg-gray-light pt-4">
            <h1 className="text-center text-primary mb-4">Title</h1>
            <div
              className="w-full justify-center border-b-2 border-primary p-4 cursor-move"
              draggable
              onDragStart={(e) => dragStart(e)}
              onDragEnd={(e) => dragEnd(e, 'SIGNATURE')}>
              <h3>Alejandro Parra</h3>
            </div>
          </div>

          <div className="w-3/4 flex justify-center py-6 h-175 bg-gray-light">
            <div className="w-full h-full" ref={viewerRef}></div>
          </div>
        </div>

        <div className="flex justify-center">
          <div className="flex justify-center w-9/12">
            <div className="w-1/2 p-2">
              <Button
                label="Cancelar"
                variant="secondary"
                onClick={onCloseModal}
              />
            </div>
            <div className="w-1/2 p-2">
              <Button
                label="Agregar firmas"
                variant="primary"
                onClick={applyFields}
              />
            </div>
          </div>
        </div>
      </>
    );
  };

export default ContentModalLocaleSignature;

Can you show me the code you did to get that result?

Sure.

  annotationManager.addEventListener('annotationChanged', (annots, action) => {
    if (action === 'add') {
      annots.forEach((annot) => {
        annot.Font = 'Great Vibes';
      });
    }
  });

I pasted your listener on my codebase and i’m getting the same result.

Can you show me how you save the document? Or you full codebase, I’m not sure what is the error on my code

I’m making this way:

webViewerInstance.UI.downloadPdf({
    flatten: true,
});

Hi,

I have just tried downloading with ‘flatten: true’ and the result is the same for me. Maybe you can try it without your customizations and make sure it works for you first, then add your customizations back one by one and see which one caused it not working.

Also, which version are you using? v8.0?

Wanbo

Hi, I rewrited everything and i found the error.

I was using the property LockedContents, on my free annotation, so, when i was trying to download file. I was getting as block content. However, i think is an error, because i shouldn’t be able to see it on webviewer either.

annotationToCreate.LockedContents = true

Thanks for your support.
I really appreciate it

No worries, glad to help.