GetResizedFile.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. import re
  2. from os import path, getcwd
  3. import cv2
  4. from PIL import Image
  5. from eventlet import tpool
  6. from flask import abort, send_from_directory
  7. from flask.views import View
  8. from pycs.database.Database import Database
  9. class GetResizedFile(View):
  10. """
  11. returns binary file after resizing
  12. """
  13. # pylint: disable=arguments-differ
  14. methods = ['GET']
  15. def __init__(self, db: Database):
  16. # pylint: disable=invalid-name
  17. self.db = db
  18. def dispatch_request(self, file_id: int, resolution: str):
  19. # get file from database
  20. file = self.db.file(file_id)
  21. if file is None:
  22. return abort(404)
  23. project = file.project()
  24. # extract desired resolution
  25. resolution = re.split(r'[^0-9]', resolution)
  26. max_width = int(resolution[0])
  27. max_height = int(resolution[1]) if len(resolution) > 1 else 2 ** 24
  28. # send data
  29. file_directory, file_name = tpool.execute(self.resize_file,
  30. project, file, max_width, max_height)
  31. return send_from_directory(file_directory, file_name)
  32. @staticmethod
  33. def resize_file(project, file, max_width, max_height):
  34. """
  35. If file type equals video this function extracts a thumbnail first. It calls resize_image
  36. to resize and returns the resized files directory and name.
  37. :param project: associated project
  38. :param file: file object
  39. :param max_width: maximum image or thumbnail width
  40. :param max_height: maximum image or thumbnail height
  41. :return: resized file directory, resized file name
  42. """
  43. # get absolute path
  44. if path.isabs(file.path):
  45. abs_file_path = file.path
  46. else:
  47. abs_file_path = path.join(getcwd(), file.path)
  48. # extract video thumbnail
  49. if file.type == 'video':
  50. abs_target_path = path.join(getcwd(), project.root_folder, 'temp', f'{file.uuid}.jpg')
  51. GetResizedFile.create_thumbnail(abs_file_path, abs_target_path)
  52. abs_file_path = abs_target_path
  53. # resize image file
  54. abs_target_path = path.join(getcwd(), project.root_folder,
  55. 'temp', f'{file.uuid}_{max_width}_{max_height}.jpg')
  56. result = GetResizedFile.resize_image(abs_file_path, abs_target_path, max_width, max_height)
  57. # return path
  58. if result is not None:
  59. return path.split(abs_target_path)
  60. return path.split(abs_file_path)
  61. @staticmethod
  62. def resize_image(file_path, target_path, max_width, max_height):
  63. """
  64. resize an image so width < max_width and height < max_height
  65. :param file_path: path to source file
  66. :param target_path: path to target file
  67. :param max_width: maximum image width
  68. :param max_height: maximum image height
  69. :return:
  70. """
  71. # return if file exists
  72. if path.exists(target_path):
  73. return True
  74. # load full size image
  75. image = Image.open(file_path)
  76. img_width, img_height = image.size
  77. # abort if file is smaller than desired
  78. if img_width < max_width and img_height < max_height:
  79. return None
  80. # calculate target size
  81. target_width = int(max_width)
  82. target_height = int(max_width * img_height / img_width)
  83. if target_height > max_height:
  84. target_height = int(max_height)
  85. target_width = int(max_height * img_width / img_height)
  86. # resize image
  87. resized_image = image.resize((target_width, target_height))
  88. # save to file
  89. resized_image.save(target_path, quality=80)
  90. return True
  91. @staticmethod
  92. def create_thumbnail(file_path, target_path):
  93. """
  94. extract a thumbnail from a video
  95. :param file_path: path to source file
  96. :param target_path: path to target file
  97. :return:
  98. """
  99. # return if file exists
  100. if path.exists(target_path):
  101. return
  102. # load video
  103. video = cv2.VideoCapture(file_path)
  104. # create thumbnail
  105. _, image = video.read()
  106. cv2.imwrite(target_path, image)
  107. # close video file
  108. video.release()