Thumbnails for images and videos #87

Merged
Anna Sirota merged 28 commits from thumbnails into main 2024-04-25 17:50:58 +02:00
Showing only changes of commit 361c0490a6 - Show all commits

View File

@ -1,4 +1,5 @@
from pathlib import Path from pathlib import Path
import datetime
import hashlib import hashlib
import io import io
import logging import logging
@ -221,10 +222,16 @@ def get_thumbnail_upload_to(file_hash: str, width: int = None, height: int = Non
def resize_image(image: Image, size: tuple, output, output_format: str = 'PNG', **output_params): def resize_image(image: Image, size: tuple, output, output_format: str = 'PNG', **output_params):
"""Resize a models.ImageField to a given size and write it into output file.""" """Resize a models.ImageField to a given size and write it into output file."""
start_t = datetime.datetime.now()
source_image = image.convert('RGBA' if output_format == 'PNG' else 'RGB') source_image = image.convert('RGBA' if output_format == 'PNG' else 'RGB')
source_image.thumbnail(size, Image.LANCZOS) source_image.thumbnail(size, Image.LANCZOS)
source_image.save(output, output_format, **output_params) source_image.save(output, output_format, **output_params)
end_t = datetime.datetime.now()
args = {'source': image, 'size': size, 'time': (end_t - start_t).microseconds / 1000}
logger.info('%(source)s to %(size)s done in %(time)sms', args)
def make_thumbnails( def make_thumbnails(
source_path: str, file_hash: str, output_format: str = THUMBNAIL_FORMAT source_path: str, file_hash: str, output_format: str = THUMBNAIL_FORMAT
@ -234,6 +241,7 @@ def make_thumbnails(
Resulting thumbnail paths a derived from the given file hash and thumbnail sizes. Resulting thumbnail paths a derived from the given file hash and thumbnail sizes.
Return a dict of size keys to output paths of generated thumbnail images. Return a dict of size keys to output paths of generated thumbnail images.
""" """
start_t = datetime.datetime.now()
thumbnails = {} thumbnails = {}
abs_path = os.path.join(settings.MEDIA_ROOT, source_path) abs_path = os.path.join(settings.MEDIA_ROOT, source_path)
image = Image.open(abs_path) image = Image.open(abs_path)
@ -259,12 +267,17 @@ def make_thumbnails(
default_storage.save(output_path, f) default_storage.save(output_path, f)
thumbnails[size_key] = {'size': size, 'path': output_path} thumbnails[size_key] = {'size': size, 'path': output_path}
image.close() image.close()
end_t = datetime.datetime.now()
args = {'source': source_path, 'time': (end_t - start_t).microseconds / 1000}
logger.info('%(source)s done in %(time)sms', args)
return thumbnails return thumbnails
def extract_frame(source_path: str, output_path: str, at_time: str = '00:00:00.01'): def extract_frame(source_path: str, output_path: str, at_time: str = '00:00:00.01'):
"""Extract a single frame of a video at a given path, write it to the given output path.""" """Extract a single frame of a video at a given path, write it to the given output path."""
try: try:
start_t = datetime.datetime.now()
abs_path = os.path.join(settings.MEDIA_ROOT, output_path) abs_path = os.path.join(settings.MEDIA_ROOT, output_path)
ffmpeg = ( ffmpeg = (
FFmpeg() FFmpeg()
@ -276,6 +289,10 @@ def extract_frame(source_path: str, output_path: str, at_time: str = '00:00:00.0
if not os.path.isdir(output_dir): if not os.path.isdir(output_dir):
os.mkdir(output_dir) os.mkdir(output_dir)
ffmpeg.execute() ffmpeg.execute()
end_t = datetime.datetime.now()
args = {'source': source_path, 'time': (end_t - start_t).microseconds / 1000}
logger.info('%(source)s done in %(time)sms', args)
except (FFmpegError, FFmpegFileNotFound, FFmpegInvalidCommand) as e: except (FFmpegError, FFmpegFileNotFound, FFmpegInvalidCommand) as e:
logger.exception(f'Failed to extract a frame: {e.message}, {" ".join(ffmpeg.arguments)}') logger.exception(f'Failed to extract a frame: {e.message}, {" ".join(ffmpeg.arguments)}')
raise raise