Angular 10|9 Embed PDF Document Viewer with Controls to Zoom, Rotate, Search & OCR

In this Angular tutorial, we are going to discuss how to embed a PDF document viewer in Angular 10/9/8/7/6/5/4 application with the help of ng2-pdf-viewer package.

Popular browsers like Chrome and Firefox come with a built-in PDF viewer, which provides many required features like Zoom, Search, Rotate, etc.

But sometimes we may need a PDF viewer inside the application itself so that the user doesn’t need to open the document in a new tab.

In this article, we’ll discuss how to easily embed a PDF viewer inside the Angular application with lots of awsome controls and event handling with the help of ng2-pdf-viewer package module.

There are several features available in this PDF viewer:

  • Render text in the PDF document by OCR.
  • Rotation of pages in the PDF document.
  • Document zooming methods.
  • Scaling page on screen to fit the screen.
  • Show borders to the pages in the document.

 

 

Let’s start implementation…

Setup Angular CLI

First, install or update the Angular CLI tool to the latest version by running the below NPM command

$ npm install -g @angular/cli

You can check the version of Angular currently installed

$ ng --version

 

Create a New Angular Application

Run following ng command to create a new Angular project

$ ng new angular-pdf-viewer-app
# ? Would you like to add Angular routing? No
# ? Which stylesheet format would you like to use? CSS

Enter the project directory

$ cd angular-pdf-viewer-app

Run the application

$ ng serve --open

 

Install the ng2-pdf-viewer Package

Run following NPM command to install the ng2-pdf-viewer package in Angular project

$ npm install ng2-pdf-viewer --save

 

Embedding the PDF Viewer in Component Page

The PDF viewer can be embedded by just adding the <pdf-viewer/>component in the page with [src] property to provide the path of the PDF file.

<pdf-viewer [src]="pdfSrc"></pdf-viewer>

 

Adding Controls for PDF Viewer

Before discussing each property option available, let’s quickly create a fully-featured application with all controls

 

The <pdf-viewer/> can have a number of properties and callback event methods to render PDF documents in the page template.

Update the app.component.html template with following

<div class="pdf-viewer-wrap">

  <div class="pdf-viewer-controls-wrap">
    <h2>PDF Viewer Controls</h2>
    <div class="pdf-viewer-controls">
      <div class="pdfv-control" *ngIf="renderText">
        Search:
        <input #queryInp id="pdfQueryInput" type="text" placeholder="Search..." [value]="pdfQuery"
          (input)="searchQueryChanged($event.target.value)" (keyup.enter)="searchQueryChanged(queryInp.value)">
      </div>
      <div class="pdfv-control">
        Select PDF:
        <input (change)="onFileSelected()" type="file" id="file">
        <div>Total Pages:{{totalPages}}</div>
      </div>
      <div class="pdfv-control">
        <button (click)="originalSize = !originalSize">[original-size]="{{originalSize}}"</button>
      </div>
      <div class="pdfv-control">
        <button (click)="fitToPage = !fitToPage">[fit-to-page]="{{fitToPage}}"</button>
      </div>
      <div class="pdfv-control">
        <button (click)="showAll = !showAll">[show-all]="{{showAll}}"</button>
      </div>
      <div class="pdfv-control">
        <button (click)="autoresize = !autoresize">[autoresize]="{{autoresize}}"</button>
      </div>
      <div class="pdfv-control">
        <button (click)="showBorders = !showBorders">[show-borders]="{{showBorders}}"</button>
      </div>
      <div class="pdfv-control">
        <button (click)="renderText = !renderText">[render-text]="{{renderText}}"</button>
      </div>
      <div class="pdfv-control">
        Render Text Mode
        <select name="renderTextMode" [(ngModel)]="renderTextMode">
          <option [value]="o" *ngFor="let o of renderTextModes">{{o}}</option>
        </select>
        <!-- <button (click)="renderTextMode = !renderTextMode">[render-text-mode]="{{renderTextMode}}"</button> -->
      </div>
      <div class="pdfv-control">
        <button (click)="zoomOut()">-</button>  <button (click)="zoomIn()">+</button> 
        zoom (*{{zoom}})
      </div>
      <div class="pdfv-control">
        zoom-scale
        <select name="zoomScales" [(ngModel)]="zoomScale">
          <option [value]="o" *ngFor="let o of zoomScales">{{o}}</option>
        </select>
      </div>

      <div class="pdfv-control">
        <button (click)="rotateDoc()">🔄</button> 
        Rotation (*{{rotation}}°)
      </div>
    </div>
  </div>

  <div class="pdf-viewer-viewer-window">
    <pdf-viewer [src]="pdfSrc" [render-text]="renderText" [render-text-mode]="renderTextMode" [rotation]="rotation"
      [zoom]="zoom" [zoom-scale]="zoomScale" [original-size]="originalSize" [fit-to-page]="fitToPage"
      [show-all]="showAll" [autoresize]="autoresize" [show-borders]="showBorders"
      (after-load-complete)="callBackFn($event)" (page-rendered)="pageRendered($event)"
      (text-layer-rendered)="textLayerRendered($event)" (error)="onError($event)" (on-progress)="onProgress($event)">
    </pdf-viewer>
  </div>

</div>

 

Now in the Component class, we’ll define the variable and methods which will be used to configure PDF Viewer layout. Update the app.component.ts file

// app.component.ts
import { Component, ViewChild } from '@angular/core';
import { PdfViewerComponent } from 'ng2-pdf-viewer';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'angular-pdf-viewer-app';
  pdfSrc = "https://vadimdez.github.io/ng2-pdf-viewer/assets/pdf-test.pdf";

  @ViewChild(PdfViewerComponent) private pdfComponent: PdfViewerComponent;

  renderText = true;
  originalSize = false;
  fitToPage = false;
  showAll = true;
  autoresize = false;
  showBorders = true;
  renderTextModes = [0, 1, 2];
  renderTextMode = 1;
  rotation = 0;
  zoom = 1;
  zoomScale = 'page-width';
  zoomScales = ['page-width', 'page-fit', 'page-height'];
  pdfQuery = '';
  totalPages: number;

  zoomIn() {
    this.zoom += 0.05;
  }

  zoomOut() {
    if (this.zoom > 0.05)
      this.zoom -= 0.05;
  }

  rotateDoc() {
    this.rotation += 90;
  }

  // Event for search operation
  searchQueryChanged(newQuery: string) {
    if (newQuery !== this.pdfQuery) {
      this.pdfQuery = newQuery;
      this.pdfComponent.pdfFindController.executeCommand('find', {
        query: this.pdfQuery,
        highlightAll: true
      });
    } else {
      this.pdfComponent.pdfFindController.executeCommand('findagain', {
        query: this.pdfQuery,
        highlightAll: true
      });
    }
  }

  // Event handler when new PDF file is selected
  onFileSelected() {
    const $pdf: any = document.querySelector('#file');

    if (typeof FileReader !== 'undefined') {
      const reader = new FileReader();

      reader.onload = (e: any) => {
        this.pdfSrc = e.target.result;
      };

      reader.readAsArrayBuffer($pdf.files[0]);
    }
  }

  callBackFn(event) {
    console.log('callBackFn', event);
    // Setting total number of pages
    this.totalPages = event._pdfInfo.numPages
  }
  pageRendered(event) {
    console.log('pageRendered', event);
  }
  textLayerRendered(event) {
    console.log('textLayerRendered', event);
  }
  onError(event) {
    console.error('onError', event);
  }
  onProgress(event) {
    console.log('onProgress', event);
  }
}

 

To customize the layout, update app.component.css file with following custom CSS

.pdf-viewer-wrap {
    display: flex;
    height: 95vh;
    border: 5px solid #cccccc;
}
.pdf-viewer-controls-wrap {
    border: 5px solid #cccccc;
    width: 20%;
    text-align: center;
}
.pdfv-control {
    background: #f3f3f3;
    padding: 10px;
    border-bottom: 1px solid #cccc;
}
.pdfv-control button {
    background: #9dff00;
    border: none;
    padding: 5px 10px;
    border-radius: 5px;
    font-weight: bold;
    cursor: pointer;
}
.pdf-viewer-controls {
    overflow: auto;
}

.pdf-viewer-viewer-window {
    border: 5px solid #cccccc;
    width: 80%;
    overflow: auto;
}

That’s if now you can run the Angular app by hitting $ ng serve --open.

 

Properties of PDF Viewer

Now we’ll look into each property we used in the above application:

  • [src]: Define the path of PDF file loaded by default. It can be in any format string, object, UInt8Array.
  • [page]: To display a single page of the document. Required when [show-all]=”false” is used.
  • [stick-to-page]: Sticks view to the page. Works in combination with [show-all]=”true” and page.
  • [render-text]: Enable text rendering, allows to select text. Required and set to true to make a search in the document.
  • [render-text-mode]: Used in combination with [render-text]=”true”. Controls if the text layer is enabled, and the selection mode that is used.
  • [external-link-target]: Controls how external links will be opened. Example [external-link-target]=”‘blank'”.
  • [rotation]: Rotate PDF by changing the degree. The allowed step is 90 degrees, ex. 0, 90, 180.
  • [zoom]: Controls Zooming of the document.
  • [zoom-scale]: Defines how the Zoom scale is computed when [original-size]=”false”, by default set to ‘page-width’. Allowed values ‘page-width’|’page-fit’|’page-height’.
  • [original-size]: Change the size to the original when set to true.
  • [fit-to-page]: Fits the page to cover available areas by page width.
  • [show-all]: When set to a false only a single page is shown defined in the [page] property.
  • [autoresize]: Turn on or off auto-resize.
  • [show-borders]: Show the border by adding shadow on pages.

Method Callbacks Available on PDF Viewer

  • (after-load-complete): Triggered when the document is loaded and returns the PDF document information. We used this callback to fetch total number of pages in the PDF document.
  • (page-rendered): Triggered after each page is rendered.
  • (text-layer-rendered): Triggered when a text layer or OCR is rendered completely.
  • (error): Triggered if the error is encountered while loading the document.
  • (on-progress): Displays the progress while loading the document.

 

Source Code

Fine source code of this application example in the GitHub repository link here.

 

Conclusion

Finally, we are done with the tutorial on how to easily embed a PDF Document Viewer inside the Angular page component. The ng2-pdf-viewer package provides a wide variety of controls that can be used to create a provisional viewer in the Angular application.

Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments