2025-06-12

将 Emoji 写入一个图片的指定位置并不容易,今天折腾了一个多小时才搞定。主要是 PIL 不直接支持,Imagemagick 默认的版本也不支持。找来找去发现了pilmoji,但它在处理文字和 emoji 混合文本时在目标图片内对齐又是个问题。于是使用 pilmoji 先将文本转换为图片,再将图片贴到目标图片。代码如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
from PIL import Image, ImageFont
from pilmoji import Pilmoji
from pilmoji.source import AppleEmojiSource


def create_text_image(text, font, text_color=(0, 0, 0)):
"""使用pilmoji创建包含emoji的文字图片(透明背景)"""
# 创建一个足够大的临时图片来测量文本尺寸
temp_img = Image.new('RGBA', (1000, 200), (255, 255, 255, 0))

with Pilmoji(temp_img, source=AppleEmojiSource) as pilmoji:
# 渲染文本到临时图片
pilmoji.text((10, 10), text, text_color, font,
emoji_scale_factor=1.15, emoji_position_offset=(0, 0))

# 获取文本的实际边界框
bbox = temp_img.getbbox()
if bbox is None:
# 如果没有内容,返回空图片
return Image.new('RGBA', (1, 1), (255, 255, 255, 0))

# 裁剪到实际文本大小
text_img = temp_img.crop(bbox)

return text_img


def add_text_to_image(image_path, output_path, text):
# 打开背景图片
background = Image.open(image_path)

# 加载字体
font = ImageFont.truetype('MiSans-Medium.ttf', 70)

# 创建文字图片
text_img = create_text_image(text, font, (0, 0, 0))

# 计算文字图片在背景图片中的居中位置
bg_width, bg_height = background.size
text_width, text_height = text_img.size

x = (bg_width - text_width) // 2
y = (bg_height - text_height) // 2 - 60 # 向上偏移60像素

# 将文字图片粘贴到背景图片上
background.paste(text_img, (x, y), text_img)

final_image = background
final_image.save(output_path)
print(f"Image saved with emoji support: {output_path}")


def main():
cert_base_dir = "cert"
cert_template_path = "/Users/zouguodong/Downloads/delta证书.png"
csv_file = "/Users/zouguodong/Downloads/delta-member.csv"
with open(csv_file, 'r') as file:
lines = file.readlines()
for line in lines[1:]:
id, name, phone = line.strip().split(',')
# if "aac" in name:
print(f"Processing {name} with ID {id} and phone {phone}")
cert_out_path = f"{cert_base_dir}/{id}.png"
add_text_to_image(cert_template_path, cert_out_path, name)

if __name__ == '__main__':
cert_template_path = "/Users/zouguodong/Downloads/delta证书.png"
cert_out_path = "~/Downloads/result.png"
name = "思考🤔"
add_text_to_image(cert_template_path, cert_out_path, name)

2024-12-25

今日好奇看了下 中国统计年鉴2024,有一些印象深刻的点

  • 人口
    • 2020-2021 是人口顶峰
    • 男女比例长期有 2%的差距,也就是说有两千多万
      • 主要集中在 50 岁以下
      • 在十几岁到三十几岁的男女比例差距最大
      • 60 岁以上明显的男少女多(可能:女性寿命本身比较长、战争使得男性消耗了一波,解放战争 1950 年结束,参加过的人应该也至少 80 岁以上了)
    • 2020 年开始出生率降低到 10% 以下,现在只有 6.39%,近期出生率最高的在 2014 年的 13.83,历史上最高的在 198x 年,都是在 20%-23%
    • 死亡率一直是上升的,不过这是正常的
    • 2022 年开始,来到负增长,以前都是正增长
    • 女性的平均寿命确实比男生高出 5 岁左右
  • 教育
    • 相较于我毕业的 2015 年本科毕业生 680 万人,2023 年本科毕业生为 1047 万人
  • 进出口
    • 20-21 年间,进出口总额提升非常明显,达到 20% 左右

2024-12-12

以 python 3.12 为基础镜像的 Dockerfile 如何替换国内镜像源.

这是传统的方式

1
2
3
4
... ...
RUN sed -i 's/deb.debian.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list && \
sed -i 's|security.debian.org/debian-security|mirrors.tuna.tsinghua.edu.cn/debian-security|g' /etc/apt/sources.list
... ...

但是自从 Debian 11 (Bullseye) 开始,Debian 支持使用 .sources 文件格式来配置 APT 源,而不是传统的 sources.list 文件。这种新格式提供了更多功能,比如更好的签名支持。所以新的完整的例子如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
FROM registry.cn-beijing.aliyuncs.com/xxx/python:3.12

COPY requirements.txt .

# 使用国内的 apt 源
RUN sed -i 's|http://deb.debian.org|http://mirrors.aliyun.com|g' /etc/apt/sources.list.d/debian.sources; \
sed -i 's|http://security.debian.org|http://mirrors.aliyun.com|g' /etc/apt/sources.list.d/debian.sources; \
apt-get update && apt-get install -y ffmpeg; \
apt-get clean

WORKDIR /app
COPY . .

ARG BE_PODCAST_WORKER

ENV BE_PODCAST_WORKER=$BE_PODCAST_WORKER
ENV PYTHONUNBUFFERED=1

RUN pip install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt

CMD ["python", "worker_main.py"]

2024-11-22

如果 git 操作时报 ”Account has been blocked“ 怎么办?

先确定 ssh 连接是否成功;再确定 git server 把我们当成了哪个用户。然后看这个用户是否真的被 block 了

1
2
# ssh -v 是个好办法,它能让我们知道 git 选择了哪个秘钥进行 ssh 认证
GIT_SSH_COMMAND="ssh -v" git clone [email protected]:g1/xxxx/prod.git
1
2
3
4
5
6
7
8
9
# 然后看一下这个秘钥在 git server 对应的到底是哪个用户

# ssh -i 是个好办法
ssh -i /home/www/.ssh/id_rsa [email protected]

# ssh -T 也是可以的,甚至可以不用先 ssh -v 看用的是哪个秘钥
ssh -T [email protected]
# 它的输出可能如下
Welcome to GitLab, @zouguodong!

2024-11-12

最近在看《浪潮之巅》,突然想起来列一下中美部分主要科技公司创建的时间线。

以前只知道美国科技公司早起发展时我们还在原地踏步,但不是很有具体的概念,列一下加深印象。

中美科技公司创立时间线

从图中大致可以看出

  • 苹果、微软这样的老牌厂商创建时,我们还在经历文化大革命。
  • 我们的知名企业都是在临近或改革开放之后发展起来的。
  • 1984 年前后是网络设备的发展;1994 年前后是互联网公司兴起的时间点。

2024-08-02

阿里云 OSS 支持 STS \ 签名URL \ 服务端签名 等三种主要客户端上传方式,一直想用签名 URL 上传,但今天试了下发现使用它时两个比较不方便的点:

  • 需要客户端提供后缀
  • 需要客户端提供 Content-Type,否则就是 application/octet-stream,意味着客户端上传时也要讲 Content-Type 设置为 application/octet-stream,访问文件时,也是该请求头,这意味着文件无法预览.

个人认为这非常不易用:客户端上传时一般是不会关心文件是什么格式,MIME 类型是什么,相较而言,现在我更加倾向于 STS 的上传方式了.

2024-06-29

Google Authenticator 背后的技术其实非常简单:HOTP 或 TOTP,如果要自己实现一个服务端,只需要做两件事

2024-05-14

  • 今天又做了一件秀逗的事:zipfile 打包时,将 zip 打包到自己,触发了死循环,从而导致内存溢出。
⬆︎TOP