Authors: | Michael JasonSmith
Richard Waid |
---|---|
Contact: | Michael JasonSmith <mpj17@onlinegroups.net> |
Date: | 2014-11-14 |
Organization: | GroupServer.org |
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 profiles [1], in posts [2], 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. - Finally [4], 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 | 40 |
50 < s <= 200px | 60 |
s > 200px | 75 |
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 the
size , 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: |
|
---|---|
Description: | The |
Arguments: |
|
Returns: | A new image. The width will not exceed |
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: |
|
---|---|
Description: | The |
Arguments: |
|
Returns: | A new image. The width be |
Create a square thumbnail image.
Synopsis: |
|
---|---|
Description: | The
|
Arguments: |
|
Returns: | A new image. The width will be |
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
[1] | See gs.profile.image.base for the profile-image code:
<https://github.com/groupserver/gs.profile.image.base/> |
[2] | See gs.group.messages.post for the post-rendering code:
<https://github.com/groupserver/gs.group.messages.post/> |
[3] | See gs.group.messages.image for the Image page:
<https://github.com/groupserver/gs.group.messages.image/> |
[4] | The get_resized method is a good example of why
command-coupling is a Bad Thing. |