Skip to content

Commit 11bfcb9

Browse files
committed
add challenge 3: Add watermark for png pictures
1 parent e650a18 commit 11bfcb9

9 files changed

+370
-0
lines changed

003_Add_text_watermark_on_pictures.md

+279
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
# Add text watermark on pictures
2+
3+
## Requirements
4+
5+
1. Run the code in console using command line.
6+
2. It'll ask you what's the text you want to add as watermark, and the text size, transparency and position. Please use 20, 50% and bottom right as the default values.
7+
3. It'll add the text watermark on every png pictures in the 'images' dirtionary of the current path, and save these pictures into 'watermark' dirtionary.
8+
9+
## What will we practice in this project?
10+
11+
- for loop
12+
- input text
13+
- if conditions
14+
- functions
15+
- tuple
16+
- Open/save files
17+
- Image RGBA conception
18+
- os package
19+
- PIL package (need to install by `pip install pillow`)
20+
21+
## A reference code
22+
23+
```python
24+
import os
25+
26+
from PIL import Image, ImageDraw, ImageFont
27+
28+
29+
def get_position(image_width, image_height, text_width, text_height, position_id=9, margin=10):
30+
'''
31+
Get the position of the text by the position_id
32+
1: top left, 2: top center, 3: top right
33+
4: middle left, 5: middle center, 6: middle right
34+
7: bottom left, 8: bottom center, 9: bottom right
35+
:param image_width: image width
36+
:param image_height: image height
37+
:param text_width: text width
38+
:param text_height: text height
39+
:param position_id: position_id
40+
:param margin: the text position margin value to the image
41+
:return: text position tuple
42+
'''
43+
margin = 10
44+
if position_id == 1:
45+
return (margin, margin)
46+
elif position_id == 2:
47+
return (image_width // 2 - text_width // 2, margin)
48+
elif position_id == 3:
49+
return (image_width - text_width - margin, margin)
50+
elif position_id == 4:
51+
return (margin, image_height // 2 - text_height // 2)
52+
elif position_id == 5:
53+
return (image_width // 2 - text_width // 2, image_height // 2 - text_height // 2)
54+
elif position_id == 6:
55+
return (image_width - text_width - margin, image_height // 2 - text_height // 2)
56+
elif position_id == 7:
57+
return (margin, image_height - text_height - margin)
58+
elif position_id == 8:
59+
return (image_width // 2 - text_width // 2, image_height - text_height - margin)
60+
elif position_id == 9:
61+
return (image_width - text_width - margin, image_height - text_height - margin)
62+
63+
64+
def add_watermark(filename, text, font_name='Roboto-Italic.ttf', font_size=20, font_opacity=50, position_id=9):
65+
'''
66+
Add watermark function
67+
:param filename: origin image filename
68+
:param text: watermark text
69+
:param font_name: Roboto-Italic.ttf, you can use your font, please make sure your program can find it
70+
:param font_size: font size, default is 20
71+
:param font_opacity: font opacity, default is 50
72+
:param position_id: position id, defalut is 9 (bottom right)
73+
:return:
74+
'''
75+
# get an image
76+
with Image.open(filename).convert("RGBA") as base:
77+
# make a blank image for the text, initialized to transparent text color
78+
txt = Image.new("RGBA", base.size, (255, 255, 255, 0))
79+
80+
# get a font
81+
fnt = ImageFont.truetype(font_name, font_size)
82+
# get a drawing context
83+
d = ImageDraw.Draw(txt)
84+
# get the text widht and height
85+
text_width, text_height = d.textsize(text, font=fnt)
86+
# get the text position of the image
87+
pos = get_position(base.size[0], base.size[1], text_width, text_height, position_id=position_id)
88+
# draw text with opacity
89+
d.text(pos, text, font=fnt, fill=(255, 255, 255, 256 * font_opacity // 100))
90+
out = Image.alpha_composite(base, txt)
91+
92+
# save the image file
93+
out_filename = 'watermark/{}'.format(os.path.basename(filename))
94+
if not os.path.exists('watermark'):
95+
os.makedirs('watermark')
96+
out.save(out_filename, 'PNG')
97+
98+
99+
if __name__ == '__main__':
100+
text = input('Please input a watermark text: ').strip()
101+
font_size = int(input('Please input the font size: [20]') or '20')
102+
font_opacity = int(input('Please input the font opacity: [50]') or '50')
103+
# 1: top left, 2: top center, 3: top right
104+
# 4: middle left, 5: middle center, 6: middle right
105+
# 7: bottom left, 8: bottom center, 9: bottom right
106+
position_id = int(input('Please input the position: [9]') or '9')
107+
108+
for f in os.listdir('images'):
109+
if f.endswith('.png'):
110+
filename = 'images/{}'.format(f)
111+
print('add watermark for {}'.format(filename))
112+
add_watermark(filename=filename, text=text, font_size=font_size, font_opacity=font_opacity,
113+
position_id=position_id)
114+
115+
```
116+
117+
## Run the demo
118+
119+
- make sure you have a `image` dirtionary and put some `png` files in this dirtionary
120+
- use `pip install requirements.txt` to install packages
121+
- run it in console
122+
123+
```shell
124+
python 3.py
125+
```
126+
127+
- it'll add watermark on every picture in `images` dirtionary and save them to `watermark` dirtionary.
128+
129+
![](images/challenge_3_1.png)
130+
131+
![](images/challenge_3_2.png)
132+
133+
![](images/challenge_3_3.png)
134+
135+
![](images/challenge_3_4.png)
136+
137+
![](images/challenge_3_5.png)
138+
139+
# 给图片增加文字水印
140+
141+
## 项目需求
142+
143+
1. 在命令行窗口运行;
144+
2. 程序运行时,会提示输入水印的文字,以及水印文字大小,透明度和位置,文字大小默认值为20,透明度默认为50%,位置默认为右下角。使用数字1-9分别代表左上、中上、右上、中左、正中、中右、下左、下中、下右;
145+
3. 程序会给当前目录下的images目录中所有png文件增加水印,并保存到watermark目录中。
146+
147+
## Python编程知识点
148+
149+
- for循环
150+
- 用户输入字符串
151+
- 条件判断
152+
- 自定义函数
153+
- 元组
154+
- 打开、保存图片文件
155+
- 图片RGBA概念
156+
- os模块
157+
- PIL 模块 (需要使用`pip install pillow`安装)
158+
159+
## 参考代码
160+
161+
```python
162+
import os
163+
164+
from PIL import Image, ImageDraw, ImageFont
165+
166+
167+
def get_position(image_width, image_height, text_width, text_height, position_id=9, margin=10):
168+
'''
169+
获取文字位置,position_id
170+
1: 左上, 2: 中上, 3: 右上
171+
4: 中左, 5: 正中, 6: 中右
172+
7: 左下, 8: 下中, 9: 右下
173+
:param image_width: 图片宽度
174+
:param image_height: 图片高度
175+
:param text_width: 文字宽度
176+
:param text_height: 文字高度
177+
:param position_id: 位置ID,1-9,默认是9(右下)
178+
:param margin: 边距值,默认为10px
179+
:return: 文字位置的(x, y)元组
180+
'''
181+
margin = 10
182+
if position_id == 1:
183+
return (margin, margin)
184+
elif position_id == 2:
185+
return (image_width // 2 - text_width // 2, margin)
186+
elif position_id == 3:
187+
return (image_width - text_width - margin, margin)
188+
elif position_id == 4:
189+
return (margin, image_height // 2 - text_height // 2)
190+
elif position_id == 5:
191+
return (image_width // 2 - text_width // 2, image_height // 2 - text_height // 2)
192+
elif position_id == 6:
193+
return (image_width - text_width - margin, image_height // 2 - text_height // 2)
194+
elif position_id == 7:
195+
return (margin, image_height - text_height - margin)
196+
elif position_id == 8:
197+
return (image_width // 2 - text_width // 2, image_height - text_height - margin)
198+
elif position_id == 9:
199+
return (image_width - text_width - margin, image_height - text_height - margin)
200+
201+
202+
def add_watermark(filename, text, font_name='Roboto-Italic.ttf', font_size=20, font_opacity=50, position_id=9):
203+
'''
204+
增加水印
205+
:param filename: 要加水印的文件(dir/file.png)
206+
:param text: 水印文字
207+
:param font_name: 默认为Roboto-Italic.ttf字体
208+
你也可以使用自己的字体,确保代码能够找到这个字体文件(在当前目录或者系统字体目录中)
209+
:param font_size: 字体大小,默认值为20px
210+
:param font_opacity: 透明度,默认为50%
211+
:param position_id: 位置ID,1-9,默认是9(右下)
212+
:return:
213+
'''
214+
# 打开原图片文件
215+
with Image.open(filename).convert("RGBA") as base:
216+
# 创建一个新的透明画面,大小和原图片一样
217+
txt = Image.new("RGBA", base.size, (255, 255, 255, 0))
218+
# 使用指定的字体
219+
fnt = ImageFont.truetype(font_name, font_size)
220+
# 准备“画”文字
221+
d = ImageDraw.Draw(txt)
222+
# 得到文字的宽度和高度
223+
text_width, text_height = d.textsize(text, font=fnt)
224+
# 得到文字的位置
225+
pos = get_position(base.size[0], base.size[1], text_width, text_height, position_id=position_id)
226+
# 将文字“画”到画布上
227+
d.text(pos, text, font=fnt, fill=(255, 255, 255, 256 * font_opacity // 100))
228+
# 将画布和原图片合并
229+
out = Image.alpha_composite(base, txt)
230+
231+
# 保存图片文件
232+
out_filename = 'watermark/{}'.format(os.path.basename(filename))
233+
if not os.path.exists('watermark'):
234+
os.makedirs('watermark')
235+
out.save(out_filename, 'PNG')
236+
237+
238+
if __name__ == '__main__':
239+
text = input('请输入水印文字: ').strip()
240+
font_size = int(input('请输入文字大小: [20]') or '20')
241+
font_opacity = int(input('请输入文字透明度: [50]') or '50')
242+
# 1: 左上, 2: 中上, 3: 右上
243+
# 4: 中左, 5: 正中, 6: 中右
244+
# 7: 左下, 8: 下中, 9: 右下
245+
position_id = int(input('请输入水印位置: [9]') or '9')
246+
247+
for f in os.listdir('images'):
248+
if f.endswith('.png'):
249+
filename = 'images/{}'.format(f)
250+
print('{}增加水印'.format(filename))
251+
add_watermark(filename=filename, text=text, font_size=font_size, font_opacity=font_opacity,
252+
position_id=position_id)
253+
254+
255+
```
256+
257+
## 运行测试
258+
259+
- 将需要加水印的图片放到当前目录的`images`目录中
260+
- 使用 `pip install requirements.txt`来安装工具包
261+
- 运行
262+
263+
```shell
264+
python 3.py
265+
```
266+
267+
- 程序会将`images`目录中所有png图片增加水印并保存到`watermark`目录中
268+
269+
![](images/challenge_3_1.png)
270+
271+
![](images/challenge_3_2.png)
272+
273+
![](images/challenge_3_3.png)
274+
275+
![](images/challenge_3_4.png)
276+
277+
![](images/challenge_3_5.png)
278+
279+
> 注意,如果要增加汉字水印,请使用一个汉字字体

code/3/3.py

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import os
2+
3+
from PIL import Image, ImageDraw, ImageFont
4+
5+
6+
def get_position(image_width, image_height, text_width, text_height, position_id=9, margin=10):
7+
'''
8+
Get the position of the text by the position_id
9+
1: top left, 2: top center, 3: top right
10+
4: middle left, 5: middle center, 6: middle right
11+
7: bottom left, 8: bottom center, 9: bottom right
12+
:param image_width: image width
13+
:param image_height: image height
14+
:param text_width: text width
15+
:param text_height: text height
16+
:param position_id: position_id
17+
:param margin: the text position margin value to the image
18+
:return: text position tuple
19+
'''
20+
margin = 10
21+
if position_id == 1:
22+
return (margin, margin)
23+
elif position_id == 2:
24+
return (image_width // 2 - text_width // 2, margin)
25+
elif position_id == 3:
26+
return (image_width - text_width - margin, margin)
27+
elif position_id == 4:
28+
return (margin, image_height // 2 - text_height // 2)
29+
elif position_id == 5:
30+
return (image_width // 2 - text_width // 2, image_height // 2 - text_height // 2)
31+
elif position_id == 6:
32+
return (image_width - text_width - margin, image_height // 2 - text_height // 2)
33+
elif position_id == 7:
34+
return (margin, image_height - text_height - margin)
35+
elif position_id == 8:
36+
return (image_width // 2 - text_width // 2, image_height - text_height - margin)
37+
elif position_id == 9:
38+
return (image_width - text_width - margin, image_height - text_height - margin)
39+
40+
41+
def add_watermark(filename, text, font_name='Roboto-Italic.ttf', font_size=20, font_opacity=50, position_id=9):
42+
'''
43+
Add watermark function
44+
:param filename: origin image filename
45+
:param text: watermark text
46+
:param font_name: Roboto-Italic.ttf, you can use your font, please make sure your program can find it
47+
:param font_size: font size, default is 20
48+
:param font_opacity: font opacity, default is 50
49+
:param position_id: position id, defalut is 9 (bottom right)
50+
:return:
51+
'''
52+
# get an image
53+
with Image.open(filename).convert("RGBA") as base:
54+
# make a blank image for the text, initialized to transparent text color
55+
txt = Image.new("RGBA", base.size, (255, 255, 255, 0))
56+
57+
# get a font
58+
fnt = ImageFont.truetype(font_name, font_size)
59+
# get a drawing context
60+
d = ImageDraw.Draw(txt)
61+
# get the text widht and height
62+
text_width, text_height = d.textsize(text, font=fnt)
63+
# get the text position of the image
64+
pos = get_position(base.size[0], base.size[1], text_width, text_height, position_id=position_id)
65+
# draw text with opacity
66+
d.text(pos, text, font=fnt, fill=(255, 255, 255, 256 * font_opacity // 100))
67+
out = Image.alpha_composite(base, txt)
68+
69+
# save the image file
70+
out_filename = 'watermark/{}'.format(os.path.basename(filename))
71+
if not os.path.exists('watermark'):
72+
os.makedirs('watermark')
73+
out.save(out_filename, 'PNG')
74+
75+
76+
if __name__ == '__main__':
77+
text = input('Please input a watermark text: ').strip()
78+
font_size = int(input('Please input the font size: [20]') or '20')
79+
font_opacity = int(input('Please input the font opacity: [50]') or '50')
80+
# 1: top left, 2: top center, 3: top right
81+
# 4: middle left, 5: middle center, 6: middle right
82+
# 7: bottom left, 8: bottom center, 9: bottom right
83+
position_id = int(input('Please input the position: [9]') or '9')
84+
85+
for f in os.listdir('images'):
86+
if f.endswith('.png'):
87+
filename = 'images/{}'.format(f)
88+
print('add watermark for {}'.format(filename))
89+
add_watermark(filename=filename, text=text, font_size=font_size, font_opacity=font_opacity,
90+
position_id=position_id)

code/3/images/1.png

553 KB
Loading

code/3/requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pillow

images/challenge_3_1.png

51.5 KB
Loading

images/challenge_3_2.png

495 KB
Loading

images/challenge_3_3.png

56.1 KB
Loading

images/challenge_3_4.png

553 KB
Loading

images/challenge_3_5.png

493 KB
Loading

0 commit comments

Comments
 (0)