Add icon composition support, add several combined new icons, switch to icon base64 redering

This commit is contained in:
Roberto Rosario
2012-09-29 01:03:09 -04:00
parent e8a0e2b5ab
commit 7681f82321
4 changed files with 146 additions and 22 deletions

View File

@@ -2,26 +2,60 @@ from __future__ import absolute_import
import os
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
import PIL
from django.utils.safestring import mark_safe
from django.conf import settings
from .literals import ERROR, SIZE_SMALL, SIZE_BIG
from .literals import (ERROR, SIZE_SMALL, SIZE_BIG, ICONSETS_STATIC_DIRECTORY)
class Icon(object):
_registry = {}
_cache = {}
def __init__(self, id, icon_set=None):
self.id = id
self.icon_set = icon_set
self.__class__._registry[id] = self
def get_url(self, size):
def get_iconset(self):
from .settings import ICON_SET
return IconSetBase.get_by_name(self.icon_set or ICON_SET).get_url(self, size)
return IconSetBase.get_by_name(self.icon_set or ICON_SET)
#def get_url(self, size):
# #from .settings import ICON_SET
# #return IconSetBase.get_by_name(self.icon_set or ICON_SET).get_url_of_icon(self, size)
# return self.get_iconset().get_url_of_icon(self, size)
#def get_as_base64(self, size):
# from .settings import ICON_SET
# return IconSetBase.get_by_name(self.icon_set or ICON_SET).get_as_base64(self, size)
#def get_as_filename(self, size):
# #from .settings import ICON_SET
# #return IconSetBase.get_by_name(self.icon_set or ICON_SET).get_filename_of_icon(self, size)
# return self.get_iconset().get_filename_of_icon(self, size)
def display(self, size): # TODO: move to widgets?
return mark_safe('<img style="vertical-align: middle;" src="%sicons/%s" />' % (settings.STATIC_URL, self.get_url(size)))
#return mark_safe('<img style="vertical-align: middle;" src="%s" />' % self.get_url(size))
#return mark_safe('<img style="vertical-align: middle;" src="%s" />' % self.get_as_base64(size))
#return mark_safe('<img style="vertical-align: middle;" src="%s" />' % self.process(size))
#return mark_safe('<img style="vertical-align: middle;" src="%s" />' % self.get_iconset().compose(self, size))
# Cache a composed icon result for a specific size
try:
result = self.__class__._cache['%d_%s' % (id(self), size)]
except KeyError:
result = self.get_iconset().compose(self, size)
self.__class__._cache['%d_%s' % (id(self), size)] = result
return mark_safe('<img style="vertical-align: middle;" src="%s" />' % result)
def display_small(self):
return self.display(SIZE_SMALL)
@@ -29,12 +63,6 @@ class Icon(object):
def display_big(self):
return self.display(SIZE_BIG)
#def get_filepath(self):
# if settings.DEVELOPMENT:
# return os.path.join(settings.PROJECT_ROOT, 'apps', 'icons', 'static', 'icons', self.get_file_name(SIZE_BIG))
# else:
# return os.path.join(settings.STATIC_ROOT, self.get_file_name(SIZE_BIG))
class IconSetBase(object):
_registry = {}
@@ -50,9 +78,74 @@ class IconSetBase(object):
def __init__(self):
self.__class__._registry[self.name] = self
def get_filename(self, icon, size):
return os.path.join([self.path, size, self.dictionary.get(icon.id, ERROR)])
def get_url(self, icon, size):
return '%s/%s/%s' % (self.path, size, self.dictionary.get(icon.id, ERROR))
#def get_filename_of_icon(self, icon, size):
# if settings.DEVELOPMENT:
# return os.path.join(settings.PROJECT_ROOT, 'apps', 'icons', 'static', ICONSETS_STATIC_DIRECTORY, self.directory, size, self.dictionary.get(icon.id, ERROR))
# else:
# return os.path.join(settings.STATIC_ROOT, ICONSETS_STATIC_DIRECTORY, self.directory, size, self.dictionary.get(icon.id, ERROR))
def get_filename_of_image(self, image_name, size):
if settings.DEVELOPMENT:
return os.path.join(settings.PROJECT_ROOT, 'apps', 'icons', 'static', ICONSETS_STATIC_DIRECTORY, self.directory, size, image_name)
else:
return os.path.join(settings.STATIC_ROOT, ICONSETS_STATIC_DIRECTORY, self.directory, size, image_name)
#def get_url_of_icon(self, icon, size):
# return '%s%s/%s/%s/%s' % (settings.STATIC_URL, ICONSETS_STATIC_DIRECTORY, self.directory, size, self.dictionary.get(icon.id, ERROR))
def get_major_minor(self, icon):
return self.dictionary.get(icon.id, ERROR)
def compose(self, icon, size):
try:
major, minor = self.get_major_minor(icon)
except ValueError:
major = self.get_major_minor(icon)
minor = None
major_image = PIL.Image.open(self.get_filename_of_image(major, size))
if minor:
major_width, major_height = major_image.size
minor_image = PIL.Image.open(self.get_filename_of_image(minor, size))
minor_image.thumbnail((major_width / 1.6, major_height / 1.6))#, PIL.Image.ANTIALIAS)
minor_width, minor_height = minor_image.size
major_image.paste(minor_image, (major_width - minor_width, major_height - minor_height), minor_image)
output = StringIO()
major_image.save(output, 'PNG')
contents = output.getvalue().encode('base64')
output.close()
return 'data:image/png;base64,%s' % contents
class Verb(object):
pass
class Load(Verb):
def __init__(self, filename):
self.filename = filename
def execute(self):
return PIL.Image.open(self.filename)
class Resize(Verb):
def __init__(self, image, size, antialias=False):
self.image = image
self.size = size
self.antialias = antialias
def execute(self):
if self.antialias:
self.image.thumbnail(self.size, PIL.Image.ANTIALIAS)
else:
self.image.thumbnail(self.size)
class Rotate(Verb):
def __init__(self, degrees):
self.degrees = degrees
def execute(self):
pass

View File

@@ -8,6 +8,7 @@ class IconSet(IconSetBase):
path = 'custom'
name = 'custom'
label = _(u'Custom')
directory='custom'
dictionary = {
FILE_EXTENSION_ERROR: 'file_extension_error.png',
FILE_EXTENSION_UNKNOWN: 'file_extension_unknown.png'

View File

@@ -7,20 +7,25 @@ from icons.classes import IconSetBase
class IconSet(IconSetBase):
name='fat_cow'
label=_(u'Fat cow')
path='fat_cow'
directory='fat_cow'
available_sizes=['32x32', '16x16']
dictionary={
ADD: 'add.png',
APPLICATION_VIEW_ICONS: 'application_view_icons.png',
ARROW_TURN_RIGHT: 'arrow_turn_right.png',
ARROW_TURN_LEFT: 'arrow_turn_left.png',
ARROW_UP: 'arrow_up.png',
BIN_CLOSED: 'bin_closed.png',
BIN: 'bin.png',
BIN_CLOSED: 'bin_closed.png',
BIN_EMPTY: 'bin_empty.png',
BIN_EMPTY_OUT: ['bin_empty.png', 'arrow_turn_right.png'],
BIN_MULTIPLE: ['bin_closed.png', 'bin_closed.png'],
BIN_RECYCLE: ['bin.png', 'recycle.png'],
BLACKBOARD_SUM: 'blackboard_sum.png',
BOOK: 'book.png',
BOOK_GO: 'book_go.png',
BOOK_OPEN: 'book_open.png',
BULLET_GO: 'bullet_go.png',
CAMERA_DELETE: 'camera_delete.png',
CD_BURN: 'cd_burn.png',
COG: 'cog.png',
@@ -59,6 +64,7 @@ class IconSet(IconSetBase):
GROUP_DELETE: 'group_delete.png',
GROUP_KEY: 'group_key.png',
GROUP_LINK: 'group_link.png',
GROUP_MEMBERS: ['group.png', 'arrow_refresh.png'],
HOURGLASS: 'hourglass.png',
HOUSE: 'house.png',
INDEX: 'index.png',
@@ -86,8 +92,12 @@ class IconSet(IconSetBase):
MAGNIFIER: 'magnifier.png',
MEDAL_GOLD: 'medal_gold_1.png',
MEDAL_GOLD_ADD: 'medal_gold_add.png',
MEDAL_GOLD_EDIT: ['medal_gold_1.png', 'pencil.png'],
MEDAL_GOLD_DELETE: 'medal_gold_delete.png',
NODE: 'node.png',
NODE_TREE: 'node-tree.png',
NODE_TREE_ADD: ['node-tree.png', 'add.png'],
NODE_TREE_EDIT: ['node-tree.png', 'pencil.png'],
NODE_TREE_DELETE: ['node-tree.png', 'delete.png'],
PACKAGE: 'package.png',
PAGE: 'page.png',
PAGE_COPY: 'page_copy.png',
@@ -126,7 +136,7 @@ class IconSet(IconSetBase):
TAB_ADD: 'tab_add.png',
TAB_DELETE: 'tab_delete.png',
TAB_EDIT: 'tab_edit.png',
TAB_VIEW: 'tab_view.png',
TAB_GO: 'tab_go.png',
TABLE: 'table.png',
TABLE_ADD: 'table_add.png',
TABLE_EDIT: 'table_edit.png',
@@ -154,12 +164,17 @@ class IconSet(IconSetBase):
VCARD: 'vcard.png',
VCARD_EDIT: 'vcard_edit.png',
WIZARD: 'wizard.png',
WIZARD_ADD: ['wizard.png', 'add.png'],
WIZARD_DELETE: ['wizard.png', 'delete.png'],
WIZARD_EDIT: ['wizard.png', 'pencil.png'],
WIZARD_LIGHTNING: ['wizard.png', 'lightning.png'],
WORLD_GO: 'world_go.png',
WRENCH: 'wrench.png',
XHTML: 'xhtml.png',
XHTML_GO: 'xhtml_go.png',
XHTML_ADD: 'xhtml_add.png',
XHTML_DELETE: 'xhtml_delete.png',
XHTML_EDIT: ['xhtml.png', 'pencil.png'],
ZOOM: 'zoom.png',
ZOOM_IN: 'zoom_in.png',
ZOOM_OUT: 'zoom_out.png',

View File

@@ -2,6 +2,7 @@ SIZE_SMALL = '16x16'
SIZE_BIG = '32x32'
DEFAULT_ICON_SET = 'fat_cow'
ICONSETS_STATIC_DIRECTORY = 'icons'
ADD = 'add'
APPLICATION_VIEW_ICONS = 'application_view_icons'
@@ -11,10 +12,14 @@ ARROW_UP = 'arrow_up'
BIN_CLOSED = 'bin_closed'
BIN = 'bin'
BIN_EMPTY = 'bin_empty'
BIN_EMPTY_OUT = 'bin_empty_out'
BIN_MULTIPLE = 'bin_multiple'
BIN_RECYCLE = 'bin_recyle'
BLACKBOARD_SUM = 'blackboard_sum'
BOOK = 'book'
BOOK_GO = 'book_go'
BOOK_OPEN = 'book_open'
BULLET_GO = 'bullet_go'
CAMERA_DELETE = 'camera_delete'
CD_BURN = 'cd_burn'
COG = 'cog'
@@ -49,12 +54,13 @@ FOLDER_DELETE = 'folder_delete'
FOLDER_GO = 'folder_go'
FOLDER_PAGE = 'folder_page'
FOLDER_USER = 'folder_user'
GROUP = 'user'
GROUP = 'group'
GROUP_ADD = 'group_add'
GROUP_EDIT = 'group_edit'
GROUP_DELETE = 'group_delete'
GROUP_KEY = 'group_key'
GROUP_LINK = 'group_link'
GROUP_MEMBERS = 'group_members'
HOURGLASS = 'hourglass'
HOUSE = 'house'
INDEX = 'index'
@@ -82,8 +88,12 @@ MAGIC_WAND_2 = 'magic_wand_2'
MAGNIFIER = 'magnifier'
MEDAL_GOLD = 'medal_gold'
MEDAL_GOLD_ADD = 'medal_gold_add'
MEDAL_GOLD_EDIT = 'medal_gold_edit'
MEDAL_GOLD_DELETE = 'medal_gold_delete'
NODE = 'node'
NODE_TREE = 'node_tree'
NODE_TREE_ADD = 'node_tree_add'
NODE_TREE_EDIT = 'node_tree_edit'
NODE_TREE_DELETE = 'node_tree_delete'
PACKAGE = 'package'
PAGE = 'page'
PAGE_COPY = 'page_copy'
@@ -122,7 +132,7 @@ TAB = 'tab'
TAB_ADD = 'tab_add'
TAB_DELETE = 'tab_delete'
TAB_EDIT = 'tab_edit'
TAB_VIEW = 'tab_view'
TAB_GO = 'tab_go'
TABLE = 'table'
TABLE_ADD = 'table_add'
TABLE_EDIT = 'table_edit'
@@ -150,12 +160,17 @@ USER_SILHOUETTE = 'user_silhouette'
VCARD = 'vcard'
VCARD_EDIT = 'vcard_edit'
WIZARD = 'wizard'
WIZARD_ADD = 'wizard_add'
WIZARD_DELETE = 'wizard_delete'
WIZARD_EDIT = 'wizard_edit'
WIZARD_LIGHTNING = 'wizard_lightning'
WORLD_GO = 'world_go'
WRENCH = 'wrench'
XHTML = 'xhtml'
XHTML_GO = 'xhtml_go'
XHTML_ADD = 'xhtml_add'
XHTML_DELETE = 'xhtml_delete'
XHTML_EDIT = 'xhtml_edit'
ZOOM = 'zoom'
ZOOM_IN = 'zoom_in'
ZOOM_OUT = 'zoom_out'