javascript - 如何在使用 Javascript 提交之前调整 Django Imagefield 中的图像大小

标签 javascript django django-forms javascript-objects dom-events

简介:我有一篇文章,其中用户最多可以上传 8 张图片。我的部署方法不允许我上传总大小(所有图像的总和超过 10mb)。所以我不能使用 Pillow 或其他在上传后减小图像大小的软件包。我在想如果我使用 Javascript,我什至可以在提交表单之前减小图像大小。这样,当我点击提交时,图像已经缩小,并且所有图像的总大小小于 9mb(只是为了安全起见)

代码借自:

使用https://github.com/josefrichter/resize/blob/master/public/preprocess.js

我不知道如何使用它们。下面是我的表单模板

This is just for my main post_image I still have to figure out how to reduce the size of my formset images

{% extends 'posts/post_base.html' %}
{% load bootstrap3 %}
{% load staticfiles %}    
{% block postcontent %}

<h2> Add a new Post</h2>
<form action="" method="post" enctype="multipart/form-data" id="form">
    {% csrf_token %}
    {% bootstrap_form form %}
    <img id="preview" src="" width="100" />
    {{formset.management_form}}
    {% for f in formset %}
        <div style="border-style: inset; padding:20px;">
          <p class="text-warning">Extra Image {{forloop.counter}}</p>
          {% bootstrap_form f %}
          <img src="" width="60" id="preview-extra{{forloop.counter}}"/>
        </div>
    {% endfor %}

    <br/><br/><input type="submit" class="btn btn-primary" value="Post"/>

</form>


<script >

var fileinput = document.getElementById('fileinput');

var max_width = 500;
var max_height = 500;

var preview = document.getElementById('preview');

var form = document.getElementById('form');

function processfile(file) {

    if( !( /image/i ).test( file.type ) )
        {
            alert( "File "+ file.name +" is not an image." );
            return false;
        }

    // read the files
    var reader = new FileReader();
    reader.readAsArrayBuffer(file);

    reader.onload = function (event) {
      // blob stuff
      var blob = new Blob([event.target.result]); // create blob...
      window.URL = window.URL || window.webkitURL;
      var blobURL = window.URL.createObjectURL(blob); // and get it is URL

      // helper Image object
      var image = new Image();
      image.src = blobURL;
      //preview.appendChild(image); // preview commented out, I am using the canvas instead
      image.onload = function() {
        // have to wait till it is loaded
        var resized = resizeMe(image); // send it to canvas
        var newinput = document.createElement("input");
        newinput.type = 'hidden';
        newinput.name = 'images[]';
        newinput.value = resized; // put result from canvas into new hidden input
        form.appendChild(newinput);
      }
    };
}

function readfiles(files) {

    // remove the existing canvases and hidden inputs if user re-selects new pics
    var existinginputs = document.getElementsByName('images[]');
    var existingcanvases = document.getElementsByTagName('canvas');
    // it is a live list so removing the first element each time DOMNode.prototype.remove = function() {this.parentNode.removeChild(this);}
    while (existinginputs.length > 0) {
      form.removeChild(existinginputs[0]);
      preview.removeChild(existingcanvases[0]);
    }

    for (var i = 0; i < files.length; i++) {
      processfile(files[i]); // process each file at once
    }
    fileinput.value = ""; //remove the original files from fileinput
    // TODO remove the previous hidden inputs if user selects other files
}

// this is where it starts. event triggered when user selects files
fileinput.onchange = function(){
  if ( !( window.File && window.FileReader && window.FileList && window.Blob ) ) {
    alert('The File APIs are not fully supported in this browser.');
    return false;
    }
  readfiles(fileinput.files);
};

// === RESIZE ====

function resizeMe(img) {

  var canvas = document.createElement('canvas');

  var width = img.width;
  var height = img.height;

  // calculate the width and height, constraining the proportions
  if (width > height) {
    if (width > max_width) {
      //height *= max_width / width;
      height = Math.round(height *= max_width / width);
      width = max_width;
    }
  } else {
    if (height > max_height) {
      //width *= max_height / height;
      width = Math.round(width *= max_height / height);
      height = max_height;
    }
  }

  // resize the canvas and draw the image data into it
  canvas.width = width;
  canvas.height = height;
  var ctx = canvas.getContext("2d");
  ctx.drawImage(img, 0, 0, width, height);

  preview.appendChild(canvas); // do the actual resized preview

  return canvas.toDataURL("image/jpeg",0.7); // get the data from canvas as 70% JPG (can be also PNG, etc.)

}
</script>
{% endblock %}

I wanted image size to be reduced to 400kb. if the user uploads less than that then no resize needed

尝试您的解决方案时出现以下错误

enter image description here

enter image description here

最佳答案

以下部分代码可帮助您解决此问题:

views.py:

import re
import io
import base64

from django.core.files import File
from django.shortcuts import render

from .forms import StoreImageForm


def upload_canvas(request):
    form = StoreImageForm()
    if request.method == 'POST':
        image_base64 = request.POST.get('image_base64', '')
        res = re.match(r'^([^,]*),(.*)$', image_base64)
        if res:
            ext = re.match(r'^data:image/(.+);base64$', res.groups()[0]).groups()[0]
            image = base64.b64decode(res.groups()[-1])
            buf = io.BytesIO(image)
            form = StoreImageForm(files={'upload_file': File(buf, name=f'name.{ext}')})
            try:
                form.is_valid()
            except Exception as err:
                return render(request, 'form.html', {'message': err, 'form': form})
            instance = form.save()
            return render(request, 'form.html', {'message': 'Image Uploaded Successfuly', 'form': form})
        return render(request, 'form.html', {'message': 'Image Upload Failed', 'form': form})
    return render(request, 'form.html', {'message': 'Upload Image...', 'form': form})

form.html:

<html>
    <head>
        <title>Upload Canvas</title>
        <script lang="javascript">
            function resize_image(event) {
                var canvas = document.getElementById("my_canvas");
                var ctx = canvas.getContext("2d");
                var reader = new FileReader();
                var img = new Image();
                var type = '';
                var ratio = 1;

                img.onerror = function(e) {
                  console.log("Not ok", e);
                }

                img.onload = function (img_onload_event) {
                    canvas.height = canvas.width * (img.height / img.width);

                    // step 1 - resize to 50%
                    var oc = document.createElement('canvas'),
                        octx = oc.getContext('2d');

                    oc.width = img.width * ratio;
                    oc.height = img.height * ratio;
                    octx.drawImage(img, 0, 0, oc.width, oc.height);

                    // step 2
                    octx.drawImage(oc, 0, 0, oc.width, oc.height);

                    // step 3, resize to final size
                    ctx.drawImage(oc, 0, 0, oc.width, oc.height, 0, 0, canvas.width, canvas.height);

                    var dataURL = oc.toDataURL(type, ratio)
                    // var blob = dataURItoBlob(dataURL)

                    b64 = dataURL;
                    padding = (b64.charAt(b64.length - 2) === '=') ? 2 : ((b64.charAt(b64.length - 1) === '=') ? 1 : 0);
                    fileSize = (b64.length * 0.75 - padding) / 1024;
                    if(fileSize > 500) {
                        img.src = b64;
                        return;
                    }

                    var my_image_base64 = document.getElementById('my_image_base64')
                    my_image_base64.setAttribute("value", dataURL)
                }

                reader.onload = function (e) {
                    b64 = reader.result;
                    padding = (b64.charAt(b64.length - 2) === '=') ? 2 : ((b64.charAt(b64.length - 1) === '=') ? 1 : 0);
                    fileSize = (b64.length * 0.75 - padding) / 1024;
                    if(fileSize > 500){
                        ratio = 0.8
                    }

                    img.src = e.target.result;
                }
                type = event.target.files[0].type || 'image/jpeg';
                reader.readAsDataURL(event.target.files[0]);
            }


            window.onload = function(){
                document.getElementById('my_image').addEventListener('change', resize_image, false);
            }
        </script>
    </head>

    <body>
        <h2>{{ message }}</h2>
        <form method="post">
            {% csrf_token %}
            <input  type="file"  id="my_image" />
            <input  type="hidden" id="my_image_base64" name="image_base64" />
            <button id="upload_button"> Upload </button>
        </form>
        <br/>
        <canvas id="my_canvas" width="500" />
    </body>
</html>

forms.py:

from django import forms

from .models import UploadModel


class StoreImageForm(forms.ModelForm):
    class Meta:
        model = UploadModel
        fields = ['upload_file']

models.py:

from django.db import models


class UploadModel(models.Model):
    upload_file = models.ImageField()

查看我的image-minimizer-uploader github 中的项目。

关于javascript - 如何在使用 Javascript 提交之前调整 Django Imagefield 中的图像大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53574026/

相关文章:

django - 外键和 Django 模板

django - 有没有办法动态定义字段,但不是最后一个字段?

javascript - jQuery.append() 在与转换一起使用时出现异步

javascript - 如何更改 div 内 div 的内容?

javascript - Bootstrap 图像滑动时更改 div 背景颜色

python - Django 站点地图静态页面

返回属性而不是字符串(unicode)的 Python 字符串格式?

python - 将 Django 中的 ManyToMany 关系表示为两个多项选择

django模型形式带有外键的干净方法

javascript - QML 报告 ReferenceError : XYZ is not defined on C++ object added to context