【python PIL学习】给照片打水印
不知道别人是怎么做的,闲着无聊就根据前几天看到的一些PIL里面的函数,写了这个小程序,经过测试,基本可以给所有像宽400以上的图片打上从左下到右上的看上去质量尚可的水印,更小的图片水印偏下。写完觉得很简单,还是写出来记录一下,唔,我现在仍然很无聊。
我的思路很简单:
- 一个比较大的空白图像上添加文字(为什么比较大呢,因为图像旋转之后一不小心会截取出界)
- 旋转写过字的空白图像
- 截取空白图像中的文字部分(为什么要截取呢,因为旋转过后的图像直接与需要水印的图像合并,整个图像都会是旋转状态,达不到水印倾斜的效果,所以把倾斜的文字图像截取成一个文字倾斜但是整体水平的图像)
- 将截取到的文字部分粘贴在与要水印的图像大小相等的另一个空白图像上(为什么要粘贴呢,因为要合并的两个图像尺寸必须相同)
- 将被粘贴过的图像与要水印的图像按照较低的alpha合并
好吧,讲得有点乱,下面一点点看看我的程序以及示例吧:
1、第一部分,主要是程序要用到的库的调用,以及需要的基本信息初始化,如下:
import Image import ImageDraw import ImageFont import math fileName = input("Please input your iamge name:") #输入要打水印的图片名称 text = input("Please input your text to ink:") #输入要打得水印 im = Image.open(fileName) #打开要打水印的相片 imageW,imageH = im.size #获取图片尺寸 textImageW = int(imageW*1.5) #确定写文字图片的尺寸,如前所述,要比照片大,我取1.5倍 textImageH = int(imageH*1.5) blank = Image.new("RGB",(textImageW,textImageH),"white") #创建用于添加文字的空白图像 d = ImageDraw.Draw(blank) #创建draw对象
2、第二部分,根据图片大小确定打水印的文字大小。对于不同大小的相片,如果添加水印过大,甚至不能全部显示,或者过小都不美观。但是像素值与字号之间的对应关系我不知道是否有直接的工具可以实现,问了许久也没有办法解决,于是选择了最拙劣的分区赋值。还好最后测试的效果还算可以,只是图片过小的时候会稍稍偏下,不过像宽400以上基本上没有问题
if imageW < 400: k = 32 elif imageW < 600: k = 48 elif imageW < 800: k = 64 elif imageW < 1000: k = 80 elif imageW < 1200: k = 100 elif imageW < 1400: k =128 elif imageW < 1800: k= 156 elif imageW < 2200: k = 192 elif imageW < 2600: k = 256 elif imageW < 3100: k = 300 print "fontsize:",k
3、在空白图片上添加文字。为了实现更好的裁剪,我将文字写在空白图像的正中间
Font = ImageFont.truetype("C:\Windows\Fonts\SHOWG.TTF",k) #创建Font对象,k之为字号 textW,textH = Font.getsize(text) #获取文字尺寸 d.ink = 0 + 0 * 256 + 0 * 256 * 256 #黑色 d.text([(textImageW-textW)/2,(textImageH-textH)/2],text,font = Font)#将文字写在空白图像正中间效果如下:
4、旋转图像,实现文字倾斜
#旋转文字 textRotate = blank.rotate(30) #textRotate.show()效果如下:
从上图可以看出,旋转后的图像周围会有黑色背景,所以如果截取尺寸过大,四个角度会有阴影遗留下来印到图片上。故前面我选用比相片更大尺寸的空白图像添加文字。
5、截取文字区域。要从上图中截取出最大的不触及黑色背景的图片,可以根据旋转角度以及图像尺寸计算出,可截取的最大尺寸,方法如下:
rLen = math.sqrt((textW/2)**2+(textH/2)**2) oriAngle = math.atan(textH/textW) cropW = rLen*math.cos(oriAngle + math.pi/6) *2 #被截取区域的宽高 cropH = rLen*math.sin(oriAngle + math.pi/6) *2 box = [int((textImageW-cropW)/2-1),int((textImageH-cropH)/2-1)-50,int((textImageW+cropW)/2+1),int((textImageH+cropH)/2+1)] textIm = textRotate.crop(box) #截取文字图片效果如下:
6、截取后的图片贴在另一个跟相片尺寸相同的空白图像上。达到比较好的效果,要粘贴在空白图像的正中央
pasteW,pasteH = textIm.size #旋转后的文字图片粘贴在一个新的blank图像上 textBlank = Image.new("RGB",(imageW,imageH),"white") pasteBox = (int((imageW-pasteW)/2-1),int((imageH-pasteH)/2-1)) textBlank.paste(textIm,pasteBox)
效果如下:
7、图像合并,水印完成。可改变alpha值,改变水印的深浅程度
waterImage = Image.blend(im,textBlank,0.2)效果如下:
其他水印图: