root/CMFPlone_membership_hotfix/trunk/utils.py

Revision 557 (checked in by chervol, 2 years ago)

support of all old Plone versions added

  • Property svn:eol-style set to native
Line 
1 from cStringIO import StringIO
2 from PIL import Image
3
4 # Settings for member image resize quality
5 PIL_SCALING_ALGO = Image.ANTIALIAS
6 PIL_QUALITY = 88
7 MEMBER_IMAGE_SCALE = (75, 100)
8
9 def scale_image(image_file, max_size=MEMBER_IMAGE_SCALE,
10                 default_format = 'PNG'):
11     """Scales an image down to at most max_size preserving aspect ratio
12     from an input file
13
14         >>> import Products.CMFPlone
15         >>> import os
16         >>> from StringIO import StringIO
17         >>> from Products.CMFPlone.utils import scale_image
18         >>> from PIL import Image
19
20     Let's make a couple test images and see how it works (all are
21     100x100), the gif is palletted mode::
22
23         >>> plone_path = os.path.dirname(Products.CMFPlone.__file__)
24         >>> pjoin = os.path.join
25         >>> path = pjoin(plone_path, 'tests', 'images')
26         >>> orig_jpg = open(pjoin(path, 'test.jpg'))
27         >>> orig_png = open(pjoin(path, 'test.png'))
28         >>> orig_gif = open(pjoin(path, 'test.gif'))
29
30     We'll also make some evil non-images, including one which
31     masquerades as a jpeg (which would trick OFS.Image)::
32
33         >>> invalid = StringIO('<div>Evil!!!</div>')
34         >>> sneaky = StringIO('\377\330<div>Evil!!!</div>')
35
36     OK, let's get to it, first check that our bad images fail:
37
38         >>> scale_image(invalid, (50, 50))
39         Traceback (most recent call last):
40         ...
41         IOError: cannot identify image file
42         >>> scale_image(sneaky, (50, 50))
43         Traceback (most recent call last):
44         ...
45         IOError: cannot identify image file
46
47     Now that that's out of the way we check on our real images to make
48     sure the format and mode are preserved, that they are scaled, and that they
49     return the correct mimetype::
50
51         >>> new_jpg, mimetype = scale_image(orig_jpg, (50, 50))
52         >>> img = Image.open(new_jpg)
53         >>> img.size
54         (50, 50)
55         >>> img.format
56         'JPEG'
57         >>> mimetype
58         'image/jpeg'
59
60         >>> new_png, mimetype = scale_image(orig_png, (50, 50))
61         >>> img = Image.open(new_png)
62         >>> img.size
63         (50, 50)
64         >>> img.format
65         'PNG'
66         >>> mimetype
67         'image/png'
68
69         >>> new_gif, mimetype = scale_image(orig_gif, (50, 50))
70         >>> img = Image.open(new_gif)
71         >>> img.size
72         (50, 50)
73         >>> img.format
74         'GIF'
75         >>> img.mode
76         'P'
77         >>> mimetype
78         'image/gif'
79
80     We should also preserve the aspect ratio by scaling to the given
81     width only unless told not to (we need to reset out files before
82     trying again though::
83
84         >>> orig_jpg.seek(0)
85         >>> new_jpg, mimetype = scale_image(orig_jpg, (70, 100))
86         >>> img = Image.open(new_jpg)
87         >>> img.size
88         (70, 70)
89
90         >>> orig_jpg.seek(0)
91         >>> new_jpg, mimetype = scale_image(orig_jpg, (70, 50))
92         >>> img = Image.open(new_jpg)
93         >>> img.size
94         (50, 50)
95
96     """
97     # Make sure we have ints
98     size = (int(max_size[0]), int(max_size[1]))
99     # Load up the image, don't try to catch errors, we want to fail miserably
100     # on invalid images
101     image = Image.open(image_file)
102     # When might image.format not be true?
103     format = image.format
104     mimetype = 'image/%s'%format.lower()
105     cur_size = image.size
106     # from Archetypes ImageField
107     # consider image mode when scaling
108     # source images can be mode '1','L,','P','RGB(A)'
109     # convert to greyscale or RGBA before scaling
110     # preserve palletted mode (but not pallette)
111     # for palletted-only image formats, e.g. GIF
112     # PNG compression is OK for RGBA thumbnails
113     original_mode = image.mode
114     if original_mode == '1':
115         image = image.convert('L')
116     elif original_mode == 'P':
117         image = image.convert('RGBA')
118     # Rescale in place with an method that will not alter the aspect ratio
119     # and will only shrink the image not enlarge it.
120     image.thumbnail(size, resample=PIL_SCALING_ALGO)
121     # preserve palletted mode for GIF and PNG
122     if original_mode == 'P' and format in ('GIF', 'PNG'):
123         image = image.convert('P')
124     # Save
125     new_file = StringIO()
126     image.save(new_file, format, quality=PIL_QUALITY)
127     new_file.seek(0)
128     # Return the file data and the new mimetype
129     return new_file, mimetype
130
Note: See TracBrowser for help on using the browser.