GetResizedFile.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import cv2
  2. import os
  3. import re
  4. from PIL import Image
  5. from eventlet import tpool
  6. from flask import abort
  7. from flask import send_from_directory
  8. from flask.views import View
  9. from pycs.database.File import File
  10. from pycs.database.Project import Project
  11. class GetResizedFile(View):
  12. """
  13. returns binary file after resizing
  14. """
  15. # pylint: disable=arguments-differ
  16. methods = ['GET']
  17. def dispatch_request(self, file_id: int, resolution: str):
  18. # get file from database
  19. file = File.query.get(file_id)
  20. if file is None:
  21. return abort(404, "file object not found")
  22. if not os.path.exists(file.path):
  23. return abort(404, "image not found!")
  24. project = file.project
  25. # extract desired resolution
  26. resolution = re.split(r'[^0-9]', resolution)
  27. max_width = int(resolution[0])
  28. max_height = int(resolution[1]) if len(resolution) > 1 else 2 ** 24
  29. # send data
  30. file_directory, file_name = tpool.execute(resize_file,
  31. project.id, file.id, max_width, max_height)
  32. return send_from_directory(file_directory, file_name)
  33. def resize_file(project_id, file_id, 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. file = File.query.get(file_id)
  44. project = Project.query.get(project_id)
  45. # get absolute path
  46. if os.path.isabs(file.path):
  47. abs_file_path = file.path
  48. else:
  49. abs_file_path = os.path.join(getcwd(), file.path)
  50. # extract video thumbnail
  51. if file.type == 'video':
  52. abs_target_path = os.path.join(os.getcwd(), project.root_folder, 'temp', f'{file.uuid}.jpg')
  53. create_thumbnail(abs_file_path, abs_target_path)
  54. abs_file_path = abs_target_path
  55. # resize image file
  56. abs_target_path = os.path.join(os.getcwd(), project.root_folder,
  57. 'temp', f'{file.uuid}_{max_width}_{max_height}.jpg')
  58. result = resize_image(abs_file_path, abs_target_path, max_width, max_height)
  59. # return path
  60. if result is not None:
  61. return os.path.split(abs_target_path)
  62. return os.path.split(abs_file_path)
  63. def resize_image(file_path, target_path, max_width, max_height):
  64. """
  65. resize an image so width < max_width and height < max_height
  66. :param file_path: path to source file
  67. :param target_path: path to target file
  68. :param max_width: maximum image width
  69. :param max_height: maximum image height
  70. :return:
  71. """
  72. # return if file exists
  73. if os.path.exists(target_path):
  74. return True
  75. # load full size image
  76. image = Image.open(file_path)
  77. img_width, img_height = image.size
  78. # abort if file is smaller than desired
  79. if img_width < max_width and img_height < max_height:
  80. return None
  81. # calculate target size
  82. target_width = int(max_width)
  83. target_height = int(max_width * img_height / img_width)
  84. if target_height > max_height:
  85. target_height = int(max_height)
  86. target_width = int(max_height * img_width / img_height)
  87. # resize image
  88. resized_image = image.resize((target_width, target_height))
  89. # save to file
  90. resized_image.save(target_path, quality=80)
  91. return True
  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 os.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()