c5e0bf9b3f8dc96d7177b985e61c8113941b1577
[Portfolio.git] / Extensions / composite.py
1 # -*- coding: utf-8 -*-
2 ############################################################
3 # Copyright © 2005-2008 Benoît PIN <benoit.pin@ensmp.fr> #
4 # Plinn - http://plinn.org #
5 # #
6 # This program is free software; you can redistribute it #
7 # and/or modify it under the terms of the Creative Commons #
8 # "Attribution-Noncommercial 2.0 Generic" #
9 # http://creativecommons.org/licenses/by-nc/2.0/ #
10 ############################################################
11 """
12
13
14 """
15
16 from AccessControl import Unauthorized
17 from PIL.Image import new as newImage, open as imgopen, composite
18 from cStringIO import StringIO
19
20 def compositeSolidColor(self, image, mask, color=0xffffff
21 , margin_right=0, margin_bottom=0
22 , margin_left=0, margin_top=0) :
23 iw, ih = image.size
24 if iw > 800 or ih > 800 :
25 raise Unauthorized, "You are not allowed to get an image larger than 800px"
26 mask = imgopen(StringIO(mask))
27 assert mask.mode=='L', "mask must be in L mode"
28
29 mw, mh = mask.size
30
31 if margin_right and margin_bottom :
32 box = (iw-mw - margin_right, ih-mh - margin_bottom, iw - margin_right, ih - margin_bottom)
33 else :
34 box = (margin_left, margin_top, margin_left+mw, margin_top+mh)
35
36 tile = image.crop(box)
37
38 coloredImage = newImage('RGB', mask.size, color)
39
40 mergedImage = composite(coloredImage, tile, mask)
41
42 image.paste(mergedImage, box)
43
44
45
46 def outline(self, image, mask, distance=128
47 , margin_right=0, margin_bottom=0
48 , margin_left=0, margin_top=0) :
49 iw, ih = image.size
50 if iw > 800 or ih > 800 :
51 raise Unauthorized, "You are not allowed to get an image larger than 800px"
52
53 mask = imgopen(StringIO(mask))
54 assert mask.mode=='L', "mask must be in L mode"
55
56 mw, mh = mask.size
57 if margin_right and margin_bottom :
58 box = (iw-mw - margin_right, ih-mh - margin_bottom, iw - margin_right, ih - margin_bottom)
59 else :
60 box = (margin_left, margin_top, margin_left+mw, margin_top+mh)
61 tile = image.crop(box)
62
63 lumAverage = getLumAverage(tile)
64
65 gray = lumAverage - distance
66 if gray < 0 :
67 gray = lumAverage + distance
68
69 assert gray <= 256
70
71 color = gray + (gray<<8) + (gray<<16)
72 coloredImage = newImage('RGB', mask.size, color)
73 mergedImage = composite(coloredImage, tile, mask)
74
75 image.paste(mergedImage, box)
76
77
78
79 def getLumHistogram(im) :
80 histo = im.histogram()
81 layers = len(histo) / 256
82
83 lHisto = []
84 shifts = [i*256 for i in range(layers)]
85
86 for i in xrange(256) :
87 indexes = [n+i for n in shifts]
88 tot = reduce(lambda a, b : a+b, [histo[p] for p in indexes])
89 tot = int(round(tot / float(layers)))
90 lHisto.append(tot)
91
92 return lHisto
93
94
95 def getLumAverage(im) :
96 lHisto = getLumHistogram(im)
97 L = 0
98 for i in xrange(256) :
99 L += i * lHisto[i]
100
101 L = float(L) / reduce(lambda a,b : a + b, lHisto)
102 L = round(L)
103 L = int(L)
104 return L