diff options
Diffstat (limited to 'old/server/app/main')
| -rw-r--r-- | old/server/app/main/__init__.py | 5 | ||||
| -rw-r--r-- | old/server/app/main/errors.py | 32 | ||||
| -rw-r--r-- | old/server/app/main/forms.py | 60 | ||||
| -rw-r--r-- | old/server/app/main/img_proc_config.py | 20 | ||||
| -rw-r--r-- | old/server/app/main/paths.py | 19 | ||||
| -rw-r--r-- | old/server/app/main/tasks.py | 374 | ||||
| -rw-r--r-- | old/server/app/main/utils.py | 37 | ||||
| -rw-r--r-- | old/server/app/main/views.py | 300 |
8 files changed, 847 insertions, 0 deletions
diff --git a/old/server/app/main/__init__.py b/old/server/app/main/__init__.py new file mode 100644 index 00000000..a21e2754 --- /dev/null +++ b/old/server/app/main/__init__.py @@ -0,0 +1,5 @@ +from flask import Blueprint + +main = Blueprint('main', __name__) + +from . import views, errors, tasks, utils
\ No newline at end of file diff --git a/old/server/app/main/errors.py b/old/server/app/main/errors.py new file mode 100644 index 00000000..60b5f227 --- /dev/null +++ b/old/server/app/main/errors.py @@ -0,0 +1,32 @@ +from flask import render_template, request, jsonify +from . import main + + +@main.app_errorhandler(403) +def forbidden(e): + if request.accept_mimetypes.accept_json and \ + not request.accept_mimetypes.accept_html: + response = jsonify({'error': 'forbidden'}) + response.status_code = 403 + return response + return render_template('403.html'), 403 + + +@main.app_errorhandler(404) +def page_not_found(e): + if request.accept_mimetypes.accept_json and \ + not request.accept_mimetypes.accept_html: + response = jsonify({'error': 'not found'}) + response.status_code = 404 + return response + return render_template('404.html'), 404 + + +@main.app_errorhandler(500) +def internal_server_error(e): + if request.accept_mimetypes.accept_json and \ + not request.accept_mimetypes.accept_html: + response = jsonify({'error': 'internal server error'}) + response.status_code = 500 + return response + return render_template('500.html'), 500 diff --git a/old/server/app/main/forms.py b/old/server/app/main/forms.py new file mode 100644 index 00000000..bc1399ad --- /dev/null +++ b/old/server/app/main/forms.py @@ -0,0 +1,60 @@ +from flask.ext.wtf import Form +from wtforms import StringField, TextAreaField, BooleanField, SelectField,\ + SubmitField +from wtforms.validators import Required, Length, Email, Regexp +from wtforms import ValidationError +from flask.ext.pagedown.fields import PageDownField +from ..models import Role, User + + +class NameForm(Form): + name = StringField('What is your name?', validators=[Required()]) + submit = SubmitField('Submit') + + +class EditProfileForm(Form): + name = StringField('Real name', validators=[Length(0, 64)]) + location = StringField('Location', validators=[Length(0, 64)]) + about_me = TextAreaField('About me') + submit = SubmitField('Submit') + + +class EditProfileAdminForm(Form): + email = StringField('Email', validators=[Required(), Length(1, 64), + Email()]) + username = StringField('Username', validators=[ + Required(), Length(1, 64), Regexp('^[A-Za-z][A-Za-z0-9_.]*$', 0, + 'Usernames must have only letters, ' + 'numbers, dots or underscores')]) + confirmed = BooleanField('Confirmed') + role = SelectField('Role', coerce=int) + name = StringField('Real name', validators=[Length(0, 64)]) + location = StringField('Location', validators=[Length(0, 64)]) + about_me = TextAreaField('About me') + submit = SubmitField('Submit') + + def __init__(self, user, *args, **kwargs): + super(EditProfileAdminForm, self).__init__(*args, **kwargs) + self.role.choices = [(role.id, role.name) + for role in Role.query.order_by(Role.name).all()] + self.user = user + + def validate_email(self, field): + if field.data != self.user.email and \ + User.query.filter_by(email=field.data).first(): + raise ValidationError('Email already registered.') + + def validate_username(self, field): + if field.data != self.user.username and \ + User.query.filter_by(username=field.data).first(): + raise ValidationError('Username already in use.') + + +class PostForm(Form): + body = PageDownField("What's on your mind?", validators=[Required()]) + submit = SubmitField('Submit') + + +class CommentForm(Form): + body = StringField('Enter your comment', validators=[Required()]) + submit = SubmitField('Submit') diff --git a/old/server/app/main/img_proc_config.py b/old/server/app/main/img_proc_config.py new file mode 100644 index 00000000..db124978 --- /dev/null +++ b/old/server/app/main/img_proc_config.py @@ -0,0 +1,20 @@ +# paths for image processors +import os +from os.path import join + +class ImgProcConfig: + + def __init__(self): + dir_models = '/data_store/apps/dulldream/dnn_models' + + # mask rcnn + self.mask_rcnn_class_config = '/dulldream/src/config/coco_meta.json' + self.mask_rcnn_model = join(dir_models,'tf/mask_rcnn_coco.h5') + + # p2p + self.p2p_ckpts_dir = join(dir_models,'p2p/coco2014_person') + self.p2p_epoch = 'latest' + + # p2p objects only + self.p2p_bg_ckpts_dir = join(dir_models,'p2p/coco2014_objects') + self.p2p_bg_epoch = 'latest' diff --git a/old/server/app/main/paths.py b/old/server/app/main/paths.py new file mode 100644 index 00000000..69c21627 --- /dev/null +++ b/old/server/app/main/paths.py @@ -0,0 +1,19 @@ +from flask import current_app as app + +def get_paths(agree): + if agree: + return ( + app.config['UPLOADS'], + app.config['RENDERS'], + app.config['JSON_DIR'], + app.config['UPLOADS_URI'], + app.config['RENDERS_URI'], + ) + else: + return ( + app.config['UPLOADS_PRIVATE'], + app.config['RENDERS_PRIVATE'], + app.config['JSON_PRIVATE_DIR'], + app.config['UPLOADS_PRIVATE_URI'], + app.config['RENDERS_PRIVATE_URI'], + ) diff --git a/old/server/app/main/tasks.py b/old/server/app/main/tasks.py new file mode 100644 index 00000000..970e6988 --- /dev/null +++ b/old/server/app/main/tasks.py @@ -0,0 +1,374 @@ +import os +import sys +import time +import datetime +import json +from PIL import Image, ImageFilter +import cv2 as cv +import numpy as np +from . import main, utils +from .. import basemodels +from flask import current_app as app +from .paths import get_paths +celery = basemodels.celery +from celery.utils.log import get_task_logger +celery_logger = get_task_logger(__name__) +import imutils + + +# init image processors +sys.path.append('/dulldream/src/') +from .img_proc_config import ImgProcConfig +from image_processors.mask_rcnn import MaskRCNN +from image_processors.pix2pix import Pix2Pix +from utils import imx +from utils import fiox + + +# initialize image processor +img_proc_config = ImgProcConfig() +p2p = Pix2Pix(img_proc_config.p2p_ckpts_dir,epoch=img_proc_config.p2p_epoch) +p2p_objects = Pix2Pix(img_proc_config.p2p_bg_ckpts_dir,epoch=img_proc_config.p2p_epoch) + +mask_rcnn = MaskRCNN(img_proc_config.mask_rcnn_class_config, + model_path=img_proc_config.mask_rcnn_model) + + +@celery.task(bind=True) +def task_dull(self, uuid_name, agree, mask_rcnn_result): + """Process image and update during""" + celery_logger.debug('process_image_task, uuid: {}'.format(uuid_name)) + + upload_dir, render_dir, json_dir, upload_uri, render_uri = get_paths(agree) + + files = [] + im = Image.open(os.path.join(upload_dir, uuid_name + '.jpg')).convert('RGB') + #im_np = cv.cvtColor(imx.ensure_np(im),cv.COLOR_RGB2BGR) + im_np = imx.ensure_np(im) + im_np = im_np[:,:,::-1] + im = im.resize((256,256)) + im_np_256 = imutils.resize(im_np,width=256) + + # Add original + fpath = os.path.join(render_dir, uuid_name + '_orig.jpg') + im.save(fpath, 'JPEG', quality=95) + files.append({ + 'title': 'Original', + 'fn': render_uri + uuid_name + '_orig.jpg' + }) + + if mask_rcnn_result['valid']: + # ----------------------------------------------- + # Segment image (processed in views) + # seems to be an error with async celery processor? + # ----------------------------------------------- + + # parse mrcnn data + im_mask = cv.imread(mask_rcnn_result['fp_im_mask']) + seg_mask = cv.imread(mask_rcnn_result['fp_seg_mask']) + #score = mask_rcnn_result['score'] + #name = mask_rcnn_result['name'] + #color = mask_rcnn_result['color'] + files.append({ + 'title': 'Semantic Segmentation', + 'fn': render_uri + uuid_name + '_seg_mask.jpg' + }) + files.append({ + 'title': 'Semantic Segmentation Isolate', + 'fn': render_uri + uuid_name + '_im_mask.jpg' + }) + + + # ----------------------------------------------- + # run rag generator + # ----------------------------------------------- + + self.update_state( + state = 'PROCESSING', + meta = { + 'percent': 0.50, + 'message': 'Applying Region Adjacency Graph', + 'uuid': uuid_name + }) + + # save the regions adjancency graph + im_rag = imx.create_rag_mean(im_mask,compactness=30,n_segments=128) + fpath = os.path.join(render_dir, uuid_name + '_rgraph.jpg') + imx.save_np_as_pil(fpath,im_rag,quality=95) + files.append({ + 'title': 'Region Adjacency Graph', + 'fn': render_uri + uuid_name + '_rgraph.jpg' + }) + + + # ----------------------------------------------- + # generate p2p fake + # ----------------------------------------------- + + self.update_state( + state = 'PROCESSING', + meta = { + 'percent': 0.75, + 'message': 'Running generative adversarial network...', + 'uuid': uuid_name + }) + + + # convert segmentation to mask + seg_mask_gray = cv.cvtColor(seg_mask,cv.COLOR_BGR2GRAY) + seg_mask_gray[seg_mask_gray > 1] = 255 + + # find best P2P fit + ims_p2p = [] + match_amts = [] + iters = 15 + for i in range(0,iters): + im_p2p = p2p.create_p2p(im_rag) + ims_p2p.append(im_p2p) + im_p2p_mask = cv.cvtColor(im_p2p,cv.COLOR_RGB2GRAY) + im_p2p_mask[im_p2p_mask > 1] = 255 + # find where masks intersect + matches = np.bitwise_and(im_p2p_mask,seg_mask_gray) + amt = len(np.where(matches == 255)[0]) + match_amts.append(amt) + self.update_state( + state = 'PROCESSING', + meta = { + 'percent': 0.75, + 'message': 'Generating ({}/{})'.format(i,iters), + 'uuid': uuid_name + }) + + best_idx = np.argmax(match_amts) + im_p2p = ims_p2p[best_idx] + + fpath = os.path.join(render_dir, uuid_name + '_gan.jpg') + imx.save_np_as_pil(fpath,im_p2p,quality=95) + files.append({ + 'title': 'Generative Adversarial Network', + 'fn': render_uri + uuid_name + '_gan.jpg' + }) + + + # ----------------------------------------------- + # generate p2p fake + # ----------------------------------------------- + + # announce to user + self.update_state( + state = 'PROCESSING', + meta = { + 'percent': 0.90, + 'message': 'Compositing images...', + 'uuid': uuid_name + }) + + + # apply masked cloning + im_p2p_gray = cv.cvtColor(im_p2p,cv.COLOR_BGR2GRAY) + im_clone_mask = np.zeros_like(im_p2p_gray,dtype=np.uint8) + im_clone_mask[im_p2p_gray > 1] = 255 + + + # apply smoothed copy+paste clone + im_blur_mask = np.zeros(im_np_256.shape[:2],dtype=np.float64) + im_blur_mask[im_p2p_gray > 1] = 1.0 + im_blur_mask = np.array([im_blur_mask,im_blur_mask,im_blur_mask]).transpose((1,2,0)) + + # erode mask to remove black border + kernel = np.ones((3,3),np.uint8) + im_blur_mask = cv.erode(im_blur_mask,kernel,iterations = 3) + + # feather mask + feather_amt = (3,3) + im_blur_mask = (cv.GaussianBlur(im_blur_mask,feather_amt, 0) > 0) * 1.0 #? + im_blur_mask = cv.GaussianBlur(im_blur_mask,feather_amt, 0) + im_blur_mask = np.clip(im_blur_mask,0.0,1.0) + + # mask p2p fg --> photo bg + im_dull = im_np_256.astype(np.float64) * (1.0 - im_blur_mask) + im_p2p.astype(np.float64) * im_blur_mask + im_dull = im_dull.astype(np.uint8) + + + else: + print('No person. Apply background P2P') + celery_logger.debug('No person. Apply background P2P, uuid: {}'.format(uuid_name)) + im_bg_blur = cv.GaussianBlur(im_np_256,(31,31),0) + im_bg_rag = imx.create_rag_mean(im_bg_blur,compactness=30,n_segments=64) + + # apply gan + im_dull = p2p_objects.create_p2p(im_bg_rag) + + # resize back to full 512px + im_dull_512 = imutils.resize(im_dull,width=512) + + # save dulldream image + fpath = os.path.join(render_dir, uuid_name + '_dull.jpg') + imx.save_np_as_pil(fpath,im_dull_512,quality=95) + files.append({ + 'title': 'Your DullDream', + 'fn': render_uri + uuid_name + '_dull.jpg' + }) + + + # ----------------------------------------------- + # Write data to disk + # ----------------------------------------------- + + data = { + 'uuid': uuid_name, + 'date': str(datetime.datetime.now()), + 'files': files + } + + json_path = os.path.join(json_dir, uuid_name + '.json') + with open(json_path, 'w') as json_file: + json.dump(data, json_file) + + return { + 'percent': 100, + 'state': 'complete', + 'uuid': uuid_name + } + + + + +@celery.task(bind=True) +def blur_task(self, uuid_name, agree, extra): + """Process image and update during""" + celery_logger.debug('process_image_task, uuid: {}'.format(uuid_name)) + + upload_dir, render_dir, json_dir, upload_uri, render_uri = get_paths(agree) + + files = [] + + im = Image.open(os.path.join(upload_dir, uuid_name + '.jpg')).convert('RGB') + im = im.resize((256,256)) + files.append({ + 'title': 'Original image', + 'fn': upload_uri + uuid_name + '.jpg' + }) + + self.update_state( + state = 'PROCESSING', + meta = { + 'percent': 0.25, + 'message': 'Applying blur', + 'uuid': uuid_name + }) + + im_np = utils.ensure_np(im) + im_blur = cv.blur(im_np, (5,5), 1.0) + im_blur_pil = utils.ensure_pil(im_blur) + + fn = uuid_name + '_blur.jpg' + fpath = os.path.join(render_dir, fn) + im_blur_pil.save(fpath, 'JPEG', quality=95) + + files.append({ + 'title': 'Blurred image', + 'fn': render_uri + uuid_name + '_blur.jpg' + }) + + time.sleep(3) + + self.update_state( + state = 'PROCESSING', + meta = { + 'percent': 0.50, + 'message': 'Sleeping for some reason', + 'uuid': uuid_name + }) + time.sleep(2) + + self.update_state( + state = 'PROCESSING', + meta = { + 'percent': 0.75, + 'message': 'Sleeping some more', + 'uuid': uuid_name + }) + time.sleep(2) + + data = { + 'uuid': uuid_name, + 'date': str(datetime.datetime.now()), + 'files': files + } + + json_path = os.path.join(json_dir, uuid_name + '.json') + with open(json_path, 'w') as json_file: + json.dump(data, json_file) + + celery_logger.debug('ok') + + return { + 'percent': 100, + 'state': 'complete', + 'uuid': uuid_name, + } + +@celery.task(bind=True) +def sleep_task(self, uuid_name): + celery_logger.debug('sleep_task'.format(uuid_name)) + msgs = [ + {'msg':'Uploaded OK','time':.1}, + {'msg':'Segmenting Image...','time':2}, + {'msg':'Found: Person, Horse','time':1}, + {'msg':'Creating Pix2Pix','time':2} + ] + for i,m in enumerate(msgs): + percent = int(float(i)/float(len(msgs))*100.0) + self.update_state( + state = 'PROCESSING', + meta = { + 'percent': percent, + 'message': m['msg'], + 'uuid': uuid_name + }) + celery_logger.debug(m['msg']) + time.sleep(m['time']) + + return { + 'percent': 100, + 'state': 'complete', + 'uuid': uuid_name + } + +def make_task_json(): + dropdown = {} + for k,v in task_lookup.items(): + if 'active' not in v or v['active'] is not False: + is_default = 'default' in v and v['default'] is True + task = { + 'name': k, + 'title': v['title'], + 'selected': is_default, + } + dropdown[k] = task + return json.dumps(dropdown) + +# Add all valid tasks to this lookup. +# Set 'active': False to disable a task +# Set 'default': True to define the default task + +task_lookup = { + 'sleep': { + 'title': 'Sleep Test', + 'task': sleep_task, + 'active': False + }, + 'blur': { + 'title': 'Blur', + 'task': blur_task, + 'active': False + }, + 'task_dull': { + 'title': 'DullDream V2', + 'task': task_dull, + 'active': True, + 'default': True + } +} + diff --git a/old/server/app/main/utils.py b/old/server/app/main/utils.py new file mode 100644 index 00000000..62d9c95f --- /dev/null +++ b/old/server/app/main/utils.py @@ -0,0 +1,37 @@ +from flask import current_app as app +from PIL import Image +import numpy as np +import cv2 as cv +import os +from os.path import join + +def ensure_pil(im): + try: + im.verify() + return im + except: + return Image.fromarray(im.astype('uint8'), 'RGB') + +def ensure_np(im): + if type(im) == np.ndarray: + return im + return np.asarray(im, np.uint8) + +def get_recent_uploads(limit=10): + d_uploads = app.config['UPLOADS'] + d_renders = app.config['RENDERS'] + + # list all files in uploads dir + filenames = [s for s in os.listdir(d_uploads) + if os.path.isfile(os.path.join(d_uploads, s))] + # sort uploaded files by date + filenames.sort(key=lambda s: os.path.getmtime(os.path.join(d_uploads, s)),reverse=True) + basenames = [os.path.splitext(os.path.basename(f))[0] for f in filenames] + basenames = basenames[:limit] + filenames = [f for f in basenames if os.path.isfile(join(d_renders,'{}_dull.jpg'.format(f)))] + + # create list for uploads and renders + uploads = [join('/img/uploads',f) for f in filenames] + renders = [join('/img/renders','{}_dull'.format(f)) for f in filenames] + urls = [join('/d',f) for f in basenames] + return uploads, renders, urls diff --git a/old/server/app/main/views.py b/old/server/app/main/views.py new file mode 100644 index 00000000..11a8ca53 --- /dev/null +++ b/old/server/app/main/views.py @@ -0,0 +1,300 @@ +import os +import uuid +import json +from flask import render_template, redirect, url_for, send_from_directory +from flask import request, make_response, jsonify +from . import main, utils +from .tasks import task_lookup, make_task_json +from PIL import Image, ImageOps +import cv2 as cv + +from .paths import get_paths + +from flask import current_app as app +from werkzeug.utils import secure_filename +import imutils + +# ------------------------------------------------------------ +# Temp: run mask rcnn outside celery +# ------------------------------------------------------------ + +# init image processors +import sys +from .img_proc_config import ImgProcConfig +sys.path.append('/dulldream/src/') +from image_processors.mask_rcnn import MaskRCNN +from utils import imx +from utils import fiox + +img_proc_congif = ImgProcConfig() +mask_rcnn = MaskRCNN(img_proc_congif.mask_rcnn_class_config, + model_path=img_proc_congif.mask_rcnn_model) + +# ------------------------------------------------------------ +# Tasks +# ------------------------------------------------------------ + +@main.route('/status/<task_name>/<task_id>') +def task_status(task_name, task_id): + """Return celery image processing status""" + if task_name in task_lookup: + task = task_lookup[task_name]['task'].AsyncResult(task_id) + else: + return jsonify({ + 'state': 'error', + 'percent': 100, + 'message': 'Unknown task' + }) + + app.logger.info('task state: {}'.format(task.state)) + if task.state == 'PENDING': + response = { + 'state': task.state, + 'percent': 0, + 'message': 'Pending...' + } + elif task.state != 'FAILURE': + response = { + 'state': task.state, + 'percent': task.info.get('percent', 0), + 'uuid': task.info.get('uuid', 0), + 'message': task.info.get('message', '') + } + if 'result' in task.info: + response['result'] = task.info['result'] + else: + # something went wrong in the background job + response = { + 'state': task.state, + 'percent': 100, + 'message': str(task.info), # this is the exception raised + } + return jsonify(response) + +# ------------------------------------------------------------ +# POST Routes +# ------------------------------------------------------------ + +@main.route('/upload/sleep', methods=['GET', 'POST']) +def sleep_test(): + async_task = task_lookup['sleep']['task'].apply_async(args=['sleep_test']) + task_url = url_for('main.task_status', task_name='sleep', task_id=async_task.id) + return jsonify({ + 'result': True, + 'task_url': task_url, + }) + +@main.route('/upload', methods=['POST']) +def upload(): + + style = request.form['style'] + print('style',style) + if style in task_lookup: + task = task_lookup[style]['task'] + print('task',task) + else: + return jsonify({ + 'result': False, + 'error': 'Unknown task', + }) + + file = request.files['user_image'] + agree = bool(request.form['agree']) + ext = request.form['ext'] + if ext is None: + ext = request.files['ext'] + + uuid_name = str(uuid.uuid4()) + + app.logger.info('[+] style: {}'.format(style)) + app.logger.info('[+] ext: {}'.format(ext)) + app.logger.info('[+] uuid_name: {}'.format(uuid_name)) + app.logger.info('[+] agreed: {}'.format(agree)) + + # convert PNG to JPG + print('[+] Resizing image') + + # LOL MaskRCNN needs to be run outside of the Celery Task + im = Image.open(file.stream).convert('RGB') + im = ImageOps.fit(im,(512,512)) + if agree: + upload_folder = app.config['UPLOADS'] + else: + upload_folder = app.config['UPLOADS_PRIVATE'] + + fpath = os.path.join(upload_folder, uuid_name + '.jpg') + + # Save image to disk + print('[+] Save image to {}'.format(fpath)) + im.save(fpath, 'JPEG', quality=100) + im_pil_256 = im.resize((256,256)) + + print('[+] ensure_np...') + im_np = imx.ensure_np(im_pil_256) + #print('[+] resize np...') + #im_np = imutils.resize(im_np,width=256) + + upload_dir, render_dir, json_dir, upload_uri, render_uri = get_paths(agree) + + print('[+] Run mrcnn...') + try: + result = mask_rcnn.create_segmentations(im_np,concat=True) + except: + print('[-] Error. Could not run mask_rcnn') + result = [] + + if len(result) > 0: + result = result[0] + + # save data, then pass to celery task + print('[+] Save masks') + seg_mask = result['seg_mask'] + fpath_seg_mask = os.path.join(render_dir, uuid_name + '_seg_mask.jpg') + #cv.imwrite(fpath_seg_mask,cv.cvtColor(seg_mask,cv.COLOR_BGR2RGB)) + #seg_mask = seg_mask[:,:,::-1] + seg_mask_pil = imx.ensure_pil(seg_mask) + seg_mask_pil.save(fpath_seg_mask, 'JPEG', quality=100) + + im_mask = result['im_mask'] + fpath_im_mask = os.path.join(render_dir, uuid_name + '_im_mask.jpg') + #im_mask = im_mask[:,:,::-1] + im_mask_pil = imx.ensure_pil(im_mask) + im_mask_pil.save(fpath_im_mask, 'JPEG',quality=100) + #cv.imwrite(fpath_im_mask,cv.cvtColor(im_mask,cv.COLOR_BGR2RGB)) + + celery_result = { + 'score':str(result['score']), + 'name':str(result['name']), + 'class_index':str(result['class_index']), + 'color':str(result['color']), + 'fp_im_mask':fpath_im_mask, + 'fp_seg_mask':fpath_seg_mask, + 'valid':True + } + else: + print('[-] no reults. process background only') + celery_result = { + 'score':None, + 'name':None, + 'class_index':None, + 'color':None, + 'fp_im_mask':None, + 'fp_seg_mask':None, + 'valid':False + } + + print('[+] Start celery') + async_task = task.apply_async(args=[uuid_name, agree, celery_result]) + task_url = url_for('main.task_status', task_name=style, task_id=async_task.id) + + return jsonify({ + 'result': True, + 'task_url': task_url, + 'uuid': uuid_name + }) + + + +# ---------------------------------------------------- +# Fileserver, temp solution +# ---------------------------------------------------- + +@main.route('/img/<string:imtype>/<string:uuid_name>') +def get_image(imtype,uuid_name): + """Return image files from render or uploads""" + if imtype == 'uploads': + d = app.config['UPLOADS'] + suffix = '' + elif imtype == 'renders': + d = app.config['RENDERS'] + suffix = '' + elif imtype == 'fcn': + d = app.config['RENDERS'] + suffix = '_fcn8' + + fname = uuid_name + suffix + '.jpg' + fpath = os.path.join(d, fname) + + if os.path.isfile(fpath): + return send_from_directory(d,fname) + else: + return send_from_directory('static', 'img/404.jpg') + +# ---------------------------------------------------- +# Deleting images +# ---------------------------------------------------- + +def destroy_data(uuid_name, is_public): + uri_base = app.config['URI_BASE'] + upload_dir, render_dir, json_dir, upload_uri, render_uri = get_paths(is_public) + + json_path = os.path.join(json_dir, uuid_name + '.json') + with open(json_path) as json_file: + data = json.load(json_file) + for f in data['files']: + path = os.path.join(uri_base, f['fn'][1:]) + if os.path.exists(path): + os.remove(path) + os.remove(json_path) + +@main.route('/d/<uuid_name>/destroy', strict_slashes=False) # public +def route_public_destroy(uuid_name): + destroy_data(uuid_name, True) + return redirect("/", code=302) + +@main.route('/p/<uuid_name>/destroy', strict_slashes=False) # private +def route_private_destroy(uuid_name): + destroy_data(uuid_name, False) + return redirect("/", code=302) + +# ---------------------------------------------------- +# Static routes +# ---------------------------------------------------- + +# Most of the pages are served with the single page app in index.html: + +task_json = make_task_json() + +@main.route('/', strict_slashes=False) +def index(): + return render_template('index.html', task_json=task_json) + +@main.route('/about', strict_slashes=False) +def about(): + return render_template('index.html', task_json=task_json) + +@main.route('/d/<uuid_name>', strict_slashes=False) # public +def route_public(uuid_name): + return render_template('index.html', task_json=task_json) + +@main.route('/p/<uuid_name>', strict_slashes=False) # private +def route_private(uuid_name): + return render_template('index.html', task_json=task_json) + +@main.route('/privacy', strict_slashes=False) +def privacy(): + return render_template('index.html', task_json=task_json) + +# Some of the pages have their own static file: + +@main.route('/gallery', strict_slashes = False) +def gallery(): + app.logger.info('access gallery') + uploads, renders, urls = utils.get_recent_uploads(limit=50) + uuids = [os.path.splitext(os.path.basename(f))[0] for f in uploads] + images = [{'upload':u,'render':r, 'url':url} for u,r,url in zip(uploads,renders,urls)] + return render_template('gallery.html',images=images) + +@main.route('/zkm', strict_slashes=False) +def zkm(): + app.logger.info('access ZkM') + return render_template('zkm.html') + +@main.route('/celery', strict_slashes=False) +def celery_route(): + return render_template('celery.html') + +@main.route('/projector', strict_slashes=False) +def projector(): + uploads, renders,urls = utils.get_recent_uploads() + return render_template('projector.html', uploads=uploads, renders=renders) |
