В питоне есть замечательная библиотека 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)