Capture image through webcam using WebcamJS and convert into Pdf
Tags: Convert To Pdf Format, Js, Django, Python, Webcam

Photo by Álvaro Bernal on Unsplash

Django provide ways to save image/file in model. But capturing image through webcam and sending over server will requires external libraries. For that there are many JS libraries which provide such features, WebcamJS is one of them.

For converting image into pdf, i’m going to use JsPdf .

Make sure you have WebcamJS library,JsPdf and Bootstrap in your index file of template . Bootstrap is for css purpose and for its other features. I’m going to use bootstrap modal for webcam.

<button class="btn btn-primary mt-3" data-toggle="modal" data-target="#CaptureModal">Snap</button <div class="modal" id="CaptureModal">

<div class="modal-dialog modal-lg">

<div class="modal-content ">

<div class="modal-header p-2">

<h5 class="modal-title">Webcam Preview</h5>

<button type="button" class="close" data-dismiss="modal">×</button>

</div>

<div class="modal-body p-0">

<div class="row">

<div class="col-md-4">

<div class="" id="my_camera"></div>

<div class="btn-section" style="text-align:center;">

<ul class="list-inline text-center m-1" id="pre_take_buttons">

<li class="list-inline-item" onClick="preview_snapshot()">

<div class=" bg-success rounded text-white p-1" >

<button>Add</button>

</div>

</li>

<li class="list-inline-item" id="upload-section" onClick="upload_pdf()">

<div class="bg-success rounded text-white p-1">

<button>Upload</button>

</div>

</li>

</ul>

<ul class="list-inline m-1" id="post_take_buttons" style="display:none">

<li class="list-inline-item" onClick="save_photo()">

<div class=" bg-success rounded text-white p-1" style="">

<button>Save</button>

</div>

</li>

<li class="list-inline-item" onClick="cancel_preview()" >

<div class="bg-danger rounded text-white p-1" >

<button>Cancel</button>

</div>

</li>

</ul>

</div>

</div>

<div class="col-md-8 ">

<iframe id="pdf_preview" type="application/pdf" src="" style="width:100%;height:350px"></iframe>

</div>

</div>

</div>

</div>

</div>

</div>

Bootstrap modal is all set with few events button . These Buttons are Add,Upload,Save,Cancel binded with onClick event . Before moving to JS part of these buttons , let’s have a look over some feature and function of WebcamJS which i’m going to use.

WebcamJS provides lots of features, some of them are —

Webcam.set() for setting camera with certain parameters.These parameters are -

Webcam.set({

// live preview size

width: 273,

height: 350,



// device capture size

dest_width: 640,

dest_height: 480,



// final cropped size

width: 273,

height: 350,



// format and quality

image_format: 'jpeg',

jpeg_quality: 90,



// flip horizontal (mirror mode)

flip_horiz: false,

}); Second function is Webcam.attach() . Used for initializing and activating a live camera viewer to DOM element.

Webcam.freeze() is used to freeze the camera for previewing the captured image.

Webcam.unfreeze() is used to unfreeze the camera.

Webcam.snap()

To snap a picture, just call the Webcam.snap() function, passing in a callback function. The image data will be passed to your function as a Data URI, which you can then display in your web page, or submit to a server.

document.getElementById('my_result').innerHTML = '<img src="'+data_uri+'"/>';

} );

For more details,you can visit its Webcam.snap( function(data_uri) {document.getElementById('my_result').innerHTML = ' ';} );For more details,you can visit its git repo or link

Now coming to JS part, i’m going to hide and show buttons based on requirements and convert captured image into pdf format.

Note: WebcamJS return Base64 image but it provide methods to convert into different formats also. I’m going to create a js file with name image2pdf.js and will place all js code here only .

var preview_snapshot;

var cancel_preview;

var save_photo;

var save_pdf;

$(document).ready(function(){

$('#CaptureModal').on('shown.bs.modal', function () {

Webcam.set({

// live preview size

width: 273,

height: 350,



// device capture size

dest_width: 640,

dest_height: 480,



// final cropped size

width: 273,

height: 350,



// format and quality

image_format: 'jpeg',

jpeg_quality: 90,



// flip horizontal (mirror mode)

flip_horiz: false,

});

Webcam.attach( '#my_camera' );

});



var images = [];

$("#pdf_preview").hide();

$("#upload-section").hide();



preview_snapshot = function () {

// freeze camera so user can preview current frame

Webcam.freeze();



// swap button sets

$("#post_take_buttons").show();

$("#pre_take_buttons").hide();

}



cancel_preview = function() {

// cancel preview freeze and return to live camera view

Webcam.unfreeze();

// swap buttons back to first set

$("#post_take_buttons").hide();

$("#pre_take_buttons").show();

}



save_photo = function(upload=0) {

// actually snap photo (from preview freeze) and display it

Webcam.snap( function(data_uri) {

const doc = window.jspdf.jsPDF({});

images.push(data_uri)

if(upload){

// handle uplooad part here

for(img in images){

doc.addImage(images[img], 'JPEG', 15, 40, 180, 180);

if(img != images.length-1){

doc.addPage();

}

}

doc.output("datauristring") // return pdf base64 data

console.log(doc.output("datauristring"))



}

else{

for(img in images){

doc.addImage(images[img], 'JPEG', 15, 40, 180, 180);

if(img != images.length-1){

doc.addPage();

}

}



$("#pdf_preview").show();

$("#pdf_preview").attr('src', doc.output("datauristring"))

localStorage.setItem("doc_pdf",doc.output("datauristring"));



// $("#results").show();

$("#upload-section").show();

$("#post_take_buttons").hide();

$("#pre_take_buttons").show();

}

} );



}



});





$('#CaptureModal').on('hidden.bs.modal', function () {



Webcam.reset();

});

Don’t worry, i’ll describe above code. Once browser is loaded i’m triggering my capture modal (id-#CaptureModal) to display then setting my webcam with essential parameters. Webcam is all set now time to initialise the webcam using function - Webcam.attach( ‘#my_camera’ ); . image array is for capturing all image data.

preview_snapshot = function () {

// freeze camera so user can preview current frame

Webcam.freeze();



// swap button sets

$("#post_take_buttons").show();

$("#pre_take_buttons").hide();



} Here camera freezed and we can able to preview the image which is going to be captured.

If you didn’t like preview image and want to take another shot, cancel function provide this feature.

cancel_preview = function() {

// cancel preview freeze and return to live camera view

Webcam.unfreeze();

// swap buttons back to first set

$("#post_take_buttons").hide();

$("#pre_take_buttons").show();

}

In save_photo method i’m converting base64 image into pdf using JsPdf and showing pdf preview in <iframe> .

localStorage.setItem("doc_pdf",doc.output("datauristring"));

i'm storing pdf data into browser local storage for sending over server.

Now i’m going to send this pdf file in django view through ajax.

function upload_pdf(){

var form_doc = localStorage.getItem("doc_pdf");

$.ajax({

url: "{%url 'scan-upload' pk=user.pk%}",

type:'POST',

data:{'form_doc':form_doc},

headers: {'X-CSRFToken': $.cookie("csrftoken")},

success: function(result){

localStorage.clear()

window.location.href = window.location.href

}

})

}

For handling CSRF Token use below cdn.

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>

Now in my view.py file .

def scan_and_upload(request,pk):

user = User.objects.get(pk=pk)

form_doc = request.POST.get('form_doc',None) frmt, pdfstr = form_doc.split(';base64,')

ext = frmt.split('.')[-1]

pdf_data = ContentFile(base64.b64decode(pdfstr), name='{}_doc.{}'.format(user,ext))

form = DocScanUploadForm(request.POST,instance={'user':user})

if form.is_valid():

form.instance.form_doc = pdf_data

form.save()

messages.success(request,'Document uploaded')

result = 'success'

else:

result = 'error'

messages.error(request,form.errors)



return JsonResponse({'result':result})

In scan_upload view i’m decoding base64 pdf data and then saving it to my model .

That’s it !! Thank you.