雜項之圖像處理pillow
本節內容
- 參考文獻
- 生成驗證碼源碼
- 一些小例子
1. 參考文獻
http://pillow-cn.readthedocs.io/zh_CN/latest/ pillow中文文檔
http://pillow.readthedocs.io/en/3.4.x/ pillow官方文檔
http://blog.csdn.net/orangleliu/article/details/43529319 一些小例子
http://python.jobbole.com/83685/ pillow使用方法集合php
2. 生成驗證碼源碼
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter
_letter_cases = "abcdefghjkmnpqrstuvwxy"
_upper_cases = _letter_cases.upper()
_numbers = ''.join(map(str, range(3, 10)))
init_chars = ''.join((_letter_cases, _upper_cases, _numbers))
def create_validate_code(size=(120, 30), chars=init_chars, img_type="GIF", mode="RGB", bg_color=(255, 255, 255), fg_color=(0, 0, 255), font_size=18, font_type="simkai.ttf", length=4, draw_lines=True, n_line=(1, 2), draw_points=True, point_chance = 2):
''' @todo: 生成驗證碼圖片 @param size: 圖片的大小,格式(寬,高),默認爲(120, 30) @param chars: 容許的字符集合,格式字符串 @param img_type: 圖片保存的格式,默認爲GIF,可選的爲GIF,JPEG,TIFF,PNG @param mode: 圖片模式,默認爲RGB @param bg_color: 背景顏色,默認爲白色 @param fg_color: 前景色,驗證碼字符顏色,默認爲藍色#0000FF @param font_size: 驗證碼字體大小 @param font_type: 驗證碼字體,默認爲 ae_AlArabiya.ttf @param length: 驗證碼字符個數 @param draw_lines: 是否劃干擾線 @param n_lines: 干擾線的條數範圍,格式元組,默認爲(1, 2),只有draw_lines爲True時有效 @param draw_points: 是否畫干擾點 @param point_chance: 干擾點出現的機率,大小範圍[0, 100] @return: [0]: PIL Image實例 @return: [1]: 驗證碼圖片中的字符串 '''
width, height = size
img = Image.new(mode, size, bg_color)
draw = ImageDraw.Draw(img)
def get_chars():
'''生成給定長度的字符串,返回列表格式'''
return random.sample(chars, length)
def create_lines():
'''繪製干擾線'''
line_num = random.randint(*n_line)
for i in range(line_num):
begin = (random.randint(0, size[0]), random.randint(0, size[1]))
end = (random.randint(0, size[0]), random.randint(0, size[1]))
draw.line([begin, end], fill=(0, 0, 0))
def create_points():
'''繪製干擾點'''
chance = min(100, max(0, int(point_chance)))
for w in range(width):
for h in range(height):
tmp = random.randint(0, 100)
if tmp > 100 - chance:
draw.point((w, h), fill=(0, 0, 0))
def create_strs():
'''繪製驗證碼字符'''
c_chars = get_chars()
strs = ' %s ' % ' '.join(c_chars)
font = ImageFont.truetype(font_type, font_size)
font_width, font_height = font.getsize(strs)
draw.text(((width - font_width) / 3, (height - font_height) / 3),
strs, font=font, fill=fg_color)
return ''.join(c_chars)
if draw_lines:
create_lines()
if draw_points:
create_points()
strs = create_strs()
params = [1 - float(random.randint(1, 2)) / 100,
0,
0,
0,
1 - float(random.randint(1, 10)) / 100,
float(random.randint(1, 2)) / 500,
0.001,
float(random.randint(1, 2)) / 500
]
img = img.transform(size, Image.PERSPECTIVE, params)
img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)
return img, strs
from io import BytesIO
def test(req):
mstream = BytesIO()
validate_code = check_code.create_validate_code()
img = validate_code[0]
img.save(mstream, "GIF")
return HttpResponse(mstream.getvalue())
''' img = img.transform(size, Image.PERSPECTIVE, params) # 建立扭曲 Image.transform(size, method, data=None, resample=0, fill=1) 參數 Transforms this image. This method creates a new image with the given size, and the same mode as the original, and copies data to the new image using the given transform. Parameters: size – The output size. 輸出圖片大小 method – The transformation method. This is one of PIL.Image.EXTENT (cut out a rectangular subregion), 範圍 PIL.Image.AFFINE (affine transform), 輪廓 PIL.Image.PERSPECTIVE (perspective transform), 透視 PIL.Image.QUAD (map a quadrilateral to a rectangle), 四方 PIL.Image.MESH (map a number of source quadrilaterals in one operation). 網格 data – Extra data to the transformation method. resample – Optional resampling filter. It can be one of PIL.Image.NEAREST (use nearest neighbour), PIL.Image.BILINEAR (linear interpolation in a 2x2 environment), or PIL.Image.BICUBIC (cubic spline interpolation in a 4x4 environment). If omitted, or if the image has mode 「1」 or 「P」, it is set to PIL.Image.NEAREST. Returns: 返回一個新的image對象 An Image object. '''
''' img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 濾鏡,邊界增強(閾值更大) 圖像濾波在ImageFilter 模塊中,在該模塊中,預先定義了不少加強濾波器,能夠經過filter( )函數使用,預約義濾波器包括: BLUR、均值濾波 CONTOUR、找輪廓 DETAIL、詳細 EDGE_ENHANCE、邊緣增強 EDGE_ENHANCE_MORE、 EMBOSS、突出 FIND_EDGES、邊緣檢測 SMOOTH、平滑 SMOOTH_MORE、 SHARPEN、銳化濾鏡 使用該模塊時,需先導入 '''
注意:畫筆能提供的功能封裝路徑:C:\Python35\Lib\site-packages\PIL\ImageDraw.py中的類ImageDraw中python
一些小例子
''' pil處理圖片,驗證,處理 大小,格式 過濾 壓縮,截圖,轉換 圖片庫最好用Pillow 還有一個測試圖片test.jpg, 一個log圖片,一個字體文件 '''
try:
from PIL import Image, ImageDraw, ImageFont, ImageEnhance
except ImportError:
import Image, ImageDraw, ImageFont, ImageEnhance
def compress_image(img, w=128, h=128):
''''' 縮略圖 '''
img.thumbnail((w,h))
im.save('test1.png', 'PNG')
print u'成功保存爲png格式, 壓縮爲128*128格式圖片'
def cut_image(img):
''''' 截圖, 旋轉,再粘貼 '''
width, height = img.size
box = (width-200, height-100, width, height)
region = img.crop(box)
region = region.transpose(Image.ROTATE_180)
img.paste(region, box)
img.save('test2.jpg', 'JPEG')
print u'從新拼圖成功'
def logo_watermark(img, logo_path):
''''' 添加一個圖片水印,原理就是合併圖層,用png比較好 '''
baseim = img
logoim = Image.open(logo_path)
bw, bh = baseim.size
lw, lh = logoim.size
baseim.paste(logoim, (bw-lw, bh-lh))
baseim.save('test3.jpg', 'JPEG')
print u'logo水印組合成功'
def text_watermark(img, text, out_file="test4.jpg", angle=23, opacity=0.50):
''''' 添加一個文字水印,作成透明水印的模樣,應該是png圖層合併 http://www.pythoncentral.io/watermark-images-python-2x/ 這裏會產生著名的 ImportError("The _imagingft C module is not installed") 錯誤 Pillow經過安裝來解決 pip install Pillow '''
watermark = Image.new('RGBA', img.size, (255,255,255))
FONT = "msyh.ttf"
size = 2
n_font = ImageFont.truetype(FONT, size)
n_width, n_height = n_font.getsize(text)
text_box = min(watermark.size[0], watermark.size[1])
while (n_width+n_height < text_box):
size += 2
n_font = ImageFont.truetype(FONT, size=size)
n_width, n_height = n_font.getsize(text)
text_width = (watermark.size[0] - n_width) / 2
text_height = (watermark.size[1] - n_height) / 2
draw = ImageDraw.Draw(watermark, 'RGBA')
draw.text((text_width,text_height),
text, font=n_font, fill="#21ACDA")
watermark = watermark.rotate(angle, Image.BICUBIC)
alpha = watermark.split()[3]
alpha = ImageEnhance.Brightness(alpha).enhance(opacity)
watermark.putalpha(alpha)
Image.composite(watermark, img, watermark).save(out_file, 'JPEG')
print u"文字水印成功"
def resizeImg(img, dst_w=0, dst_h=0, qua=85):
''''' 只給了寬或者高,或者兩個都給了,而後取比例合適的 若是圖片比給要壓縮的尺寸都要小,就不壓縮了 '''
ori_w, ori_h = im.size
widthRatio = heightRatio = None
ratio = 1
if (ori_w and ori_w > dst_w) or (ori_h and ori_h > dst_h):
if dst_w and ori_w > dst_w:
widthRatio = float(dst_w) / ori_w
if dst_h and ori_h > dst_h:
heightRatio = float(dst_h) / ori_h
if widthRatio and heightRatio:
if widthRatio < heightRatio:
ratio = widthRatio
else:
ratio = heightRatio
if widthRatio and not heightRatio:
ratio = widthRatio
if heightRatio and not widthRatio:
ratio = heightRatio
newWidth = int(ori_w * ratio)
newHeight = int(ori_h * ratio)
else:
newWidth = ori_w
newHeight = ori_h
im.resize((newWidth,newHeight),Image.ANTIALIAS).save("test5.jpg", "JPEG", quality=qua)
print u'等比壓縮完成'
''''' Image.ANTIALIAS還有以下值: NEAREST: use nearest neighbour BILINEAR: linear interpolation in a 2x2 environment BICUBIC:cubic spline interpolation in a 4x4 environment ANTIALIAS:best down-sizing filter '''
def clipResizeImg(im, dst_w, dst_h, qua=95):
''''' 先按照一個比例對圖片剪裁,而後在壓縮到指定尺寸 一個圖片 16:5 ,壓縮爲 2:1 而且寬爲200,就要先把圖片裁剪成 10:5,而後在等比壓縮 '''
ori_w,ori_h = im.size
dst_scale = float(dst_w) / dst_h
ori_scale = float(ori_w) / ori_h
if ori_scale <= dst_scale:
width = ori_w
height = int(width/dst_scale)
x = 0
y = (ori_h - height) / 2
else:
height = ori_h
width = int(height*dst_scale)
x = (ori_w - width) / 2
y = 0
box = (x,y,width+x,height+y)
newIm = im.crop(box)
im = None
ratio = float(dst_w) / width
newWidth = int(width * ratio)
newHeight = int(height * ratio)
newIm.resize((newWidth,newHeight),Image.ANTIALIAS).save("test6.jpg", "JPEG",quality=95)
print "old size %s %s"%(ori_w, ori_h)
print "new size %s %s"%(newWidth, newHeight)
print u"剪裁後等比壓縮完成"
if __name__ == "__main__":
''''' 主要是實現功能, 代碼沒怎麼整理 '''
im = Image.open('test.jpg')
compress_image(im)
im = Image.open('test.jpg')
cut_image(im)
im = Image.open('test.jpg')
logo_watermark(im, 'logo.png')
im = Image.open('test.jpg')
text_watermark(im, 'Orangleliu')
im = Image.open('test.jpg')
resizeImg(im, dst_w=100, qua=85)
im = Image.open('test.jpg')
clipResizeImg(im, 100, 200)