codepet 1.0.9 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codepet",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "在编程软件里养电子宠物 — 支持 Claude Code / Codex / Cursor / VS Code 等 10+ 平台",
5
5
  "main": "core/index.js",
6
6
  "bin": {
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env python3
2
- """拍立得相框 — 生成 PNG 图片版(Windows 和通用平台)"""
2
+ """拍立得相框 — 像素风 PNG 图片版"""
3
3
 
4
4
  import sys, os, json, platform
5
- from PIL import Image, ImageDraw, ImageFont
5
+ from PIL import Image, ImageDraw, ImageFont, ImageFilter
6
6
 
7
7
  SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
8
8
  SPRITE_DIR = os.path.join(SCRIPT_DIR, "..", "sprites")
@@ -15,27 +15,15 @@ SCENE_ZH = {
15
15
  }
16
16
 
17
17
  def load_font(size):
18
- """跨平台加载字体"""
19
18
  system = platform.system()
20
19
  candidates = []
21
20
  if system == "Darwin":
22
- candidates = [
23
- "/System/Library/Fonts/PingFang.ttc",
24
- "/System/Library/Fonts/Hiragino Sans GB.ttc",
25
- ]
21
+ candidates = ["/System/Library/Fonts/PingFang.ttc", "/System/Library/Fonts/Hiragino Sans GB.ttc"]
26
22
  elif system == "Windows":
27
23
  windir = os.environ.get("WINDIR", "C:\\Windows")
28
- candidates = [
29
- os.path.join(windir, "Fonts", "msyh.ttc"),
30
- os.path.join(windir, "Fonts", "simhei.ttf"),
31
- os.path.join(windir, "Fonts", "arial.ttf"),
32
- ]
24
+ candidates = [os.path.join(windir, "Fonts", "msyh.ttc"), os.path.join(windir, "Fonts", "simhei.ttf"), os.path.join(windir, "Fonts", "arial.ttf")]
33
25
  else:
34
- candidates = [
35
- "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
36
- "/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc",
37
- "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
38
- ]
26
+ candidates = ["/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc", "/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc", "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"]
39
27
  for fp in candidates:
40
28
  if os.path.exists(fp):
41
29
  try:
@@ -44,6 +32,12 @@ def load_font(size):
44
32
  continue
45
33
  return ImageFont.load_default()
46
34
 
35
+ def pixelate(img, pixel_size=8):
36
+ """把图片像素化 — 缩小再放大,产生像素颗粒感"""
37
+ w, h = img.size
38
+ small = img.resize((w // pixel_size, h // pixel_size), Image.NEAREST)
39
+ return small.resize((w, h), Image.NEAREST)
40
+
47
41
  def main():
48
42
  character = sys.argv[1] if len(sys.argv) > 1 else 'bagayalu'
49
43
  scene = sys.argv[2] if len(sys.argv) > 2 else 'normal'
@@ -62,45 +56,60 @@ def main():
62
56
 
63
57
  scene_zh = SCENE_ZH.get(scene, '一个瞬间')
64
58
 
65
- # 加载角色图片
59
+ # 加载并像素化角色图片
66
60
  sprite = Image.open(img_path).convert("RGBA")
67
61
 
62
+ # 统一缩放到 400px 宽
63
+ target_w = 400
64
+ ratio = target_w / sprite.width
65
+ target_h = int(sprite.height * ratio)
66
+ sprite = sprite.resize((target_w, target_h), Image.LANCZOS)
67
+
68
+ # 像素化处理 — 强烈像素风,类似拼豆/像素游戏
69
+ sprite = pixelate(sprite, pixel_size=14)
70
+
68
71
  # 拍立得尺寸
69
- padding = 40
70
- bottom_area = 120
72
+ padding = 50
73
+ bottom_area = 140
71
74
  photo_w = sprite.width + padding * 2
72
75
  photo_h = sprite.height + padding + bottom_area
73
76
 
74
- # 白色拍立得底板
75
- card = Image.new("RGBA", (photo_w, photo_h), (255, 255, 255, 255))
77
+ # 奶白色拍立得底板
78
+ card = Image.new("RGBA", (photo_w, photo_h), (252, 250, 245, 255))
76
79
 
77
- # 贴角色图片
80
+ # 贴像素化的角色图片
78
81
  card.paste(sprite, (padding, padding), sprite)
79
82
 
80
- # 画边框阴影
81
83
  draw = ImageDraw.Draw(card)
82
- draw.rectangle([0, 0, photo_w - 1, photo_h - 1], outline=(200, 200, 200), width=2)
84
+
85
+ # 图片区域细边框
86
+ draw.rectangle(
87
+ [padding - 2, padding - 2, padding + sprite.width + 1, padding + sprite.height + 1],
88
+ outline=(220, 218, 210), width=1
89
+ )
90
+
91
+ # 外边框阴影
92
+ draw.rectangle([0, 0, photo_w - 1, photo_h - 1], outline=(210, 208, 200), width=2)
83
93
 
84
94
  # 底部文字
85
- font_caption = load_font(18)
86
- font_studio = load_font(14)
95
+ font_caption = load_font(20)
96
+ font_studio = load_font(15)
87
97
 
88
98
  caption = f"📸 刚才抓拍到了{name}{scene_zh}..."
89
99
  studio = "🐋 Ai小蓝鲸照相馆"
90
100
 
91
- caption_y = sprite.height + padding + 15
92
- studio_y = caption_y + 35
101
+ caption_y = sprite.height + padding + 20
102
+ studio_y = caption_y + 45
93
103
 
94
104
  draw.text((padding, caption_y), caption, fill=(80, 80, 80), font=font_caption)
95
- draw.text((padding, studio_y), studio, fill=(140, 140, 140), font=font_studio)
105
+ draw.text((padding, studio_y), studio, fill=(160, 158, 150), font=font_studio)
96
106
 
97
107
  # 保存
98
108
  os.makedirs(os.path.dirname(OUTPUT), exist_ok=True)
99
- card_rgb = Image.new("RGB", card.size, (255, 255, 255))
109
+ card_rgb = Image.new("RGB", card.size, (252, 250, 245))
100
110
  card_rgb.paste(card, mask=card.split()[3])
101
111
  card_rgb.save(OUTPUT, "PNG", quality=95)
102
112
 
103
- # 不在这里打开,让 Node.js 调用方负责打开
104
113
  print(OUTPUT)
105
114
 
106
115
  if __name__ == '__main__':