Add image resizer and some cleanup of old code
authorRodney Ewing <ewing.rj@gmail.com>
Mon, 12 Aug 2013 18:37:59 +0000 (11:37 -0700)
committerRodney Ewing <ewing.rj@gmail.com>
Fri, 16 Aug 2013 22:30:17 +0000 (15:30 -0700)
mediagoblin/media_types/image/__init__.py
mediagoblin/media_types/image/processing.py
mediagoblin/processing/__init__.py

index 774b9bfa08bc0cfd35af21700e94a46553fd5016..f8c4a7d1a09051b23f5be90a9b3a83efa4c5ff6e 100644 (file)
@@ -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"
 
index 01e5cce52f59979de2999a6a33fe399bc79ca50d..6eb8302cbc85446fa7ad39500b580d7ae738c885 100644 (file)
@@ -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__':
index 684ffe04e622e84cecae336d6215e27c4c8446b3..d5ec1fba254d3bc47f8dac1da97eeac520aa8bad 100644 (file)
@@ -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):