forked from stefanfoulis/django-image-filer
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Stefan Foulis
committed
Apr 23, 2009
0 parents
commit cd4e914
Showing
21 changed files
with
4,983 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
from django.contrib import admin | ||
from models import Folder, Image, FolderPermission, ImagePermission | ||
from models import ImageManipulationProfile, ImageManipulationStep, ImageManipulationTemplate | ||
from models import Bucket, BucketItem | ||
|
||
admin.site.register([FolderPermission, ImagePermission, ImageManipulationTemplate]) | ||
|
||
|
||
class ImageAdmin(admin.ModelAdmin): | ||
list_display = ('label','admin_thumbnail', 'has_all_mandatory_data') | ||
list_per_page = 10 | ||
search_fields = ['name', 'original_filename','default_alt_text','default_caption','usage_restriction_notes','notes'] | ||
admin.site.register(Image, ImageAdmin) | ||
|
||
class FolderAdmin(admin.ModelAdmin): | ||
list_display = ('name', 'owner',) | ||
list_per_page = 20 | ||
admin.site.register(Folder, FolderAdmin) | ||
|
||
class ImageManipulationStepInline(admin.TabularInline): | ||
model = ImageManipulationStep | ||
class ImageManipulationProfileAdmin(admin.ModelAdmin): | ||
inlines = [ ImageManipulationStepInline, ] | ||
admin.site.register(ImageManipulationProfile, ImageManipulationProfileAdmin) | ||
|
||
|
||
|
||
class BucketItemInline(admin.TabularInline): | ||
model = BucketItem | ||
class BucketAdmin(admin.ModelAdmin): | ||
model = Bucket | ||
inlines = [ BucketItemInline, ] | ||
admin.site.register(Bucket, BucketAdmin) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# -*- coding: utf-8 -*- | ||
# --------------------------------------- fields.py --------------------------------------- # | ||
# http://www.djangosnippets.org/snippets/513/ | ||
# 2009-04-05 Stefan Foulis: added base64 encoding to avoid problems with unicode strings | ||
|
||
from django.db import models | ||
|
||
try: | ||
import cPickle as pickle | ||
except ImportError: | ||
import pickle | ||
|
||
class PickledObject(str): | ||
"""A subclass of string so it can be told whether a string is | ||
a pickled object or not (if the object is an instance of this class | ||
then it must [well, should] be a pickled one).""" | ||
pass | ||
|
||
class PickledObjectField(models.Field): | ||
__metaclass__ = models.SubfieldBase | ||
|
||
def to_python(self, value): | ||
if isinstance(value, PickledObject): | ||
# If the value is a definite pickle; and an error is raised in de-pickling | ||
# it should be allowed to propogate. | ||
return pickle.loads( str(value).decode('base64') ) | ||
else: | ||
try: | ||
return pickle.loads( str(value).decode('base64') ) | ||
except: | ||
# If an error was raised, just return the plain value | ||
return value | ||
|
||
def get_db_prep_save(self, value): | ||
if value is not None and not isinstance(value, PickledObject): | ||
value = PickledObject( pickle.dumps(value).encode('base64') ) | ||
return value | ||
|
||
def get_internal_type(self): | ||
return 'TextField' | ||
|
||
def get_db_prep_lookup(self, lookup_type, value): | ||
if lookup_type == 'exact': | ||
value = self.get_db_prep_save(value) | ||
return super(PickledObjectField, self).get_db_prep_lookup(lookup_type, value) | ||
elif lookup_type == 'in': | ||
value = [self.get_db_prep_save(v) for v in value] | ||
return super(PickledObjectField, self).get_db_prep_lookup(lookup_type, value) | ||
else: | ||
raise TypeError('Lookup type %s is not supported.' % lookup_type) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
from inspect import isclass | ||
try: | ||
import Image | ||
import ImageColor | ||
import ImageFile | ||
import ImageFilter | ||
import ImageEnhance | ||
except ImportError: | ||
try: | ||
from PIL import Image | ||
from PIL import ImageColor | ||
from PIL import ImageFile | ||
from PIL import ImageFilter | ||
from PIL import ImageEnhance | ||
except ImportError: | ||
raise ImportError("The Python Imaging Library was not found.") | ||
|
||
filters = [] | ||
|
||
class BaseFilter(object): | ||
pass | ||
|
||
class ResizeFilter(BaseFilter): | ||
name = "Resize to specified dimensions" | ||
identifier = "resize_simple" | ||
def render(self, im, size_x=128, size_y=64, crop=True, crop_from='top', upscale=True): | ||
cur_width, cur_height = im.size | ||
new_width, new_height = (size_x, size_y) | ||
if crop: | ||
ratio = max(float(new_width)/cur_width,float(new_height)/cur_height) | ||
x = (cur_width * ratio) | ||
y = (cur_height * ratio) | ||
xd = abs(new_width - x) | ||
yd = abs(new_height - y) | ||
x_diff = int(xd / 2) | ||
y_diff = int(yd / 2) | ||
if crop_from == 'top': | ||
box = (int(x_diff), 0, int(x_diff+new_width), new_height) | ||
elif crop_from == 'left': | ||
box = (0, int(y_diff), new_width, int(y_diff+new_height)) | ||
elif crop_from == 'bottom': | ||
box = (int(x_diff), int(yd), int(x_diff+new_width), int(y)) # y - yd = new_height | ||
elif crop_from == 'right': | ||
box = (int(xd), int(y_diff), int(x), int(y_diff+new_height)) # x - xd = new_width | ||
else: | ||
box = (int(x_diff), int(y_diff), int(x_diff+new_width), int(y_diff+new_height)) | ||
im = im.resize((int(x), int(y)), Image.ANTIALIAS).crop(box) | ||
else: | ||
if not new_width == 0 and not new_height == 0: | ||
ratio = min(float(new_width)/cur_width, | ||
float(new_height)/cur_height) | ||
else: | ||
if new_width == 0: | ||
ratio = float(new_height)/cur_height | ||
else: | ||
ratio = float(new_width)/cur_width | ||
new_dimensions = (int(round(cur_width*ratio)), | ||
int(round(cur_height*ratio))) | ||
if new_dimensions[0] > cur_width or \ | ||
new_dimensions[1] > cur_height: | ||
if not upscale: | ||
return im | ||
im = im.resize(new_dimensions, Image.ANTIALIAS) | ||
return im | ||
filters.append(ResizeFilter) | ||
class TinyResizeFilterHack(ResizeFilter): | ||
name = "Tiny Resize Filter Hack" | ||
def render(self, im, size_x=24, size_y=24, crop=True, crop_from='top', upscale=True): | ||
return super(TinyResizeFilterHack, self).render(im, size_x=size_x, size_y=size_y) | ||
filters.append(TinyResizeFilterHack) | ||
|
||
class ReflectionFilter(BaseFilter): | ||
name = "Sexy Web 2.0 reflection filter" | ||
identifier = "reflection" | ||
def render(self, im, bgcolor="#FFFFFF", amount=0.4, opacity=0.6): | ||
""" Returns the supplied PIL Image (im) with a reflection effect | ||
bgcolor The background color of the reflection gradient | ||
amount The height of the reflection as a percentage of the orignal image | ||
opacity The initial opacity of the reflection gradient | ||
Originally written for the Photologue image management system for Django | ||
and Based on the original concept by Bernd Schlapsi | ||
""" | ||
# convert bgcolor string to rgb value | ||
background_color = ImageColor.getrgb(bgcolor) | ||
|
||
# copy orignial image and flip the orientation | ||
reflection = im.copy().transpose(Image.FLIP_TOP_BOTTOM) | ||
|
||
# create a new image filled with the bgcolor the same size | ||
background = Image.new("RGB", im.size, background_color) | ||
|
||
# calculate our alpha mask | ||
start = int(255 - (255 * opacity)) # The start of our gradient | ||
steps = int(255 * amount) # the number of intermedite values | ||
increment = (255 - start) / float(steps) | ||
mask = Image.new('L', (1, 255)) | ||
for y in range(255): | ||
if y < steps: | ||
val = int(y * increment + start) | ||
else: | ||
val = 255 | ||
mask.putpixel((0, y), val) | ||
alpha_mask = mask.resize(im.size) | ||
|
||
# merge the reflection onto our background color using the alpha mask | ||
reflection = Image.composite(background, reflection, alpha_mask) | ||
|
||
# crop the reflection | ||
reflection_height = int(im.size[1] * amount) | ||
reflection = reflection.crop((0, 0, im.size[0], reflection_height)) | ||
|
||
# create new image sized to hold both the original image and the reflection | ||
composite = Image.new("RGB", (im.size[0], im.size[1]+reflection_height), background_color) | ||
|
||
# paste the orignal image and the reflection into the composite image | ||
composite.paste(im, (0, 0)) | ||
composite.paste(reflection, (0, im.size[1])) | ||
|
||
# return the image complete with reflection effect | ||
return composite | ||
filters.append(ReflectionFilter) | ||
|
||
""" | ||
Create image filter objects for all the built in PIL filters | ||
""" | ||
for n in dir(ImageFilter): | ||
klass = getattr(ImageFilter, n) | ||
if isclass(klass) and issubclass(klass, ImageFilter.BuiltinFilter) and \ | ||
hasattr(klass, 'name'): | ||
class NewSubclass(BaseFilter): | ||
_pil_filter = klass | ||
name = klass.name | ||
identifier = klass.name | ||
def render(self, im): | ||
return im.filter(self._pil_filter) | ||
NewSubclass.__name__ = "%s%s" % (klass.name, "Filter") | ||
filters.append(NewSubclass) | ||
|
||
|
||
|
||
filters_by_identifier = {} | ||
for filter in filters: | ||
filters_by_identifier[filter.identifier] = filter |
Oops, something went wrong.