Skip to content

Commit

Permalink
Merge pull request #7 from dealfonso/render-scale
Browse files Browse the repository at this point in the history
tweak the rendering scale to get better resolution
  • Loading branch information
dealfonso authored Feb 16, 2024
2 parents dc78453 + 0209bf7 commit aa2f9b1
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 37 deletions.
31 changes: 17 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

The distribution of [Mozilla's PDF.js](https://mozilla.github.io/pdf.js/) includes an example of a viewer that can be used in a web page by means of inserting using an `iframe`. But the viewer cannot be easily used or customized for using it as part of a web application.

PDFjs-viewer is a embeddable and easily customizable PDF viewer that is implemented using the PDF.js library.
PDFjs-viewer is an embeddable and easily customizable PDF viewer that is implemented using the PDF.js library.

So, if you have a `div` in your web application, you can convert it in a PDF viewer as in the next example:
So, if you have a `div` in your web application, you can convert it into a PDF viewer as in the next example:

```html
<div class="pdfjs-viewer">
Expand All @@ -27,9 +27,9 @@ The PDFjsViewer is customizable and has different options and callbacks that ena
Some examples included in the distribution:
- A simple PDF viewer, for a simple document.
- A simpler PDF viewer, using the declarative way (i.e. setting the _pdfjs-viewer_ class to any object).
- A PDF viewer with a toolbar that enables to navigate through the document.
- A PDF viewer with a toolbar that enables navigation through the document.
- A PDF viewer with thumbnails that interact with the main document.
- A PDF viewer in which it is possible to create selections and move them accross different pages.
- A PDF viewer in which it is possible to create selections and move them across different pages.

**DISCLAIMER:** _PDFjs-viewer is written from scratch and has nothing to do with the example viewer in the PDF.js distribution._

Expand All @@ -43,10 +43,10 @@ But if (as in my case) you need more than simply a PDF viewer embedded in an `if
### Technical facts

- The pages of each of the document are rendered on demand, to avoid having all the pages using the memory of the browser. The viewer detects the pages which are visible, and renders each of them. Although rendering is fast, using the options (i.e. `extraPagesToLoad`) it is advisable to render some extra pages to enable a better user experience when scrolling the document.
- The pages of each document are rendered on demand, to avoid having all the pages using the memory of the browser. The viewer detects the visible pages, and renders each of them. Although rendering is fast, using the options (i.e. `extraPagesToLoad`) it is advisable to render some extra pages to enable a better user experience when scrolling the document.
- PDFjs-viewer adds some callbacks that are called upon different events: `onDocumentReady`, `onNewPage`, `onPageRender`, `onZoomChange`, `onActivePageChanged`. Each callback is binded to the PDFjsViewer instance, so it is possible to use `this` to refer to it.
- PDFjs-viewer renders the pages according to the size of the DIVs in which they are included. In this way, the amount of memory is adjusted to the minimum needed. It is important that the `PDFjsViewer` considers the `pixel_ratio` feature to increase the resolution of the images according to the features of the device in which the document has been opened (e.g. retina displays and so on).
- PDFjs-viewer includes support for zooming the pages, so that the user does not need to deal with this typical feature.
- PDFjs-viewer renders the pages according to the size of the DIVs in which they are included. In this way, the amount of memory is adjusted to the minimum needed. `PDFjsViewer` considers the `pixel_ratio` feature to increase the resolution of the images according to the features of the device in which the document has been opened (e.g. retina displays and so on).
- PDFjs-viewer includes support for zooming the pages so that the user does not need to deal with this typical feature.

## Using

Expand All @@ -55,18 +55,18 @@ PDFjs-viewer depends on Mozilla's [PDF.js library](https://mozilla.github.io/pdf

```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.4.120/pdf.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js"></script>
<script>
var pdfjsLib = window['pdfjs-dist/build/pdf'];
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.4.120/pdf.worker.min.js';
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js';
</script>
```

### From source

There is a single _javascript_ file that contain the whole PDFjsViewer class (in folder `js`).
There is a single _javascript_ file that contains the whole PDFjsViewer class (in folder `js`).

There are also a set of _css_ files that contain some styles to be used in the library and the examples. These files can also be included individually in your project, or combined into a single file by concatenating them.
There are also a set of _css_ files that contain some styles to be used in the library and examples. These files can also be included individually in your project, or combined into a single file by concatenating them.

A `Makefile` is provided to create the single all-in-one minified `js` and `css` files for the library.

Expand All @@ -82,7 +82,7 @@ cleancss css/*.css --format beautify | cat notice - > pdfjs-viewer.css
cleancss css/*.css | cat notice.min - > pdfjs-viewer.min.css
```

Now you can use files `pdfjs-viewer.min.js` and `pdfjs-viewer.min.css` in your project (jQuery is a prerrequisite):
Now you can use files `pdfjs-viewer.min.js` and `pdfjs-viewer.min.css` in your project (jQuery is a prerequisite):

```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
Expand All @@ -102,7 +102,7 @@ It is possible to use `pdfjs-viewer` directly from a CDN:

## API

The creation of a PDF viewer consists in creating a `PDFjsViewer` object, setting the jQuery object in which the PDF viewer should be set, and configuring the options that we may need.
The creation of a PDF viewer consists of creating a `PDFjsViewer` object, setting the jQuery object in which the PDF viewer should be set, and configuring the options that we may need.

```javascript
var options = {
Expand Down Expand Up @@ -143,6 +143,9 @@ emptyContent: () => $('<div class="loader"></div>')
errorPage: () => {
$(`<div class="placeholder"></div>`).addClass(this.settings.pageClass).append($(`<p class="m-auto"></p>`).text("could not load document"))
},
// The scale to which the pages are rendered (1.5 is the default value for the PDFjs viewer); a higher value will render the pages with a higher resolution
// but it will consume more memory and CPU. A lower value will render the pages with a lower resolution, but they will be uglier.
renderingScale: 1.5,
```

### Methods
Expand Down Expand Up @@ -255,7 +258,7 @@ Check the example at [PDFjs-viewer example-2](https://codepen.io/dealfonso/pen/q

### Example 3 - a document with thumbnails and a toolbar

Each of the PDFjsViewer object is independent one from each other, and so it is possible to include multiple PDF documents in the same web application.
Each of the PDFjsViewer objects is independent from each other, so it is possible to include multiple PDF documents in the same web application.

In this example, we have included two independent documents (which at the end, have the same PDF source): one to act as thumbnails and other to act as the main document. Then using the callbacks, it is possible to make them interact one with the other to mark the _active page_ in the thumbnails when scrolling the main document, or showing a specific page when clicking on one of the pages in the thumbnails documents.

Expand Down
31 changes: 19 additions & 12 deletions js/pdfjs-viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@
// Percentage of the container that will be filled with the page
zoomFillArea: 0.95,
// Function called to get the content of an empty page
emptyContent: () => $('<div class="loader"></div>')
emptyContent: () => $('<div class="loader"></div>'),
// The scale to which the pages are rendered (1.5 is the default value for the PDFjs viewer); a higher value will render the pages with a higher resolution
// but it will consume more memory and CPU. A lower value will render the pages with a lower resolution, but they will be uglier.
renderingScale: 1.5,
}

// Class used to help in zoom management; probably it can be moved to the main class, but it is used to group methods
Expand Down Expand Up @@ -250,7 +253,6 @@
// Create a scroll handler that prevents reentrance if called multiple times and the loading of pages is not finished
let scrollLock = false;
let scrollPos = { top:0 , left:0 };

this.__scrollHandler = function(e) {
// Avoid re-entrance for the same event while loading pages
if (scrollLock === true) {
Expand Down Expand Up @@ -564,13 +566,14 @@
_renderPage(page, i) {
// Get the pageinfo structure
let pageinfo = this.pages[i];
let scale = this.settings.renderingScale;

// Calculate the pixel ratio of the device (we'll use a minimum of 1)
let pixel_ratio = Math.max(window.devicePixelRatio || 1, 1);
let pixel_ratio = window.devicePixelRatio || 1;
// Update the information that we know about the page to the actually loaded page
let viewport = page.getViewport({rotation: this._rotation, scale: this._zoom.current * pixel_ratio});
pageinfo.width = (viewport.width / this._zoom.current) / pixel_ratio;
pageinfo.height = (viewport.height / this._zoom.current) / pixel_ratio;
let viewport = page.getViewport({rotation: this._rotation, scale: this._zoom.current * scale});
pageinfo.width = (viewport.width / this._zoom.current) / scale;
pageinfo.height = (viewport.height / this._zoom.current) / scale;
pageinfo.$div.data("width", pageinfo.width);
pageinfo.$div.data("height", pageinfo.height);
pageinfo.$div.width(pageinfo.width * this._zoom.current);
Expand All @@ -581,12 +584,16 @@
let $canvas = $('<canvas></canvas>');
let canvas = $canvas.get(0);
let context = canvas.getContext('2d');
canvas.height = viewport.height; // * pixel_ratio;
canvas.width = viewport.width; // * pixel_ratio;
canvas.getContext("2d"); //.scale(pixel_ratio, pixel_ratio);
canvas.height = viewport.height * pixel_ratio;
canvas.width = viewport.width * pixel_ratio;
canvas.getContext("2d")//.scale(pixel_ratio, pixel_ratio);
var transform = pixel_ratio !== 1
? [pixel_ratio, 0, 0, pixel_ratio, 0, 0]
: null;
var renderContext = {
canvasContext: context,
viewport: viewport
viewport: viewport,
transform: transform,
};

// Render the page and put the resulting rendered canvas into the page $div
Expand Down Expand Up @@ -787,15 +794,15 @@
let options = recoverAttributes(element, Object.assign({
pdfDocument: "", initialZoom: ""
}, defaults));
let pdfViewer = new PDFjsViewer($(element), options);
if (options["pdfDocument"] != null) {
let pdfViewer = new PDFjsViewer($(element), options);
pdfViewer.loadDocument(options["pdfDocument"]).then(function() {
if (options["initialZoom"] != null) {
pdfViewer.setZoom(options["initialZoom"]);
}
})
element.get(0).pdfViewer = pdfViewer;
}
element.get(0).pdfViewer = pdfViewer;
}

$(function() {
Expand Down
24 changes: 14 additions & 10 deletions pdfjs-viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
onZoomChange: zoomlevel => {},
onActivePageChanged: (page, i) => {},
zoomFillArea: .95,
emptyContent: () => $('<div class="loader"></div>')
emptyContent: () => $('<div class="loader"></div>'),
renderingScale: 1.5
};
class Zoomer {
constructor(viewer, options = {}) {
Expand Down Expand Up @@ -359,13 +360,14 @@
}
_renderPage(page, i) {
let pageinfo = this.pages[i];
let pixel_ratio = Math.max(window.devicePixelRatio || 1, 1);
let scale = this.settings.renderingScale;
let pixel_ratio = window.devicePixelRatio || 1;
let viewport = page.getViewport({
rotation: this._rotation,
scale: this._zoom.current * pixel_ratio
scale: this._zoom.current * scale
});
pageinfo.width = viewport.width / this._zoom.current / pixel_ratio;
pageinfo.height = viewport.height / this._zoom.current / pixel_ratio;
pageinfo.width = viewport.width / this._zoom.current / scale;
pageinfo.height = viewport.height / this._zoom.current / scale;
pageinfo.$div.data("width", pageinfo.width);
pageinfo.$div.data("height", pageinfo.height);
pageinfo.$div.width(pageinfo.width * this._zoom.current);
Expand All @@ -374,12 +376,14 @@
let $canvas = $("<canvas></canvas>");
let canvas = $canvas.get(0);
let context = canvas.getContext("2d");
canvas.height = viewport.height;
canvas.width = viewport.width;
canvas.height = viewport.height * pixel_ratio;
canvas.width = viewport.width * pixel_ratio;
canvas.getContext("2d");
var transform = pixel_ratio !== 1 ? [ pixel_ratio, 0, 0, pixel_ratio, 0, 0 ] : null;
var renderContext = {
canvasContext: context,
viewport: viewport
viewport: viewport,
transform: transform
};
return page.render(renderContext).promise.then(function() {
this._setPageContent(pageinfo.$div, $canvas);
Expand Down Expand Up @@ -542,15 +546,15 @@
pdfDocument: "",
initialZoom: ""
}, defaults));
let pdfViewer = new PDFjsViewer($(element), options);
if (options["pdfDocument"] != null) {
let pdfViewer = new PDFjsViewer($(element), options);
pdfViewer.loadDocument(options["pdfDocument"]).then(function() {
if (options["initialZoom"] != null) {
pdfViewer.setZoom(options["initialZoom"]);
}
});
element.get(0).pdfViewer = pdfViewer;
}
element.get(0).pdfViewer = pdfViewer;
}
$(function() {
$(".pdfjs-viewer").each(function() {
Expand Down
Loading

0 comments on commit aa2f9b1

Please sign in to comment.