PIL Tutorial: How to Create a Button Generator
Python Imaging Library (PIL) is an external library for Python. It supports opening, manipulating, and saving different image file formats. PIL is well documented and easy to install.
In this tutorial I'm focusing on the paste function. At the end of the tutorial, I'll explain a useful script that converts any icon into a web 2.0 style button, just like these:
The paste function
im.paste(im, box=None, mask=None)
The first argument can either be an
Image object or a color. If it is an Image, the image will be pasted into this image. If it is a color, the region specified by the box argument will be filled with a single color.The
box argument defines the size and position of the pasting region. It can be a 2-tuple that defines the left upper corner, or a 4-tuple that defines the left, upper, right and lower pixel coordinate. It defaults to None, which translates to (0, 0, self.width, self.height)1.When providing a
mask argument, it only pastes the regions indicated by the mask. You can either use "1", "L" or "RGBA" images. In the latter case, the alpha band is used as mask. Where the mask is 255, the given source is copied as is. Where the mask is 0, the current value is preserved. Intermediate values can be used for transparency effects.
Examples
as a background for illustrative purposes only; it's not actually a part of the image itself.2We have two images, a flower and a butterfly.3

We want to paste the butterfly image on top of the flower. Since the butterfly image is smaller in size, we need to set the box argument. Otherwise, PIL will complain saying "Images do not match". I will set the box to (40, 10), which is roughly the top edge of the flower.
flower = Image.open('flower.png') butterfly = Image.open('butterfly.png') flower.paste(butterfly, (40, 10))
Now let's see how the result looks:

Oops, transparency was pasted on the flower along with the butterfly's image, definitely not what we want!
But that is to be expected; we asked to paste the image as it is. We should have specified a mask argument to tell PIL what to paste and what to leave.
If we specify a mask that is the same as the source then we will get the effect we want.
flower = Image.open('flower.png') butterfly = Image.open('butterfly.png') flower.paste(butterfly, (40, 10), butterfly)

Where the mask's alpha is 255 (opaque), the source is copied as it is. Where the alpha is 0 (transparent), the source is not copied.
Very simple button effect
Now let's say we want to create a very simple button effect. For this purpose we need an image with a transparent border effect.4

border = Image.open('border.png') flower.paste(border, mask=border)

No, this is not what we want. Part of the transparency is being copied along with the border, but why?
Because as we learned in the previous example, transparency is not ignored by the paste function. In fact transparency in the source image is being treated as any other color band.5 Therefore, even when using the same image as the source and mask, the intermediate transparency levels will be copied from the source into the result. To work around this, we should get rid of the alpha band in the source image, while keeping it in the mask. And what is easier to achieve this than converting the image into 'RGB'.
border = Image.open('border.png') source = border.convert('RGB') flower.paste(source, mask=border)

Now this worked!
Putting it all together
We'll put everything we learned together to create a web 2.0 style button.
First we need a mask image to crop the icon in the shape and size we want. Then, we need a highlight image to create the button effect.6

The mask and highlight images need to be of the same size for our example to work.
Let's convert this Blogger icon into a button

highlight = Image.open('round.png') mask = Image.open('round-mask.png') # Read the icon and convert it into 'RGBA' in case it wasn't icon = Image.open('blogger.png').convert('RGBA') button = Image.new('RGBA', mask.size) # Resize Icon icon = ImageOps.fit( icon, highlight.size, method=Image.ANTIALIAS, centering=(0.5, 0.5) ) # Create a helper image that will hold the icon after the reshape helper = button.copy() # Cut the icon by the shape of the mask helper.paste(icon, mask=mask) # Fill with a solid color by the mask's shape button.paste((255, 255, 255), mask=mask) # Get rid of the icon's alpha band icon = icon.convert('RGB') # Paste the icon on the solid background # Note we are using the reshaped icon as a mask button.paste(icon, mask=helper) # Get a copy of the highlight image without the alpha band overlay = highlight.copy().convert('RGB') button.paste(overlay, mask=highlight) button.save('button.png')
And the result is:

You may wonder why ImageOps.fit was used instead of Image.resize. Image.resize will work perfectly fine with images that have the same aspect ratio as the new size, but will distort the image otherwise. ImageOps.fit will resize and crop the image to match the requested aspect ratio and size. You have the option to control the cropping position, which is the center (0.5, 0.5) in our case.
You have to keep in mind that if we want our script to handle icons with transparent backgrounds, we need to specify a background color that fills the transparent spaces, or we'll end up with buttons that look like this:

This is why I fill the button's background with a solid color before pasting the icon.
Web 2.0 style buttons generator
Now here is the complete script with command line arguments support using getopt module
Example of usage:
./make-button.py feed.png ./make-button.py delicious.gif blogger.png butterfly.png --shape round ./make-button.py butterfly.png --shape heart --color 200 120 22
I've also attached the full script with helper images in a zip file for convenience. The helper images include round, heart and square shaped button effects.
#!/usr/bin/python # Button generator script # Author: Nadia Alramli http://nadiana.com from PIL import Image import ImageOps from optparse import OptionParser import os.path def create_button(iconPath, shape, bgColor): highlight = Image.open('helper/%s.png' % shape) mask = Image.open('helper/%s-mask.png' % shape) # Read the icon and convert it into 'RGBA' in case it wasn't icon = Image.open(iconPath).convert('RGBA') button = Image.new('RGBA', mask.size) # Resize Icon icon = ImageOps.fit( icon, highlight.size, method=Image.ANTIALIAS, centering=(0.5, 0.5) ) # Create a helper image that will hold the icon after the reshape helper = button.copy() # Cut the icon by the shape of the mask helper.paste(icon, mask=mask) # Fill with a solid color by the mask's shape button.paste((255, 255, 255), mask=mask) # Get rid of the icon's alpha band icon = icon.convert('RGB') # Paste the icon on the solid background # Note we are using the reshaped icon as a mask button.paste(icon, mask=helper) # Get a copy of the highlight image without the alpha band overlay = highlight.copy().convert('RGB') button.paste(overlay, mask=highlight) iconPath, ext = os.path.splitext(iconPath) button.save('%s-%s.png' % (iconPath, shape)) def main(): usage = 'usage: %prog file [file] [option]' parser = OptionParser(usage) parser.add_option('-s', '--shape', dest='shape', help='button shape') parser.add_option( '-c', '--color', dest='color', help='background color', nargs=3, type= int ) parser.set_defaults(shape='square', color=(255, 255, 255)) options, args = parser.parse_args() if len(args) < 1: parser.error('Missing file operand') shape = options.shape bgColor = options.color for arg in args: iconPath = arg create_button(iconPath, shape, bgColor) if __name__ == '__main__': main()
With this script you can add as many button effects as you want. All you need is two images: a mask and a highlight.
Let's say the style you want is a "star" then name the highlight image as star.png and the mask image as star-mask.png and place both of them in the helper folder.
Then run:
./make-button.py icon.png --shape star
- 1. PIL's documentation says the default is (0, 0), but I checked the source code of version 1.1.6 and found this not to be the case.
- 2. Those unfortunate to use IE6 (or older) won't be able to view the transparent parts, but I guess this won't affect the readability of the tutorial.
- 3. The flower and butterfly icons were downloaded from iconspedia
- 4. I created the border image with GIMP.
- 5. This is actually a personal conclusion from numerous tests.
- 6. Both the mask and the round button effect were created with GIMP.
| Attachment | Size |
|---|---|
| button_generator.zip | 60.1 KB |
- 598 reads


Comments
Post new comment