diff options
author | Rodney Ewing <ewing.rj@gmail.com> | 2013-08-12 11:37:59 -0700 |
---|---|---|
committer | Rodney Ewing <ewing.rj@gmail.com> | 2013-08-16 15:30:17 -0700 |
commit | 583501415acce95ff458e5cf12733d1b61332e0e (patch) | |
tree | 7990545395e56be0b423c899fb6cd975a0fae6f0 | |
parent | af51c423fb4c808b46afbec12d3aa832c53c0034 (diff) | |
download | mediagoblin-583501415acce95ff458e5cf12733d1b61332e0e.tar.lz mediagoblin-583501415acce95ff458e5cf12733d1b61332e0e.tar.xz mediagoblin-583501415acce95ff458e5cf12733d1b61332e0e.zip |
Add image resizer and some cleanup of old code
-rw-r--r-- | mediagoblin/media_types/image/__init__.py | 5 | ||||
-rw-r--r-- | mediagoblin/media_types/image/processing.py | 236 | ||||
-rw-r--r-- | mediagoblin/processing/__init__.py | 4 |
3 files changed, 58 insertions, 187 deletions
diff --git a/mediagoblin/media_types/image/__init__.py b/mediagoblin/media_types/image/__init__.py index 774b9bfa..f8c4a7d1 100644 --- a/mediagoblin/media_types/image/__init__.py +++ b/mediagoblin/media_types/image/__init__.py @@ -17,8 +17,8 @@ import datetime import logging from mediagoblin.media_types import MediaManagerBase -from mediagoblin.media_types.image.processing import ProcessImage, \ - sniff_handler, ImageProcessingManager +from mediagoblin.media_types.image.processing import sniff_handler, \ + ImageProcessingManager from mediagoblin.tools import pluginapi _log = logging.getLogger(__name__) @@ -34,7 +34,6 @@ def setup_plugin(): class ImageMediaManager(MediaManagerBase): human_readable = "Image" - processor = staticmethod(ProcessImage) display_template = "mediagoblin/media_displays/image.html" default_thumb = "images/media_thumbs/image.png" diff --git a/mediagoblin/media_types/image/processing.py b/mediagoblin/media_types/image/processing.py index 01e5cce5..6eb8302c 100644 --- a/mediagoblin/media_types/image/processing.py +++ b/mediagoblin/media_types/image/processing.py @@ -23,17 +23,14 @@ import logging import argparse from mediagoblin import mg_globals as mgg -from mediagoblin.db.models import MediaEntry from mediagoblin.processing import ( BadMediaFail, FilenameBuilder, MediaProcessor, ProcessingManager, request_from_args, get_orig_filename, store_public, copy_original) -from mediagoblin.submit.lib import run_process_media from mediagoblin.tools.exif import exif_fix_image_orientation, \ extract_exif, clean_exif, get_gps_data, get_useful, \ exif_image_needs_rotation -from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ _log = logging.getLogger(__name__) @@ -130,181 +127,6 @@ def sniff_handler(media_file, **kw): return None -class ProcessImage(object): - """Code to process an image. Will be run by celery. - - A Workbench() represents a local tempory dir. It is automatically - cleaned up when this function exits. - """ - def __init__(self, proc_state=None): - if proc_state: - self.proc_state = proc_state - self.entry = proc_state.entry - self.workbench = proc_state.workbench - - # Conversions subdirectory to avoid collisions - self.conversions_subdir = os.path.join( - self.workbench.dir, 'convirsions') - - self.orig_filename = proc_state.get_orig_filename() - self.name_builder = FilenameBuilder(self.orig_filename) - - # Exif extraction - self.exif_tags = extract_exif(self.orig_filename) - - os.mkdir(self.conversions_subdir) - - def reprocess_action(self, args): - """ - List the available actions for media in a given state - """ - if args[0].state == 'processed': - print _('\n Available reprocessing actions for processed images:' - '\n \t --resize: thumb or medium' - '\n Options:' - '\n \t --size: max_width max_height (defaults to' - 'config specs)') - return True - - def _parser(self, args): - """ - Parses the unknown args from the gmg parser - """ - parser = argparse.ArgumentParser() - parser.add_argument( - '--resize', - choices=['thumb', 'medium']) - parser.add_argument( - '--size', - nargs=2, - metavar=('max_width', 'max_height'), - type=int) - parser.add_argument( - '--initial_processing', - action='store_true') - - return parser.parse_args(args[1]) - - def _check_eligible(self, entry_args, reprocess_args): - """ - Check to see if we can actually process the given media as requested - """ - - if entry_args.state == 'processed': - if reprocess_args.initial_processing: - raise Exception(_('You can not run --initial_processing on' - ' media that has already been processed.')) - - if entry_args.state == 'failed': - if reprocess_args.resize: - raise Exception(_('You can not run --resize on media that has' - ' not been processed.')) - if reprocess_args.size: - _log.warn('With --initial_processing, the --size flag will be' - ' ignored.') - - if entry_args.state == 'processing': - raise Exception(_('We currently do not support reprocessing on' - ' media that is in the "processing" state.')) - - def initial_processing(self): - # Is there any GPS data - gps_data = get_gps_data(self.exif_tags) - - # Always create a small thumbnail - resize_tool(self.proc_state, True, 'thumb', self.orig_filename, - self.name_builder.fill('{basename}.thumbnail{ext}'), - self.conversions_subdir, self.exif_tags) - - # Possibly create a medium - resize_tool(self.proc_state, False, 'medium', self.orig_filename, - self.name_builder.fill('{basename}.medium{ext}'), - self.conversions_subdir, self.exif_tags) - - # Copy our queued local workbench to its final destination - self.proc_state.copy_original(self.name_builder.fill('{basename}{ext}')) - - # Remove queued media file from storage and database - self.proc_state.delete_queue_file() - - # 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): - for key in list(gps_data.keys()): - gps_data['gps_' + key] = gps_data.pop(key) - self.entry.media_data_init(**gps_data) - - def reprocess(self, reprocess_info): - """ - This function actually does the reprocessing when called by - ProcessMedia in gmg/processing/task.py - """ - new_size = None - - # Did they specify a size? They must specify either both or none, so - # we only need to check if one is present - if reprocess_info.get('max_width'): - max_width = reprocess_info['max_width'] - max_height = reprocess_info['max_height'] - - new_size = (max_width, max_height) - - resize_tool(self.proc_state, False, reprocess_info['resize'], - self.name_builder.fill('{basename}.medium{ext}'), - self.conversions_subdir, self.exif_tags, new_size) - - def media_reprocess(self, args): - """ - This function handles the all of the reprocessing logic, before calling - gmg/submit/lib/run_process_media - """ - reprocess_args = self._parser(args) - entry_args = args[0] - - # Can we actually process the given media as requested? - self._check_eligible(entry_args, reprocess_args) - - # Do we want to re-try initial processing? - if reprocess_args.initial_processing: - for id in entry_args.media_id: - entry = MediaEntry.query.filter_by(id=id).first() - run_process_media(entry) - - # Are we wanting to resize the thumbnail or medium? - elif reprocess_args.resize: - - # reprocess all given media entries - for id in entry_args.media_id: - entry = MediaEntry.query.filter_by(id=id).first() - - # For now we can only reprocess with the original file - if not entry.media_files.get('original'): - raise Exception(_('The original file for this media entry' - ' does not exist.')) - - reprocess_info = self._get_reprocess_info(reprocess_args) - run_process_media(entry, reprocess_info=reprocess_info) - - # If we are here, they forgot to tell us how to reprocess - else: - _log.warn('You must set either --resize or --initial_processing' - ' flag to reprocess an image.') - - def _get_reprocess_info(self, args): - """ Returns a dict with the info needed for reprocessing""" - reprocess_info = {'resize': args.resize} - - if args.size: - reprocess_info['max_width'] = args.size[0] - reprocess_info['max_height'] = args.size[1] - - return reprocess_info - - class CommonImageProcessor(MediaProcessor): """ Provides a base for various media processing steps @@ -342,16 +164,15 @@ class CommonImageProcessor(MediaProcessor): # Exif extraction self.exif_tags = extract_exif(self.orig_filename) - def generate_medium_if_applicable(self, size=None): resize_tool(self.entry, False, 'medium', self.orig_filename, self.name_builder.fill('{basename}.medium{ext}'), - self.conversions_subdir, self.exif_tags) + self.conversions_subdir, self.exif_tags, size) def generate_thumb(self, size=None): resize_tool(self.entry, True, 'thumb', self.orig_filename, self.name_builder.fill('{basename}.thumbnail{ext}'), - self.conversions_subdir, self.exif_tags) + self.conversions_subdir, self.exif_tags, size) def copy_original(self): copy_original( @@ -408,6 +229,7 @@ class InitialProcessor(CommonImageProcessor): parser.add_argument( '--thumb-size', nargs=2, + metavar=('max_width', 'max_height'), type=int) return parser @@ -417,19 +239,69 @@ class InitialProcessor(CommonImageProcessor): return request_from_args( args, ['size', 'thumb_size']) - def process(self, size=None, thumb_size=None): self.common_setup() self.generate_medium_if_applicable(size=size) self.generate_thumb(size=thumb_size) self.copy_original() self.extract_metadata() + self.delete_queue_file() + + +class Resizer(CommonImageProcessor): + """ + Resizing process steps for processed media + """ + name = 'resize' + description = 'Resize image' + + @classmethod + def media_is_eligible(cls, entry): + """ + Determine if this media type is eligible for processing + """ + return entry.state in 'processed' + + ############################### + # Command line interface things + ############################### + + @classmethod + def generate_parser(cls): + parser = argparse.ArgumentParser( + description=cls.description, + prog=cls.name) + + parser.add_argument( + '--size', + nargs=2, + metavar=('max_width', 'max_height'), + type=int) + + parser.add_argument( + 'file', + choices=['medium', 'thumb']) + + return parser + + @classmethod + def args_to_request(cls, args): + return request_from_args( + args, ['size', 'file']) + + def process(self, file, size=None): + self.common_setup() + if file == 'medium': + self.generate_medium_if_applicable(size=size) + elif file == 'thumb': + self.generate_thumb(size=size) class ImageProcessingManager(ProcessingManager): def __init__(self): super(self.__class__, self).__init__() self.add_processor(InitialProcessor) + self.add_processor(Resizer) if __name__ == '__main__': diff --git a/mediagoblin/processing/__init__.py b/mediagoblin/processing/__init__.py index 684ffe04..d5ec1fba 100644 --- a/mediagoblin/processing/__init__.py +++ b/mediagoblin/processing/__init__.py @@ -90,7 +90,7 @@ class MediaProcessor(object): - resize: resize an image - transcode: transcode a video - ... etc. + ... etc. Some information on producing a new MediaProcessor for your media type: @@ -193,7 +193,7 @@ class ProcessingManager(object): name = processor.name if name is None: raise AttributeError("Processor class's .name attribute not set") - + self.processors[name] = processor def list_eligible_processors(self, entry): |