Home > Blockchain >  Saving image captured from webcam
Saving image captured from webcam

Time:07-11

I'm building a Django project in which I need to take a picture from webcam, and then store it in my database and as a file. I'm saving the source in the database, but I'm having some trouble saving it as a file. Here is my code:

html:

<form method="POST" action="{% url 'takePhoto' %}" enctype="multipart/form-data">
    {% csrf_token %}
                                     
            <video id="video" autoplay ></video>                               
            <canvas id="canvas"></canvas>                                
                     
            <input type="hidden" name="photo" id="photo" value=""/>
            <button id="startbutton1" >Take Photo</button>
            <button id="submit" type="submit">submit</button>
            <script src="{% static 'scripts/script.js' %}"></script>             

javascript:

(function() {

var width = 320;    
  var height = 0;    
  var streaming = false;  
  var video = null;
  var canvas = null;
  var photo = null;
  var startbutton1 = null;

  function startup() {
    video = document.getElementById('video');
    canvas = document.getElementById('canvas');

photo = document.getElementById('photo');
startbutton1 = document.getElementById('startbutton1');

navigator.mediaDevices.getUserMedia({video: true, audio: false})
.then(function(stream) {
  video.srcObject = stream;
  video.play();
})
.catch(function(err) {
  console.log("An error occurred: "   err);
});

video.addEventListener('canplay', function(ev){
  if (!streaming) {
    height = video.videoHeight / (video.videoWidth/width);


    if (isNaN(height)) {
      height = width / (4/3);
    }

    video.setAttribute('width', width);
    video.setAttribute('height', height);
    canvas.setAttribute('width', width);
    canvas.setAttribute('height', height);
    streaming = true;
  }
}, false);

startbutton1.addEventListener('click', function(ev){
  takepicture();
  ev.preventDefault();
}, false);

clearphoto();


}
  



function clearphoto() {
    var context = canvas.getContext('2d');
    context.fillStyle = "#AAA";
    context.fillRect(0, 0, canvas.width, canvas.height);
var data = canvas.toDataURL('image/png');
photo.setAttribute('src', data);


 }

  function takepicture() {
    var context = canvas.getContext('2d');
    if (width && height) {
  canvas.width = width;
  canvas.height = height;
  context.drawImage(video, 0, 0, width, height);

  var data = canvas.toDataURL('image/png');
  photo.value=data;
} else {
  clearphoto();


 } 


}



window.addEventListener('load', startup, false);
})();

views:

def takePhoto(request):
   print("works")
   if not request.session.get('logged_in'):
       return redirect('/appChallenge/login')
   if request.method== 'POST':        
       user = User.objects.get(username=request.session["username"])
       img = request.POST.get("photo")
       image = img
       imagePath="/media"
       a=str(img)
       image = image.save(f"{imagePath}/{a}.png")
       imgInfo= Image(user=user, img=img)
       imgInfo.save()    
       print("works")
       return render(request, 'page.html')

When I click submit, it says "'str' object has no attribute 'save'" Please help. Thanks.

CodePudding user response:

If your js/html code works, you will receive a raw image data encoded to base64 in your view 'takePhoto'. Try print(img) to see something like "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUAAAADwCAYAA...."

Maybe you will see just "iVBORw0KGgoAAAANSUhEUgAAAUAAAADwCAYAA...." without meta data.

So your 'img' is just a string with base64 encoded value, that hasn't method 'save'.

First, you need to get rid of "data:image/png;base64," in your raw image data, if your image string contains it. It is meta data and base64 could not decode it. You can do it at front end side:

var data = canvas.toDataURL('image/png').replace(/^data:image\/png;base64,/, "")

Or back end:

img = request.POST.get("photo").replace('data:image/png;base64,', '')

Next you need to use django ContentFile to create a file-like object. You need to simulate file with its method .read(). Also you need to decode base64 encoded image data:

import base64
from django.core.files.base import ContentFile
    
def takePhoto(request):
   print("works")
   if not request.session.get('logged_in'):
       return redirect('/appChallenge/login')
   if request.method== 'POST':        
       user = request.user
       
       # remove meta data from base64 encoded data, you can also 
       # use 'split(',')[1]' to remove all before ','
       img = request.POST.get("photo").replace('data:image/png;base64,', '')
       # create a file-like object with your image data 
       image_file_like = ContentFile(base64.b64decode(img))
       
       # first you need to create object
       image = Image(user=user)
       
       # and then save image into your model object
       # note: only if your 'img' field is 'ImageField' or similar 
       image.img.save("filename.png", image_file_like)
       image.save() 

       print("works")
       return render(request, 'page.html') 

P.S:

You don't need to add 'media' prefix in your image file name while saving it.

You should add MEDIA_ROOT variable in your settings.py like this:

BASE_DIR = Path(__file__).resolve().parent.parent # or manually set the path of your project
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

And all files automatically will be saved in your project media directory.

  • Related