Complete guide to PDF.js

Table of contents

    PDF.js is a popular open-source JavaScript library that allows for PDF rendering directly in the browser. While it’s great for simple PDF viewing, businesses often need more—advanced features, scalable performance, and dedicated support. For those enterprise needs, Nutrient Web SDK is the ideal solution. In this guide, we’ll walk you through how to use PDF.js, highlight its limitations, and show you how Nutrient Web SDK offers more powerful features to support complex workflows, large-scale document handling, and security requirements.
    Complete guide to PDF.js
    TL;DR

    PDF.js is Mozilla’s open-source JavaScript library for rendering PDFs in browsers without plugins. This guide covers PDF.js setup, rendering with the Canvas API, navigation controls, zoom functionality, and handling basic annotations. However, for enterprise applications requiring advanced features, high performance, and dedicated support, Nutrient Web SDK is the ideal solution. Nutrient enhances PDF workflows with features like dynamic annotations, digital signatures, redactions, and enterprise-level scalability.

    What is PDF.js?

    PDF.js is an open-source JavaScript library developed by Mozilla to render PDF files directly in web browsers without the need for external plugins. It’s great for basic PDF rendering, especially for displaying documents on websites, but lacks many of the advanced capabilities required for enterprise applications.

    If you’re working on a simple project or a website that requires basic PDF viewing, PDF.js may be all you need. However, if your business is dealing with large-scale documents or requires advanced PDF manipulation, Nutrient Web SDK offers the tools and capabilities to take your PDF workflows to the next level.

    How PDF.js works: Core concepts and architecture

    PDF.js is designed for parsing and rendering PDFs with a modular architecture, where each module focuses on a specific task. It’s a web standards-based platform for parsing, ensuring robust and versatile handling of PDF documents in various web environments. This modular architecture allows you to include only the modules you need, reducing the size of your code and improving performance. PDF.js has several layers, each with its own purpose:

    1. Core layer — This is the lowest-level layer of PDF.js, responsible for parsing the binary format of a PDF file and converting it into an internal representation that can be used by higher-level layers. The core layer is typically used directly only by advanced users who need fine-grained control of the parsing process.
    2. Display layer — The display layer builds upon the core layer and provides a more user-friendly API for rendering PDF files. With the display layer, you can easily render a PDF page into a <canvas> element using just a few lines of JavaScript code. This layer is suitable for most day-to-day use cases.
    3. Viewer layer — The viewer layer is a ready-to-use user interface (UI) that comes with PDF.js. It includes features like search, rotation, a thumbnail sidebar, and more. The viewer layer is built on top of the display layer and provides a complete PDF viewing experience out of the box.

    PDF.js key features

    PDF.js provides a set of features for viewing, annotating, and manipulating PDF documents:

    • Render PDF documents in the browser using the HTML5 <canvas> element
    • Search for text within a document
    • View page thumbnails
    • Zoom in and out of pages
    • Rotate pages
    • Display existing annotations (text highlights, comments, links)
    • Display and fill basic AcroForm fields (limited support; no XFA)
    • View and navigate bookmarks and document outlines

    Limitations of PDF.js

    While PDF.js is a powerful library for rendering PDF documents in the browser, it has several limitations that can hinder performance and functionality, particularly for enterprise-level applications:

    • Performance: PDF.js rendering can be slow and resource-intensive, especially when processing large or complex PDF documents, which can lead to slower performance and longer load times.
    • Text Selection and Searching: For documents with complex formatting or embedded images, text selection and searching can be inaccurate or sluggish, impacting user experience.
    • Rendering Accuracy: The accuracy of PDF.js rendering can vary depending on the browser and platform being used, which may lead to inconsistent behavior across different environments.
    • Feature Gaps: PDF.js may not fully support advanced PDF features such as interactive forms, multimedia elements, or custom annotations. Additionally, some documents may not render correctly or be compatible with PDF.js at all.
    • Limited Functionality: PDF.js lacks critical features required by enterprises, such as dynamic annotations, redactions, form filling, and more. It also doesn’t support the latest PDF specification in its entirety.
    • Scalability Issues: Handling large volumes of PDFs or supporting high-traffic applications can lead to performance bottlenecks with PDF.js, making it less suitable for scalable, high-demand environments.
    • Security: PDF.js does not offer built-in security features like document encryption or watermarking, which are essential for businesses dealing with sensitive or regulated documents.

    For enterprises looking to scale, secure, and enhance their PDF workflows, Nutrient Web SDK is the ideal solution. Unlike PDF.js, Nutrient provides enhanced performance, advanced features, robust security, and seamless scalability, ensuring smooth handling of large volumes and complex workflows.

    How Nutrient Web SDK solves these issues

    Advanced features with Nutrient

    Nutrient Web SDK goes far beyond PDF.js with features that cater to complex business needs:

    • Annotations and Redactions: While PDF.js provides basic annotation rendering, Nutrient Web SDK allows for custom annotations, redactions, and more advanced markup directly on the PDF, making it ideal for legal, medical, and financial industries.
    • Digital Signatures: Nutrient provides robust digital signatures, ensuring documents are signed and secure, a feature not available in PDF.js.
    • Form Filling and Manipulation: Nutrient supports interactive forms, dynamic field population, and form submission capabilities, providing comprehensive PDF manipulation.
    • Enterprise Scalability: Nutrient is designed to handle high volumes of PDFs, ensuring consistent performance even for large-scale document processing tasks.

    To see how Nutrient Web SDK enhances PDF workflows, try out our demo. Upload a PDF, JPG, PNG, or TIFF file by clicking Open Document under the Standalone option (if you don’t see this option, select Choose Example from the dropdown). Once your document is displayed in the viewer, explore the ability to draw freehand, add notes, apply crops, or add eSignatures.

    Enhanced performance and security

    • Optimized Rendering: Nutrient Web SDK is optimized for high-performance document rendering, even for large PDFs or documents with multimedia.
    • Built-in Security: Nutrient includes security features like document encryption, watermarking, and access control, ensuring that sensitive documents are kept secure throughout the process.

    Dedicated Support

    Unlike PDF.js, which relies on community support, Nutrient Web SDK comes with dedicated technical support(opens in a new tab) for enterprise clients, ensuring that any issues are resolved quickly and efficiently.

    Why Choose Nutrient Web SDK over PDF.js?

    While PDF.js is a great open-source tool for basic PDF viewing, Nutrient Web SDK is the premium solution for businesses needing advanced features and performance. Here’s why Nutrient is the better choice:

    • Advanced Features: Real-time annotations, redactions, form filling, and digital signatures.
    • Scalability: Handles high-volume document workflows seamlessly.
    • Security: Built-in encryption, watermarking, and other security features.
    • Support: Access to dedicated technical support ensures smooth operations.

    Next Steps: Start using Nutrient Web SDK

    If your PDF workflows are outgrowing the capabilities of PDF.js, it's time to explore Nutrient Web SDK. Get started with a demo or request a personalized consultation to learn how Nutrient can solve your advanced PDF needs.

    To learn more about the limitations of PDF.js and how Nutrient Web SDK addresses them, check out our detailed comparison guide.

    Now, let's walk through how to set up and use PDF.js for simpler use cases.

    Getting started with PDF.js

    1. Download or clone PDF.js — You can download(opens in a new tab) the library as a ZIP file or clone the repository using Git.
    2. Prepare the files — Extract the ZIP file and copy the pdf.mjs and pdf.worker.mjs files from the build/ folder to your project directory.
    3. Include PDF.js in your HTML — Add the following script tag to your HTML file to load the PDF.js library:
    <script src="./pdf.mjs" type="module"></script>

    After including the script tag, you can start using PDF.js to render PDF files on your webpage.

    Rendering a PDF file with PDF.js

    To render a PDF file using PDF.js, follow these steps.

    1. Add a <canvas>(opens in a new tab) element to your HTML where the PDF will be displayed:

      <canvas id="pdf-canvas"></canvas>
    2. Create a file named index.js.

      Next, use document.getElementById to select the <canvas> element in your HTML where the PDF will be displayed:

      const canvas = document.getElementById("pdf-canvas");

      Define the URL of the PDF file you want to render. Ensure this file is accessible from your project directory:

      const pdfUrl = "pspdfkit-web-demo.pdf";

      Set the path to the PDF.js worker file to enable PDF rendering. Use pdfjsLib.getDocument(pdfUrl).promise to load the PDF file, which returns a Promise resolving to a PDFDocumentProxy object:

      pdfjsLib.GlobalWorkerOptions.workerSrc = "./pdf.worker.mjs";
      pdfjsLib.getDocument(pdfUrl).promise.then(function (pdfDoc) {
      // Continue with further steps.
      });

      Retrieve the desired page from the loaded PDF document using pdfDoc.getPage(1). This returns a Promise resolving to a PDFPageProxy object representing the page:

      pdfDoc.getPage(1).then(function (page) {
      // Continue with further steps.
      });

      Calculate and set the dimensions of the canvas to match the size of the PDF page to ensure correct display:

      const viewport = page.getViewport({ scale: 1 });
      canvas.width = viewport.width;
      canvas.height = viewport.height;

      Get the 2D rendering context from the canvas. Create a renderContext object with the canvas context and viewport settings. Call the page.render() method to render the PDF page onto the canvas:

      const ctx = canvas.getContext("2d");
      const renderContext = {
      canvasContext: ctx,
      viewport: viewport,
      };
      page.render(renderContext);

      Implement error handling to manage cases where the PDF file might be missing or corrupted. Use the catch() method to log errors to the console or display an appropriate message:

      pdfjsLib
      .getDocument(pdfUrl)
      .promise.then(function (pdfDoc) {
      // Handling and rendering logic.
      })
      .catch(function (error) {
      console.log("Error loading PDF file:", error);
      });
    3. Include the index.js file in your HTML file:

    <script src="./index.js" type="module"></script>

    The type="module" attribute allows the use of ES6 features like import/export and ensures that the script is loaded asynchronously, avoiding global scope issues.

    Make sure to add your PDF file to the same directory as the HTML file. You can use the demo PDF file as an example.

    This is a simple example of how to render a PDF file using PDF.js. PDF.js provides many more options and features that you’ll explore in the next sections.

    Running the project

    To run the project:

    1. Install the serve package:

      Terminal window
      npm install --global serve
    2. Serve the current directory:

      Terminal window
      serve -l 8080 .
    3. Visit http://localhost:8080 to view the project.

    pdfjs demo

    User interface enhancements

    To improve the user experience when working with PDFs, you can add various UI enhancements such as navigation controls and zoom functionalities. The next sections explain how you can integrate these features.

    Adding navigation controls

    1. Include buttons for navigation in your HTML file:

      <button id="prev-page">Previous Page</button>
      <button id="next-page">Next Page</button>
    2. Update your index.js to handle page navigation. Add event listeners to the buttons and manage page navigation:

    index.js
    const initialState = {
    pdfDoc: null,
    currentPage: 1,
    zoom: 1,
    };
    document.getElementById("prev-page").addEventListener("click", function () {
    4 collapsed lines
    if (initialState.pdfDoc && initialState.currentPage > 1) {
    initialState.currentPage--;
    renderPage(initialState.currentPage);
    }
    });
    document.getElementById("next-page").addEventListener("click", function () {
    7 collapsed lines
    if (
    initialState.pdfDoc &&
    initialState.currentPage < initialState.pdfDoc.numPages
    ) {
    initialState.currentPage++;
    renderPage(initialState.currentPage);
    }
    });
    function renderPage(pageNumber) {
    if (!initialState.pdfDoc) return;
    initialState.pdfDoc
    .getPage(pageNumber)
    .then((page) => {
    const viewport = page.getViewport({
    scale: initialState.zoom,
    });
    canvas.width = viewport.width;
    canvas.height = viewport.height;
    const ctx = canvas.getContext("2d");
    const renderContext = {
    canvasContext: ctx,
    viewport: viewport,
    };
    page
    .render(renderContext)
    .promise.then(() => {
    console.log("Rendering complete");
    })
    .catch((error) => {
    console.log("Error rendering page:", error);
    });
    })
    .catch((error) => {
    console.log("Error loading page:", error);
    });
    }

    Adding zoom controls

    1. Include buttons for zoom controls in your HTML file:

      <button id="zoom-in">Zoom In</button> <button id="zoom-out">Zoom Out</button>
    2. Update index.js to manage zoom functionality. Add event listeners to the zoom buttons and adjust the scale of the viewport:

    document.getElementById("zoom-in").addEventListener("click", function () {
    if (initialState.pdfDoc) {
    initialState.zoom *= 4 / 3; // Increase zoom scale.
    renderPage();
    }
    });
    document.getElementById("zoom-out").addEventListener("click", function () {
    if (initialState.pdfDoc) {
    initialState.zoom *= 2 / 3; // Decrease zoom scale.
    renderPage();
    }
    });

    Advanced features and customizations

    This section explores more advanced features and customizations you can add to your PDF viewer. These include handling annotations, enabling text selection, controlling rendering options, navigating documents, and manipulating PDFs. Each feature enhances the functionality and user experience of your PDF viewer, making it more interactive and efficient.

    Handling PDF annotations

    PDF.js is primarily designed as a viewer(opens in a new tab) for rendering PDF files, and it doesn’t provide a built-in mechanism for editing or modifying PDF documents. However, it does provide a way to access PDF annotations such as links, highlights, and comments. PDF annotations can be accessed using the getAnnotations() method on a PDF page.

    Here’s an example of how to render PDF annotations:

    // Load annotation data.
    page
    .getAnnotations()
    .then(function (annotations) {
    annotations.forEach(function (annotation) {
    if (annotation.subtype === "Text") {
    // Render a text annotation.
    const textRect = annotation.rect;
    const text = document.createElement("div");
    text.style.position = "absolute";
    text.style.left = textRect[0] + "px";
    text.style.top = textRect[1] + "px";
    text.style.width = textRect[2] - textRect[0] + "px";
    text.style.height = textRect[3] - textRect[1] + "px";
    text.style.backgroundColor = "green";
    text.style.opacity = "0.5";
    text.innerText = annotation.contents;
    canvas.parentNode.appendChild(text);
    } else if (annotation.subtype === "Highlight") {
    // Render a highlight annotation.
    const highlightRect = annotation.rect;
    const highlight = document.createElement("div");
    highlight.style.position = "absolute";
    highlight.style.left = highlightRect[0] + "px";
    highlight.style.top = highlightRect[1] + "px";
    highlight.style.width = highlightRect[2] - highlightRect[0] + "px";
    highlight.style.height = highlightRect[3] - highlightRect[1] + "px";
    highlight.style.backgroundColor = "yellow";
    highlight.style.opacity = "0.5";
    canvas.parentNode.appendChild(highlight);
    }
    });
    })
    .catch(function (error) {
    console.log("Error loading annotations:", error);
    });

    Make sure the PDF file you’re using actually contains annotations.

    This code snippet retrieves all the annotations for the current page using the page.getAnnotations() method. It then loops through each annotation and checks its subtype to determine what type of annotation it is.

    For text annotations, it creates a div element, sets its position and dimensions using the annotation’s rectangle coordinates, and adds it to the container element with a green background color and opacity of 0.5. Similarly, for highlight annotations, it creates a div element, sets its position and dimensions using the annotation’s rectangle coordinates, and adds it to the container element with a yellow background color and opacity of 0.5.

    This code will render text annotations as green semi-transparent rectangles with the text contents of the annotation on top of the PDF page at the position specified by the annotation’s rectangle coordinates, and it’ll highlight annotations as yellow rectangles with 50 percent opacity.

    Check out the source code for this example on GitHub(opens in a new tab).

    Handling PDF text selection

    PDF.js provides support for selecting and copying text from PDF files. PDF text can be accessed using the getTextContent() method on a PDF page.

    Here’s an example of how to extract text from a PDF page:

    page.getTextContent().then(function (textContent) {
    let text = "";
    for (let i = 0; i < textContent.items.length; i++) {
    const item = textContent.items[i];
    text += item.str;
    }
    console.log(text);
    });

    This code will extract all the text from the PDF page and log it to the console.

    Controlling PDF rendering

    PDF.js provides many options for controlling how PDF files are rendered. These options can be passed as parameters to the page.render() method.

    Here are some of the most common options:

    • canvasContext — Specifies the rendering context to use for rendering the PDF page. This is typically a 2D canvas context.
    • viewport — Specifies the viewport to use for rendering the PDF page. The viewport defines the part of the PDF page that should be displayed on the canvas. It can be customized with options such as scale, rotation, and offset.
    • background — Specifies the color or pattern to use for the background of the canvas. This can be set to a CSS color value or a canvas pattern object.

    Here’s an example of how to use some of these options:

    page.render({
    canvasContext: ctx,
    viewport: page.getViewport({ scale: 1.5 }),
    background: "rgb(255,0, 0)",
    });

    This will render the PDF page with a 1.5x zoom and with a red background.

    PDF.js provides several methods for navigating PDF documents, including scrolling, zooming, and searching. Here’s an overview of some of the most commonly used navigation methods:

    • Scrolling — PDF.js allows you to scroll through a document using the mouse or touchpad. You can also use the scrollbar to navigate through the document.
    • Zooming — You can zoom in and out of a PDF document using the mouse or touchpad. You can also use the zoom buttons on the toolbar to zoom in and out.
    • Searching — PDF.js provides a search bar that allows you to search for specific words or phrases in a PDF document. You can also use the “find” command to search for text within the document.

    Manipulating a PDF document with PDF.js

    While PDF.js is primarily a PDF viewer, it offers some manipulation capabilities, such as filling out forms:

    • Users can complete and submit PDF forms.
    • Saved forms can be saved as new PDF documents.

    For more advanced PDF document manipulation, consider using a dedicated PDF library like Nutrient Web SDK.

    Troubleshooting and debugging

    Encountering issues with PDF.js? Follow these steps to resolve common problems:

    • Check the browser console for errors — Open the browser console to identify errors related to PDF.js. These logs can provide valuable insights into the issue.
    • Verify the PDF file — Ensure the PDF file you’re trying to render is valid and not corrupted, as damaged files can cause rendering issues.
    • Update to the latest version — Use the latest version of PDF.js to benefit from bug fixes and performance improvements.
    • Ensure browser compatibility — Confirm that your browser supports the JavaScript features required by PDF.js. Older browsers may not be fully compatible.
    • Review configuration settings — Verify that your PDF.js configuration aligns with your requirements. Incorrect settings may result in unexpected behavior.

    By addressing these areas, you can troubleshoot and resolve many common issues, ensuring a seamless experience with PDF.js.

    Best practices for rendering PDFs

    To optimize the performance and reliability of rendering PDFs with PDF.js, follow these best practices:

    • Use the latest version of PDF.js — Always update to the latest version to benefit from new features, performance improvements, and bug fixes.
    • Optimize PDF files — Reduce PDF file sizes to enhance rendering speed and overall performance. Optimization tools can significantly improve the user experience.
    • Implement caching — Use caching strategies to reduce server load and accelerate rendering. Cached content can be delivered more quickly to users.
    • Leverage a content delivery network (CDN) — Serve PDFs via a CDN to improve load times and rendering performance, particularly for users across various locations.
    • Monitor and tune performance — Continuously monitor your PDF.js implementation’s performance. Adjust configurations as needed to maintain optimal rendering and user satisfaction.

    By following these best practices, you can ensure efficient, fast, and reliable PDF rendering with PDF.js.

    Conclusion

    While PDF.js is a strong tool for basic PDF rendering, it falls short for enterprises requiring advanced functionality, performance, and scalability. Whether your needs include high-volume document processing, interactive form filling, custom annotations, or ensuring document security, Nutrient Web SDK is the ideal solution. With Nutrient, you gain access to enhanced features, faster performance, and dedicated support to tackle even the most complex PDF workflows. For businesses aiming to streamline their document management processes, Nutrient is the advanced alternative to PDF.js that you can rely on.

    Ready to explore the difference Nutrient Web SDK can make? Try out the demo today, or contact our Sales team for a personalized consultation to learn how we can optimize your PDF workflows.

    FAQ

    What is Nutrient Web SDK?

    Nutrient Web SDK is a powerful commercial PDF rendering and manipulation library designed for enterprises. It offers advanced features like real-time annotations, redactions, digital signatures, and full PDF document editing. Unlike open-source libraries like PDF.js, Nutrient provides high performance, scalability, and dedicated support tailored to complex document workflows.

    How does Nutrient Web SDK enhance PDF workflows?

    Nutrient Web SDK empowers businesses by enabling dynamic annotations, secure redactions, legally binding digital signatures, and comprehensive form filling and manipulation. This makes it an ideal choice for enterprises that need to enhance PDF workflows with features that go beyond basic viewing. While PDF.js is suitable for simple applications, Nutrient excels in environments where advanced functionality is required.

    Why should I choose Nutrient Web SDK over PDF.js?

    While PDF.js is great for basic PDF rendering, Nutrient Web SDK offers enterprise-grade functionality that PDF.js cannot match. Nutrient is built to handle complex workflows, large document volumes, and secure document processing. It provides full-featured support for custom annotations, digital signatures, encryption, and more. Additionally, with Nutrient, you get dedicated technical support, making it the more robust solution for businesses with advanced PDF needs.

    What features does Nutrient Web SDK offer that PDF.js lacks?

    Nutrient Web SDK provides advanced features such as custom annotations, redactions, digital signatures, and interactive form filling, which are essential for industries like legal and finance. Unlike PDF.js, Nutrient also supports high-volume processing and secure document workflows. These features make Nutrient the ideal choice for enterprises, while PDF.js is limited to basic document viewing and manipulation.

    How does Nutrient Web SDK improve PDF rendering performance?

    Nutrient Web SDK is optimized for high performance, enabling fast rendering even for large or complex PDFs. It ensures that performance remains consistent, even under heavy workloads, making it suitable for applications that require fast and reliable document processing. This level of optimization is something PDF.js struggles with, particularly when dealing with large documents or high volumes.

    Can Nutrient Web SDK handle large volumes of PDFs?

    Yes, Nutrient Web SDK is specifically designed to handle large volumes of PDF documents. It ensures smooth performance even in high-traffic environments, unlike PDF.js, which can experience performance bottlenecks when scaling to handle thousands of documents. Nutrient's robust architecture makes it the ideal solution for enterprises dealing with high-volume document workflows.

    How do I get started with Nutrient Web SDK?

    Getting started with Nutrient Web SDK is easy. You can sign up for a free trial or request a personalized consultation to discuss how Nutrient can enhance your PDF workflows. Our detailed documentation and dedicated support team(opens in a new tab) will help you integrate the SDK into your project smoothly and efficiently.

    Hulya Masharipov

    Hulya Masharipov

    Technical Writer

    Hulya is a frontend web developer and technical writer at Nutrient who enjoys creating responsive, scalable, and maintainable web experiences. She’s passionate about open source, web accessibility, cybersecurity privacy, and blockchain.

    Explore related topics

    FREE TRIAL Ready to get started?