diff --git a/requirements/base.txt b/requirements/base.txt index 7774738..03dd5b1 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -72,3 +72,4 @@ redis==2.10.5 trans==2.1.0 python-decouple==3.0 flake8==3.2.1 +numpy==1.13.0 diff --git a/src/customer/urls.py b/src/customer/urls.py index 12b922f..b650399 100644 --- a/src/customer/urls.py +++ b/src/customer/urls.py @@ -82,4 +82,5 @@ urlpatterns = \ name='customer_clients_delete_ajax'), url(r'^tmp_upload/ajax/$', profile.tmp_upload, name='upload_tmp_file'), + url(r'^upload-image/ajax/$', profile.upload_image, name='upload-image'), ) diff --git a/src/customer/views/profile.py b/src/customer/views/profile.py index 8880eb3..2f02946 100644 --- a/src/customer/views/profile.py +++ b/src/customer/views/profile.py @@ -1,11 +1,20 @@ # -*- coding: utf-8 -*- import os import json + +import shutil import tempfile + +from PIL import Image +import numpy as np + +from base64 import b64decode from email.header import Header +from django.core.files.storage import FileSystemStorage from django.shortcuts import render, redirect from django.core.files import File +from django.core.files.base import ContentFile from django.views.decorators.csrf import csrf_protect from django.contrib.auth.decorators import login_required from django.template.loader import render_to_string @@ -82,11 +91,14 @@ def profile_view(request): @login_required @csrf_protect def profile_edit(request): - """Редактировать профиль пользователя.""" + """ + Редактировать профиль пользователя. + """ raise_if_no_profile(request) template_name = 'customer/profile/edit.html' success_url = 'customer_profile_view' + tmp_dir = '' if request.method == 'POST' and '_cancel' in request.POST: return redirect(success_url) @@ -105,20 +117,21 @@ def profile_edit(request): item = form.save(commit=False) for img_url in ('tmb_logo', 'tmb_boss_sign', 'tmb_glavbuh_sign', 'tmb_stamp'): + if form.cleaned_data[img_url]: - # TODO ? - chg_file = open(settings.MEDIA_ROOT + '/cache/imgs/' + - form.cleaned_data[img_url], mode='rb+') + path = f'{settings.MEDIA_ROOT}/cache/images/{form.cleaned_data[img_url]}' + tmp_dir = form.cleaned_data[img_url].split('/')[0] + chg_file = open(path, mode='rb+') item_attr = img_url[4:] getattr(item, item_attr).\ save('%s.%s' % (item_attr, form.cleaned_data[img_url].split('.')[-1]), File(chg_file)) chg_file.close() - # - elif form.cleaned_data: - pass + item.save() + if tmp_dir: + shutil.rmtree(f'{settings.MEDIA_ROOT}/cache/images/{tmp_dir}') return redirect(success_url) else: form = form_class(instance=profile) @@ -161,6 +174,55 @@ def tmp_upload(request): return HttpResponse(json.dumps(data), content_type='application/json') +def save_file(path, file): + fs = FileSystemStorage() + file_path = fs.save(path, file) + return file_path + + +def clean_background(file): + + threshold = 100 + dist = 5 + img = Image.open(file).convert('RGBA') + # np.asarray(img) is read only. Wrap it in np.array to make it modifiable. + arr = np.array(np.asarray(img)) + r, g, b, a = np.rollaxis(arr, axis=-1) + mask = ((r > threshold) + & (g > threshold) + & (b > threshold) + & (np.abs(r - g) < dist) + & (np.abs(r - b) < dist) + & (np.abs(g - b) < dist) + ) + arr[mask, 3] = 0 + img = Image.fromarray(arr, mode='RGBA') + img.save(file) + return file + + +def upload_image(request): + + name = request.POST.get('name') + if not os.path.exists(settings.MEDIA_ROOT + '/cache/images/'): + os.makedirs(settings.MEDIA_ROOT + '/cache/images/') + tmp_dir = tempfile.mkdtemp('img_tmp', settings.MEDIA_ROOT + '/cache/images/') + b64_text = request.POST.get('image') + format_file, img_str = b64_text.split(';base64,') + ext = format_file.split('/')[-1] + file_name = f'{name}.{ext}' + full_path = f'{tmp_dir}/{file_name}' + file = ContentFile(b64decode(img_str), name=file_name) + file = save_file(full_path, file) + if name != 'logo': + file = clean_background(file) + url = os.path.join(settings.MEDIA_URL, os.path.relpath(file, settings.MEDIA_ROOT)) + short_url = os.path.basename(tmp_dir) + '/' + file_name + data = {'msg': 'success', 'url': url, 'short_url': short_url} + + return HttpResponse(json.dumps(data), content_type='application/json') + + @login_required def _profile_get_pdf(request, profile=None, account=None, filters=None): """ diff --git a/src/dokumentor/static/js/profile/asset.js b/src/dokumentor/static/js/profile/asset.js index 6d3f80f..d4dc89d 100644 --- a/src/dokumentor/static/js/profile/asset.js +++ b/src/dokumentor/static/js/profile/asset.js @@ -36,19 +36,50 @@ $(document).ready(function () { } } - $uploadCrop = $('#imageCropper').croppie({ + function getCropForm(field) { + var result; + if (field === 'stamp') { + result = 'circle' + } else { + result = 'square' + } + return result + } + + function getCropHeight(field) { + var result; + if (field === 'stamp' || field === 'logo') { + result = 200 + } else { + result = 76 + } + return result + } + + function initCropper(width, height, type) { + $uploadCrop = $('#imageCropper').croppie({ enableExif: true, enforceBoundary: false, viewport: { - width: 200, - height: 200, - type: 'circle' + width: width, + height: height, + type: type }, boundary: { width: 300, height: 300 } - }); + }); + } + + function uploadImageOnServer(data) { + // $('#' + imagePreview + ' img').attr('src', imgBase); + $('#' + imagePreview + ' img').attr('src', data['url']); + $('#id_tmb_' + imagePreview).val(data['short_url']); + $('#' + imagePreview + ' .del_image').show(); + // console.log('id_tmb_' + imagePreview); + console.log(data) + } // select file $('.img_load img').on('click', function() { @@ -62,7 +93,10 @@ $(document).ready(function () { }); // set file in input hidden filed - $('.img_load input[type=file]').on('change', function () {readFile(this)}); + $('.img_load input[type=file]').on('change', function () { + initCropper(200,getCropHeight(imagePreview), getCropForm(imagePreview)); + console.log($uploadCrop); + readFile(this)}); $('#containerUpload').on("ShowModal", function( ) { $('#containerUpload').visible(); @@ -80,15 +114,32 @@ $(document).ready(function () { size: 'viewport' }).then(function (resp) { // console.log(resp); - $('#' + imagePreview + ' img').attr('src', resp); + + var formData = new FormData(); + formData.append('image', resp); + formData.append('name', imagePreview); + + $.ajax({ + type: 'POST', + url: '/my/upload-image/ajax/', + success: uploadImageOnServer, + data: formData, + cache: false, + contentType: false, + processData: false + }).done(function(json) { + console.log(json); + }); + $('#containerUpload').trigger("CloseModal"); - $('#' + imagePreview + ' .del_image').show(); + }) }); $('#containerUpload').on("CloseModal", function( ) { $('#containerUpload').invisible(); $('#' + imageInputField).val(''); + $('#imageCropper').croppie('destroy'); }); var closeButtons=document.getElementsByClassName("modal-upload__cleaner-btn"); diff --git a/src/dokumentor/templates/customer/profile/edit.html b/src/dokumentor/templates/customer/profile/edit.html index cffe51a..a0d1065 100644 --- a/src/dokumentor/templates/customer/profile/edit.html +++ b/src/dokumentor/templates/customer/profile/edit.html @@ -509,93 +509,21 @@ }; + + + + + + + + - {% comment %} - -{% endcomment %} - - - - - - - - - - - {% include 'hbs/bank-tpl.html' %} + {% include 'hbs/bank-tpl.html' %} {% endblock js %}