annotate photologue/utils/reflection.py @ 204:f6c1723fec1d

Update copyright banner.
author Brian Neal <bgneal@gmail.com>
date Sun, 06 Nov 2022 17:38:09 -0600
parents e2868ad47a1e
children
rev   line source
bgneal@1 1 """ Function for generating web 2.0 style image reflection effects.
bgneal@1 2
bgneal@1 3 Copyright (c) 2007, Justin C. Driscoll
bgneal@1 4 All rights reserved.
bgneal@1 5
bgneal@1 6 Redistribution and use in source and binary forms, with or without modification,
bgneal@1 7 are permitted provided that the following conditions are met:
bgneal@1 8
bgneal@1 9 1. Redistributions of source code must retain the above copyright notice,
bgneal@1 10 this list of conditions and the following disclaimer.
bgneal@1 11
bgneal@1 12 2. Redistributions in binary form must reproduce the above copyright
bgneal@1 13 notice, this list of conditions and the following disclaimer in the
bgneal@1 14 documentation and/or other materials provided with the distribution.
bgneal@1 15
bgneal@1 16 3. Neither the name of reflection.py nor the names of its contributors may be used
bgneal@1 17 to endorse or promote products derived from this software without
bgneal@1 18 specific prior written permission.
bgneal@1 19
bgneal@1 20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
bgneal@1 21 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
bgneal@1 22 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
bgneal@1 23 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
bgneal@1 24 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
bgneal@1 25 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
bgneal@1 26 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
bgneal@1 27 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
bgneal@1 28 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
bgneal@1 29 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
bgneal@1 30
bgneal@1 31 """
bgneal@1 32
bgneal@1 33 try:
bgneal@1 34 import Image
bgneal@1 35 import ImageColor
bgneal@1 36 except ImportError:
bgneal@1 37 try:
bgneal@1 38 from PIL import Image
bgneal@1 39 from PIL import ImageColor
bgneal@1 40 except ImportError:
bgneal@1 41 raise ImportError("The Python Imaging Library was not found.")
bgneal@1 42
bgneal@1 43
bgneal@1 44 def add_reflection(im, bgcolor="#00000", amount=0.4, opacity=0.6):
bgneal@1 45 """ Returns the supplied PIL Image (im) with a reflection effect
bgneal@1 46
bgneal@1 47 bgcolor The background color of the reflection gradient
bgneal@1 48 amount The height of the reflection as a percentage of the orignal image
bgneal@1 49 opacity The initial opacity of the reflection gradient
bgneal@1 50
bgneal@1 51 Originally written for the Photologue image management system for Django
bgneal@1 52 and Based on the original concept by Bernd Schlapsi
bgneal@1 53
bgneal@1 54 """
bgneal@1 55 # convert bgcolor string to rgb value
bgneal@1 56 background_color = ImageColor.getrgb(bgcolor)
bgneal@1 57
bgneal@1 58 # copy orignial image and flip the orientation
bgneal@1 59 reflection = im.copy().transpose(Image.FLIP_TOP_BOTTOM)
bgneal@1 60
bgneal@1 61 # create a new image filled with the bgcolor the same size
bgneal@1 62 background = Image.new("RGB", im.size, background_color)
bgneal@1 63
bgneal@1 64 # calculate our alpha mask
bgneal@1 65 start = int(255 - (255 * opacity)) # The start of our gradient
bgneal@1 66 steps = int(255 * amount) # the number of intermedite values
bgneal@1 67 increment = (255 - start) / float(steps)
bgneal@1 68 mask = Image.new('L', (1, 255))
bgneal@1 69 for y in range(255):
bgneal@1 70 if y < steps:
bgneal@1 71 val = int(y * increment + start)
bgneal@1 72 else:
bgneal@1 73 val = 255
bgneal@1 74 mask.putpixel((0, y), val)
bgneal@1 75 alpha_mask = mask.resize(im.size)
bgneal@1 76
bgneal@1 77 # merge the reflection onto our background color using the alpha mask
bgneal@1 78 reflection = Image.composite(background, reflection, alpha_mask)
bgneal@1 79
bgneal@1 80 # crop the reflection
bgneal@1 81 reflection_height = int(im.size[1] * amount)
bgneal@1 82 reflection = reflection.crop((0, 0, im.size[0], reflection_height))
bgneal@1 83
bgneal@1 84 # create new image sized to hold both the original image and the reflection
bgneal@1 85 composite = Image.new("RGB", (im.size[0], im.size[1]+reflection_height), background_color)
bgneal@1 86
bgneal@1 87 # paste the orignal image and the reflection into the composite image
bgneal@1 88 composite.paste(im, (0, 0))
bgneal@1 89 composite.paste(reflection, (0, im.size[1]))
bgneal@1 90
bgneal@1 91 # return the image complete with reflection effect
bgneal@1 92 return composite
bgneal@1 93