annotate core/image.py @ 887:9a15f7c27526

Actually save model object upon change. This commit was tested on the comments model. Additional logging added. Added check for Markdown image references. Added TODOs after observing behavior on comments.
author Brian Neal <bgneal@gmail.com>
date Tue, 03 Feb 2015 21:09:44 -0600
parents 36d988b800c2
children 24fc302f9076
rev   line source
bgneal@265 1 """
bgneal@265 2 This file contains common utility functions for manipulating images for
bgneal@265 3 the rest of the applications in the project.
bgneal@265 4 """
bgneal@265 5 from PIL import ImageFile
bgneal@265 6 from PIL import Image
bgneal@265 7
bgneal@265 8
bgneal@265 9 def parse_image(file):
bgneal@265 10 """
bgneal@265 11 Returns a PIL Image from the supplied Django file object.
bgneal@265 12 Throws IOError if the file does not parse as an image file or some other
bgneal@265 13 I/O error occurred.
bgneal@265 14
bgneal@265 15 """
bgneal@265 16 parser = ImageFile.Parser()
bgneal@265 17 for chunk in file.chunks():
bgneal@265 18 parser.feed(chunk)
bgneal@265 19 image = parser.close()
bgneal@265 20 return image
bgneal@265 21
bgneal@265 22
bgneal@265 23 def downscale_image_square(image, size):
bgneal@265 24 """
bgneal@265 25 Scale an image to the square dimensions given by size (in pixels).
bgneal@265 26 The new image is returned.
bgneal@265 27 If the image is already smaller than (size, size) then no scaling
bgneal@265 28 is performed and the image is returned unchanged.
bgneal@265 29
bgneal@265 30 """
bgneal@265 31 # don't upscale
bgneal@265 32 if (size, size) >= image.size:
bgneal@265 33 return image
bgneal@265 34
bgneal@265 35 (w, h) = image.size
bgneal@265 36 if w > h:
bgneal@265 37 diff = (w - h) / 2
bgneal@265 38 image = image.crop((diff, 0, w - diff, h))
bgneal@265 39 elif h > w:
bgneal@265 40 diff = (h - w) / 2
bgneal@265 41 image = image.crop((0, diff, w, h - diff))
bgneal@265 42 image = image.resize((size, size), Image.ANTIALIAS)
bgneal@265 43 return image
bgneal@837 44
bgneal@837 45
bgneal@837 46 # Various image transformation functions:
bgneal@837 47 def flip_horizontal(im):
bgneal@837 48 return im.transpose(Image.FLIP_LEFT_RIGHT)
bgneal@837 49
bgneal@837 50 def flip_vertical(im):
bgneal@837 51 return im.transpose(Image.FLIP_TOP_BOTTOM)
bgneal@837 52
bgneal@837 53 def rotate_180(im):
bgneal@837 54 return im.transpose(Image.ROTATE_180)
bgneal@837 55
bgneal@837 56 def rotate_90(im):
bgneal@837 57 return im.transpose(Image.ROTATE_90)
bgneal@837 58
bgneal@837 59 def rotate_270(im):
bgneal@837 60 return im.transpose(Image.ROTATE_270)
bgneal@837 61
bgneal@837 62 def transpose(im):
bgneal@837 63 return rotate_90(flip_horizontal(im))
bgneal@837 64
bgneal@837 65 def transverse(im):
bgneal@837 66 return rotate_90(flip_vertical(im))
bgneal@837 67
bgneal@837 68 # From http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/EXIF.html
bgneal@837 69 # EXIF Orientation tag values:
bgneal@837 70 # 1 = Horizontal (normal)
bgneal@837 71 # 2 = Mirror horizontal
bgneal@837 72 # 3 = Rotate 180
bgneal@837 73 # 4 = Mirror vertical
bgneal@837 74 # 5 = Mirror horizontal and rotate 270 CW
bgneal@837 75 # 6 = Rotate 90 CW
bgneal@837 76 # 7 = Mirror horizontal and rotate 90 CW
bgneal@837 77 # 8 = Rotate 270 CW
bgneal@837 78
bgneal@837 79 ORIENT_FUNCS = {
bgneal@837 80 2: flip_horizontal,
bgneal@837 81 3: rotate_180,
bgneal@837 82 4: flip_vertical,
bgneal@837 83 5: transpose,
bgneal@837 84 6: rotate_270,
bgneal@837 85 7: transverse,
bgneal@837 86 8: rotate_90,
bgneal@837 87 }
bgneal@837 88
bgneal@837 89 ORIENT_TAG = 0x112
bgneal@837 90
bgneal@837 91
bgneal@837 92 def orient_image(im):
bgneal@837 93 """Transforms the given image according to embedded EXIF data.
bgneal@837 94
bgneal@837 95 The image instance, im, should be a PIL Image.
bgneal@837 96 If there is EXIF information for the image, and the orientation tag
bgneal@837 97 indicates that the image should be transformed, perform the transformation.
bgneal@837 98
bgneal@837 99 Returns a tuple of the form (flag, image) where flag is True if the image
bgneal@837 100 was oriented and False otherwise. image is either a new transformed image or
bgneal@837 101 the original image instance.
bgneal@837 102
bgneal@837 103 """
bgneal@837 104 if hasattr(im, '_getexif'):
bgneal@837 105 exif = im._getexif()
bgneal@837 106 if exif and ORIENT_TAG in exif:
bgneal@839 107 orientation = exif[ORIENT_TAG]
bgneal@839 108 func = ORIENT_FUNCS.get(orientation)
bgneal@839 109 if func:
bgneal@839 110 return (True, func(im))
bgneal@837 111
bgneal@837 112 return (False, im)