Reputation: 1
Up to now i have successfully display the first page preview for one pdf file but it doesn't work for remaining others.
models.py
import uuid
from django.db import models
class PdfUploader(models.Model):
uuid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False)
docfile = models.FileField(upload_to='documents/%Y/%m/%d')
uploaded_at = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'pdf_uploader'
ordering = ['-uploaded_at']
@property
def filename(self):
return self.docfile.name.split("/")[4].replace('_',' ').replace('-',' ')
views.py
class PdfUploadView(CreateView):
def get(self, request, *args, **kwargs):
context = {'form': PdfUploadForm()}
return render(request, 'partials/pdf_upload_form.htm', context)
def post(self, request, *args, **kwargs):
form = PdfUploadForm(request.POST, request.FILES)
files = request.FILES.getlist('docfile')
if form.is_valid():
for f in files:
file_instance = PdfUploader(docfile=f)
file_instance.save()
return HttpResponseRedirect(reverse_lazy('pdf-list'))
return render(request, 'partials/pdf_upload_form.htm', {'form': form})
pdf_upload_form.htm
{% block "content" %}
<div role="main" class="main">
<section class="section section-default pt-5 m-0">
<div class="container">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Upload</button>
</form>
</div>
</section>
</div>
{% endblock %}
pdf_lists.htm By following official official django docs, I am passing a context variable as JSON to the pdf.js.
{% for obj in pdfs %}
<tr>
<td>
{{ forloop.counter }}
</td>
<td>
<a href="{{ obj.docfile.url }}" target="_blank" rel="noopener noreferrer">{{obj.filename}}</a>
</td>
<td>
{{ obj.uploaded_at|date:"d-M-Y" }}
</td>
<td>
<a href="{{obj.docfile.url}}" target="_blank" rel="noopener noreferrer">
<canvas id="the-canvas" style="height:250px;">
</canvas>
{{obj.docfile.url|json_script:'mydata'}}
</a>
</td>
</tr>
{% endfor %}
pdf.js Now I'm reading the previously passed JSON, which contains the path to the user's submitted pdf file to further process it using JS to display the first page of pdf as preview.
const mydata = JSON.parse(document.getElementById('mydata').textContent);
console.log(mydata);
// The workerSrc property shall be specified.
pdfjsLib.GlobalWorkerOptions.workerSrc = '//mozilla.github.io/pdf.js/build/pdf.worker.js';
// Asynchronous download of PDF
var loadingTask = pdfjsLib.getDocument(mydata);
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');
var scale = 0.5;
var viewport = page.getViewport({ scale: scale });
// Prepare canvas using PDF page dimensions
var canvas = document.getElementById('the-canvas');
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
// Render PDF page into canvas context
var renderContext = {
canvasContext: context,
viewport: viewport
};
var renderTask = page.render(renderContext);
renderTask.promise.then(function () {
console.log('Page rendered');
});
});
}, function (reason) {
// PDF loading error
console.error(reason);
});
screenshot of the result: As you can see, the first pdf file displays a preview, while the rest do not.
Upvotes: 0
Views: 4027
Reputation: 600
It can be achieved by creating specific canvas for each PDF file. Please replace the PDF file with your server files.
Here is the js code
function LoadAndPrint()
{
var files = [{name:'sample1.pdf',url:'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/examples/learning/helloworld.pdf'},{name:'sample2.pdf',url:'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/examples/learning/helloworld.pdf'}];
var pdfjsLib = window['pdfjs-dist/build/pdf'];
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://mozilla.github.io/pdf.js/build/pdf.worker.js';
files.forEach(myFunc);
function myFunc(file,i){
idContainer.innerHTML +=
'<span>'+file.name+'</span><canvas id="the-canvas'+i+'"></canvas><hr><br>';
var loadingTask = pdfjsLib.getDocument(file.url);
loadingTask.promise.then(function(pdf) {
console.log('PDF loaded');
var pageNumber = 1;
pdf.getPage(pageNumber).then(function(page) {
console.log('Page loaded');
var scale = 1.1;
var viewport = page.getViewport({scale: scale});
var canvas = document.getElementById("the-canvas"+i);
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 () {
console.log('Page rendered');
});
});
}, function (reason) {
console.error(reason);
});
}
}
.html
<!DOCTYPE html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<script src="https://mozilla.github.io/pdf.js/build/pdf.js"></script>
</head>
<body>
<button id="idPrint" onclick="LoadAndPrint()">Load and Print</button><br>
<div id="idContainer"></div>
</body>
</html>
And here is the JSFiffle
Upvotes: 2
Reputation: 2943
The problem is that you only call your script 1 time. Its input is 1 object with id 'mydata' and one canvas with id 'the-canvas' that serves as output.
What you should do:
First, assign a unique ID to each data and to each canvas element.
For canvas it is simple:
<canvas id="the-canvas{{ forloop.counter }}" style="height:250px;">
</canvas>
For data it is a little more complex due to json_script filter, something like this:
{% with mydata_id="mydata"|add:forloop.counter %}
{{obj.docfile.url|json_script:mydata_id}}
{% endwith %}
Then you also have to know the length of pdfs
, so maybe add something like this after the for loop, quick and dirty:
<script> const mypdfslength = {{ pdfs | length }}; </script>
Just make sure to place this before your JS.
Next, in your js, you have to put all your code inside a for loop from 0 to mypdfslength
.
And, of course, when resolving mydata
and canvas
, make sure to reference them by their new ID, which would be, considering i
is your for loop index:
const mydata = JSON.parse(document.getElementById(`mydata{i}`).textContent);
and
var canvas = document.getElementById(`the-canvas{i}`);
That's it.
Disclaimer: I didn't really test it, but that is definitely the direction.
Upvotes: 0