Skip to content

Commit dd8092e

Browse files
authored
[newFeature] setOpacity processor (#79)
* [newFeature] setOpacity processor Processor used to set the max alpha value of a picture. - processor added to base.py - test added to test_processors.py
1 parent 9e0cef3 commit dd8092e

3 files changed

Lines changed: 98 additions & 1 deletion

File tree

‎pilkit/processors/base.py‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,3 +223,46 @@ def process(self, img):
223223
new_img = Image.new('RGBA', img.size, self.background_color)
224224
new_img.paste(img, img)
225225
return new_img
226+
227+
class SetOpacity(object):
228+
"""
229+
Convert an image to RGBA mode, retrive the maximum opacity of the image and set this maximum opacity to a given value.
230+
- On a RGB image, the opacity will be even.
231+
- On a RGBA image, the pixel with the higher alpha value will be set to the given value.
232+
The other values will be linearly interpolated.
233+
"""
234+
235+
def __init__(self, max_alpha = 255):
236+
"""
237+
:param max_alpha: integer between (0,255) representing the highest value wanted for the alpha chanel
238+
:param interpolation: interpolation type (only "LINEAR" available for now)
239+
"""
240+
#check values
241+
if type(max_alpha) != int :
242+
raise TypeError("max_alpha shall be an integer")
243+
if max_alpha < 0 or max_alpha > 255 :
244+
raise ValueError("max_alpha shall be an integer between [0;255]")
245+
246+
#init
247+
self.max_alpha = max_alpha
248+
249+
def interpolate(self, x, max_y, max_x):
250+
y = float(x)*float(max_y)/float(max_x)
251+
return int(y)
252+
253+
def process(self, img):
254+
#convert to RGBA
255+
new_img = img.convert("RGBA")
256+
257+
#split chanels
258+
r,g,b,a = new_img.split()
259+
260+
#retrive max alpha value
261+
max_alpha_original = a.getextrema()[1]
262+
263+
#interpolate each pixel
264+
for y in range(new_img.height):
265+
for x in range(new_img.width):
266+
a.putpixel((x,y), self.interpolate(a.getpixel((x,y)), self.max_alpha, max_alpha_original))
267+
268+
return Image.merge("RGBA",(r,g,b,a))
160 Bytes
Loading

‎tests/test_processors.py‎

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from pilkit.lib import Image, ImageDraw, ImageColor
66
from pilkit.processors import (Resize, ResizeToFill, ResizeToFit, SmartCrop,
7-
SmartResize, MakeOpaque, ColorOverlay, Convert,
7+
SmartResize, MakeOpaque, SetOpacity, ColorOverlay, Convert,
88
GaussianBlur, ImageOverlay)
99
from pilkit.processors.resize import Thumbnail
1010
from .utils import create_image, compare_images, get_image_file
@@ -206,3 +206,57 @@ def test_make_gifs_opaque():
206206
path = os.path.join(dir, 'assets', 'cat.gif')
207207
gif = Image.open(path)
208208
MakeOpaque().process(gif)
209+
210+
def test_setOpacity():
211+
#test on RGB image
212+
ref_1 = Image.open(get_image_file("reference.png")).convert("RGB")
213+
nb_pixels = ref_1.width*ref_1.height
214+
result_1 = SetOpacity(0).process(ref_1)
215+
assert result_1.mode == "RGBA" #mode of the output is RGBA
216+
expected_histogram_1 = [0]*256 #initialize an empty histogram
217+
expected_histogram_1[0] = nb_pixels #all pixels at 0
218+
r,g,b,a = result_1.split()
219+
assert a.histogram() == expected_histogram_1 #opacity is 0 on every pixel
220+
221+
result_2 = SetOpacity(50).process(ref_1)
222+
assert result_2.mode == "RGBA" #mode of the output is RGBA
223+
expected_histogram_2 = [0]*256 #initialize an empty histogram
224+
expected_histogram_2[50] = nb_pixels #all pixels at 50
225+
r,g,b,a = result_2.split()
226+
assert a.histogram() == expected_histogram_2 #opacity is 0 on every pixel
227+
228+
result_3 = SetOpacity(125).process(ref_1)
229+
assert result_3.mode == "RGBA" #mode of the output is RGBA
230+
expected_histogram_3 = [0]*256 #initialize an empty histogram
231+
expected_histogram_3[125] = nb_pixels #all pixels at 125
232+
r,g,b,a = result_3.split()
233+
assert a.histogram() == expected_histogram_3 #opacity is 0 on every pixel
234+
235+
#test on RGBA image
236+
ref_2 = Image.open(get_image_file("multiple_alpha_image.png")) #image 60x30px with following alpha values [0, 8, 32, 78, 147, 244] (300px for each values)
237+
result_4 = SetOpacity(244).process(ref_2) #no modification
238+
assert compare_images(result_4,ref_2)
239+
240+
result_5 = SetOpacity(100).process(ref_2) #no modification
241+
expected_histogram_5 = [0]*256 #initialize an empty histogram
242+
expected_histogram_5[0] = 300 #all px @0 stay @0
243+
expected_histogram_5[3] = 300 #px @8 lower to @3
244+
expected_histogram_5[13] = 300 #px @32 lower to @13
245+
expected_histogram_5[31] = 300 #px @78 lower to @31
246+
expected_histogram_5[60] = 300 #px @147 lower to @60
247+
expected_histogram_5[100] = 300 #px @244 lower to @100 (as wanted)
248+
r,g,b,a = result_5.split()
249+
assert a.histogram() == expected_histogram_5
250+
251+
# test error
252+
with pytest.raises(ValueError) :
253+
SetOpacity(-1).process(ref2) #Value error
254+
255+
with pytest.raises(ValueError) :
256+
SetOpacity(256).process(ref2) #Value error
257+
258+
with pytest.raises(TypeError) :
259+
SetOpacity(0.1).process(ref2) #Type error
260+
261+
with pytest.raises(TypeError) :
262+
SetOpacity("255").process(ref2) #Type error

0 commit comments

Comments
 (0)