Implement Raw Image media type plugin
authorOdin Hørthe Omdal <odinho@opera.com>
Mon, 12 May 2014 21:41:03 +0000 (23:41 +0200)
committerChristopher Allan Webber <cwebber@dustycloud.org>
Wed, 16 Jul 2014 19:29:58 +0000 (14:29 -0500)
docs/source/siteadmin/media-types.rst
mediagoblin/media_types/image/__init__.py
mediagoblin/media_types/raw_image/__init__.py [new file with mode: 0644]
mediagoblin/media_types/raw_image/models.py [new file with mode: 0644]
mediagoblin/media_types/raw_image/processing.py [new file with mode: 0644]

index 3e8a94e9e5ade4156ed9c8188330dd009e067986..44ad02bb32c24d8cb23fb5780cef84e3b87ca124 100644 (file)
@@ -1,6 +1,6 @@
 .. MediaGoblin Documentation
 
-   Written in 2011, 2012 by MediaGoblin contributors
+   Written in 2011, 2012, 2014 by MediaGoblin contributors
 
    To the extent possible under law, the author(s) have dedicated all
    copyright and related and neighboring rights to this software to
@@ -18,8 +18,8 @@ Media Types
 ====================
 
 In the future, there will be all sorts of media types you can enable,
-but in the meanwhile there are five additional media types: video, audio,
-ascii art, STL/3d models, PDF and Document.
+but in the meanwhile there are six additional media types: video, audio,
+raw image, ascii art, STL/3d models, PDF and Document.
 
 First, you should probably read ":doc:`configuration`" to make sure
 you know how to modify the mediagoblin config file.
@@ -149,6 +149,28 @@ Run
 You should now be able to upload and listen to audio files!
 
 
+Raw image
+=========
+
+To enable raw image you need to install pyexiv2.  On Debianoid systems
+
+.. code-block:: bash
+
+    sudo apt-get install python-pyexiv2
+
+Add ``[[mediagoblin.media_types.raw_image]]`` under the ``[plugins]``
+section in your ``mediagoblin_local.ini`` and restart MediaGoblin.
+
+Run
+
+.. code-block:: bash
+
+    ./bin/gmg dbupdate
+
+Now you should be able to submit raw images, and mediagoblin should
+extract the JPEG preview from them.
+
+
 Ascii art
 =========
 
index f5b49f018ee82096390cd629b43776d666a48c0a..06e0f08f888dd0bfab895a8101cae0bb001b4557 100644 (file)
@@ -27,8 +27,6 @@ _log = logging.getLogger(__name__)
 ACCEPTED_EXTENSIONS = ["jpg", "jpeg", "png", "gif", "tiff"]
 MEDIA_TYPE = 'mediagoblin.media_types.image'
 
-def setup_plugin():
-    config = pluginapi.get_config(MEDIA_TYPE)
 
 class ImageMediaManager(MediaManagerBase):
     human_readable = "Image"
diff --git a/mediagoblin/media_types/raw_image/__init__.py b/mediagoblin/media_types/raw_image/__init__.py
new file mode 100644 (file)
index 0000000..046a9b2
--- /dev/null
@@ -0,0 +1,37 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2014 MediaGoblin contributors.  See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from mediagoblin.media_types.image import ImageMediaManager
+from mediagoblin.media_types.raw_image.processing import (
+    ACCEPTED_EXTENSIONS, MEDIA_TYPE,
+    RawImageProcessingManager, sniff_handler)
+
+
+class RawImageMediaManager(ImageMediaManager):
+    human_readable = "Raw image"
+
+
+def get_media_type_and_manager(ext):
+    if ext in ACCEPTED_EXTENSIONS:
+        return MEDIA_TYPE, RawImageMediaManager
+
+
+hooks = {
+    'get_media_type_and_manager': get_media_type_and_manager,
+    'sniff_handler': sniff_handler,
+    ('media_manager', MEDIA_TYPE): lambda: RawImageMediaManager,
+    ('reprocess_manager', MEDIA_TYPE): lambda: RawImageProcessingManager,
+}
diff --git a/mediagoblin/media_types/raw_image/models.py b/mediagoblin/media_types/raw_image/models.py
new file mode 100644 (file)
index 0000000..d3d68b9
--- /dev/null
@@ -0,0 +1,21 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2014 MediaGoblin contributors.  See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from mediagoblin.media_types.image.models import (
+    BACKREF_NAME, DATA_MODEL)
+
+
+MODELS = None
diff --git a/mediagoblin/media_types/raw_image/processing.py b/mediagoblin/media_types/raw_image/processing.py
new file mode 100644 (file)
index 0000000..83b0155
--- /dev/null
@@ -0,0 +1,82 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2014 MediaGoblin contributors.  See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import logging
+
+# This needs to handle the case where it's missing
+import pyexiv2
+
+from mediagoblin.media_types.image.processing import (
+    InitialProcessor, Resizer)
+from mediagoblin.processing import (
+    FilenameBuilder, ProcessingManager)
+
+
+_log = logging.getLogger(__name__)
+
+MEDIA_TYPE = 'mediagoblin.media_types.raw_image'
+ACCEPTED_EXTENSIONS = ['nef',]
+
+
+# The entire function have to be copied
+
+def sniff_handler(media_file, filename):
+    _log.info('Sniffing {0}'.format(MEDIA_TYPE))
+    name, ext = os.path.splitext(filename)
+    clean_ext = ext[1:].lower()  # Strip the . from ext and make lowercase
+
+    if clean_ext in ACCEPTED_EXTENSIONS:
+        _log.info('Found file extension in supported filetypes')
+        return MEDIA_TYPE
+    else:
+        _log.debug('Media present, extension not found in {0}'.format(
+                ACCEPTED_EXTENSIONS))
+
+    return None
+
+
+class InitialRawProcessor(InitialProcessor):
+    def common_setup(self):
+        """
+        Pull out a full-size JPEG-preview
+        """
+        super(self.__class__, self).common_setup()
+
+        self._original_raw = self.process_filename
+
+        # Read EXIF data
+        md = pyexiv2.ImageMetadata(self._original_raw)
+        md.read()
+        self.process_filename = os.path.join(self.conversions_subdir,
+            self.entry.queued_media_file[-1])
+
+        # Extract the biggest preview and write it as our working image
+        md.previews[-1].write_to_file(
+            self.process_filename.encode('utf-8'))
+        self.process_filename += ".jpg"
+        _log.debug('Wrote new file from {0} to preview (jpg) {1}'.format(
+            self._original_raw, self.process_filename))
+
+        # Override the namebuilder with our new jpg-based name
+        self.name_builder = FilenameBuilder(self.process_filename)
+
+
+class RawImageProcessingManager(ProcessingManager):
+    def __init__(self):
+        super(self.__class__, self).__init__()
+        self.add_processor(InitialRawProcessor)
+        self.add_processor(Resizer)