Title: Use image filters to create disabled button images in Python
My earlier post Use image filters to emboss images in Python explained an image filtering technique that produces embossed images. My even earlier post Use gradient brushes to make button images in Python explained how you can generate numbered buttons. This post combines those two techniques to provide images for disabled buttons.
There are two main points of interest in this post: the code that creates the embossing filter and the code that uses it.
Making the Embossing Filter
The parts of the program that apply filters work much as does the post Use image filters to emboss images in Python. The Filter class represents the filter, its factory methods create and return filters, and its apply method applies the filter to an image. The only really new piece is the following code, which creates the filter used to create the disabled button image.
@classmethod
def embossing_filter_disabled(cls, filter_type):
'''Create an embossing filter for disabled buttons.'''
# Experiment with different kernels, weights, and offsets.
if filter_type.lower() == 'normal':
return cls(
[
[ 1, 0, 0],
[ 0, 0, 0],
[ 0, 0, -1],
], weight=2, offset=170)
else:
return cls(
[
[ 1, 0, 0, 0, 0],
[ 0, 1, 0, 0, 0],
[ 0, 0, 0, 0, 0],
[ 0, 0, 0, -1, 0],
[ 0, 0, 0, 0, -1],
], weight=4, offset=127)
This method returns one of two possible embossing filters, depending on whether its filter_type parameter is normal or strong. The normal filter produces a fairly standard light gray result that should work for most disabled buttons. The strong filter is generally darker and has darker shadows and lighter highlights.
The picture on the right shows normal and strong images.
Feel free to experiment with other embossing filters. For example, you could try rearranging the kernel values to give the shadows different orientations. Increase offset to lighten the result and decrease it to darken the result.
Using the Embossing Filter
Here's the code that generates the button images. The changes that I made to emboss the image are highlighted in blue.
def make_button_image(self, num, bg_color, fg_color, width, border,
font, filter_type):
'''Draw a button for this number.'''
# Add a margin because the filter can't go to the edge of the image.
margin = 2
wid = (width + margin) * self.SCALE
image = Image.new('RGBA', (wid, wid), color=None)
dr = ImageDraw.Draw(image)
# Convert the colors into PIL colors.
bg_pil_color = ImageColor.getrgb(bg_color) + (255,)
fg_pil_color = ImageColor.getrgb(fg_color) + (255,)
# Draw the button.
# Outer circle.
wid = width * self.SCALE
radius = cx = cy = wid / 2
center = (cx, cy)
dr.circle(center, radius, fill=fg_pil_color)
# Inner circle.
radius -= border * self.SCALE
dr.circle(center, radius, fill=bg_pil_color)
# Text.
dr.text(xy=(cx, cy), text=f'{num}', fill=fg_color, font=font, anchor='mm')
# Emboss the image.
image = Filter.embossing_filter_disabled(filter_type).apply(image)
# Scale to desired size.
image = image.resize((width, width), resample=Image.LANCZOS)
# Convet to PhotoImage and return.
photo_image = ImageTk.PhotoImage(image)
return image, photo_image
First, the code adds a margin to the desired button size. If you remember how filters work (see my post Use image filters to emboss images in Python), you know that the kernel cannot be applied to pixels right on the edges of an image because the kernel hangs off the side of the image so some pixel values are undefined. The margin gives a little extra room for the kernel to fit over the button's actual pixels.
The code creates the button image and draws the button as before. It then applies the embossing filter. It finishes by scaling the image to the desired size and returning the image and a PhotoImage as before.
Conclusion
That's all there is to it. The program creates the button image much as in my gradient button post and then applies an embossing filter as described in my Use image filters to emboss images in Python post. If you like, you might try modifying the program to make disabled images to go with the buttons described in my post Make glassy button images in Python.
The pictures shown in this post use a white background and a black foreground. If you reverse the colors, you'll get a similar result except with the highlights and shadows swapped.
If you try using brighter colors like red and blue, the highlights and shadows will use modified versions of those colors. For best results, use colors that differ greatly in brightness. For example, try a cyan background and a red foreground.
Download the example to experiment with it and to see additional details. The following picture shows 10 disabled button images.
|