Welcome, guest | Sign In | My Account | Store | Cart

This recipe demonstrates the use of the Python Imaging Library to apply a gaussian blur drop shadow to an image.

Python, 58 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
"""
Drop shadows with PIL.

Author: Kevin Schluff
License: Python license
"""
from PIL import Image, ImageFilter

def dropShadow( image, offset=(5,5), background=0xffffff, shadow=0x444444, 
                border=8, iterations=3):
  """
  Add a gaussian blur drop shadow to an image.  
  
  image       - The image to overlay on top of the shadow.
  offset      - Offset of the shadow from the image as an (x,y) tuple.  Can be
                positive or negative.
  background  - Background colour behind the image.
  shadow      - Shadow colour (darkness).
  border      - Width of the border around the image.  This must be wide
                enough to account for the blurring of the shadow.
  iterations  - Number of times to apply the filter.  More iterations 
                produce a more blurred shadow, but increase processing time.
  """
  
  # Create the backdrop image -- a box in the background colour with a 
  # shadow on it.
  totalWidth = image.size[0] + abs(offset[0]) + 2*border
  totalHeight = image.size[1] + abs(offset[1]) + 2*border
  back = Image.new(image.mode, (totalWidth, totalHeight), background)
  
  # Place the shadow, taking into account the offset from the image
  shadowLeft = border + max(offset[0], 0)
  shadowTop = border + max(offset[1], 0)
  back.paste(shadow, [shadowLeft, shadowTop, shadowLeft + image.size[0], 
    shadowTop + image.size[1]] )
  
  # Apply the filter to blur the edges of the shadow.  Since a small kernel
  # is used, the filter must be applied repeatedly to get a decent blur.
  n = 0
  while n < iterations:
    back = back.filter(ImageFilter.BLUR)
    n += 1
    
  # Paste the input image onto the shadow backdrop  
  imageLeft = border - min(offset[0], 0)
  imageTop = border - min(offset[1], 0)
  back.paste(image, (imageLeft, imageTop))
  
  return back
  
if __name__ == "__main__":
  import sys

  image = Image.open(sys.argv[1])
  image.thumbnail( (200,200), Image.ANTIALIAS)

  dropShadow(image).show()
  dropShadow(image, background=0xeeeeee, shadow=0x444444, offset=(0,5)).show()
   
    

Adding a gaussian blur drop shadow is an easy way to give a flat image a natural looking 3D effect.

The dropShadow() function given here uses PIL's built in BLUR filter to produce a blurred shadow. Since this filter uses a small kernel (5x5), it must be applied a number of times to give a smooth blur at the edges of the shadow. As a result, processing of large images or multiple small images can be fairly slow.

One possible speedup is to cache the backdrop (shadow+background) images. An application, such as a web thumbnail gallery, that has many images of the same size could reuse these backdrops without re-applying the filter.

Other possible enhancments include support for non-rectangular images, like text, or the use of an alpha channel rather than a solid backgound for a semi-transparent shadow.

4 comments

Peter Bengtsson 14 years, 9 months ago  # | flag

Image as a background, not a colour. How would I do to make the background an image rather than just a background colour?

cberg aegag 12 years, 8 months ago  # | flag

Thanks for the code, helped alot. I was running into problems with putting a drop shadow on rectangles with rounded edges. To get it to work I used a mask when pasting the image. Code looks like this: # Paste the input image onto the shadow backdrop
imageLeft = border - min(offset[0], 0) imageTop = border - min(offset[1], 0) back.paste(image, (imageLeft, imageTop), image)#my change here return back

cberg aegag 12 years, 8 months ago  # | flag

back.paste(image, (imageLeft, imageTop), image)#sorry that was ugly this is the line that I changed

Ameet 9 years, 7 months ago  # | flag

Hi, Could anybody please me some suggestions on adding shadows to the object/objects inside an image?. How to modify the above program for non rectangular boundaries?

Thanks, Ameet.

Created by Kevin Schluff on Sat, 4 Mar 2006 (PSF)
Python recipes (4591)
Kevin Schluff's recipes (3)

Required Modules

Other Information and Tasks