PIL简介
什么是PIL
PIL:是Python Image Library的缩写,图像处理的模块。主要的类包括Image,ImageFont,ImageDraw,ImageFilter
PIL的导入
首先需要安装一下pillow包
| 1 | pip install pillow | 
然后就可以调用PIL里的类了
| 1 2 3 4 | fromPIL importImagefromPIL importImageFontfromPIL importImageDrawfromPIL importImageFilter | 
PIL常用方法
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | open()  #打开图片new(mode,size,color)   #创建一张空白图片save("test.gif","GIF")   #保存(新图片路径和名称,保存格式)size()   #获取图片大小thumbnail(weight,high)   #缩放图片大小(宽,高)show()    #显示图片blend(img1,img2,alpha)   #两张图片相加,alpha表示img1和img2的比例参数。crop()   #剪切,提取某个矩阵大小的图像。它接收一个四元素的元组作为参数,各元素为(left, upper, right, lower),坐标系统的原点(0, 0)是左上角。rotate(45)    #逆时针旋转45度transpose()    #旋转图像    transpose(Image.FLIP_LEFT_RIGHT)       #左右对换。    transpose(Image.FLIP_TOP_BOTTOM)       #上下对换。    transpose(Image.ROTATE_90)             #旋转 90 度角。    transpose(Image.ROTATE_180)            #旋转 180 度角。    transpose(Image.ROTATE_270)            #旋转 270 度角。paste(im,box)#粘贴box大小的im到原先的图片对象中。convert()    #用来将图像转换为不同色彩模式。filters()     #滤镜    BLUR   #虚化    EMBOSSresize((128,128))     #resize成128*128像素大小convert("RGBA")    #图形类型转换getpixel((4,4))   #获取某个像素位置的值putpixel((4,4),(255,0,0))    #写入某个像素位置的值 | 
PIL应用
我们主要用PIL来生成一张验证码的随机图,下面,我们就一步步来做一个小示例
1、生成一张固定尺寸固定颜色的图片
| 1 2 3 4 5 6 | fromPIL importImage# 获取一个Image对象,参数分别是RGB模式。宽150,高30,红色image =Image.new(‘RGB‘,(150,30),‘red‘)# 保存到硬盘,名为test.png格式为png的图片image.save(open(‘test.png‘,‘wb‘),‘png‘) | 
2、生成一张随机颜色的图片
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 | fromPIL importImageimportrandomdefgetRandomColor():    ‘‘‘获取一个随机颜色(r,g,b)格式的‘‘‘    c1 =random.randint(0,255)    c2 =random.randint(0,255)    c3 =random.randint(0,255)    return(c1,c2,c3)# 获取一个Image对象,参数分别是RGB模式。宽150,高30,随机颜色image =Image.new(‘RGB‘,(150,30),getRandomColor())# 保存到硬盘,名为test.png格式为png的图片image.save(open(‘test.png‘,‘wb‘),‘png‘) | 
3、生成一张带有固定字符串的随机颜色的图片
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | fromPIL importImagefromPIL importImageDrawfromPIL importImageFontimportrandomdefgetRandomColor():    ‘‘‘获取一个随机颜色(r,g,b)格式的‘‘‘    c1 =random.randint(0,255)    c2 =random.randint(0,255)    c3 =random.randint(0,255)    return(c1,c2,c3)# 获取一个Image对象,参数分别是RGB模式。宽150,高30,随机颜色image =Image.new(‘RGB‘,(150,30),getRandomColor())# 获取一个画笔对象,将图片对象传过去draw =ImageDraw.Draw(image)# 获取一个font字体对象参数是ttf的字体文件的目录,以及字体的大小font=ImageFont.truetype("kumo.ttf",size=32)# 在图片上写东西,参数是:定位,字符串,颜色,字体draw.text((20,0),‘fuyong‘,getRandomColor(),font=font)# 保存到硬盘,名为test.png格式为png的图片image.save(open(‘test.png‘,‘wb‘),‘png‘) | 
 效果:
4、生成一张带有随机字符串随机颜色的图片
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | fromPIL importImagefromPIL importImageDrawfromPIL importImageFontimportrandomdefgetRandomColor():    ‘‘‘获取一个随机颜色(r,g,b)格式的‘‘‘    c1 =random.randint(0,255)    c2 =random.randint(0,255)    c3 =random.randint(0,255)    return(c1,c2,c3)defgetRandomStr():    ‘‘‘获取一个随机字符串,每个字符的颜色也是随机的‘‘‘    random_num =str(random.randint(0, 9))    random_low_alpha =chr(random.randint(97, 122))    random_upper_alpha =chr(random.randint(65, 90))    random_char =random.choice([random_num, random_low_alpha, random_upper_alpha])    returnrandom_char# 获取一个Image对象,参数分别是RGB模式。宽150,高30,随机颜色image =Image.new(‘RGB‘,(150,30),getRandomColor())# 获取一个画笔对象,将图片对象传过去draw =ImageDraw.Draw(image)# 获取一个font字体对象参数是ttf的字体文件的目录,以及字体的大小font=ImageFont.truetype("kumo.ttf",size=26)fori inrange(5):    # 循环5次,获取5个随机字符串    random_char =getRandomStr()    # 在图片上一次写入得到的随机字符串,参数是:定位,字符串,颜色,字体    draw.text((10+i*30, 0),random_char , getRandomColor(), font=font)# 保存到硬盘,名为test.png格式为png的图片image.save(open(‘test.png‘,‘wb‘),‘png‘) | 
  效果:
5、生成一张带有噪点的验证码图片
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | fromPIL importImagefromPIL importImageDrawfromPIL importImageFontimportrandomdefgetRandomColor():    ‘‘‘获取一个随机颜色(r,g,b)格式的‘‘‘    c1 =random.randint(0,255)    c2 =random.randint(0,255)    c3 =random.randint(0,255)    return(c1,c2,c3)defgetRandomStr():    ‘‘‘获取一个随机字符串,每个字符的颜色也是随机的‘‘‘    random_num =str(random.randint(0, 9))    random_low_alpha =chr(random.randint(97, 122))    random_upper_alpha =chr(random.randint(65, 90))    random_char =random.choice([random_num, random_low_alpha, random_upper_alpha])    returnrandom_char# 获取一个Image对象,参数分别是RGB模式。宽150,高30,随机颜色image =Image.new(‘RGB‘,(150,30),getRandomColor())# 获取一个画笔对象,将图片对象传过去draw =ImageDraw.Draw(image)# 获取一个font字体对象参数是ttf的字体文件的目录,以及字体的大小font=ImageFont.truetype("kumo.ttf",size=26)fori inrange(5):    # 循环5次,获取5个随机字符串    random_char =getRandomStr()    # 在图片上一次写入得到的随机字符串,参数是:定位,字符串,颜色,字体    draw.text((10+i*30, 0),random_char , getRandomColor(), font=font)# 噪点噪线width=150height=30# 划线fori inrange(5):    x1=random.randint(0,width)    x2=random.randint(0,width)    y1=random.randint(0,height)    y2=random.randint(0,height)    draw.line((x1,y1,x2,y2),fill=getRandomColor())# 画点fori inrange(30):    draw.point([random.randint(0, width), random.randint(0, height)], fill=getRandomColor())    x =random.randint(0, width)    y =random.randint(0, height)    draw.arc((x, y, x +4, y +4), 0, 90, fill=getRandomColor())<br># 保存到硬盘,名为test.png格式为png的图片image.save(open(‘test.png‘, ‘wb‘), ‘png‘) | 
  效果:
6、对验证码图片生成进行封装
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | fromPIL importImagefromPIL importImageDrawfromPIL importImageFontimportrandomclassValidCodeImg:    def__init__(self,width=150,height=30,code_count=5,font_size=32,point_count=20,line_count=3,img_format=‘png‘):        ‘‘‘        可以生成一个经过降噪后的随机验证码的图片        :param width: 图片宽度 单位px        :param height: 图片高度 单位px        :param code_count: 验证码个数        :param font_size: 字体大小        :param point_count: 噪点个数        :param line_count: 划线个数        :param img_format: 图片格式        :return 生成的图片的bytes类型的data        ‘‘‘        self.width =width        self.height =height        self.code_count =code_count        self.font_size =font_size        self.point_count =point_count        self.line_count =line_count        self.img_format =img_format    @staticmethod    defgetRandomColor():        ‘‘‘获取一个随机颜色(r,g,b)格式的‘‘‘        c1 =random.randint(0,255)        c2 =random.randint(0,255)        c3 =random.randint(0,255)        return(c1,c2,c3)    @staticmethod    defgetRandomStr():        ‘‘‘获取一个随机字符串,每个字符的颜色也是随机的‘‘‘        random_num =str(random.randint(0, 9))        random_low_alpha =chr(random.randint(97, 122))        random_upper_alpha =chr(random.randint(65, 90))        random_char =random.choice([random_num, random_low_alpha, random_upper_alpha])        returnrandom_char    defgetValidCodeImg(self):        # 获取一个Image对象,参数分别是RGB模式。宽150,高30,随机颜色        image =Image.new(‘RGB‘,(self.width,self.height),self.getRandomColor())        # 获取一个画笔对象,将图片对象传过去        draw =ImageDraw.Draw(image)        # 获取一个font字体对象参数是ttf的字体文件的目录,以及字体的大小        font=ImageFont.truetype("kumo.ttf",size=self.font_size)        temp =[]        fori inrange(self.code_count):            # 循环5次,获取5个随机字符串            random_char =self.getRandomStr()            # 在图片上一次写入得到的随机字符串,参数是:定位,字符串,颜色,字体            draw.text((10+i*30, -2),random_char , self.getRandomColor(), font=font)            # 保存随机字符,以供验证用户输入的验证码是否正确时使用            temp.append(random_char)        valid_str ="".join(temp)        # 噪点噪线        # 划线        fori inrange(self.line_count):            x1=random.randint(0,self.width)            x2=random.randint(0,self.width)            y1=random.randint(0,self.height)            y2=random.randint(0,self.height)            draw.line((x1,y1,x2,y2),fill=self.getRandomColor())        # 画点        fori inrange(self.point_count):            draw.point([random.randint(0, self.width), random.randint(0, self.height)], fill=self.getRandomColor())            x =random.randint(0, self.width)            y =random.randint(0, self.height)            draw.arc((x, y, x +4, y +4), 0, 90, fill=self.getRandomColor())        # 在内存生成图片        fromio importBytesIO        f =BytesIO()        image.save(f, self.img_format)        data =f.getvalue()        f.close()        returndata,valid_strif__name__ ==‘__main__‘:    img =ValidCodeImg()    data, valid_str =img.getValidCodeImg()    print(valid_str)    f =open(‘test.png‘, ‘wb‘)    f.write(data) | 
  效果:
7、应用到实际开发中
login.html
| 1 2 | <inputid="valid-inp"name="validcode"class="form-control"type="password"placeholder="请输入验证码"autocomplete="off">             <span id="valid-img"><img id="img"src="/get_valid_img"title="点击再换一张"alt="验证码图片"></span> | 
urls.py
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | fromdjango.conf.urls importurlfromdjango.contrib importadminfromblog importviewsurlpatterns =[    url(r‘^admin/‘, admin.site.urls),    url(r‘^$‘,views.Main.as_view(),name=‘main‘),    url(r‘^login$‘,views.Login.as_view(),name=‘login‘),    # 登录页面验证码图片请求    url(r‘^get_valid_img‘,views.GetValidImg.as_view(),name=‘get_valid_img‘),] | 
views.py
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | classMain(View):    defget(self,request):        returnrender(request,‘main.html‘)classLogin(View):    defget(self,request):        returnrender(request, ‘login.html‘)    defpost(self,request):        username =request.POST.get(‘username‘)        password =request.POST.get(‘password‘)        valid_code =request.POST.get(‘valid_code‘)        # print(valid_code)        # print(request.session.get(‘valid_code‘))        ifvalid_code.upper() !=request.session.get(‘valid_code‘).upper():            returnJsonResponse({‘state‘:False,‘msg‘:‘验证码错误‘})        user =auth.authenticate(request,username=username,password=password)        ifuser:            # 登录成功,通过auth的login方法将用户写到session中            auth.login(request,user)            # 提交表单登录成功后跳转到用户自己的博客首页            redirect_url =‘/{}‘.format(user.username)            returnJsonResponse({‘state‘:True,‘msg‘:‘登录成功!‘,‘url‘:redirect_url})        else:            returnJsonResponse({‘state‘:False,‘msg‘:‘用户名或密码错误!‘})classGetValidImg(View):    defget(self,request):        obj =ValidCodeImg()        img_data,valid_code =obj.getValidCodeImg()        request.session[‘valid_code‘] =valid_code        returnHttpResponse(img_data) | 
 
        