python 图片常用操作


一, 图片与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')

执行结果:



四, 生成随机图形验证码

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')))


执行程序前的图片:

执行结果输出:

我爱你

执行程序后写入字符串的图片:


猜你喜欢

转载自blog.csdn.net/a649344475/article/details/80864600