mirror of
https://git.anonymousland.org/anonymousland/synapse-product.git
synced 2025-01-07 15:37:50 -05:00
Fix up thumbnailing function
This commit is contained in:
parent
e3428d26ca
commit
505371414f
@ -206,7 +206,7 @@ class MediaRepository(object):
|
|||||||
"media_length": content_length,
|
"media_length": content_length,
|
||||||
}
|
}
|
||||||
|
|
||||||
yield self._generate_local_thumbnails(media_id, media_info)
|
yield self._generate_thumbnails(None, media_id, media_info)
|
||||||
|
|
||||||
defer.returnValue("mxc://%s/%s" % (self.server_name, media_id))
|
defer.returnValue("mxc://%s/%s" % (self.server_name, media_id))
|
||||||
|
|
||||||
@ -339,7 +339,7 @@ class MediaRepository(object):
|
|||||||
"filesystem_id": file_id,
|
"filesystem_id": file_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
yield self._generate_remote_thumbnails(
|
yield self._generate_thumbnails(
|
||||||
server_name, media_id, media_info
|
server_name, media_id, media_info
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -385,6 +385,8 @@ class MediaRepository(object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if t_byte_source:
|
if t_byte_source:
|
||||||
|
t_width, t_height = t_byte_source.dimensions
|
||||||
|
|
||||||
output_path = yield self.write_to_file(
|
output_path = yield self.write_to_file(
|
||||||
t_byte_source,
|
t_byte_source,
|
||||||
self.filepaths.local_media_thumbnail_rel(
|
self.filepaths.local_media_thumbnail_rel(
|
||||||
@ -414,6 +416,8 @@ class MediaRepository(object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if t_byte_source:
|
if t_byte_source:
|
||||||
|
t_width, t_height = t_byte_source.dimensions
|
||||||
|
|
||||||
output_path = yield self.write_to_file(
|
output_path = yield self.write_to_file(
|
||||||
t_byte_source,
|
t_byte_source,
|
||||||
self.filepaths.remote_media_thumbnail_rel(
|
self.filepaths.remote_media_thumbnail_rel(
|
||||||
@ -432,13 +436,28 @@ class MediaRepository(object):
|
|||||||
defer.returnValue(output_path)
|
defer.returnValue(output_path)
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def _generate_local_thumbnails(self, media_id, media_info, url_cache=False):
|
def _generate_thumbnails(self, server_name, media_id, media_info, url_cache=False):
|
||||||
|
"""Generate and store thumbnails for an image.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
server_name(str|None): The server name if remote media, else None if local
|
||||||
|
media_id(str)
|
||||||
|
media_info(dict)
|
||||||
|
url_cache(bool): If we are thumbnailing images downloaded for the URL cache,
|
||||||
|
used exclusively by the url previewer
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Deferred[dict]: Dict with "width" and "height" keys of original image
|
||||||
|
"""
|
||||||
media_type = media_info["media_type"]
|
media_type = media_info["media_type"]
|
||||||
|
file_id = media_info.get("filesystem_id")
|
||||||
requirements = self._get_thumbnail_requirements(media_type)
|
requirements = self._get_thumbnail_requirements(media_type)
|
||||||
if not requirements:
|
if not requirements:
|
||||||
return
|
return
|
||||||
|
|
||||||
if url_cache:
|
if server_name:
|
||||||
|
input_path = self.filepaths.remote_media_filepath(server_name, file_id)
|
||||||
|
elif url_cache:
|
||||||
input_path = self.filepaths.url_cache_filepath(media_id)
|
input_path = self.filepaths.url_cache_filepath(media_id)
|
||||||
else:
|
else:
|
||||||
input_path = self.filepaths.local_media_filepath(media_id)
|
input_path = self.filepaths.local_media_filepath(media_id)
|
||||||
@ -454,22 +473,40 @@ class MediaRepository(object):
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
local_thumbnails = []
|
# We deduplicate the thumbnail sizes by ignoring the cropped versions if
|
||||||
|
# they have the same dimensions of a scaled one.
|
||||||
def generate_thumbnails():
|
thumbnails = {}
|
||||||
for r_width, r_height, r_method, r_type in requirements:
|
for r_width, r_height, r_method, r_type in requirements:
|
||||||
t_byte_source = self._generate_thumbnail(
|
if r_method == "crop":
|
||||||
thumbnailer, r_width, r_height, r_method, r_type,
|
thumbnails.setdefault[(r_width, r_height)] = (r_method, r_type)
|
||||||
|
elif r_method == "scale":
|
||||||
|
t_width, t_height = thumbnailer.aspect(t_width, t_height)
|
||||||
|
t_width = min(m_width, t_width)
|
||||||
|
t_height = min(m_height, t_height)
|
||||||
|
thumbnails[(t_width, t_height)] = (r_method, r_type)
|
||||||
|
|
||||||
|
# Now we generate the thumbnails for each dimension, store it
|
||||||
|
for (r_width, r_height), (r_method, r_type) in thumbnails.iteritems():
|
||||||
|
t_byte_source = thumbnailer.crop(t_width, t_height, t_type)
|
||||||
|
|
||||||
|
if r_type == "crop":
|
||||||
|
t_byte_source = yield make_deferred_yieldable(
|
||||||
|
threads.deferToThread, thumbnailer.crop,
|
||||||
|
r_width, r_height, r_type,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
t_byte_source = yield make_deferred_yieldable(
|
||||||
|
threads.deferToThread, thumbnailer.scale,
|
||||||
|
r_width, r_height, r_type,
|
||||||
)
|
)
|
||||||
|
|
||||||
local_thumbnails.append((
|
t_width, t_height = t_byte_source.dimensions
|
||||||
r_width, r_height, r_method, r_type, t_byte_source
|
|
||||||
))
|
|
||||||
|
|
||||||
yield make_deferred_yieldable(threads.deferToThread, generate_thumbnails)
|
if server_name:
|
||||||
|
file_path = self.filepaths.remote_media_thumbnail_rel(
|
||||||
for t_width, t_height, t_method, t_type, t_byte_source in local_thumbnails:
|
server_name, file_id, t_width, t_height, t_type, t_method
|
||||||
if url_cache:
|
)
|
||||||
|
elif url_cache:
|
||||||
file_path = self.filepaths.url_cache_thumbnail_rel(
|
file_path = self.filepaths.url_cache_thumbnail_rel(
|
||||||
media_id, t_width, t_height, t_type, t_method
|
media_id, t_width, t_height, t_type, t_method
|
||||||
)
|
)
|
||||||
@ -481,61 +518,15 @@ class MediaRepository(object):
|
|||||||
output_path = yield self.write_to_file(t_byte_source, file_path)
|
output_path = yield self.write_to_file(t_byte_source, file_path)
|
||||||
t_len = os.path.getsize(output_path)
|
t_len = os.path.getsize(output_path)
|
||||||
|
|
||||||
yield self.store.store_local_thumbnail(
|
if server_name:
|
||||||
media_id, t_width, t_height, t_type, t_method, t_len
|
|
||||||
)
|
|
||||||
|
|
||||||
defer.returnValue({
|
|
||||||
"width": m_width,
|
|
||||||
"height": m_height,
|
|
||||||
})
|
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
|
||||||
def _generate_remote_thumbnails(self, server_name, media_id, media_info):
|
|
||||||
media_type = media_info["media_type"]
|
|
||||||
file_id = media_info["filesystem_id"]
|
|
||||||
requirements = self._get_thumbnail_requirements(media_type)
|
|
||||||
if not requirements:
|
|
||||||
return
|
|
||||||
|
|
||||||
remote_thumbnails = []
|
|
||||||
|
|
||||||
input_path = self.filepaths.remote_media_filepath(server_name, file_id)
|
|
||||||
thumbnailer = Thumbnailer(input_path)
|
|
||||||
m_width = thumbnailer.width
|
|
||||||
m_height = thumbnailer.height
|
|
||||||
|
|
||||||
def generate_thumbnails():
|
|
||||||
if m_width * m_height >= self.max_image_pixels:
|
|
||||||
logger.info(
|
|
||||||
"Image too large to thumbnail %r x %r > %r",
|
|
||||||
m_width, m_height, self.max_image_pixels
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
for r_width, r_height, r_method, r_type in requirements:
|
|
||||||
t_byte_source = self._generate_thumbnail(
|
|
||||||
thumbnailer, r_width, r_height, r_method, r_type,
|
|
||||||
)
|
|
||||||
|
|
||||||
remote_thumbnails.append((
|
|
||||||
r_width, r_height, r_method, r_type, t_byte_source
|
|
||||||
))
|
|
||||||
|
|
||||||
yield make_deferred_yieldable(threads.deferToThread, generate_thumbnails)
|
|
||||||
|
|
||||||
for t_width, t_height, t_method, t_type, t_byte_source in remote_thumbnails:
|
|
||||||
file_path = self.filepaths.remote_media_thumbnail_rel(
|
|
||||||
server_name, file_id, t_width, t_height, t_type, t_method
|
|
||||||
)
|
|
||||||
|
|
||||||
output_path = yield self.write_to_file(t_byte_source, file_path)
|
|
||||||
t_len = os.path.getsize(output_path)
|
|
||||||
|
|
||||||
yield self.store.store_remote_media_thumbnail(
|
yield self.store.store_remote_media_thumbnail(
|
||||||
server_name, media_id, file_id,
|
server_name, media_id, file_id,
|
||||||
t_width, t_height, t_type, t_method, t_len
|
t_width, t_height, t_type, t_method, t_len
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
yield self.store.store_local_thumbnail(
|
||||||
|
media_id, t_width, t_height, t_type, t_method, t_len
|
||||||
|
)
|
||||||
|
|
||||||
defer.returnValue({
|
defer.returnValue({
|
||||||
"width": m_width,
|
"width": m_width,
|
||||||
|
@ -171,8 +171,8 @@ class PreviewUrlResource(Resource):
|
|||||||
logger.debug("got media_info of '%s'" % media_info)
|
logger.debug("got media_info of '%s'" % media_info)
|
||||||
|
|
||||||
if _is_media(media_info['media_type']):
|
if _is_media(media_info['media_type']):
|
||||||
dims = yield self.media_repo._generate_local_thumbnails(
|
dims = yield self.media_repo._generate_thumbnails(
|
||||||
media_info['filesystem_id'], media_info, url_cache=True,
|
None, media_info['filesystem_id'], media_info, url_cache=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
og = {
|
og = {
|
||||||
@ -217,8 +217,8 @@ class PreviewUrlResource(Resource):
|
|||||||
|
|
||||||
if _is_media(image_info['media_type']):
|
if _is_media(image_info['media_type']):
|
||||||
# TODO: make sure we don't choke on white-on-transparent images
|
# TODO: make sure we don't choke on white-on-transparent images
|
||||||
dims = yield self.media_repo._generate_local_thumbnails(
|
dims = yield self.media_repo._generate_thumbnails(
|
||||||
image_info['filesystem_id'], image_info, url_cache=True,
|
None, image_info['filesystem_id'], image_info, url_cache=True,
|
||||||
)
|
)
|
||||||
if dims:
|
if dims:
|
||||||
og["og:image:width"] = dims['width']
|
og["og:image:width"] = dims['width']
|
||||||
|
@ -54,7 +54,7 @@ class Thumbnailer(object):
|
|||||||
"""Rescales the image to the given dimensions.
|
"""Rescales the image to the given dimensions.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
BytesIO: the bytes of the encoded image ready to be written to disk
|
ImageIO: the bytes of the encoded image ready to be written to disk
|
||||||
"""
|
"""
|
||||||
scaled = self.image.resize((width, height), Image.ANTIALIAS)
|
scaled = self.image.resize((width, height), Image.ANTIALIAS)
|
||||||
return self._encode_image(scaled, output_type)
|
return self._encode_image(scaled, output_type)
|
||||||
@ -71,7 +71,7 @@ class Thumbnailer(object):
|
|||||||
max_height: The larget possible height.
|
max_height: The larget possible height.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
BytesIO: the bytes of the encoded image ready to be written to disk
|
ImageIO: the bytes of the encoded image ready to be written to disk
|
||||||
"""
|
"""
|
||||||
if width * self.height > height * self.width:
|
if width * self.height > height * self.width:
|
||||||
scaled_height = (width * self.height) // self.width
|
scaled_height = (width * self.height) // self.width
|
||||||
@ -92,6 +92,13 @@ class Thumbnailer(object):
|
|||||||
return self._encode_image(cropped, output_type)
|
return self._encode_image(cropped, output_type)
|
||||||
|
|
||||||
def _encode_image(self, output_image, output_type):
|
def _encode_image(self, output_image, output_type):
|
||||||
output_bytes_io = BytesIO()
|
output_bytes_io = ImageIO(output_image.size)
|
||||||
output_image.save(output_bytes_io, self.FORMATS[output_type], quality=80)
|
output_image.save(output_bytes_io, self.FORMATS[output_type], quality=80)
|
||||||
|
output_image.close()
|
||||||
return output_bytes_io
|
return output_bytes_io
|
||||||
|
|
||||||
|
|
||||||
|
class ImageIO(BytesIO):
|
||||||
|
def __init__(self, dimensions):
|
||||||
|
super(ImageIO, self).__init__()
|
||||||
|
self.dimensions = dimensions
|
||||||
|
Loading…
Reference in New Issue
Block a user