不知道别人是怎么做的,闲着无聊就根据前几天看到的一些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)

效果如下:

其他水印图:

【python PIL学习】给照片打水印的更多相关文章

  1. Python,PIL压缩裁剪图片

    自己写了用来压缩 DC 照片的,批量处理整目录文件,非常方便.需要安装 PIL #!/usr/bin/env python import Image import os import os.path ...

  2. 《Python爬虫学习系列教程》学习笔记

    http://cuiqingcai.com/1052.html 大家好哈,我呢最近在学习Python爬虫,感觉非常有意思,真的让生活可以方便很多.学习过程中我把一些学习的笔记总结下来,还记录了一些自己 ...

  3. Python PIL模块笔记

    利用python pil 实现给图片上添加文字 图片中添加文字#-*- coding: utf-8 -*- from PIL import Image,ImageDraw,ImageFont ttfo ...

  4. [转]《Python爬虫学习系列教程》

    <Python爬虫学习系列教程>学习笔记 http://cuiqingcai.com/1052.html 大家好哈,我呢最近在学习Python爬虫,感觉非常有意思,真的让生活可以方便很多. ...

  5. python PIL 图像处理

    python PIL 图像处理 This blog is from: https://www.jianshu.com/p/e8d058767dfa Image读出来的是PIL的类型,而skimage. ...

  6. 【原】Learning Spark (Python版) 学习笔记(三)----工作原理、调优与Spark SQL

    周末的任务是更新Learning Spark系列第三篇,以为自己写不完了,但为了改正拖延症,还是得完成给自己定的任务啊 = =.这三章主要讲Spark的运行过程(本地+集群),性能调优以及Spark ...

  7. 60分钟Python快速学习(给发哥一个交代)

    60分钟Python快速学习 之前和同事谈到Python,每次下班后跑步都是在听他说,例如Python属于“胶水语言啦”,属于“解释型语言啦!”,是“面向对象的语言啦!”,另外没有数据类型,逻辑全靠空 ...

  8. python爬虫学习(1) —— 从urllib说起

    0. 前言 如果你从来没有接触过爬虫,刚开始的时候可能会有些许吃力 因为我不会从头到尾把所有知识点都说一遍,很多文章主要是记录我自己写的一些爬虫 所以建议先学习一下cuiqingcai大神的 Pyth ...

  9. python爬虫学习 —— 总目录

    开篇 作为一个C党,接触python之后学习了爬虫. 和AC算法题的快感类似,从网络上爬取各种数据也很有意思. 准备写一系列文章,整理一下学习历程,也给后来者提供一点便利. 我是目录 听说你叫爬虫 - ...

随机推荐

  1. BZOJ3640 : JC的小苹果

    设$f[i][j]$表示$hp$为$i$,在$j$点的概率,$d[i]$表示$i$的度数,$w[i]$表示经过$i$点要扣掉的血量. 对于$j$到$k$这条边,$f[i-w[k]][k]+=\frac ...

  2. BZOJ3787 : Gty的文艺妹子序列

    将序列分成$\sqrt{n}$块,预处理出每两块之间的逆序对数,以及ap[i]表示前i块内数字出现次数的树状数组 预处理:$O(n\sqrt{n}\log n)$ 修改时,ap[i]可以在$O(\sq ...

  3. C#中的String.Format方法(转)

    一.定义String.Format是将指定的 String类型的数据中的每个格式项替换为相应对象的值的文本等效项. 如: (1)string p1 = "Jackie";strin ...

  4. nosql数据库比较

  5. Hibernate使用MyExclipse10自动生成配置文件报错

    使用MyExclipse10自动生成hibernate映射文件如下: 结果发现启动服务时报以下错误: 原因:因为hibernate换过项目地址,所以dtd文件的地址也换掉了.在hbm.xml文件里面把 ...

  6. 转:值得推荐的C/C++框架和库(真的很强大)

    目录(?)[+] 值得学习的C语言开源项目 - 1 Webbench - 2 Tinyhttpd - 3 cJSON - 4 CMockery - 5 Libev - 6 Memcached - 7 ...

  7. IOS 开发的官方文档链接

    下面这些文章都是苹果官方的开发文档,非常有用: iOS Developer Library https://developer.apple.com/library/ios/navigation/ 总入 ...

  8. apache磁盘缓存配置

    确保mod_cache和mod_disk_cache是开启的 配置如下: CacheDefaultExpire 86400 #失效时间,单位秒CacheEnable disk /      #缓存路径 ...

  9. 使用fsck修复文件系统错误

    1.问题描述 服务器maint_samba   由于服务器maint_samba (debian操作系统)没有正常关机,在重新启动过程中/dev/sdb1出现文件系统错误,需要手动使用fsck进行扫描 ...

  10. = splice

    <script> function wf(w){ console.log(w); } var wa = [3,66,7]; var wb = wa; wa.splice(1,1); wf( ...