GetResizedFile.py 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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, max_width: int, max_height: int = 2**24):
  18. # get file from database
  19. file = File.query.get(file_id)
  20. if file is None:
  21. abort(404, "file object not found")
  22. if not os.path.exists(file.path):
  23. abort(404, "image not found!")
  24. project = file.project
  25. # send data
  26. file_directory, file_name = tpool.execute(resize_file,
  27. project.id, file.id, max_width, max_height)
  28. return send_from_directory(file_directory, file_name)
  29. def resize_file(project_id, file_id, max_width, max_height):
  30. """
  31. If file type equals video this function extracts a thumbnail first. It calls resize_image
  32. to resize and returns the resized files directory and name.
  33. :param project: associated project
  34. :param file: file object
  35. :param max_width: maximum image or thumbnail width
  36. :param max_height: maximum image or thumbnail height
  37. :return: resized file directory, resized file name
  38. """
  39. file = File.query.get(file_id)
  40. project = Project.query.get(project_id)
  41. # get absolute path
  42. if os.path.isabs(file.path):
  43. abs_file_path = file.path
  44. else:
  45. abs_file_path = os.path.join(os.getcwd(), file.path)
  46. # extract video thumbnail
  47. if file.type == 'video':
  48. abs_target_path = os.path.join(os.getcwd(), project.root_folder, 'temp', f'{file.uuid}.jpg')
  49. create_thumbnail(abs_file_path, abs_target_path)
  50. abs_file_path = abs_target_path
  51. # resize image file
  52. abs_target_path = os.path.join(os.getcwd(), project.root_folder,
  53. 'temp', f'{file.uuid}_{max_width}_{max_height}.jpg')
  54. result = resize_image(abs_file_path, abs_target_path, max_width, max_height)
  55. # return path
  56. if result is not None:
  57. return os.path.split(abs_target_path)
  58. return os.path.split(abs_file_path)
  59. def resize_image(file_path, target_path, max_width, max_height):
  60. """
  61. resize an image so width < max_width and height < max_height
  62. :param file_path: path to source file
  63. :param target_path: path to target file
  64. :param max_width: maximum image width
  65. :param max_height: maximum image height
  66. :return:
  67. """
  68. # return if file exists
  69. if os.path.exists(target_path):
  70. return True
  71. # load full size image
  72. image = Image.open(file_path)
  73. img_width, img_height = image.size
  74. # abort if file is smaller than desired
  75. if img_width < max_width and img_height < max_height:
  76. return None
  77. # calculate target size
  78. target_width = int(max_width)
  79. target_height = int(max_width * img_height / img_width)
  80. if target_height > max_height:
  81. target_height = int(max_height)
  82. target_width = int(max_height * img_width / img_height)
  83. # resize image
  84. resized_image = image.resize((target_width, target_height))
  85. # save to file
  86. resized_image.save(target_path, quality=80)
  87. return True
  88. def create_thumbnail(file_path, target_path):
  89. """
  90. extract a thumbnail from a video
  91. :param file_path: path to source file
  92. :param target_path: path to target file
  93. :return:
  94. """
  95. # return if file exists
  96. if os.path.exists(target_path):
  97. return
  98. # load video
  99. video = cv2.VideoCapture(file_path)
  100. # create thumbnail
  101. _, image = video.read()
  102. cv2.imwrite(target_path, image)
  103. # close video file
  104. video.release()