123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- 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()
|