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


执行程序前的图片:

执行结果输出:

我爱你

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

八、图片背景透明化

from PIL import Image
import numpy
import os


def get_convert_middle(img_path):
    I = Image.open(img_path)
    L = I.convert('L')
    im = numpy.array(L)
    im4 = 255.0 * (im / 255.0) ** 2  # 对图像的像素值求平方后得到的图像
    middle = (int(im4.min()) + int(im4.max())) / 2
    return middle


def transparent_background(path):
    """ 读取图片,把背景透明化,再写入原图片 """
    try:
        img = Image.open(path)
        img = img.convert("RGBA")  # 转换获取信息
        pixdata = img.load()
        color_no = get_convert_middle(path) + 30  # 抠图的容错值

        for y in range(img.size[1]):
            for x in range(img.size[0]):
                if pixdata[x, y][0] > color_no and pixdata[x, y][1] > color_no and pixdata[x, y][2] > color_no and \
                        pixdata[x, y][3] > color_no:
                    pixdata[x, y] = (255, 255, 255, 0)

        if not path.endswith('png'):
            os.remove(path)
            replace_path_list = path.split('.')
            replace_path_list = replace_path_list[:-1]
            path = '.'.join(replace_path_list) + '.png'

        img.save(path)
        img.close()
    except Exception as e:
        print(e)

九、PDF文件转换为图片

我的环境是Windows10、Python3.6

1、先安装所需要的Python库
pip install traits
pip install fitz
pip install PyMuPDF

2、示例代码如下

import fitz


def pdf_to_image(pdf_name, to_imgs, x, y, rotate):
    """pdf_name pdf文件名称
        to_imgs 图片要保存的目录
        x x方向的缩放系数
        y y方向的缩放系数
        rotate 旋转角度
        注:x和y一般取相同值,值越大,图像分辨率越高。
    """
    # 打开PDF文件
    pdf = fitz.open(pdf_name)
    # 逐页读取PDF
    for pg in range(0, pdf.pageCount):
        page = pdf[pg]
        # 设置缩放和旋转系数
        trans = fitz.Matrix(x, y).preRotate(rotate)
        pm = page.getPixmap(matrix=trans, alpha=False)
        # 开始写图像
        pm.writePNG(to_imgs+str(pg)+".png")
    pdf.close()


pdf_to_image('我的合同.pdf', 'c\\', 5, 5, 0)

十、图片转换为PDF文件

1、安装所需的库

pip install reportlab

2、示例代码如下

from reportlab.pdfgen import canvas
from reportlab.lib.units import inch, cm
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Image, PageBreak
from reportlab.lib.pagesizes import A4,A3,A2,A1, legal, landscape
from reportlab.lib.utils import ImageReader
from PIL import Image, ExifTags
from os import listdir
import os, re
import time
from reportlab.lib.units import inch


def img_search(mypath, filenames):
    for lists in os.listdir(mypath):
        path = os.path.join(mypath,lists)
        if os.path.isfile(path):
            expression = r'[\w]+\.(jpg|png|jpeg)$'
            if re.search(expression, path, re.IGNORECASE):
                filenames.append(path)
        elif os.path.isdir(path):
            img_search(path, filenames)


def rotate_img_to_proper(image):
    try:
        if hasattr(image, '_getexif'):
            for orientation in ExifTags.TAGS.keys():
                if ExifTags.TAGS[orientation] == 'Orientation':
                    break
            e = image._getexif()  
            if e is not None:
                exif = dict(e.items())
                orientation = exif[orientation]
                if orientation == 3:
                    image = image.transpose(Image.ROTATE_180)
                elif orientation == 6:
                    image = image.transpose(Image.ROTATE_270)
                elif orientation == 8:
                    image = image.rotate(90, expand=True)
    except Exception as ex:
        print(ex)
    return image


def main(imgs, compress=0.5):
    """
        imgs:图片存储路径
        compress:图片缩放比例
    """
    save_name = 'new.pdf'  # 保存文件名
    imgDoc = canvas.Canvas(save_name)  # pagesize=0.5
    imgDoc.setPageSize(A4)
    document_width, document_height = A4
    filenames=[]
    start = time.clock()
    img_search(imgs, filenames)
    end = time.clock()
    print('find file cost time: ', end-start, 'find files: ', len(filenames))

    for image in filenames:
        try:
            image_file = Image.open(image)
            w, h = image_file.size  # 原图尺寸
            image_file = image_file.resize((int(w*compress), int(h*compress)), Image.ANTIALIAS)  # 调整图片尺寸
            image_file = rotate_img_to_proper(image_file)

            image_width, image_height = image_file.size
            print('img size:', image_file.size)
            if not(image_width>0 and image_height>0):
                raise Exception
            image_aspect = image_height/float(image_width)
            
            print_width  = document_width
            print_height = document_width*image_aspect
            imgDoc.drawImage(ImageReader(image_file),document_width-print_width,
                         document_height-print_height,width=print_width,
                             height=print_height,preserveAspectRatio=True)
            imgDoc.showPage()
        except Exception as e:
            print('error:', e, image)
    imgDoc.save()
    print(save_name)


main(r'C:\Users\Administrator\Desktop\pimg\images')

十一、图片拼接,拼接多张图片为一张

from PIL import Image, ImageDraw, ImageFont
import cv2
import numpy as np


def jigsaw(imgs, direction=None, gap=0):
    """ direction:horizontal,vertical;水平,垂直,为空则根据图片方向选择 """
    imgs = [Image.fromarray(img) for img in imgs]
    w, h = imgs[0].size
    if direction == "horizontal" or (not direction and w <= h):
        result = Image.new(imgs[0].mode, ((w+gap)*len(imgs)-gap, h))
        for i, img in enumerate(imgs):
            result.paste(img, box=((w+gap)*i, 0))
    elif direction == "vertical" or (not direction and w > h):
        result = Image.new(imgs[0].mode, (w, (h+gap)*len(imgs)-gap))
        for i, img in enumerate(imgs):
            result.paste(img, box=(0, (h+gap)*i))
    else:
        result = {}
        print("请选择拼接方向,水平或者垂直拼接!")

    return np.array(result)


def main():
    img1 = cv2.imread("a1.jpg")
    img2 = cv2.imread("a2.jpg")
    img3 = cv2.imread("a3.jpg")
    img = jigsaw([img1, img2, img3])
    # cv2.imwrite("new_img.png", img)
    cv2.imwrite("new_img.jpg", img)

main()

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值