"""Convert Thumbnails to specified formats.""" from decimal import Decimal import io import os import urllib from PIL import Image from video.connectors import s3 from video.constants import assets from video.constants import job_io_fields from video.logic.activity_task_logger import activity_task_logger from video.utils import maths def get_frame_resolution(image_width, image_height, output_aspect_ratio): """Get frame resolution. Args: image_width (int): Image width. image_height (int): Image height. output_aspect_ratio (Decimal): Desired output aspect ratio. Returns: tuple: (width, height). """ image_width = Decimal(image_width) image_height = Decimal(image_height) input_aspect_ratio = image_width / image_height width_scaling_factor = output_aspect_ratio / input_aspect_ratio height_scaling_factor = 1 / width_scaling_factor scaled_width = width_scaling_factor * image_width scaled_height = height_scaling_factor * image_height output_width = maths.find_multiple_of_n_nearest_x( 2, max(image_width, scaled_width)) output_height = maths.find_multiple_of_n_nearest_x( 2, max(image_height, scaled_height)) return output_width, output_height def get_upper_left_corner_coordinates_for_centering( image_width, image_height, frame_width, frame_height): """Get upper left corner coordinates for centering. Args: image_width (int): Image width. image_height (int): Image height. frame_width (int): Frame width. frame_height (int): Frame height. Returns: tuple: (x, y). """ image_width = Decimal(image_width) image_height = Decimal(image_height) frame_width = Decimal(frame_width) frame_height = Decimal(frame_height) upper_left_x = maths.find_multiple_of_n_nearest_x( 2, (frame_width - image_width) / 2) upper_left_y = maths.find_multiple_of_n_nearest_x( 2, (frame_height - image_height) / 2) return upper_left_x, upper_left_y def _download_and_convert_thumbnail(thumbnail_s3_url): """Download thumbnails from s3 and convert them to tiffs. Args: thumbnail_s3_url (string): thumbnail s3 url Returns: tuple: ( in_memory_original_size_image_object, in_memory_16_9_image_object) """ with urllib.request.urlopen(thumbnail_s3_url) as url: image = Image.open(io.BytesIO(url.read())) in_memory_original_size_image_object = io.BytesIO() in_memory_16_9_image_object = io.BytesIO() image_16_9_resolution = get_frame_resolution( image.width, image.height, Decimal(16) / 9) image_16_9 = Image.new('RGB', image_16_9_resolution) image_16_9.paste(image, get_upper_left_corner_coordinates_for_centering( image.width, image.height, image_16_9.width, image_16_9.height)) image.save(in_memory_original_size_image_object, 'TIFF') image_16_9.save(in_memory_16_9_image_object, 'TIFF') in_memory_original_size_image_object.seek(0) in_memory_16_9_image_object.seek(0) return in_memory_original_size_image_object, in_memory_16_9_image_object def _save_tiff_thumbnails_to_s3(images_to_save): """Save tiff thumbnails to s3. Args: images_to_save (dict): images to save """ s3_client = s3.get_s3_client() for save_path, image_to_save in images_to_save.items(): s3_client.upload_fileobj( image_to_save, assets.VIDEO_S3_BUCKET, save_path) def _get_custom_thumbnail_s3_url( jpg_custom_thumbnail_s3_key, default_thumbnail_s3_url ): """Return custom thumbnail if it exists, otherwise return default thumbnail.""" # noqa if jpg_custom_thumbnail_s3_key: return s3.get_url_for_s3_object( assets.VIDEO_S3_BUCKET, jpg_custom_thumbnail_s3_key) return default_thumbnail_s3_url def _convert_thumbnails_to_tiffs(inputs): """Convert all thumbnails to tiffs and upload to S3. Args: inputs (dict): Inputs. Returns: dict: empty. """ outputs = {} workflow_job_id = inputs[job_io_fields.WORKFLOW_JOB_ID] jpg_default_thumbnail_s3_key = inputs[job_io_fields.THUMBNAIL_S3_KEY] default_thumbnail_s3_url = s3.get_url_for_s3_object( assets.VIDEO_S3_BUCKET, jpg_default_thumbnail_s3_key) in_memory_original_size_default_image_object, in_memory_16_9_default_image_object = ( # noqa _download_and_convert_thumbnail(default_thumbnail_s3_url)) filename = os.path.splitext(os.path.basename(default_thumbnail_s3_url))[0] tiff_s3_key = assets.MEZZANINE_S3_KEY_TEMPLATE.format( video_codec='tiff', workflow_job_id=workflow_job_id, file_name='{}'.format(filename)) outputs[job_io_fields.TIFF_THUMBNAIL_S3_KEY] = tiff_s3_key s2_s3_key = assets.TIFF_S2_THUMBNAIL_FILENAME_S3_KEY_TEMPLATE.format( tiff_thumbnail_path=tiff_s3_key) s5_s3_key = assets.TIFF_S5_THUMBNAIL_FILENAME_S3_KEY_TEMPLATE.format( tiff_thumbnail_path=tiff_s3_key) images_to_save = { s2_s3_key: in_memory_original_size_default_image_object, s5_s3_key: in_memory_16_9_default_image_object, } outputs = { **outputs, job_io_fields.VIDEO_IMAGE_S2: s2_s3_key, job_io_fields.VIDEO_IMAGE_S5: s5_s3_key, } jpg_custom_thumbnail_s3_key = inputs.get( job_io_fields.CUSTOM_THUMBNAIL_S3_KEY) custom_thumbnail_s3_url = _get_custom_thumbnail_s3_url( jpg_custom_thumbnail_s3_key, default_thumbnail_s3_url) in_memory_original_size_custom_image_object, in_memory_16_9_custom_image_object = ( # noqa _download_and_convert_thumbnail(custom_thumbnail_s3_url)) filename = os.path.splitext( os.path.basename(custom_thumbnail_s3_url))[0] tiff_s3_key = assets.MEZZANINE_S3_KEY_TEMPLATE.format( video_codec='tiff', workflow_job_id=workflow_job_id, file_name='{}'.format(filename)) s10_s3_key = assets.TIFF_S10_THUMBNAIL_FILENAME_S3_KEY_TEMPLATE.format( tiff_thumbnail_path=tiff_s3_key) s11_s3_key = assets.TIFF_S11_THUMBNAIL_FILENAME_S3_KEY_TEMPLATE.format( tiff_thumbnail_path=tiff_s3_key) images_to_save = { **images_to_save, s10_s3_key: in_memory_original_size_custom_image_object, s11_s3_key: in_memory_16_9_custom_image_object, } outputs = { **outputs, job_io_fields.VIDEO_IMAGE_S10: s10_s3_key, job_io_fields.VIDEO_IMAGE_S11: s11_s3_key, } _save_tiff_thumbnails_to_s3(images_to_save) return outputs @activity_task_logger([ job_io_fields.WORKFLOW_JOB_ID, job_io_fields.THUMBNAIL_S3_KEY, job_io_fields.CUSTOM_THUMBNAIL_S3_KEY, ]) def convert_thumbnails_to_tiffs(inputs): """Convert all thumbnails to tiffs and upload to S3. Args: inputs (dict): Inputs. Returns: dict: empty. """ outputs = _convert_thumbnails_to_tiffs(inputs) del outputs[job_io_fields.TIFF_THUMBNAIL_S3_KEY] return outputs @activity_task_logger([ job_io_fields.WORKFLOW_JOB_ID, job_io_fields.THUMBNAIL_S3_KEY, ]) def convert_default_thumbnail_to_tiff(inputs): """Convert chosen thumbnail to tif format in memory and upload to S3. Args: inputs (dict): Inputs. Returns: dict: empty. """ outputs = _convert_thumbnails_to_tiffs(inputs) return { job_io_fields.TIFF_THUMBNAIL_S3_KEY: outputs[job_io_fields.TIFF_THUMBNAIL_S3_KEY] }