Merge Multiple Base64 Decoded pdf to one pdf using reactjs - javascript

I am getting a base64 encoded pdf as multiple response and I have to decode it to create one pdf.
Here is my code for reference.
var pdf_base1 = "data:application/pdf;base64,JVBERi0xLjQKJfbk/N8KMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMiAwIFIKL0Fjcm9Gb3JtIDMgMCBSCi9NZXRhZGF0YSA0IDAgUgo+PgplbmRvYmoKNSAwIG9iago8PAovUHJvZHVZXIgKFJBRCBQREYg..." //shortend
var pdf_base2 = "data:application/pdf;base64,JVBERi0xLjQKJfbk/N8KMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMiAwIFIKL0Fjcm9Gb3JtIDMgMCBSCi9NZXRhZGF0YSA0IDAgUgo+PgplbmRvYmoKNSAwIG9iago8PAovUHJvZHVZXIgKFJBRCBQREYg..." //shortend
var pdfDoc,pageNum= 1,pageNumPending = null,pageRendering = false,
pdf= [];
pdf.push(pdf_base1,pdf_base2);
pdf.map(each=>{
this.callPdfLib(each);
})
callPdfLib=(data)=>{
var self = this;
// var files = self.state.files;
var pageCount = this.pageCount;
var arrrBuffer = self.base64ToArrayBuffer(data);
pdfjsLib.getDocument({data:arrrBuffer}).promise.then(function(page) {
pdfDoc = page;
pageCount.textContent = page.numPages;
self.renderPage(pageNum);
});
}
renderPage=(num)=>{
var canvas = this.canvas;
pageRendering = true;
pdfDoc.getPage(num).then(function(page) {
var scale = 1.5;
var viewport = page.getViewport({scale: scale});
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: context,
viewport: viewport
};
var renderTask = page.render(renderContext);
renderTask.promise.then(function() {
pageRendering = false;
if (pageNumPending !== null) {
this.renderPage(pageNumPending);
pageNumPending = null;
}
});
})
}
Both variables are base64 encode pdfs.
By doing this, I am getting an error.
Unhandled Rejection (Error): Cannot use the same canvas during multiple render() operations. Use different canvas or ensure previous operations were cancelled or completed.

you have to create a canvas for each page and append it to the body of your container element, also as it is an async operation you can use async/await so that it previews the first page then the second, and so on.
You can use this link for reference
https://gist.github.com/fcingolani/3300351

Related

PDF loading is extremely slow for large files using pdf.js

I am facing huge performance issues in loading large pdf documents (around 30/40 MB) using pdf.js
I am new to the ways it works and read a lot about it , but nothing helped.
Following is my code samples.
In HTML file
<div id="divCanvasTemplate">
<div id="divCanvasContainer-{pageIndex}" class="canvas-container">
<canvas id="cnvDesigner-{pageIndex} class="canvas-designer"></canvas>
</div>
</div>
In JS file , I have the following method.
var _loadFile = function() {
var pdfjsLib = window['pdfjs-dist/build/pdf'];
pdfjsLib.GlobalWorkerOptions.workerSrc = _workerUrl;
$ajax({
url: "GEtPDFFileBytes",
type: "GET",
data: {
"documentid": _documentId
},
success: function(result) {
var raw = atob(result);
var loadintask = pdfjsLib.getDocument({
data: raw
});
loadingtask.promise.then(function(pdfDoc_) {
_pageCount = pdfDoc_._pdfInfo.numPages;
_currentpageNumber = _getbasePage();
var canvasTemplate = $("#divCanvasTemplate").html();
var activeRange = _getActiveRange(_currentpageNumber);
for (let pagenumber = 1; pagenumber <= _pagecount; pagenumber++) {
var canvashtml = canvasTemplate.replace(/pageindex}/g, pagenumber);
$("#divMasterCanvas").append(canvasHtml);
pdfDoc = PdfDoc_;
renderPDFPage(pageNumber);
}
});
}
});
}
}
function renderPDFPage(num) {
pdfDoc.getPage(num).then(function(page) {
var currentpagenumber = page._pageindex + 1;
var viewport = page.getViewPort({
scale: scale
});
var canvas = document.getelementbyid('cnvDesigner-' + currentpagenumber);
var context = canvas.getcontext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
var rendercontext = {
canvasContext: context,
viewport: viewport
};
var rendertask = page.render(rendercontext);
}
});
}
I read about using getImageData() and putImageData() in context to use in such scenario, but unable to get it work. Any help would be greatly appreciated.

Rendering a section of PDF

I have been following this tutorial to embed a PDF on my website using PDF.js. But I only want to embed a certain part, ie. a section in the middle of the PDF page. Is there a smart way to do this? Can I somehow crop the PDF displayed?
I use this code to render the pdf
const scale = 1,
canvas = document.querySelector('#pdf-render'),
ctx = canvas.getContext('2d');
const renderPage = num => {
pageIsRendering = true;
//get the page
pdfDoc.getPage(num).then(page => {
//set scale
const viewport = page.getViewport({scale});
canvas.height = viewport.height;
canvas.width = viewport.width;
const renderCtx = {
canvasContext: ctx,
viewport
};
page.render(renderCtx).promise.then(() => {
pageIsRendering = false;
if(pageNumIsPending !== null){
renderPage(pageNumIsPending);
pageNumIsPending = null;
}
});

PDF.JS only updates every other time

I'm trying to implement a "drag-to-pan" function for the pfd.js viewer.
However, this only works every other time, so that after panning around, I have to click the viewer again to make it re-render.
Here's the code:
var pdfScale = 1;
var activePdf;
var rotate = 0;
var addX = 0;
var addY = 0;
function renderPage(page) {
activePdf = page;
var canvas = document.getElementById('the-canvas');
var wrapperStyle = window.getComputedStyle(document.getElementsByClassName("canvas-wrapper")[0]);
var context = canvas.getContext('2d');
var viewport = page.getViewport(pdfScale, rotate);
canvas.height = parseInt(wrapperStyle.height);
canvas.width = parseInt(wrapperStyle.width);
viewport.viewBox[0] -= addX;
viewport.viewBox[2] -= addX;
viewport.viewBox[1] += addY;
viewport.viewBox[3] += addY;
addX = addY = 0;
// Render PDF page into canvas context
var renderContext = {
canvasContext: context,
viewport: viewport
};
var renderTask = page.render(renderContext);
}
$(document).ready(function() {
var start = [0,0];
$('#the-canvas').mousedown(function(event) {
start[0] = event.screenX;
start[1] = event.screenY;
}).mouseup(function(event) {
console.log(event);
addX = event.screenX - start[0];
addY = event.screenY - start[1];
setTimeout(function() {
renderPage(activePdf);
}, 500);
});
var url = 'http://localhost/test.pdf';
// Disable workers to avoid yet another cross-origin issue (workers need
// the URL of the script to be loaded, and dynamically loading a cross-origin
// script does not work).
PDFJS.disableWorker = true;
// The workerSrc property shall be specified.
PDFJS.workerSrc = 'build/pdf.worker.js';
// Asynchronous download of PDF
var loadingTask = PDFJS.getDocument(url);
loadingTask.promise.then(function(pdf) {
console.log('PDF loaded');
// Fetch the first page
var pageNumber = 1;
pdf.getPage(pageNumber).then(function(page) {
console.log('Page loaded');
renderPage(page);
});
}, function (reason) {
// PDF loading error
console.error(reason);
});
});
Even after adding the setTimeout, it still doesn't render correctly on the first time. How can I edit my logic to make it work?
Thanks!

Prevent simultanous function calls when using pdf.js?

I use pdf.js to show pdf files, but the result is not good, please have a look at my code.
My codes are as follows.
var aaa = function (pdf, page_number) {
pdf.getPage(page_number).then(function(page) {
var scale = 1.5;
var viewport = page.getViewport(scale);
var canvas = $('.pdf-view')[page_number-1];
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: context,
viewport: viewport
};
page.render(renderContext);
});
};
for (var i = 1;i < 51;i++) {
aaa(pdf, i);
if (i !== 50) {
var a = '<canvas data="{{ raw_path }}" class="pdf-view hide" style="margin-bottom:10px;"></canvas>';
$('#file-view #pdf').append(a);
}
}
There is a loop, then 50 functions (aaa) execute at the same time. The effect is disastrous, and my computer gets stuck. I want to excute a function right after the last function excuted very well.
Please help me improve it. Thank a lot. (Sorry, my English is disastrous as well.)
To avoid simultaneous run of single page load and render function aaa , you should move its call to callback of the page load - .then( part so it's called recursively. And then call aaa function only once with page_number = 1.
//define page render function
var aaa = function (pdf, page_number) {
pdf.getPage(page_number).then(function(page) {
var scale = 1.5;
var viewport = page.getViewport(scale);
var canvas = $('.pdf-view')[page_number-1];
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
var renderContext = {
canvasContext: context,
viewport: viewport
};
page.render(renderContext);
if (i < 50) {
//render first 50 pages but not all pages except #50
aaa(pdf, i);
i++;
}
});
};
//pre-generate 50 canvases
var docFragment = document.createDocumentFragment();
for (var i = 1;i < 51;i++) {
var c = document.createElement("canvas");
$(c).data({{ raw_path }});
$(c).addClass('pdf-view hide');
$(c).css('margin-bottom', '10px');
docfrag.appendChild(c);
}
$('#file-view #pdf').append(docfrag);
//call render
var i = 1;
aaa(pdf, i);

PDF.js render pdf with scrollbar

I use mozilla pdf.js. I have a code:
<canvas id="the-canvas"/>
function displayDocument(){
PDFJS.getDocument(numberOdDocument[attachment]).then(function (pdfDoc_) {
pdfDoc = pdfDoc_;
renderPage(pageNum);
});
}
function renderPage(num) {
pdfDoc.getPage(num).then(function(page) {
var viewport = page.getViewport(scale, rotate);
canvas.height = '900';
canvas.width = '500';
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
var renderTask = page.render(renderContext);
renderTask.promise.then(function () {
pageRendering = false;
if (pageNumPending !== null) {
renderPage(pageNumPending);
pageNumPending = null;
}
});
});
}
Now i see only one page in canvas tag, but I want add scrollbar to my canvvas, and I want change page with scroll. How can I do that?
Allow scroll
First, create a parent div to encapsulate the canvas element :
<div>
<canvas id="the-canvas"/>
</div>
Then, set a fixed size with a vertical scroll
<div style="width:650px;height:600px;overflow-y:scroll;">...</div>
Finally, you can set the scale you want using the variable "scale" but keep these original lines :
function renderPage(num) {
pdfDoc.getPage(num).then(function(page) {
var viewport = page.getViewport(scale);
canvas.height = viewport.height;
canvas.width = viewport.width;
...
Render all pages
Keep in mind, that render a lot of pages will take a bit of time but here is how to do it.
Idea : you need to render each page in a separate canvas element.
First, create dynamically the canvas element with a specific id during render :
<div id="pdf-viewer"></div>
...
function renderPage(num) {
pdfDoc.getPage(num).then(function(page) {
var canvasId = 'pdf-viewer-' + num;
$('#pdf-viewer').append($('<canvas/>', {'id': canvasId}));
var canvas = document.getElementById(canvasId);
...
Finally, call renderPage() for each page
function renderAllPages() {
for (var i = 1; i <= pdfDoc.numPages; i++) {
renderPage(i);
}
}

Categories