Fix #1053 - Add height and width attributes and MetadataProcess task

Added "height" and "width" attributes to "image" and "fullImage"
    in the API where possible. The height and width of images wasn't
    being stored anywhere so I've created a task to add or update
    the metadata on images and also started adding those to new images
    when they're submitted in the InitialProcessor.
This commit is contained in:
Jessica Tallon 2014-12-11 11:29:03 +00:00
parent f2698759cd
commit 4a09d5956a
2 changed files with 81 additions and 7 deletions

View File

@ -591,6 +591,22 @@ class MediaEntry(Base, MediaEntryMixin):
),
}
# Add image height and width if possible. We didn't use to store this
# data and we're not able (and maybe not willing) to re-process all
# images so it's possible this might not exist.
if self.get_file_metadata("thumb", "height"):
height = self.get_file_metadata("thumb", "height")
context["image"]["height"] = height
if self.get_file_metadata("thumb", "width"):
width = self.get_file_metadata("thumb", "width")
context["image"]["width"] = width
if self.get_file_metadata("original", "height"):
height = self.get_file_metadata("original", "height")
context["fullImage"]["height"] = height
if self.get_file_metadata("original", "height"):
width = self.get_file_metadata("original", "width")
context["fullImage"]["width"] = width
return context
def unserialize(self, data):

View File

@ -225,19 +225,32 @@ class CommonImageProcessor(MediaProcessor):
self.entry, self.process_filename,
self.name_builder.fill('{basename}{ext}'))
def extract_metadata(self):
# Is there any GPS data
def extract_metadata(self, file):
""" Extract all the metadata from the image and store """
# Extract GPS data and store in Location
gps_data = get_gps_data(self.exif_tags)
if len(gps_data):
Location.create({"position": gps_data}, self.entry)
# Insert exif data into database
exif_all = clean_exif(self.exif_tags)
if len(exif_all):
self.entry.media_data_init(exif_all=exif_all)
if len(gps_data):
Location.create({"position": gps_data}, self.entry)
self.entry.media_data_init(**gps_data)
# Extract file metadata
try:
im = Image.open(self.process_filename)
except IOError:
raise BadMediaFail()
metadata = {
"width": im.size[0],
"height": im.size[1],
}
self.entry.set_file_metadata(file, **metadata)
class InitialProcessor(CommonImageProcessor):
@ -252,6 +265,9 @@ class InitialProcessor(CommonImageProcessor):
"""
Determine if this media type is eligible for processing
"""
if entry is None and state is None:
raise ValueError("Must specify either entry or state")
if not state:
state = entry.state
return state in (
@ -301,7 +317,7 @@ class InitialProcessor(CommonImageProcessor):
quality=quality)
self.generate_thumb(size=thumb_size, filter=filter, quality=quality)
self.copy_original()
self.extract_metadata()
self.extract_metadata('original')
self.delete_queue_file()
@ -318,6 +334,9 @@ class Resizer(CommonImageProcessor):
"""
Determine if this media type is eligible for processing
"""
if entry is None and state is None:
raise ValueError("Must specify either entry or state")
if not state:
state = entry.state
return state in 'processed'
@ -366,13 +385,52 @@ class Resizer(CommonImageProcessor):
elif file == 'thumb':
self.generate_thumb(size=size, filter=filter, quality=quality)
self.extract_metadata(file)
class MetadataProcessing(CommonImageProcessor):
""" Extraction and storage of media's metadata for processed images """
name = 'metadatabuilder'
description = 'Add or update image metadata'
@classmethod
def media_is_eligible(cls, entry=None, state=None):
if entry is None and state is None:
raise ValueError("Must specify either entry or state")
if state is None:
state = entry.state
return state == 'processed'
@classmethod
def generate_parser(cls):
parser = argparse.ArgumentParser(
description=cls.description,
prog=cls.name
)
parser.add_argument(
'file',
choices=['original', 'medium', 'thumb']
)
return parser
@classmethod
def args_to_request(cls, args):
return request_from_args(args, ['file'])
def process(self, file):
self.common_setup()
self.extract_metadata(file)
class ImageProcessingManager(ProcessingManager):
def __init__(self):
super(ImageProcessingManager, self).__init__()
self.add_processor(InitialProcessor)
self.add_processor(Resizer)
self.add_processor(MetadataProcessing)
if __name__ == '__main__':
import sys