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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
#!/usr/bin/python
import StringIO
import gtk
from PIL import Image, ImageFilter
def image_to_pixbuf(image):
# this one handles transparency, unlike the default example in the pygtk FAQ
# this is also from the pygtk FAQ
IS_RGBA = image.mode=='RGBA'
return gtk.gdk.pixbuf_new_from_data(
image.tostring(), # data
gtk.gdk.COLORSPACE_RGB, # color mode
IS_RGBA, # has alpha
8, # bits
image.size[0], # width
image.size[1], # height
(IS_RGBA and 4 or 3) * image.size[0] # rowstride
)
def image_to_pixbuf_no_transparency(image):
fd = StringIO.StringIO()
image.save(fd, "ppm")
contents = fd.getvalue()
fd.close()
loader = gtk.gdk.PixbufLoader("pnm")
loader.write(contents, len(contents))
pixbuf = loader.get_pixbuf()
loader.close()
return pixbuf
def pixbuf_to_image(pb):
assert(pb.get_colorspace() == gtk.gdk.COLORSPACE_RGB)
dimensions = pb.get_width(), pb.get_height()
stride = pb.get_rowstride()
pixels = pb.get_pixels()
mode = pb.get_has_alpha() and "RGBA" or "RGB"
return Image.frombuffer(mode, dimensions, pixels,
"raw", mode, stride, 1)
class DropShadow():
"""
Adds a gaussian blur drop shadow to a PIL image.
Caches backgrounds of particular sizes for improved performance.
Backgrounds can be made transparent.
Modification of code from Kevin Schluff and Matimus
License: Python license
See:
http://code.activestate.com/recipes/474116/ (r2)
http://bytes.com/topic/python/answers/606952-pil-paste-image-top-other-dropshadow
"""
def __init__(self, offset=(5,5), background_color=0xffffff, shadow = (0x44, 0x44, 0x44, 0xff),
border=8, iterations=3, trim_border=False):
"""
offset - Offset of the shadow from the image as an (x,y) tuple. Can be
positive or negative.
background_color - 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.
trim_border - If true, the border will only be created on the
sides it needs to be (i.e. only on two sides)
iterations - Number of times to apply the filter. More iterations
produce a more blurred shadow, but increase processing time.
To make backgrounds transparent, ensure the alpha value of the shadow color is the
same as the background color, e.g. if background_color is 0xffffff, shadow's alpha should be 0xff
"""
self.backgrounds = {}
self.offset = offset
self.background_color = background_color
self.shadow = shadow
self.border = border
self.trim_border = trim_border
self.iterations = iterations
if self.offset[0] < 0 or not self.trim_border:
self.left_spacing = self.border
else:
self.left_spacing = 0
if self.offset[1] < 0 or not self.trim_border:
self.top_spacing = self.border
else:
self.top_spacing = 0
def dropShadow(self, image):
"""
image - The image to overlay on top of the shadow.
"""
dimensions = (image.size[0], image.size[1])
if not dimensions in self.backgrounds:
# Create the backdrop image -- a box in the background colour with a
# shadow on it.
if self.trim_border:
totalWidth = image.size[0] + abs(self.offset[0]) + self.border
totalHeight = image.size[1] + abs(self.offset[1]) + self.border
else:
totalWidth = image.size[0] + abs(self.offset[0]) + 2 * self.border
totalHeight = image.size[1] + abs(self.offset[1]) + 2 * self.border
back = Image.new("RGBA", (totalWidth, totalHeight), self.background_color)
# Place the shadow, taking into account the offset from the image
if self.offset[0] > 0 and self.trim_border:
shadowLeft = max(self.offset[0], 0)
else:
shadowLeft = self.border + max(self.offset[0], 0)
if self.offset[1] > 0 and self.trim_border:
shadowTop = max(self.offset[1], 0)
else:
shadowTop = self.border + max(self.offset[1], 0)
back.paste(self.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 < self.iterations:
back = back.filter(ImageFilter.BLUR)
n += 1
self.backgrounds[dimensions] = back
# Paste the input image onto the shadow backdrop
imageLeft = self.left_spacing - min(self.offset[0], 0)
imageTop = self.top_spacing - min(self.offset[1], 0)
back = self.backgrounds[dimensions].copy()
back.paste(image, (imageLeft, imageTop))
return back
if __name__ == "__main__":
import sys
import os
import common
# create another file with a drop shadow
f = sys.argv[1]
image = Image.open(f)
image.thumbnail((60,36), Image.ANTIALIAS)
image2 = image.copy()
path, name = os.path.split(f)
name, ext = os.path.splitext(name)
#image = dropShadow(image, shadow = (0x44, 0x44, 0x44, 0xff))
dropShadow = DropShadow(offset=(3,3), shadow = (0x34, 0x34, 0x34, 0xff), border=6)
image = dropShadow.dropShadow(image)
image2 = dropShadow.dropShadow(image2)
nf = os.path.join(path, "%s_small_shadow%s" % (name, ext))
nf2 = os.path.join(path, "%s_small_shadow2%s" % (name, ext))
image.save(nf)
image2.save(nf2)
print "wrote %s , %s" % (nf, nf2)
|