В питоне есть замечательная библиотека PIL, я ее немного нарастил для удобства.
#!/usr/bin/python
# -*- coding: utf-8 -*-
from PIL import Image, ImageEnhance, ImageFont, ImageDraw, ImageFilter
import re
import math
def reduce_opacity(im, opacity):
"""Returns an image with reduced opacity."""
assert opacity >= 0 and opacity <= 1
if im.mode != 'RGBA':
im = im.convert('RGBA')
else:
im = im.copy()
#im = im.filter( ImageFilter.EMBOSS )
#return im
#im = im.copy()
#print im.split()[3]
alpha = im.split()[3]
alpha = ImageEnhance.Brightness(alpha).enhance(opacity)
im.putalpha(alpha)
return im
##### установка на изображение логотипа
def watermark(im, mark, position, opacity=1):
"""Adds a watermark to an image."""
#print im.mode
if opacity < 1:
mark = reduce_opacity(mark, opacity)
#if im.mode != 'RGBA':
# im = im.convert('RGBA')
# create a transparent layer the size of the image and draw the
# watermark in that layer.
layer = Image.new('RGBA', im.size, (0,0,0,0))
if position == 'tile':
for y in range(0, im.size[1], mark.size[1]):
for x in range(0, im.size[0], mark.size[0]):
layer.paste(mark, (x, y))
elif position == 'right_top':
#print 1
(im_w, im_h) = im.size
(mark_w , mark_h) = mark.size
new_w = (im_w - mark_w) - 2
new_h = 2
layer.paste(mark, (new_w, new_h ) )
elif position == 'scale':
ratio = min( float(im.size[0]) / mark.size[0], float(im.size[1]) / mark.size[1])
w = int(mark.size[0] * ratio)
h = int(mark.size[1] * ratio)
mark = mark.resize((w, h))
layer.paste(mark, ((im.size[0] - w) / 2, (im.size[1] - h) / 2))
elif position == 'center':
(iIW, iIH) = im.size
(iLW , iLH) = mark.size
iLWNew = int(float(iIW) / 2)
iLHNew = int( float(iLH) / ( float(iLW) / float(iLWNew) ) )
oNewLogo = mark.resize( (iLWNew, iLHNew ), Image.ANTIALIAS)
iNewW = (iIW / 2) - (iLWNew / 2)
iNewH = (iIH / 2) - (iLHNew / 2)
layer.paste(oNewLogo, (iNewW, iNewH ) )
else:
layer.paste(mark, position)
return Image.composite(layer, im, layer)
#### уменьшение и обрезание изображений
def scale_and_crop(im, requested_size, opts = {} ):
x, y = [float(v) for v in im.size]
xr, yr = [float(v) for v in requested_size]
if 'crop' in opts or 'max' in opts:
r = max(xr / x, yr / y)
else:
r = min(xr / x, yr / y)
if r < 1.0 or (r > 1.0 and 'upscale' in opts):
#print int(x * r), int(y * r)
im = im.resize((int(x * r), int(y * r)), resample=Image.ANTIALIAS)
crop = opts.get('crop') or 'crop' in opts
#print crop
if crop:
# Difference (for x and y) between new image size and requested size.
x, y = [float(v) for v in im.size]
dx, dy = (x - min(x, xr)), (y - min(y, yr))
if dx or dy:
# Center cropping (default).
ex, ey = dx / 2, dy / 2
box = [ex, ey, x - ex, y - ey]
# See if an edge cropping argument was provided.
edge_crop = (isinstance(crop, basestring) and
re.match(r'(?:(-?)(\d+))?,(?:(-?)(\d+))?$', crop))
if edge_crop and filter(None, edge_crop.groups()):
x_right, x_crop, y_bottom, y_crop = edge_crop.groups()
if x_crop:
offset = min(x * int(x_crop) / 100, dx)
if x_right:
box[0] = dx - offset
box[2] = x - offset
else:
box[0] = offset
box[2] = x - (dx - offset)
if y_crop:
offset = min(y * int(y_crop) / 100, dy)
if y_bottom:
box[1] = dy - offset
box[3] = y - offset
else:
box[1] = offset
box[3] = y - (dy - offset)
# See if the image should be "smart cropped".
elif crop == 'smart':
left = top = 0
right, bottom = x, y
while dx:
slice = min(dx, 10)
l_sl = im.crop((0, 0, slice, y))
r_sl = im.crop((x - slice, 0, x, y))
if image_entropy(l_sl) >= image_entropy(r_sl):
right -= slice
else:
left += slice
dx -= slice
while dy:
slice = min(dy, 10)
t_sl = im.crop((0, 0, x, slice))
b_sl = im.crop((0, y - slice, x, y))
if image_entropy(t_sl) >= image_entropy(b_sl):
bottom -= slice
else:
top += slice
dy -= slice
box = (left, top, right, bottom)
# Finally, crop the image!
im = im.crop([int(v) for v in box])
return im
def image_entropy(im):
"""
Calculate the entropy of an image. Used for "smart cropping".
"""
hist = im.histogram()
hist_size = float(sum(hist))
hist = [h / hist_size for h in hist]
return -sum([p * math.log(p, 2) for p in hist if p != 0])
#### открываем изображение
def open( sPath, bIsAlfa = False ):
#print sPath
oImage = Image.open( sPath )
#print oImage.mode
if bIsAlfa and oImage.mode == 'RGBA':
return oImage
if oImage.mode in ('L', 'RGB', 'RGBA', 'CMYK'):
oImage = oImage.convert("RGB")
return oImage
#### Сохраняем изображение
def save( oImage, sFileName, **oOpt ):
#print oOpt
oImage.save( sFileName, oImage.format, **oOpt)