Как изменить размер изображения в Django Imagefield перед его отправкой с использованием Javascript - PullRequest
0 голосов
/ 01 декабря 2018

Введение: У меня есть сообщение, в котором пользователи могут загружать до 8 изображений.Мой метод развертывания не позволяет мою общую загрузку (общее количество всех изображений должно быть более 10 МБ).Поэтому я не могу использовать подушку или другие пакеты, которые уменьшают размер изображения после загрузки.Я думал, что если я использую Javascript, я могу уменьшить размер изображения, прежде чем я даже отправлю форму.Таким образом, когда я нажимаю «отправить», изображения уже уменьшены, и общее количество всех изображений составляет менее 9 МБ (просто для безопасности)

Код заимствован из:

Использование https://github.com/josefrichter/resize/blob/master/public/preprocess.js

Я не уверен, как их использовать.ниже мой шаблон формы

Это только для моего основного post_image. Мне все еще нужно выяснить, как уменьшить размер моих форм-изображений

{% 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 %}

Я хотел, чтобы размер изображения был уменьшен до 400 КБ.если пользователь загружает меньше, чем это, то нет необходимости в изменении размера

При попытке вашего решения получить следующую ошибку:

enter image description here

enter image description here

1 Ответ

0 голосов
/ 25 февраля 2019

частей кода, помогающих решить эту проблему:

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.

...