Loading large files issue( file size >1.5 GB) in WebView

WebViewer Version: 11.12.0

Server: 3.1.0(Docker)

We have 22 thousand page PDF file with 1000 comments across different pages.

Our setup includes:

  • fullAPI = true
  • forceServerSideRender = true
  • Streaming = true

We have two main issues:

  1. Comments are not loading faster.

  2. Page contents are not loading after few pages.

We are using ImportAnnotations method with xfdf string. Which is making application slower.

Flow:

OnDocumentLoaded → OnAnnotationsLoaded → If xfdf string is present → Delete Comments (File embedded )

We can not turn off fullAPI and forceServerSideRender .

We have tried:

  1. Closing notes panel while loading.

  2. Setting streaming = true while loading document.

  3. Setting documentXFDFRetriever in webviewer constructor.

  4. Adding chunk size while loading document. (Throws error)

  5. We have also Linearized PDF’s as suggested in Apryse documentation.

Observation:

Documents are loaded in 1MB chunk (PDFWorker.js doing this) after some time it fails to fetch with 403 an 404 response code, due to that page content are not loading, even after scrolling there are some network call to fetch the chunks but again it fails with 404 response.

Question:

How can we improve the performance of WebViewer for large PDF’s ?

1 Like

Apryse team, Is there any way to improve the large PDF loading issue with the above setup? Do we need provide any other inputs ?

1 Like

Hello ajit.komar,

Apologies for the delayed response, there was an issue with our notifications.

Documents are loaded in 1MB chunk (PDFWorker.js doing this) after some time it fails to fetch with 403 an 404 response code, due to that page content are not loading, even after scrolling there are some network call to fetch the chunks but again it fails with 404 response.

404 and 403 errors are the server responding with they cannot find the requested information. This would be an issue on the server side, likely to do with how partial content requests are set up.

WebViewer makes a request to the server for the specified chunk and if partial content is not setup correctly then the server may not understand the request and return a 404 or 403 error.

Would you be able to provide a sample project that reproduces this issue?

Best regards,
Tyler

1 Like

Hi,
I can provide the snippet of our setup.

We are using modular UI below is the webviewer constructor configured in our system.

  1. WebViewer contructor
    WebViewer(
    {
    path: “/Scripts/webviewer/lib”,
    webviewerServerURL:
    useWebviewerClient
    ? null : ${window.location.origin}/webviewer,
    licenseKey,
    disabledElements: [
    “downloadButton”,
    “printButton”,
    “thumbnailControl”,
    “documentControl”,
    ],
    fullAPI: true,
    disableLogs: true,
    forceClientSideInit: true,
    css: “/Scripts/webviewer.css”,
    ui: “default”
    },
    document.getElementById(“webviewerContainer”)
    ).then((instance) => renderWebviewer(instance, user, options));

  2. renderWebviewer will register the DocumentLoaded AnnotationChanged and AnnotationSelected events

function registerDocumentLoadedEvent() {
if (_documentLoadedHandler) {
documentViewer.removeEventListener(
“documentLoaded”,
_documentLoadedHandler,
);
}

documentViewer.addEventListener(“documentLoaded”, _documentLoadedHandler);
}

function registerAnnotationChangedEvent() {
if (_annotationChangedHandler) {
annotationManager.removeEventListener(
“annotationChanged”,
_annotationChangedHandler,
);
}

annotationManager.addEventListener(
  "annotationChanged",
  _annotationChangedHandler,
);

}

function registerAnnotationSelectedEvent() {
if (_annotationSelectedHandler) {
annotationManager.removeEventListener(
“annotationSelected”,
_annotationSelectedHandler,
);
}

annotationManager.addEventListener(
  "annotationSelected",
  _annotationSelectedHandler,
);

}

  1. Later we are loading document with instance.UI.loadDocument method.
    instance.UI.loadDocument(fileUrl, {
    filename: fileName,
    cacheKey: (btoa(window.location.origin) + "" + btoa(cacheKey))
    .replace(/[^a-zA-Z0-9
    ]/g, “”)
    .padEnd(40, “_”),
    customHeaders: { Authorization: Bearer ${user.access_token} },
    loadAnnotations: false,
    });

  2. once after document load, in _documentLoadedHandler we are importing the comments
    _documentLoadedHandler = async () => {
    documentViewer.removeEventListener(
    “documentLoaded”,
    _documentLoadedHandler,
    );

    const xfdfString = await getXfdfString();

    await annotationManager.importAnnotations(xfdfString, {
    imported: true,
    });
    };

During importAnnotations annotations arr loading very slowly comparing to legacy UI.
After loading document browser page is not responsive and crashing.
If we set the loadAnnotations = true, Annotations are duplicating multiple times. due to that we can use AnnotationLoaded event. Observed that when loadAnnotations = true then AnnotationLoaded event triggered multiple times.
I will share the GIF file of current behavior.

1 Like

Hello, Ajit,

Thank you for the information, however this is not enough to reproduce the issue.
Can you please provide:

  1. A sample project that reproduces the issue (we have ready made samples you can fork and modify here GitHub - ApryseSDK/webviewer-samples: A collection of sample projects for Apryse WebViewer SDK · GitHub)
  2. Your WebViewer Server config file
  3. The code for your _annotationChangedHandler function
  4. An example file you’re loading
  5. XFDF you’re importing

During importAnnotations annotations arr loading very slowly comparing to legacy UI.
After loading document browser page is not responsive and crashing.

The slowness could be from many things, XFDF size, PDF complexity, network or hardware slowness, etc, more info will be needed to look into this. The browser crashing/non-responsive issue as well.

If we set the loadAnnotations = true, Annotations are duplicating multiple times. due to that we can use AnnotationLoaded event.

The annotation duplication issue is likely due to annotation IDs not matching, which would mean they are treated as “new” annotations, which would look like duplication.

Observed that when loadAnnotations = true then AnnotationLoaded event triggered multiple times.

This is because there are annotations on the document which triggers the annotationLoaded event, then when you import more annotations, the event is triggered again. This is expected.

Best regards,
Tyler

I could not reproduce the issue in sample.
I can share some GIF file which shows how it was behaving with legacy UI and how it is behaving with modular UI.

  1. Server configuration.

INCLUDE_DEMO : TRUE
TRN_ALLOWED_DOMAINS : *
TRN_BALANCER_COOKIE_NAME :
TRN_DEBUG_MODE : FALSE
TRN_DISABLE_CLIENT_PDF_ACCESS : FALSE
TRN_DISABLE_VALIDATION : TRUE
TRN_ENABLE_PER_SESSION_CACHING : FALSE
TRN_ENABLE_SESSION_AUTH : FALSE
TRN_FETCH_DEFAULT_BASE_ADDR :
TRN_FETCH_DOWNGRADE_HTTPS : FALSE
TRN_FETCH_TIMEOUT_MS : 10000000
App ServiceTRN_FORCE_LOSSLESS_IMAGES : FALSE
TRN_FORWARD_CLIENT_COOKIES : FALSE
TRN_MAX_CACHE_AGE_MINUTES : 30
TRN_MAX_CACHED_MB : 15
TRN_MAX_MEMORY_CACHE_AGE_MINUTES : 10
TRN_PDFNET_KEY :
WEBSITES_ENABLE_APP_SERVICE_STORAGE : FALSE

  1. Annotation changed handler:

_annotationChangedHandler = async (annotations, action, { imported }) => {
if (!imported) {
if (annotations.length === 1) {
const annot = annotations[0];
if (
annot instanceof instance.Core.Annotations.StampAnnotation &&
action === “add”
) {
const selectedStampDetails = stampDetailsList.find(
(item) => item.pngBase64 === annot.image.src,
);
if (selectedStampDetails != null) {
annot.setCustomData(“StampName”, selectedStampDetails.name);

      const annotationWidth = annot.Width;
      const annotationHeight = annot.Height;
      annot.Width = 100;
      annot.Height = (annot.Width * annotationHeight) / annotationWidth;
      instance.Core.annotationManager.redrawAnnotation(annot);
    }
  }
}

window.removeEventListener("beforeunload", windowHandler);
window.addEventListener("beforeunload", windowHandler);
if (dialog) {
    dialog.RemoveDefaultCloseAction();
    dialog.RegisterCancelEvent(dialogHandler);
}

}
};

WebviewerLoad

Please share the email address to give access to shared one drive folder. I will share the file and xfdf.

1 Like

Hi tgordon,

We have found that the issue is when we use webviewerServerUrl in webviewer constructor. We have hosted our webviewer in azure appservice with above mentioned settings. If we use client side rendering totally then we can load large files smoothly.
I tried connecting sample to server hosted docker from the local, we can see some delay in loading pages but not significantly.
We are open to have a call and check the scenario in our environment.

1 Like