summaryrefslogtreecommitdiff
path: root/rapid/dropshadow.py
diff options
context:
space:
mode:
Diffstat (limited to 'rapid/dropshadow.py')
-rwxr-xr-xrapid/dropshadow.py183
1 files changed, 183 insertions, 0 deletions
diff --git a/rapid/dropshadow.py b/rapid/dropshadow.py
new file mode 100755
index 0000000..68b5398
--- /dev/null
+++ b/rapid/dropshadow.py
@@ -0,0 +1,183 @@
+#!/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"
+ image = Image.frombuffer(mode, dimensions, pixels,
+ "raw", mode, stride, 1)
+
+ if mode == "RGB":
+ # convert to having an alpha value, so that the image can
+ # act as a mask in the drop shadow paste
+ image = image.convert("RGBA")
+
+ return image
+
+
+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
+
+ The image must be in RGBA format.
+ """
+ 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), image)
+
+ 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)
+