繁体   English   中英

如何使用 JavaScript ajax 将网络摄像头图像上传到 Django 站点?

[英]How do I upload a webcam image using JavaScript ajax to a Django site?

我正在使用 Django 创建一个直播网站,我需要使用 ajax 发布请求将图像上传到 django 网站上的模型表单。 我正在使用以下代码:

楷模:

from django.db import models
from django.contrib.auth.models import User

class Camera(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name='camera')
    image = models.ImageField(upload_to='live/', null=True, blank=True)

意见:

from .models import Camera
from .forms import CameraForm

@login_required
@csrf_exempt
def golive(request):
    cameras = Camera.objects.filter(user=request.user)
    camera = None
    if cameras.count() == 0:
        camera = Camera.objects.create(user=request.user)
        camera.save()
    else:
        camera = cameras.first()
    if request.method == 'POST':
        print(request.FILES)
        form = CameraForm(request.POST, request.FILES, instance=camera)
        if form.is_valid():
            form.save()
        print("Working")
        return redirect('live:live')
    return render(request, 'live/golive.html', {'object': request.user.camera, 'form': CameraForm()})

@login_required
def live(request, username):
    profile = get_object_or_404(Profile, user__username=username, identity_verified=True, vendor=True)
    cameras = Camera.objects.filter(user=profile.user)
    return render(request, 'live/live.html', {'profile': profile, 'camera': cameras.first()})

模板:

{% extends 'base.html' %}
{% block content %}
<h1>Go live</h1>
<div id="container">
<video autoplay="true" id="video">
</video>
<canvas id="canvas" width="1028" height="728">
</canvas>
<button id="capture"></button>
</div>
{% endblock %}
{% block javascript %}
var video = document.getElementById('video');
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
function capture(){
    ctx.drawImage(video, 0, 0, 1024, 728);
    ctx.save();
    canvas.toBlob(function(blob){
        console.log(blob);
    var fileOfBlob = new File([blob], 'camera.png');
        var formData = new FormData();
    formData.append('image', fileOfBlob, 'camera.png');
        $.ajax({
            url: window.location.pathname,
            type: 'POST',
            data: formData,
            success: function (response) {
        console.log("Captured image.")
            },
            cache: false,
            contentType: false,
            processData: false
        });
    },'image/png');
}
setInterval(capture, 10000);
function startup() {
  navigator.mediaDevices.getUserMedia({video: true, audio: false})
  .then(function(stream) {
    video.srcObject = stream;
    video.play();
  })
  .catch(function(err) {
    console.log("An error occurred: " + err);
  });
}
startup();
{% endblock %}

形式:

from django import forms
from .models import Camera

class CameraForm(forms.ModelForm):
    class Meta:
        model = Camera
        fields = ('image',)

网络摄像头在页面上呈现得很好,但是当我尝试呈现{{ camera.image.url }}时,我看到图像尚未上传。 如何使用 ajax 将 blob 图像上传到 django 站点? 有什么我想念的吗? 这是我得到的错误:

django.http.multipartparser.MultiPartParserError: Invalid boundary in multipart: None

这有点开箱即用,但这是我想出的解决方案。 我只使用 blob 编写了自己的基本编解码器,它使用 setInterval 以较短的间隔收集图像并每 5 秒将它们上传到服务器。 然后我加载图像并拆分它们,使用另一个 setInterval 来显示它们。 这是代码:

楷模:

from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User


class Camera(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name='camera')
    src = models.TextField(default="", null=True, blank=True)
    last_frame = models.DateTimeField(default=timezone.now)

意见:

from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from users.models import Profile
from django.contrib import messages
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_exempt
import datetime
from django.utils import timezone
from django.core.paginator import Paginator
from django.utils.decorators import method_decorator
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth.decorators import user_passes_test
from feed.tests import identity_verified
from vendors.tests import is_vendor
from django.core.exceptions import PermissionDenied
from django.http import StreamingHttpResponse
from django.http import HttpResponse
from django.core.files.storage import FileSystemStorage
import uuid
import imghdr
import os
from django.conf import settings
from .models import Camera
from django.core.files import File
from django.core.files.base import ContentFile
from django.core.files.temp import NamedTemporaryFile
from django import forms
import traceback
from urllib.request import urlopen

@login_required
@user_passes_test(identity_verified, login_url='/verify/', redirect_field_name='next')
@user_passes_test(is_vendor)
@csrf_exempt
def golive(request):
    cameras = Camera.objects.filter(user=request.user)
    camera = None
    if cameras.count() == 0:
        camera = Camera.objects.create(user=request.user)
        camera.save()
    else:
        camera = cameras.first()
    if request.method == 'POST':
        try:
            p = ''
            for key, value in request.POST.items():
                value = value.split('\n')
                p = p + value[2] + value[3] + '*'
            p = p.replace(' ', '+')
            camera.last_frame = timezone.now()
            camera.src = p
            camera.save()
        except:
            print(traceback.format_exc())
        return HttpResponse(status=200)
    return render(request, 'live/golive.html', {'object': request.user.camera})

@login_required
@user_passes_test(identity_verified, login_url='/verify/', redirect_field_name='next')
@csrf_exempt
def live(request, username):
    profile = get_object_or_404(Profile, user__username=username, identity_verified=True, vendor=True)
    cameras = Camera.objects.filter(user=profile.user)
    return render(request, 'live/live.html', {'profile': profile, 'camera': cameras.first()})

@login_required
@user_passes_test(identity_verified, login_url='/verify/', redirect_field_name='next')
@csrf_exempt
def last_frame(request, username):
    profile = get_object_or_404(Profile, user__username=username, identity_verified=True, vendor=True)
    cameras = Camera.objects.filter(user=profile.user)
    return render(request, 'live/lastframe.html', {'profile': profile, 'camera': cameras.first()})


@login_required
@user_passes_test(identity_verified, login_url='/verify/', redirect_field_name='next')
@csrf_exempt
def frame(request, username):
    profile = get_object_or_404(Profile, user__username=username, identity_verified=True, vendor=True)
    cameras = Camera.objects.filter(user=profile.user)
    return render(request, 'live/liveframe.html', {'profile': profile, 'camera': cameras.first()})

模板:

-- The template for viewing the live feed:
{% extends 'base.html' %}
{% block content %}
<h1>@{{ profile.user.username }}'s Live Feed</h1>
<div id="lastFrame"></div>
<div id="container">
<canvas id="videoCanvas" width="512" height="364">
</canvas>
<iframe src="/chat/{{ profile.user.username }}/?hidenavbar=t" width="100%" height="500px">
</iframe>
{% endblock %}
{% block javascript %}
var canvas = document.getElementById("videoCanvas");
var lastFrame = document.getElementById("lastFrame");
if(window.innerWidth > window.innerHeight) {
    canvas.width = parseInt(window.innerWidth * 0.90);
    canvas.height = parseInt(canvas.width * 364/512);
} else {
    canvas.width = parseInt(window.innerWidth * 0.60);
    canvas.height = parseInt(canvas.width * 364/512);
}
let xhr = new XMLHttpRequest();
let xhr2 = new XMLHttpRequest();
function loadListener2(){
        if (xhr2.readyState === xhr2.DONE) {
        if(!xhr2.responseText.includes("Error 500")){
            lastFrame.innerHTML = xhr2.responseText;
            }
    }
}
function loadListener(){
        if (xhr.readyState === xhr.DONE) {
            var data = xhr.responseText.substring(0, xhr.responseText.length)
        data = data.replace(' ', '+');
        data = data.replace(' ', '+');
        data = data.replace('\n','');
            if(!data.includes("Error 500")){
                var images = data.split("*");
        var count = 0;
        var interval = setInterval(function(){
                    canvas.renderImage(images[count]);
            count++;
        }, {{ record_interval }});
        setTimeout(function(){
            clearInterval(interval);
        }, 5000);
        }
        }
}
function render() {
        xhr.addEventListener("load", loadListener);
        xhr.open("POST", window.location.pathname + "frame/", true);
        xhr.send(null);
    xhr2.addEventListener("load", loadListener2);
        xhr2.open("POST", window.location.pathname + "frame/last/", true)
        xhr2.send(null);
}
setInterval(render, 5000);
HTMLCanvasElement.prototype.renderImage = function(blob){
  var ctx = this.getContext('2d');
  var img = new Image();
  img.onload = function(){
    ctx.drawImage(img, 0, 0, canvas.getBoundingClientRect().width, canvas.getBoundingClientRect().height);
    ctx.save();
  };
  img.src = blob;
};
render();
{% endblock %}

-- The template for transmitting it
{% extends 'base.html' %}
{% block content %}
<h1>Go live</h1>
<div id="container">
<video autoplay="true" id="video" width="100%">
</video>
<canvas id="canvas" width="512" height="364" style="visibility: hidden;">
</canvas>
</div>
{% endblock %}
{% block javascript %}
var video = document.getElementById('video');
var canvas = document.getElementById('canvas');
var image = document.getElementById('image');
var form = document.getElementById('input-form');
var ctx = canvas.getContext('2d');
var data;
function drawImage(){
    ctx.drawImage(video, 0, 0, 512, 364);
    ctx.save();
    data = canvas.toDataURL('image/png').replace(' ', '+')
    data = data.replace('\n','');
}
function capture(){
    //console.log(data);
    var dataArray = "";
    var formData = new FormData();
    var count = 0;
    var recordInterval = setInterval(function(){
        drawImage();
        dataArray = dataArray + data + "*";
        count++;
    }, {{ record_interval }});
    setTimeout(function(){
      formData.append("image", new Blob([dataArray], {'type': 'image/png'}), "image.png");
      clearInterval(recordInterval);        
      $.ajax({
        url: window.location.pathname,
        type: 'POST',
        data: formData,
        success: function (response) {
            console.log("Captured image.")
        },
        cache: false,
        processData: false
      });
    }, 5000);
}
setInterval(capture, 5000);
function startup() {
  navigator.mediaDevices.getUserMedia({video: true, audio: false})
  .then(function(stream) {
    video.srcObject = stream;
    video.play();
  })
  .catch(function(err) {
    console.log("An error occurred: " + err);
  });
}
startup();
{% endblock %}

我知道我多次使用 .replace,但这是因为图像需要采用 URL 格式,所以我需要用 '' 替换换行符,用 + 替换空格,然后 blob 将正确呈现。 将打印的 blob 粘贴到浏览器中进行测试也很有效! 但为了获得最佳实践,我在多个地方使用替换来正确格式化 blob。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM