aboutsummaryrefslogtreecommitdiffstats
path: root/mediagoblin/media_types
diff options
context:
space:
mode:
Diffstat (limited to 'mediagoblin/media_types')
-rw-r--r--mediagoblin/media_types/__init__.py20
-rw-r--r--mediagoblin/media_types/ascii/__init__.py27
-rw-r--r--mediagoblin/media_types/ascii/asciitoimage.py172
l---------mediagoblin/media_types/ascii/fonts/Inconsolata.otf1
-rw-r--r--mediagoblin/media_types/ascii/processing.py93
5 files changed, 305 insertions, 8 deletions
diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py
index 6f94c714..7b9bf0d7 100644
--- a/mediagoblin/media_types/__init__.py
+++ b/mediagoblin/media_types/__init__.py
@@ -69,16 +69,20 @@ def get_media_type_and_manager(filename):
'''
Get the media type and manager based on a filename
'''
- for media_type, manager in get_media_managers():
- if filename.find('.') > 0:
- # Get the file extension
- ext = os.path.splitext(filename)[1].lower()
- else:
- raise InvalidFileType(
- _('Could not find any file extension in "{filename}"').format(
- filename=filename))
+ if filename.find('.') > 0:
+ # Get the file extension
+ ext = os.path.splitext(filename)[1].lower()
+ else:
+ raise Exception(
+ _(u'Could not extract any file extension from "{filename}"').format(
+ filename=filename))
+ for media_type, manager in get_media_managers():
# Omit the dot from the extension and match it against
# the media manager
if ext[1:] in manager['accepted_extensions']:
return media_type, manager
+ else:
+ raise FileTypeNotSupported(
+ # TODO: Provide information on which file types are supported
+ _(u'Sorry, I don\'t support that file type :('))
diff --git a/mediagoblin/media_types/ascii/__init__.py b/mediagoblin/media_types/ascii/__init__.py
new file mode 100644
index 00000000..21b31d0e
--- /dev/null
+++ b/mediagoblin/media_types/ascii/__init__.py
@@ -0,0 +1,27 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011 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.ascii.processing import process_ascii
+
+
+MEDIA_MANAGER = {
+ "human_readable": "ASCII",
+ "processor": process_ascii, # alternately a string,
+ # 'mediagoblin.media_types.image.processing'?
+ "display_template": "mediagoblin/media_displays/ascii.html",
+ "default_thumb": "images/media_thumbs/ascii.jpg",
+ "accepted_extensions": [
+ "txt"]}
diff --git a/mediagoblin/media_types/ascii/asciitoimage.py b/mediagoblin/media_types/ascii/asciitoimage.py
new file mode 100644
index 00000000..39c75a19
--- /dev/null
+++ b/mediagoblin/media_types/ascii/asciitoimage.py
@@ -0,0 +1,172 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011 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 Image
+import ImageFont
+import ImageDraw
+import logging
+import pkg_resources
+import os
+
+_log = logging.getLogger(__name__)
+
+class AsciiToImage(object):
+ '''
+ Converter of ASCII art into image files, preserving whitespace
+
+ kwargs:
+ - font: Path to font file
+ default: fonts/Inconsolata.otf
+ - font_size: Font size, ``int``
+ default: 11
+ '''
+
+ # Font file path
+ _font = None
+
+ _font_size = 11
+
+ # ImageFont instance
+ _if = None
+
+ # ImageFont
+ _if_dims = None
+
+ # Image instance
+ _im = None
+
+ def __init__(self, **kw):
+ if kw.get('font'):
+ self._font = kw.get('font')
+ else:
+ self._font = pkg_resources.resource_filename(
+ 'mediagoblin.media_types.ascii',
+ os.path.join('fonts', 'Inconsolata.otf'))
+
+ if kw.get('font_size'):
+ self._font_size = kw.get('font_size')
+
+ _log.info('Setting font to {0}, size {1}'.format(
+ self._font,
+ self._font_size))
+
+ self._if = ImageFont.truetype(
+ self._font,
+ self._font_size)
+
+ # ,-,-^-'-^'^-^'^-'^-.
+ # ( I am a wall socket )Oo, ___
+ # `-.,.-.,.-.-.,.-.--' ' `
+ # Get the size, in pixels of the '.' character
+ self._if_dims = self._if.getsize('.')
+ # `---'
+
+ def convert(self, text, destination):
+ # TODO: Detect if text is a file-like, if so, act accordingly
+ im = self._create_image(text)
+
+ # PIL's Image.save will handle both file-likes and paths
+ if im.save(destination):
+ _log.info('Saved image in {0}'.format(
+ destination))
+
+ def _create_image(self, text):
+ '''
+ Write characters to a PIL image canvas.
+
+ TODO:
+ - Character set detection and decoding,
+ http://pypi.python.org/pypi/chardet
+ '''
+ # TODO: Account for alternative line endings
+ lines = text.split('\n')
+
+ line_lengths = [len(i) for i in lines]
+
+ # Calculate destination size based on text input and character size
+ im_dims = (
+ max(line_lengths) * self._if_dims[0],
+ len(line_lengths) * self._if_dims[1])
+
+ _log.info('Destination image dimensions will be {0}'.format(
+ im_dims))
+
+ im = Image.new(
+ 'RGBA',
+ im_dims,
+ (255, 255, 255, 0))
+
+ draw = ImageDraw.Draw(im)
+
+ char_pos = [0, 0]
+
+ for line in lines:
+ line_length = len(line)
+
+ _log.debug('Writing line at {0}'.format(char_pos))
+
+ for _pos in range(0, line_length):
+ char = line[_pos]
+
+ px_pos = self._px_pos(char_pos)
+
+ _log.debug('Writing character "{0}" at {1} (px pos {2}'.format(
+ char,
+ char_pos,
+ px_pos))
+
+ draw.text(
+ px_pos,
+ char,
+ font=self._if,
+ fill=(0, 0, 0, 255))
+
+ char_pos[0] += 1
+
+ # Reset X position, increment Y position
+ char_pos[0] = 0
+ char_pos[1] += 1
+
+ return im
+
+ def _px_pos(self, char_pos):
+ '''
+ Helper function to calculate the pixel position based on
+ character position and character dimensions
+ '''
+ px_pos = [0, 0]
+ for index, val in zip(range(0, len(char_pos)), char_pos):
+ px_pos[index] = char_pos[index] * self._if_dims[index]
+
+ return px_pos
+
+
+if __name__ == "__main__":
+ import urllib
+ txt = urllib.urlopen('file:///home/joar/Dropbox/ascii/install-all-the-dependencies.txt')
+
+ _log.setLevel(logging.DEBUG)
+ logging.basicConfig()
+
+ converter = AsciiToImage()
+
+ converter.convert(txt.read(), '/tmp/test.png')
+
+ '''
+ im, x, y, duration = renderImage(h, 10)
+ print "Rendered image in %.5f seconds" % duration
+ im.save('tldr.png', "PNG")
+ '''
diff --git a/mediagoblin/media_types/ascii/fonts/Inconsolata.otf b/mediagoblin/media_types/ascii/fonts/Inconsolata.otf
new file mode 120000
index 00000000..4e742b5e
--- /dev/null
+++ b/mediagoblin/media_types/ascii/fonts/Inconsolata.otf
@@ -0,0 +1 @@
+../../../../extlib/inconsolata/Inconsolata.otf \ No newline at end of file
diff --git a/mediagoblin/media_types/ascii/processing.py b/mediagoblin/media_types/ascii/processing.py
new file mode 100644
index 00000000..a74690c1
--- /dev/null
+++ b/mediagoblin/media_types/ascii/processing.py
@@ -0,0 +1,93 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011 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 asciitoimage
+import chardet
+import os
+import Image
+
+from mediagoblin import mg_globals as mgg
+from mediagoblin.processing import create_pub_filepath, THUMB_SIZE
+
+
+def process_ascii(entry):
+ '''
+ Code to process a txt file
+ '''
+ workbench = mgg.workbench_manager.create_workbench()
+ # Conversions subdirectory to avoid collisions
+ conversions_subdir = os.path.join(
+ workbench.dir, 'conversions')
+ os.mkdir(conversions_subdir)
+
+ queued_filepath = entry['queued_media_file']
+ queued_filename = workbench.localized_file(
+ mgg.queue_store, queued_filepath,
+ 'source')
+
+ queued_file = file(queued_filename, 'rb')
+
+ with queued_file:
+ queued_file_charset = chardet.detect(queued_file.read())
+
+ queued_file.seek(0) # Rewind the queued file
+
+ thumb_filepath = create_pub_filepath(
+ entry, 'thumbnail.png')
+
+ tmp_thumb_filename = os.path.join(
+ conversions_subdir, thumb_filepath[-1])
+
+ converter = asciitoimage.AsciiToImage()
+
+ thumb = converter._create_image(
+ queued_file.read())
+
+ with file(tmp_thumb_filename, 'w') as thumb_file:
+ thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS)
+ thumb.save(thumb_file)
+
+ mgg.public_store.copy_local_to_storage(
+ tmp_thumb_filename, thumb_filepath)
+
+ queued_file.seek(0)
+
+ original_filepath = create_pub_filepath(entry, queued_filepath[-1])
+
+ with mgg.public_store.get_file(original_filepath, 'wb') \
+ as original_file:
+ original_file.write(queued_file.read())
+
+
+ queued_file.seek(0) # Rewind *again*
+
+ unicode_filepath = create_pub_filepath(entry, 'unicode.txt')
+
+ with mgg.public_store.get_file(unicode_filepath, 'wb') \
+ as unicode_file:
+ unicode_file.write(
+ unicode(queued_file.read().decode(
+ queued_file_charset['encoding'])).encode(
+ 'ascii',
+ 'xmlcharrefreplace'))
+
+ mgg.queue_store.delete_file(queued_filepath)
+ entry['queued_media_file'] = []
+ media_files_dict = entry.setdefault('media_files', {})
+ media_files_dict['thumb'] = thumb_filepath
+ media_files_dict['unicode'] = unicode_filepath
+ media_files_dict['original'] = original_filepath
+
+ entry.save()