import re from os import path, getcwd import cv2 from PIL import Image from eventlet import tpool from flask import abort, send_from_directory from flask.views import View from pycs.database.Database import Database class GetResizedFile(View): """ returns binary file after resizing """ # pylint: disable=arguments-differ methods = ['GET'] def __init__(self, db: Database): # pylint: disable=invalid-name self.db = db def dispatch_request(self, file_id: int, resolution: str): # get file from database file = self.db.file(file_id) if file is None: return abort(404) project = file.project() # extract desired resolution resolution = re.split(r'[^0-9]', resolution) max_width = int(resolution[0]) max_height = int(resolution[1]) if len(resolution) > 1 else 2 ** 24 # send data file_directory, file_name = tpool.execute(self.resize_file, project, file, max_width, max_height) return send_from_directory(file_directory, file_name) @staticmethod def resize_file(project, file, max_width, max_height): """ If file type equals video this function extracts a thumbnail first. It calls resize_image to resize and returns the resized files directory and name. :param project: associated project :param file: file object :param max_width: maximum image or thumbnail width :param max_height: maximum image or thumbnail height :return: resized file directory, resized file name """ # get absolute path if path.isabs(file.path): abs_file_path = file.path else: abs_file_path = path.join(getcwd(), file.path) # extract video thumbnail if file.type == 'video': abs_target_path = path.join(getcwd(), project.root_folder, 'temp', f'{file.uuid}.jpg') GetResizedFile.create_thumbnail(abs_file_path, abs_target_path) abs_file_path = abs_target_path # resize image file abs_target_path = path.join(getcwd(), project.root_folder, 'temp', f'{file.uuid}_{max_width}_{max_height}.jpg') result = GetResizedFile.resize_image(abs_file_path, abs_target_path, max_width, max_height) # return path if result is not None: return path.split(abs_target_path) return path.split(abs_file_path) @staticmethod def resize_image(file_path, target_path, max_width, max_height): """ resize an image so width < max_width and height < max_height :param file_path: path to source file :param target_path: path to target file :param max_width: maximum image width :param max_height: maximum image height :return: """ # return if file exists if path.exists(target_path): return True # load full size image image = Image.open(file_path) img_width, img_height = image.size # abort if file is smaller than desired if img_width < max_width and img_height < max_height: return None # calculate target size target_width = int(max_width) target_height = int(max_width * img_height / img_width) if target_height > max_height: target_height = int(max_height) target_width = int(max_height * img_width / img_height) # resize image resized_image = image.resize((target_width, target_height)) # save to file resized_image.save(target_path, quality=80) return True @staticmethod def create_thumbnail(file_path, target_path): """ extract a thumbnail from a video :param file_path: path to source file :param target_path: path to target file :return: """ # return if file exists if path.exists(target_path): return # load video video = cv2.VideoCapture(file_path) # create thumbnail _, image = video.read() cv2.imwrite(target_path, image) # close video file video.release()