1.0.2-alpha • Published 4 months ago

@whykhamist/vpdf v1.0.2-alpha

Weekly downloads
-
License
-
Repository
github
Last release
4 months ago

Vue PDF (VPDF)

Custom PDF viewer for Vue. Built on top of PDF.js

Features

  • Utilizes virtual scrolling to render PDFs with huge page count
  • Supports password protected PDFs
  • Textlayer support
  • PDF Thumbnails
  • PDF Bookmarks
  • Show/download Attachments

Installation

$ npm i @whykhamist/vpdf

Setup

import { createApp } from "vue";
import App from "./app.vue";
import VPdf from "@whykhamist/vpdf";

import "@whykhamist/vpdf/style.css";

async function init() {
  const app = createApp(App);
  app.use(VPdf);
  app.mount("#app");
}

init();

Usage

import { ref } from "vue";

// acrobat_reference.pdf (651 pages): https://helpx.adobe.com/pdf/acrobat_reference.pdf

// pdfreference1.7old.pdf (1310 pages)
const src = ref(
  "https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/pdfreference1.7old.pdf"
);
const smoothJump = ref(false);
const textLayer = ref(false);
const theme = ref(""); // blank for light, vpdf-dark for dark
<template>
  <VPdf
    :src="src"
    :smoothJump="smoothJump"
    :textLayer="textLayer"
    :class="theme"
  />
</template>

Styles

Colors can be customized using css variables: Default colors for light & dark modes

:root {
  --vpdf-foreground: 213deg 13% 14%;
  --vpdf-background: 0deg 0% 100%;
  --vpdf-primary: 211deg 32% 26%;
  --vpdf-secondary: 211deg 46% 69%;
  --vpdf-accent: 211deg 62% 44%;

  --vpdf-positive: 125deg 42% 50%;
  --vpdf-negative: 3deg 75% 60%;
}

.vpdf-dark {
  --vpdf-foreground: 213deg 26% 82%;
  --vpdf-background: 215deg 18% 13%;
  --vpdf-primary: 211deg 32% 74%;
  --vpdf-secondary: 211deg 46% 31%;
  --vpdf-accent: 211deg 62% 56%;
}

We can also add our custom colors

<style lang="scss">
  .vpdf-sepia {
    --vpdf-foreground: 34 33% 20%;
    --vpdf-background: 42 54% 88%;
    --vpdf-primary: 34 20% 51%;
    --vpdf-secondary: 60 19% 73%;
    --vpdf-accent: 75 19% 63%;
  }
</style>
<template>
  <VPdf
    :src="src"
    :smoothJump="smoothJump"
    :textLayer="textLayer"
    class="vpdf-sepia"
  />
</template>

Components

VPdf

A complete PDF viewer component with the most common features and configurations

Features

  • Password prompt dialog
  • Collapsible Side bar for navigation and attachments
    • Thumbnails
    • Bookmarks
    • Attachments (Download file only)
  • View toggle (Vertical/Horizontal page scrolling)
  • Rotate page
  • Zoom in/out buttons
  • ctrl + scroll to zoom in/out
  • Scale selector
    • with fit to page, width and height options
  • Page number indicator (Can enter page number and jump to that page)
  • Next/Previous page buttons

Properties

PropertyTypeDefaultDescription
srcpdfSource-PDF source
workerSrcString1.0link to your custom pdf worker
smoothJumpBooleanfalseSmooth scroll into selected page
textLayerBooleanfalseShow text layer
passwordString-Password for encrypted PDF
onPasswordFunction-Pass a callback function to create a custom prompt for password. VPdf already has a built-in dialog for password prompt.

sample onPassword

const onPassword = (cb: Function, reason: Number) => {
  const password = prompt("Please enter the password");
  cb(password);
};

VPdfViewer

A PDF viewer component without the side & top menu bars, Use this to build/style your custom PDF viewer.

VPdf uses this component internally

!NOTE You will need to use the usePdf composables to use this component

!NOTE This component uses the usePdfViewer composable internally

Properties

PropertyTypeDefaultDescription
pdfPDFDocumentLoadingTask--The loading task controls the operations required to load a PDF document (such as network requests) and provides a way to listen for completion, after which individual pages can be rendered.
scaleNumber1.0The scale/zoom factor for the PDF viewer
gapNumber10The gap between pages in pixels
rotationNumber0The rotation angle in degrees for the PDF pages. (Must be a multiple of 90)
view"vertical","horizontal"verticalThe view mode for the PDF viewer.
pageNumber1The initial page number to display.
textLayerBooleanfalseShow text layer
smoothJumpBooleanfalseSmooth scroll into selected page
renderDelayNumber50Delay in milliseconds before rendering a page
renderOffsetNumber256Offset in pixels to add around the page to determine if it is visible.
onProgressFunction-Pass a callback function to get the loading progress.

VPdfPageRenderer

Renders a single PDF page

Properties

PropertyTypeDefaultDescription
pageInfopdfPageInfo-An object that contains all relative information to render the page Use the usePdfViewer composable to get this information
pdfPDFDocumentLoadingTask---
textLayerBooleanfalseShow text layer
renderBooleanfalseRender the page
onRenderFunction-A callback function that is called whenever the page is rendered.
onErrorFunction-A callback function that is called whenever an error occurs.

Exposed

PropertyTypeDefaultDescription
contextCanvasRenderingContext2D-The canvas context
canvasHTMLCanvasElement-The canvas element

Composables

usePdf

This composable is responsible for loading PDF from a source. It returns a pdf object that can be used to render the PDF. It also returns the number of pages, outline (bookmars), attachments, metadata, progress , and javascript of the PDF.

import { usePdf } from "@whykhamist/vpdf";

const pdf = usePdf(pdfSource, options);

const src = ref(
  "https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/pdfreference1.7old.pdf"
);

const options = ref({
  workerSrc: "YOUR_WORKER_SRC",
  password: "PDF_PASSWORD_IF_NEEDED",
  onError: (error: any) => {},
  onProgress: (data: OnProgressParameters) => {},
  onPassword: (callback: Function, reason: any) => {},
});

const {
  pdf,
  pages,
  outline,
  attachments,
  metadata,
  progress,
  javascript,
  loading,
} = usePdf(src, options);

Parameters

ParameterTypeDescription
srcRef\<pdfSource> | pdfSource(Required) The source of the PDF file.
optionspdfOptions(Optional) The options for the PDF.

Returns

PropertyTypeDescription
pdfPDFDocumentLoadingTaskThe PDF object.
pagesNumberThe number of pages in the PDF.
outlineArrayThe outline of the PDF. This contains information regarding the bookmarks in the PDF.
attachmentsObjectThe list of files attached to the document
metadataanyGet the documents meta data
javascriptArrayA list of embedded javascripts on the document
progressNumberThe loading progress of the PDF.
loadingBooleanWhether the PDF is currently loading.

usePdfViewer

This computes the page information that is needed to render and position pages in the viewport based on the scale, rotation, gaps and view mode. It alsoe determines when to render a page (virtual scrolling).

import { usePdfViewer } from "@whykhamist/vpdf";
const container = ref<HTMLDivElement>();
const pdfViewer = usePdfViewer(container, options);
<div ref="container"></div>

Parameters

ParameterTypeDescription
containerRef\<HTMLElement | undefined>(Required) The container to render the PDF in
optionspdfViewerOptionsThe options for the PDF.

Parameter: options

PropertyTypeDefaultDescription
pdfPDFDocumentLoadingTask--
pageNumber1Initial page to display/focus.
scaleNumber1The scale of the PDF.
gapNumber10The gap (in pixels) between pages .
rotationNumber0The rotation of the PDF. (multiple of 90)
viewString 'vertical' | 'horizontal'verticalThe view mode of the PDF.
textLayerBooleanfalseShow text layer
smoothJumpBooleanfalseSmooth scroll into pages
renderDelayNumber50Delay in milliseconds before rendering a page
renderOffsetNumber256Offset in pixels to add around the page to determine if it is visible.
downScaleNumber0.87Multiplied to the scale to reduce the size of the canvas.

Returns

PropertyTypeDescription
totalPageNumberThe total number of pages in the PDF
pageInfoArray\<pdfPageInfo>Array list of pdfPageInfo (All Pages)
containerBoundsSizeThe maximum width & height of the container
progressOnProgressParametersThe loading progress of the PDF
renderBooleanDetermines if the page should be rendered after scrolling
currentPageNumberThe current page in focus
visiblePagesArrayArray list of pdfPageInfo (Only visible Pages in the viewport)
scaleNumberThe scale of the PDF
rotationNumberThe rotation of the PDF
viewModeString 'vertical' | 'horizontal'Scroll direction of the PDF
refreshFunctionReloads the PDF
nextPageFunctionUses the changePage to jump to the next page.
prevPageFunctionUses the changePage to jump to the previous page.
changePageFunctionJumps to a specific page with optional offset.
fitWidthFunctionFits the current page to the width of the container
fitHeightFunctionFits the current page to the height of the container
fitPageFunctionFits the current page to the size of the container

Types

Types from pdfjs

  • pdfjs-dist
    • PageViewport
  • pdfjs-dist/types/src/display/api
    • OnProgressParameters
    • PDFDocumentLoadingTask
    • PDFDocumentProxy
    • DocumentInitParameters
    • TypedArray
    • RenderParameters
type Size = {
  width: number;
  height: number;
};

type Point = {
  x: number;
  y: number;
};

type Bounds = {
  top: number;
  bottom: number;
  left: number;
  right: number;
};

type ScrollState = {
  right: boolean;
  down: boolean;
  lastX: number;
  lastY: number;
};

type pdfSource =
  | string
  | URL
  | TypedArray
  | ArrayBuffer
  | DocumentInitParameters;

interface pdfOptions {
  workerSrc?: string;
  password?: string;
  onError?: (error: any) => void;
  onProgress?: (data: OnProgressParameters) => void;
  onPassword?: (callback: Function, reason: any) => void;
}

type pdfOutlineDest = string | Array<any> | null;

type pdfOutline = Awaited<ReturnType<PDFDocumentProxy["getOutline"]>>;

type pdfOutlinePairs = {
  page: number | null;
  offsetY: number;
  offsetX: number;
  title: string;
  sub: Array<pdfOutlinePairs>;
};

type pdfViewerOptions = {
  pdf: PDFDocumentLoadingTask | undefined;
  page: number;
  scale: number;
  gap: number;
  rotation: number;
  view: "vertical" | "horizontal";
  textLayer: boolean;
  smoothJump: boolean;
  renderDelay: number;
  renderOffset: number;
  downScale?: number;
};

type pdfPageInfo = {
  id: string;
  scale: number;
  rotation: number;
  page: number;
  viewport: PageViewport;
  pos: Point;
  bounds: pdfPageBounds;
};

type pdfPageBounds = {
  inner: Bounds;
  outer: Bounds;
};

type pdfScrollState = {
  rAF: number | null;
  state: ScrollState;
  covered: Point;
  timer: ReturnType<typeof setTimeout> | null;
};

type pdfattachmentFile = {
  filename: string;
  content: TypedArray;
  rawFilename: string;
};

type pdfattachment = Record<string, pdfattachmentFile>;