一, 图片与base64编码互相转换
import base64
with open('a.jpg','rb') as f:
b6=base64.b64encode(f.read())
print(b6[:50])
# 部分base64编码如下:
# 执行结果:
b'/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQ'
# 2, 将base64编码转换成图片
with open('b.jpg','wb') as f:
f.write(base64.b64decode(b6))
二,字符串生成图片
import os
import math
import random
from uuid import uuid1
from PIL import Image, ImageDraw, ImageFont, ImageFilter
def char_img(zt,str1):
""" 字符串生成图片。zt:字体.ttf文件。str1:字符串。 """
# 实例一个图片对象240 x 60:
width = 40*len(str1) #60 * 4
height = 60
# 图片颜色
r = random.randint(0,200)
g = random.randint(0,200)
b = random.randint(0,200)
clo = (r, g, b)
image = Image.new('RGB', (width, height), clo)
# 创建Font对象:
# 字体文件可以使用操作系统的,也可以网上下载
zt = zt # 'a.ttf'
font = ImageFont.truetype(zt, 36)
# 创建Draw对象:
draw = ImageDraw.Draw(image)
# 输出文字:
# str1 = "我爱世界"
w = 4 #距离图片左边距离
h = 10 #距离图片上边距离
draw.text((w, h), str1, font=font)
# 模糊:
image.filter(ImageFilter.BLUR)
code_name = 'test_code_img.jpg'
save_dir = './{}'.format(code_name)
image.save(save_dir, 'jpeg')
print("已保存图片: {}".format(save_dir))
if __name__ == '__main__':
zt = 'HKSN.ttf'
str1 = '我爱你'
char_img(zt,str1)
执行结果:
三, 方图转换为圆形图片
import os
import math
import random
from uuid import uuid1
from PIL import Image, ImageDraw, ImageFont, ImageFilter
def circle(fn):
""" 把图片变成圆形图片。fn:图片路径 """
ima = Image.open(fn).convert("RGBA")
# ima = ima.resize((600, 600), Image.ANTIALIAS)
size = ima.size
# 因为是要圆形,所以需要正方形的图片
r2 = min(size[0], size[1])
if size[0] != size[1]:
ima = ima.resize((r2, r2), Image.ANTIALIAS)
# 最后生成圆的半径
r3 = 60
imb = Image.new('RGBA', (r3*2, r3*2),(255,255,255,0))
pima = ima.load() # 像素的访问对象
pimb = imb.load()
r = float(r2/2) #圆心横坐标
for i in range(r2):
for j in range(r2):
lx = abs(i-r) #到圆心距离的横坐标
ly = abs(j-r)#到圆心距离的纵坐标
l = (pow(lx,2) + pow(ly,2))** 0.5 # 三角函数 半径
if l < r3:
pimb[i-(r-r3),j-(r-r3)] = pima[i,j]
save_dir = "test_circle.png"
imb.save(save_dir)
print("已保存图片: {}".format(save_dir))
if __name__ == '__main__':
circle('python.jpg')
执行结果:
四, 生成随机图形验证码
扫描二维码关注公众号,回复:
1827477 查看本文章
import os
import math
import random
from uuid import uuid1
from PIL import Image, ImageDraw, ImageFont, ImageFilter
class Yzm:
""" 生成字符验证码图片 """
def __init__(self,ttf):
self.ttf = ttf
def rnd_char(self):
'''
随机一个字母或者数字
:return:
'''
# 随机一个字母或者数字
i = random.randint(1, 3)
if i == 1:
# 随机个数字的十进制ASCII码
an = random.randint(97, 122)
elif i == 2:
# 随机个小写字母的十进制ASCII码
an = random.randint(65, 90)
else:
# 随机个大写字母的十进制ASCII码
an = random.randint(48, 57)
# 根据Ascii码转成字符,return回去
return chr(an)
# 干扰
def rnd_dis(self):
'''
随机一个干扰字
:return:
'''
d = ['^', '-', '~', '_', '.']
i = random.randint(0, len(d) - 1)
return d[i]
# 两个随机颜色都规定不同的区域,防止干扰字符和验证码字符颜色一样
# 随机颜色1:
def rnd_color(self):
'''
随机颜色,规定一定范围
:return:
'''
return (random.randint(64, 255), random.randint(64, 255), random.randint(64, 255))
# 随机颜色2:
def rnd_color2(self):
'''
随机颜色,规定一定范围
:return:
'''
return (random.randint(32, 127), random.randint(32, 127), random.randint(32, 127))
def create_code(self):
# 240 x 60:
width = 60 * 4
height = 60
image = Image.new('RGB', (width, height), (192, 192, 192))
# 创建Font对象:
font = ImageFont.truetype(self.ttf, 36)
# 创建Draw对象:
draw = ImageDraw.Draw(image)
# 填充每个像素:
for x in range(0, width, 20):
for y in range(0, height, 10):
draw.point((x, y), fill=self.rnd_color())
# 填充字符
_str = ""
# 填入4个随机的数字或字母作为验证码
for t in range(4):
c = self.rnd_char()
_str = "{}{}".format(_str, c)
# 随机距离图片上边高度,但至少距离30像素
h = random.randint(1, height - 30)
# 宽度的化,每个字符占图片宽度1/4,在加上10个像素空隙
w = width / 4 * t + 10
draw.text((w, h), c, font=font, fill=self.rnd_color2())
# 实际项目中,会将验证码 保存在数据库,并加上时间字段
print("保存验证码 {} 到数据库".format(_str))
# 给图片加上字符干扰,密集度由 w, h控制
for j in range(0, width, 30):
dis = self.rnd_dis()
w = t * 15 + j
# 随机距离图片上边高度,但至少距离30像素
h = random.randint(1, height - 30)
draw.text((w, h), dis, font=font, fill=self.rnd_color())
# 模糊:
image.filter(ImageFilter.BLUR)
# uuid1 生成唯一的字符串作为验证码图片名称
code_name = '{}.jpg'.format(uuid1())
save_dir = './{}'.format(code_name)
image.save(save_dir, 'jpeg')
print("已保存图片: {}".format(save_dir))
if __name__ == "__main__":
yzm = Yzm('华康少女体\\HKSN.ttf')
yzm.create_code()
执行结果:
五, 修改图片尺寸
def img_size(fileName,width,height):
""" fileName: 图片路径,width:修改宽度,height:修改高度 """
from PIL import Image # 导入相应模块
image = Image.open(fileName)
w, h = image.size # 原图尺寸
new_img = image.resize((width,height),Image.ANTIALIAS)
_new = 'new_'+fileName
new_img.save(_new)
new_img.close()
print('原图: %s, 尺寸为: %d,%d'%(fileName,w,h))
print('修改后的图片: %s 尺寸为: %d,%d'%(_new,width,height))
img_size('a.jpg',80,90)
执行结果:
原图: a.jpg, 尺寸为: 518,545
修改后的图片: new_a.jpg 尺寸为: 80,90
六, 图片转换为字符图
from PIL import Image, ImageDraw, ImageFont
import os
import time
class IMG_STR:
def __init__(self, img_name):
self.img_name = img_name
def save(self, img, file_name):
if os.path.isfile(file_name):
file_name=file_name.split('.')
self.save(img, file_name[0] + 'o.' + file_name[1])
else:
img.save(file_name, 'JPEG')
def main(self):
f_size = 16
f_num_x = 100
font_map = [' ', '.', 'i', 'I', 'J', 'C', 'D', 'O', 'S', 'Q', 'G', 'F', 'E', '#', '&', '@']
im = Image.open(self.img_name).convert('L')
im = im.resize((f_num_x, int(f_num_x * im.size[1] / im.size[0])))
level = im.getextrema()[-1] / (len(font_map) - 1)
im = im.point(lambda i: int(i / level))
imn = Image.new('L', (im.size[0] * f_size, im.size[1] * f_size))
f = ImageFont.truetype('arial.ttf', f_size)
d = ImageDraw.Draw(imn)
for y in range(0, im.size[1]):
for x in range(0, im.size[0]):
pp = im.getpixel((x, y))
d.text((x * f_size, y * f_size), font_map[len(font_map) - pp - 1], fill=255, font=f)
self.save(imn, self.img_name)
if __name__ == '__main__':
img = IMG_STR('xn.jpg')
img.main()
执行前后比对:
七, 图片写入字符串
from PIL import Image
import sys
def makeImageEven(image):
'''取得一个PIL图形并且更改所有值为偶数(使最低有效位为0)'''
pixels=list(image.getdata()) # 得到一个列表: [(r,g,b,t)...]
evenPixels=[(r>>1<<1,g>>1<<1,b>>1<<1) for (r,g,b) in pixels] # 更改所有值为偶数
evenImage=Image.new(image.mode, image.size) # 创建一个相同大小的图片
evenImage.putdata(evenPixels) # 把上面的像素放入到图片副本
return evenImage
def constLenBin(ints):
'''返回固定长度的二进制字符串'''
binary='0'*(8-(len(bin(ints))-2))+bin(ints).replace('0b', '') # 去掉0b,并在左边补足'0'直到字符串长度为8
return binary
def encodeDataInImage(image,data):
'''将字符串编码到图片中'''
evenImage=makeImageEven(image) # 获得最低有效位为0的图片副本
binary=''.join(map(constLenBin,bytearray(data,'utf-8'))) # 将需要隐藏的字符串转换成二进制字符串
if len(binary)>len(image.getdata())*3: # 如果不能编码全部数据,抛出异常
raise Exception("Error: Cant encode more than "+len(evenImage.getdata())*3+" bits in this image. ")
# 将 binary 中的二进制字符串信息编码进像素里
encodePixels=[(r+int(binary[index*3+0]),g+int(binary[index*3+1]),b+int(binary[index*3+2])) if index*3<len(binary) else (r,g,b) for index,(r,g,b) in enumerate(list(evenImage.getdata()))]
encodedImage=Image.new(evenImage.mode, evenImage.size) # 创建新图片以存放编码后的像素
encodedImage.putdata(encodePixels) # 添加编码后的数据
return encodedImage
def binaryToString(binary):
'''从二进制字符串转为 utf-8 字符串'''
index=0
string=[]
rec=lambda x,i:x[2:8]+(rec(x[8:],i-1) if i>1 else '') if x else ''
fun=lambda x,i:x[i+1:8]+rec(x[8:], i-1)
while index+1<len(binary):
chartype=binary[index:].index('0') #存放字节所占字节数,一个字节的字符则存为0
length=chartype*8 if chartype else 8
string.append(chr(int(fun(binary[index:index+length],chartype),2)))
index+=length
return ''.join(string)
def decodeImage(image):
'''解码隐藏数据'''
pixels=list(image.getdata()) # 获得像素列表
# 读取图片中所有最低有效位中的数据
binary=''.join([str(int(r>>1<<1!=r))+str(int(g>>1<<1!=g))+str(int(b>>1<<1!=b)) for (r,g,b) in pixels])
ldn=binary.find('0'*16) # 找到数据截止处的索引
endIndex=ldn+(8-(ldn%8)) if ldn%8!=0 else ldn
data=binaryToString(binary[0:endIndex])
return data
if __name__=='__main__':
# 把字符串写入图片 a.jpg
encodeDataInImage(Image.open('a.jpg'), '我爱你').save('encodeImage.png')
# 解码隐藏的字符串
print(decodeImage(Image.open('encodeImage.png')))
执行程序前的图片:
执行结果输出:
我爱你
执行程序后写入字符串的图片: