将 Himawari 8 气象卫星的地球照片作为壁纸

iOS 16 中引入了全新的天文墙纸,可以将地球照片设置为桌面背景,并且能够根据地理位置和时间进行实时地渲染。那么有办法在 macOS 上用上类似的壁纸么?答案是肯定的,我们可以使用 Himawari 8 气象卫星的地球照片作为壁纸。

在网上搜索相关的关键词,我们可以找到很多 Windows 上的实现。而在 macOS 上,更换壁纸的方式有所不同。比较简单的方式是创建一个 Swift 脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env swift

import Cocoa

do {
// get the main (currently active) screen
if let screen = NSScreen.main {
// get path to wallpaper file from first command line argument
let url = URL(fileURLWithPath: CommandLine.arguments[1])
// set the desktop wallpaper
try NSWorkspace.shared.setDesktopImageURL(url, for: screen, options: [:])
}
} catch {
print(error)
}

将其保存为 chwall.swift,然后将其设置为可执行文件:

1
chmod +x chwall.swift

然后,我们使用一个 Python 脚本来下载 Himawari 8 的地球照片,并调用 chwall.swift 将图片设置为壁纸:

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
from PIL import Image
import os
import datetime
import requests
import subprocess
from itertools import product
import traceback
import tempfile

IMAGE_SIZE = 688
IMAGE_ROW = 2
IMAGE_COLUMN = 2

images_dir = os.path.join(os.path.dirname(__file__), 'images')
if not os.path.exists(images_dir):
os.makedirs(images_dir)

def compose_img():
# 获取最新图片的时间,感谢 @Zhmou 的建议
latest_times = requests.get('https://rammb-slider.cira.colostate.edu/data/json/himawari/full_disk/geocolor/latest_times.json')
time = str(latest_times.json()['timestamps_int'][0])
dirpath = f'{time[:4]}/{time[4:6]}/{time[6:8]}'
# 下载的是四张小图,合成一张大图做壁纸
full_image = Image.new(
'RGB', (IMAGE_SIZE * IMAGE_COLUMN, IMAGE_SIZE * IMAGE_ROW))

for i, j in product([0, 1], [0, 1]):
imgname = f'00{i}_00{j}.png'
# 图片地址样式:https://rammb-slider.cira.colostate.edu/data/imagery/2022/10/12/himawari---full_disk/geocolor/20221012123000/00/000_000.png
url = 'https://rammb-slider.cira.colostate.edu/data/imagery/' + \
dirpath + '/himawari---full_disk/geocolor/' + time + '/01/' + imgname
print(f'图片 {url} 正在下载…')
# 设置 `stream=True` 后可以直接用 PIL 打开
response = requests.get(url, stream=True)
image_path = os.path.join(images_dir, imgname)
img = Image.open(response.raw)
width, height = img.size
# 检查图片大小是否正确
assert width == height == IMAGE_SIZE
img.save(image_path)
print(f'图片 {imgname} 下载成功!')
# 合成壁纸图片
full_image.paste(img, (j * IMAGE_SIZE, i * IMAGE_SIZE))
full_image.save(os.path.join(images_dir, 'full.png'))
# 计算生成的壁纸尺寸
height = int(IMAGE_SIZE * IMAGE_ROW / 0.618)
width = int(height / 9 * 16)
image = Image.new('RGB', (width, height))
image.paste(
full_image, (int(width / 2 - IMAGE_SIZE * IMAGE_ROW / 2), int(height * 0.382 / 2)))
# 创建一个临时文件存储壁纸
image_path = tempfile.NamedTemporaryFile(suffix='.png').name
image.save(image_path)
print(f'图片 {image_path} 保存成功!')
return image_path

try:
# 设置桌面壁纸
subprocess.run(['./chwall.swift', compose_img()])
print('壁纸设置成功!')
except Exception as e:
print('壁纸设置失败!')
traceback.print_exc()

最后,使用 Launchd 来定时运行这个脚本,即可实现自动更换壁纸。

需要注意,macOS 会缓存使用过的壁纸,相关的目录包括

  • ~/Library/Application Support/Dock/desktoppicture.db
  • /private/var/folders/**/**/com.apple.desktoppicture

这些缓存不会自动清除,经常更换壁纸的话缓存占用的空间会增加。


参考文章:
How can I programmatically change the background in Mac OS X?
OS X: com.apple.desktoppicture folder grows when changing the wallpaper

有关 GitHub 仓库:
SpaceEye