- Authors
Michael JasonSmith, Richard Waid
- Contact
Michael JasonSmith <mpj17@onlinegroups.net>
- Date
2014-11-14
- Organization
- Copyright
This document is licensed under a Creative Commons Attribution-Share Alike 4.0 International License by OnlineGroups.net.
GroupServer displays images in many places, including on profiles1, in posts2, and on the Image page 3. This egg wraps some functions provided by PIL to provide support to the other products for resizing and caching images. The functionality of this product is primarily provided by two classes:
- GSImage is used to resize and implicitly cache images.
- The GSSquareImage class resizes and crops the images to ensure they are square, before implicitly caching the result.
The resizing is done by one of three utilities.
The gs.image.GSImage
class provides an application cache for images. This means the computationally-expensive task of creating a thumbnail only has to be done once. It also provides convenient methods for integrating and resizing the image.
GSImage(data)
data
:Either a
file
or a byte-array (string) containing the image.
data
:The image data.
width
:The width of the image.
height
:The height of the image.
contentType
:The content type of the image (useful for setting the HTTP response).
getSize()
:Returns the size of the image in bytes.
getImageSize()
:Returns a 2-tuple of
(GSImage.width, GSImage.height)
.get_resized(x, y, maintain_aspect=True, only_smaller=True, return_cache_path=False)
:Returns a new
GSImage
, with a maximum width ofx
and a maximum height ofy
.- If
maintain_aspect
isTrue
then the aspect ratio of the new image (x/y
) will be the same as the aspect ratio of the old image. - If
only_smaller
isTrue
then the image will be scaled only if it is smaller. - Finally4, if
return_cache
isTrue
then the path to the file in the cache is returned, not the image (see Side Effects below).
- If
The main job of the GSImage
class is to implicitly cache the scaled image when get_resized
is called. The cache is located at {clientHome}/groupserver.data/groupserver.GSImage.cache
, where clientHome
is the directory of the GroupServer instance (normally var/instance
in the installation directory).
The file-name is made up of {md5}{width}x{height}x{maintainAspect}
:
md5
: An MD5 Sum of the image data.width
: The width of the image.height
: The height of the image.maintainAspect
: If the aspect ratio was kept.
The cached image will be of the same type as the original image. However, the quality may be set to a different value.
If the base image is a JPEG, then the quality of the image is set depending on the size of the smallest dimension. The idea is that the low quality is less noticeable at small sizes. For large sizes progressive-rendering is turned on, so the time-to-glass is reduced. The different quality settings at different sizes is as follows:
Size | Quality |
---|---|
s <= 50px |
|
50 < s <= 200px |
|
s > 200px |
|
If the base image is something other than a JPEG (such as a PNG) then it is simply resized.
Resize the image in fileName
, ensuring neither dimension is more than 128px:
f = file(fileName)
i = GSImage(f)
scaledImage = i.get_resized(128, 128)
Return a scaled image from a Zope page view by over-writing the __call__
method:
class MyImage(Products.Five.BrowserView):
def __init__(self, context, request):
super(MyImage, self).__init__(context, request)
...
def __call__(self):
f = file(self.fileName)
i = GSImage(f)
scaledImage = i.get_resized(128, 128)
self.request.RESPONSE.setHeader('Content-Type',
scaledImage.contentType)
self.request.RESPONSE.setHeader('Content-Length',
scaledImage.getSize())
retval = scaledImage.data
return retval
The gs.image.GSSquareImage
class resizes images, just like the parent GSImage class, but all images are made square. It inherits the same constructor, and properties as its parent. However, the get_resized method is different.
Get a resized square image.
- Synopsis
get_resized(size)
- Description
The
get_resized
method resizes the image, so neither the width nor the height will exceed thesize
, and both will be the same. See thumbnail_img_square for more details on the algorithm used to do this.- Arguments
size
the maximum width and height of the image in pixels.- Returns
A new
GSSquareImage
.
Create a square image, 32 pixels on a side:
f = file(fileName)
i = GSSquareImage(f)
scaledImage = i.get_resized(32)
Three utilities are provided
Create a thumbnail of an image.
- Synopsis
thumbnail_img(i, x, y, method=Image.ANTIALIAS)
- Description
The
thumbnail_img
utility creates a new image, scaled down so the width will not exceedx
, and height will not exceedy
, and the aspect-ratio (x/y
) will be maintained. It is similar toImage.thumbnail
, but it returns a new image, rather than working on the image in-place.- Arguments
i
:The PIL image to resize.
x
:The maximum width.
y
:The maximum height.
method
The scaling method.
- Returns
A new image. The width will not exceed
x
, and height will not exceedy
, and the aspect-ratio (x/y
) will be maintained.
Scale a PIL image so neither dimension is more that 127px:
i = PIL.Image.open(data)
scaledImage = thumbnail_img(i, 127, 127)
Create a thumbnail of an image, without maintaining the aspect ratio.
- Synopsis
thumbnail_img(i, x, y, method=Image.ANTIALIAS)
- Description
The
thumbnail_img_noaspect
utility creates a new image, scaled down so the width will bex
, and height will bey
.- Arguments
i
:The image to resize.
x
:The width.
y
:The height.
method
The scaling method.
- Returns
A new image. The width be
x
, and height will bey
.
Create a square thumbnail image.
- Synopsis
thumbnail_img_square(i, size, method=Image.ANTIALIAS)
- Description
The
thumbnail_img_square
method creates a square version of the original image.- First, it scales the image so the shortest axis is
size
pixels, leaving the long axis unconstrained. - Second, it crops the image, so the long axis is
size
pixels. The cropping is done from the top-left corner. (There may need to be a top-right version used when non-Roman scripts are introduced to GroupServer.)
- First, it scales the image so the shortest axis is
- Arguments
i
:The image to resize.
size
:The width and height of the new image, in pixels.
method
The scaling method.
- Returns
A new image. The width will be
size
, and height will besize
.
Thanks to Kevin for the original code: <http://mail.python.org/pipermail/image-sig/2006-January/003724.html>.
- Code repository: https://github.com/groupserver/gs.image
- Questions and comments to http://groupserver.org/groups/development
- Report bugs at https://redmine.iopen.net/projects/groupserver
See
gs.profile.image.base
for the profile-image code: <https://github.com/groupserver/gs.profile.image.base/>↩See
gs.group.messages.post
for the post-rendering code: <https://github.com/groupserver/gs.group.messages.post/>↩See
gs.group.messages.image
for the Image page: <https://github.com/groupserver/gs.group.messages.image/>↩The
get_resized
method is a good example of why command-coupling is a Bad Thing.↩