Adding Drop Shadows to Images
One simple way to enhance the aesthetic appeal of a photo is to add a drop shadow. A drop shadow creates a floating effect, adding depth and dimensionality to your images.
The Process
Adding a drop shadow involves several steps using the alpha channel of the image:
- Extract the alpha channel from the foreground image to use as a mask
- Apply a blur effect to the extracted alpha channel
- Composite the blurred shadow onto the background
- Place the original image on top of the composition
Process Visualization

Implementation with OpenCV
Here is how to implement drop shadows using OpenCV in Python:
OpenCV Implementation
Python implementation using OpenCV for adding drop shadows
PYTHON
1import cv2
2import numpy as np
3
4FG_IMG_PATH = "fg.png"
5BG_IMG_PATH = "bg.jpeg"
6BLUR_AMOUNT = 32
7
8def load_image(path, color_conversion=None):
9 """Load an image and optionally convert its color."""
10 image = cv2.imread(path, cv2.IMREAD_UNCHANGED)
11 if color_conversion:
12 image = cv2.cvtColor(image, color_conversion)
13 return image
14
15def extract_alpha_channel(image):
16 """Extract the alpha channel and the RGB channels from an image."""
17 alpha_channel = image[:,:,3]
18 rgb_channels = image[:,:,0:3]
19 return alpha_channel, rgb_channels
20
21def apply_blur_to_alpha(alpha, blur_amount):
22 """Apply blur to the alpha channel."""
23 return cv2.blur(alpha, (blur_amount, blur_amount))
24
25def expand_and_normalize_alpha(alpha):
26 """Expand alpha dimensions and normalize its values to the range [0,1]."""
27 expanded_alpha = np.expand_dims(alpha, axis=2)
28 repeated_alpha = np.repeat(expanded_alpha, 3, axis=2)
29 normalized_alpha = repeated_alpha / 255
30 return normalized_alpha
31
32def create_shadow_on_bg(bg, alpha_blur):
33 """Put shadow (based on blurred alpha) on top of the background."""
34 black_canvas = np.zeros(bg.shape, dtype=np.uint8)
35 shadowed_bg = (alpha_blur * black_canvas + (1 - alpha_blur) * bg).astype(np.uint8)
36 return shadowed_bg
37
38def composite_foreground_on_bg(fg, alpha, bg_with_shadow):
39 """Put the foreground image on top of the background with shadow."""
40 composited_image = (alpha * fg + (1 - alpha) * bg_with_shadow).astype(np.uint8)
41 return composited_image
42
43if __name__ == "__main__":
44 # Load images and convert their color if necessary
45 fg = load_image(FG_IMG_PATH, cv2.COLOR_BGRA2RGBA)
46 bg = load_image(BG_IMG_PATH, cv2.COLOR_RGB2BGR)
47
48 # Extract alpha and RGB channels from the foreground image
49 alpha, fg_rgb = extract_alpha_channel(fg)
50
51 # Blur the alpha channel to get the shadow
52 alpha_blur = apply_blur_to_alpha(alpha, BLUR_AMOUNT)
53
54 # Expand and normalize the blurred alpha for shadow calculation
55 alpha_blur_normalized = expand_and_normalize_alpha(alpha_blur)
56
57 # Create a version of the background with the shadow
58 bg_with_shadow = create_shadow_on_bg(bg, alpha_blur_normalized)
59
60 # Expand and normalize the original alpha for compositing foreground over background
61 alpha_normalized = expand_and_normalize_alpha(alpha)
62
63 # Composite the foreground on the shadowed background
64 final_image = composite_foreground_on_bg(fg_rgb, alpha_normalized, bg_with_shadow)
65
66 # Display the final image (optional)
67 cv2.imshow("Final Image", final_image)
68 cv2.waitKey(0)
69 cv2.destroyAllWindows()
Implementation with Pillow
Alternative implementation using the Pillow library:
Pillow Implementation
Python implementation using Pillow for adding drop shadows
PYTHON
1from PIL import ImageOps, Image, ImageFilter
2
3FG_IMG_PATH = "fg.png"
4BG_IMG_PATH = "bg.jpeg"
5
6def load_image(path):
7 """Load an image using PIL."""
8 return Image.open(path)
9
10def extract_alpha(image):
11 """Extract the alpha channel from an image."""
12 return image.split()[-1]
13
14def create_shadow_from_alpha(alpha, blur_radius):
15 """Create a shadow based on a blurred version of the alpha channel."""
16 alpha_blur = alpha.filter(ImageFilter.BoxBlur(blur_radius))
17 shadow = Image.new(mode="RGB", size=alpha_blur.size)
18 shadow.putalpha(alpha_blur)
19 return shadow
20
21def composite_images(bg, fg, shadow):
22 """Composite the shadow and foreground onto the background."""
23 bg.paste(shadow, (0, 0), shadow)
24 bg.paste(fg, (0, 0), fg)
25 return bg
26
27if __name__ == "__main__":
28 # Load the images
29 fg = load_image(FG_IMG_PATH)
30 bg = load_image(BG_IMG_PATH)
31
32 # Create the shadow based on the alpha channel of the foreground
33 alpha = extract_alpha(fg)
34 shadow = create_shadow_from_alpha(alpha, blur_radius=25)
35
36 # Composite the shadow and foreground onto the background
37 final_image = composite_images(bg, fg, shadow)
38
39 # Display the final image (optional)
40 final_image.show()
Implementation with HTML Canvas
For web applications, you can implement drop shadows using HTML Canvas:
HTML Canvas Implementation
JavaScript implementation using HTML Canvas for adding drop shadows
JAVASCRIPT
1// Get the canvas element and its context
2var canvas = document.getElementById("dropShadowCanvas");
3var ctx = canvas.getContext("2d");
4
5// Load the background image
6var bgImage = new Image();
7bgImage.onload = function () {
8 // Set canvas size to background size
9 canvas.width = bgImage.width;
10 canvas.height = bgImage.height;
11
12 // Draw the background
13 ctx.drawImage(bgImage, 0, 0);
14
15 // Load and draw the PNG image with shadow
16 var pngImage = new Image();
17 pngImage.onload = function () {
18 // Calculate center position
19 var x = (canvas.width - pngImage.width) / 2;
20 var y = (canvas.height - pngImage.height) / 2;
21
22 // Set shadow properties
23 ctx.shadowColor = "rgba(0, 0, 0, 1)";
24 ctx.shadowBlur = 30;
25 ctx.shadowOffsetX = 0;
26 ctx.shadowOffsetY = 0;
27
28 // Draw the PNG image
29 ctx.drawImage(pngImage, x, y);
30 };
31 pngImage.src =
32 "https://withoutbg.com/images/resources/adding-drop-shadow/fg.png";
33};
34bgImage.src =
35 "https://withoutbg.com/images/resources/adding-drop-shadow/bg.jpeg";
Result
This is the final result of adding a drop shadow to an image:
