2026-09-21 22:28:37
iPhone 自带的「快捷指令」其实就能实现九宫格切图,不需要额外安装 App。本文记录如何从零创建一个“图片九宫格”快捷指令,让它支持从相册或共享菜单接收图片,并按照原图尺寸直接分割为 3×3 九张图片,同时介绍 .shortcut 文件、iCloud 分享链接,以及对应的 Python 实现和完整命令流程。最近折腾了一下 iPhone 自带的「快捷指令(Shortcuts)」,做了一个挺实用的小工具:把一张照片自动切成 3×3 的九张小图,也就是我们平时所说的九宫格切图。 以前碰到这种需求,第一反应一般都是去 App Store 找个九宫格 App,或者找一个在线网站,把照片上传以后再切割。其实完全没有必要,iPhone 自带的「快捷指令」就能完成。 而且做好一次以后,以后的操作基本就是: 选择一张照片 → 运行快捷指令 → 自动得到九张图片。 不用安装第三方 App,也不用把照片上传到什么网站。
iPhone/iOS九宫格快捷方式/代码[/caption]
.shortcut
的文件。
所以除了上面的 iCloud Link,我也可以把导出的:
图片九宫格.shortcut
放到自己的服务器上供人下载。
不过如果是公开放在博客上,我个人更推荐使用 Apple 的 iCloud Shortcut Link。
一方面安装流程更自然,点击以后直接进入 Apple 的 Shortcuts 页面;另一方面 Apple 会处理快捷指令的签名和验证。
AEA1
它实际上是一个由 Apple 签名的 Archive。
简化之后,大概可以理解成:
.shortcut
│
└── AEA1 Signed Archive
│
└── Apple Archive
│
└── Shortcut.wflow
│
└── Binary Property List
│
├── Workflow 信息
├── Shortcut 图标
├── 输入输出类型
└── WFWorkflowActions
└── 真正的一条条快捷指令命令
我这次导出来的文件大概只有 26 KB,但是里面已经包含了一条完整的 Workflow,以及 Apple 的 Signing Certificate Chain。
这也是为什么不建议直接拿 Hex Editor 或者文本编辑器去修改 .shortcut 文件。
哪怕里面真正的 Workflow 数据可以被解析出来,直接修改导出的签名文件也会破坏签名。
┌─────────────────┐
│ │
│ │
│ 原始照片 │
│ │
│ │
└─────────────────┘
直接按照原图的宽和高分别三等分,切成:
┌─────┬─────┬─────┐
│ 1 │ 2 │ 3 │
├─────┼─────┼─────┤
│ 4 │ 5 │ 6 │
├─────┼─────┼─────┤
│ 7 │ 8 │ 9 │
└─────┴─────┴─────┘
这里有一个容易误解的地方:
3×3 九宫格并不代表每一张小图都必须是正方形。
它只是把原始图片平均分成 3 行、3 列。
例如原图是:
4032 × 3024
那么每一块大约就是:
1344 × 1008
原图的宽高比不会被改变,也不需要事先从中间裁成正方形,因此不会丢掉原图左右或者上下的内容。
最后把这九张照片全部保存到相册。
快捷指令
→ 所有快捷指令
→ 右上角 +
创建一个新的快捷指令。
我给它取名:
图片九宫格
名字当然可以随便取。
打开快捷指令
→ 点击“图片九宫格”
→ 选择照片
第二种更方便:
照片
→ 选择一张图片
→ 分享
→ 图片九宫格
因此首先把 Shortcut 设置成可以从:
共享表单 / Share Sheet
接收:
图像 / Images
然后判断到底有没有传进来照片。
快捷指令前面的逻辑就是:
从共享表单接收 图像
如果“快捷指令输入”有任何值
将变量 img 设置为“快捷指令输入”
否则
选择照片
将变量 img 设置为“照片”
结束如果
这其实就是我们写程序时最普通的:
if shortcut_input:
img = shortcut_input
else:
img = select_photo()
这样后面的 Workflow 就不用关心图片到底是从哪里来的。
统一处理:
img
就行了。
Width
Height
例如一张 iPhone 照片可能是:
4032 × 3024
这里不需要把图片裁成正方形。
九宫格只是把原图横向分成三列、纵向分成三行,所以应该分别计算:
tileWidth = Width / 3
tileHeight = Height / 3
例如:
Width = 4032
Height = 3024
tileWidth = 4032 / 3
= 1344
tileHeight = 3024 / 3
= 1008
所以每张小图片的尺寸就是:
1344 × 1008
这样能够完整保留原图。
而且因为 Width 和 Height 都同时缩小为原来的三分之一,每张小图片和原图的宽高比完全相同。
(0, 0)
X 向右增加,Y 向下增加。
现在我们有两个尺寸变量:
tileWidth
tileHeight
所以九张图片的位置是:
| 图片 | X | Y |
|---|---|---|
| 1 | 0 | 0 |
| 2 | tileWidth | 0 |
| 3 | 2 × tileWidth | 0 |
| 4 | 0 | tileHeight |
| 5 | tileWidth | tileHeight |
| 6 | 2 × tileWidth | tileHeight |
| 7 | 0 | 2 × tileHeight |
| 8 | tileWidth | 2 × tileHeight |
| 9 | 2 × tileWidth | 2 × tileHeight |
Position = Custom
Width 设置成:
tileWidth
Height 设置成:
tileHeight
X 和 Y 使用上面计算出来的坐标。
for row in range(3):
for col in range(3):
x = col * tileWidth
y = row * tileHeight
crop(
x=x,
y=y,
width=tileWidth,
height=tileHeight
)
Shortcut 里面也可以使用:
重复 / Repeat
来实现。
外层:
重复 3 次
代表 Row。
先计算:
row = Repeat Index - 1
然后里面再:
重复 3 次
代表 Column。
计算:
column = Repeat Index - 1
X = column × tileWidth
Y = row × tileHeight
然后:
裁剪 img
Position = Custom
X = X
Y = Y
Width = tileWidth
Height = tileHeight
每次得到的结果加入变量:
gridImages
两个循环完成以后:
gridImages
里面正好就是九张照片。
gridImages
Shortcut 就完成了。
1. 从共享表单接收“图像”
2. 如果 Shortcut Input 有任何值
设置变量 img = Shortcut Input
否则
选择照片
设置变量 img = 照片
结束如果
3. 获取 img 的 Width
→ width
4. 获取 img 的 Height
→ height
5. 计算
tileWidth = width / 3
6. 计算
tileHeight = height / 3
7. 重复 3 次
row = Repeat Index - 1
重复 3 次
column = Repeat Index - 1
X = column × tileWidth
Y = row × tileHeight
裁剪 img
Position = Custom
X Coordinate = X
Y Coordinate = Y
Width = tileWidth
Height = tileHeight
将裁剪结果加入 gridImages
结束重复
结束重复
8. 将 gridImages 保存到照片相簿
如果从软件工程角度看,这其实已经是一个非常标准的小程序了。
有:
pip install pillow
然后可以写成:
from pathlib import Path
from PIL import Image, ImageOps
def make_nine_grid(input_file: str, output_dir: str = "nine_grid"):
input_path = Path(input_file)
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
# 打开图片
image = Image.open(input_path)
# 根据 EXIF 信息纠正手机照片的方向
image = ImageOps.exif_transpose(image)
width, height = image.size
# -------------------------
# 第一步:计算 3 × 3 的边界
# -------------------------
#
# 宽和高分别三等分。
#
# 不需要先把原图裁成正方形,
# 因此不会丢失原始图片的内容。
#
# 使用边界而不是简单的 width // 3
# 和 height // 3,可以处理尺寸不能被
# 3 整除的情况。
#
x = [
0,
width // 3,
width * 2 // 3,
width,
]
y = [
0,
height // 3,
height * 2 // 3,
height,
]
# -------------------------
# 第二步:裁成九张图片
# -------------------------
index = 1
for row in range(3):
for col in range(3):
box = (
x[col],
y[row],
x[col + 1],
y[row + 1],
)
tile = image.crop(box)
filename = output_path / f"grid_{index:02}.png"
tile.save(filename)
print(
f"{index}: "
f"row={row}, "
f"col={col}, "
f"box={box}, "
f"size={tile.size}"
)
index += 1
if __name__ == "__main__":
make_nine_grid(
"photo.jpg",
"nine_grid",
)
运行:
python nine_grid.py
最后目录里面就会得到:
nine_grid/
├── grid_01.png
├── grid_02.png
├── grid_03.png
├── grid_04.png
├── grid_05.png
├── grid_06.png
├── grid_07.png
├── grid_08.png
└── grid_09.png
4032 × 3024
那么:
4032 / 3 = 1344
3024 / 3 = 1008
最终九张图片都会是:
1344 × 1008
但是并不是所有图片的尺寸都一定可以被 3 整除。
比如原图是:
4033 × 3025
那么:
4033 / 3 = 1344.333...
3025 / 3 = 1008.333...
图片当然不可能包含:
0.333 Pixel
如果简单写:
tileWidth = width // 3
tileHeight = height // 3
得到:
tileWidth = 1344
tileHeight = 1008
那么三个 tile 加起来只有:
1344 × 3 = 4032
1008 × 3 = 3024
这样原图右边和下面都会各剩下一个 Pixel。
所以 Python 版本没有简单地固定每块尺寸,而是直接计算四条 X 边界:
x0 = 0
x1 = width // 3
x2 = width * 2 // 3
x3 = width
以及四条 Y 边界:
y0 = 0
y1 = height // 3
y2 = height * 2 // 3
y3 = height
对于:
width = 4033
X 坐标就是:
0
1344
2688
4033
三个横向区间分别是:
0 → 1344
1344 → 2688
2688 → 4033
最后一块可能会比前面的多一个 Pixel,但整个原图的所有 Pixel 都会被保留下来。
Height 也是同样的处理方式。
这种做法的关键不是要求九张图片绝对一模一样大,而是:
保证整张原始图片被完整、连续、无重叠地切成 3×3 九个区域。
3 Columns × 3 Rows
如果原图是:
4032 × 3024
它的宽高比是:
4 : 3
切成 3×3 以后,每一块大约是:
1344 × 1008
宽高比仍然是:
4 : 3
这其实正是我们想要的。
因为横向和纵向都缩小了三倍,所以每一块和原图拥有相同的 Aspect Ratio。
如果为了所谓的“九宫格”先从中间把:
4032 × 3024
裁成:
3024 × 3024
那么左右两边一共会直接丢掉:
4032 - 3024
= 1008 Pixels
对于照片来说,这可能会把原本位于画面边缘的人物或者景物直接裁掉。
所以正确的做法就是:
保持原始照片尺寸,Width 和 Height 分别三等分。
快捷指令
→ 图片九宫格
→ 选择照片
然后九张照片就会保存到相册。
我自己更喜欢从 Photos 直接运行:
照片
→ 打开一张图片
→ 分享
→ 图片九宫格
这时候照片会直接作为:
Shortcut Input
传进去。
因此连再次选择照片都不需要。
3 × 3
改成:
2 × 2
就是四宫格。
改成:
4 × 4
就是十六宫格。
甚至可以在程序开始的时候:
询问输入
请输入 N:
然后分别计算:
tileWidth = width / N
tileHeight = height / N
循环也改成:
for row in range(N):
for col in range(N):
如果用 Python 写得更加严谨一点,则依然可以直接计算所有边界:
x[i] = width * i // N
y[i] = height * i // N
其中:
i = 0, 1, 2, ..., N
这样就可以保证无论原始图片尺寸能不能被 N 整除,所有 Pixel 都会被完整使用。
这样它就不再是一个单纯的九宫格 Shortcut,而是一个:
N × N 通用图片切割工具。
Input
Variable
If / Else
Loop
Nested Loop
Arithmetic
Coordinate
Image Processing
Output
甚至还涉及到一个很典型的二维坐标问题。
核心算法实际上就是:
for row in range(3):
for col in range(3):
left = width * col // 3
right = width * (col + 1) // 3
top = height * row // 3
bottom = height * (row + 1) // 3
crop(
left,
top,
right,
bottom,
)
用 Python 写可能几十行代码就解决了,而 Shortcuts 的好处是:
写完以后直接变成了 iPhone 上随时可以使用的小工具。
以后想切九宫格的时候,只需要:
照片
→ 分享
→ 图片九宫格
几秒钟以后,九张图片就已经在相册里面了。
有些很小的需求,其实根本没必要专门安装一个 App。
iPhone 自己已经提供了一套相当不错的自动化和编程环境。
[show_file file="/var/www/wp-post-common/justyy.com/ios.php"]
[show_posts keyword="iphone"]
对了,我Vibe-code了一个把图片切割成格子的工具:图片切割:将图片精确划分为网格,预览每个分块并下载一个 ZIP 文件。图片始终保留在此设备上。
英文:Split a Photo into a 3×3 Grid with iPhone Shortcuts: Build, Install, Share and Recreate It in Python
2026-09-20 21:00:50
这两年开始参加微软每年九月份举办的 Global Hackathon。今年我也注册并加入了两个 Project。Hackathon 通常只有一周时间,最终交付往往只是一个两分钟左右的 Demo 视频,因此相比成熟产品,Idea 和 Proof of Concept 更重要。对我来说,这更像是一周难得的“合法折腾时间”:可以看看其他团队的想法、学习新技术,也可以暂时跳出日常项目的节奏,快速验证一个平时未必有机会尝试的 Idea。[caption id="attachment_73016" align="alignnone" width="1241"]
注册Hackathon就有电子徽章[/caption]
微软的 Hackathon 是每年九月份举办的一项内部创新活动,最早从 2014 年开始,到现在已经举办十多年了。规模也非常大,参与者往往来自全球不同的团队、不同的产品线,很多平时完全没有机会一起合作的人,会因为一个 Idea 临时组成一个 Team。
以前我一直知道公司有这么一个活动,不过真正开始参与,也就是最近这两年的事情。
今天微软哈克松领的东西挺多的。[/caption]
注册了,并不一定真的要参加。
参加了,也不一定要上传视频。
上传了视频,也不一定会获奖。
并不是说报名以后,这一周就必须完全停止正常工作,然后每天全职 Hack。
参与多少,其实完全取决于自己的时间和兴趣。
我今年也就是参与一下,有需要的时候帮忙做一点东西。
哈克松的本子,都不舍得拿来写。[/caption]
免费午餐 ,5.1英镑, 那天我才了解到,可以花1.5倍的价格获得大概双份的量。公司的饮料/水果是免费的,这个午餐券还包括一个甜点。[/caption]
[caption id="attachment_73009" align="alignnone" width="2048"]
免费的午餐 最香了。[/caption]
这两年,我才开始比较认真地参加微软每年一度的 Global Hackathon。
去年获得了一个奖:拿到了一个纪念杯子:这周第一次参加微软的Hackathon/黑客马拉松
[show_file file="/var/www/wp-post-common/justyy.com/microsoft.php"]
[show_posts keyword="Hackathon"]
英文:Microsoft Global Hackathon 2026: One Week to Turn an Idea into Something Real
2026-09-19 19:31:33
[bctt tweet="知道DOS甚至CP/M的都暴露年龄了。"]
回顾 CP/M——一个诞生于微软 DOS 之前、并深刻影响早期个人电脑发展的经典操作系统。从 DIR、TYPE、FORMAT 等熟悉命令中,可以看到 DOS 时代乃至后来 PC 操作系统发展的许多早期痕迹。 CP/M:微软 DOS 之前的操作系统先驱 CP/M: The Operating System Pioneer Before Microsoft DOS 在 DOS 之前:回顾 CP/M 操作系统 Before DOS: A Look Back at the CP/M Operating System CP/M:那个比 MS-DOS 更早的操作系统 CP/M: The Operating System That Came Before MS-DOS 从 CP/M 到 DOS:个人电脑操作系统的早期历史 From CP/M to DOS: The Early History of Personal Computer Operating Systems 看到 CP/M,仿佛看到了 DOS 的祖先 Looking at CP/M Feels Like Seeing an Ancestor of DOS这是 CP/M,一个比微软 DOS 还要早很多年的操作系统。 从今天的角度来看,它的命令行界面其实已经让人觉得非常熟悉了。像 DIR、COPY、TYPE、FORMAT 这样的命令,后来都成为 DOS 时代非常常见的命令。 CP/M 由 Gary Kildall(加里·基尔代尔) 在 20 世纪 70 年代开发,最初的全称是 Control Program/Monitor,后来 Digital Research 也使用过 Control Program for Microcomputers 这个解释。它曾经是早期 8 位微型计算机时代最重要、最流行的操作系统之一。 在 IBM PC 出现之前,CP/M 已经拥有相当成熟的软件生态。1981 年 IBM 推出 IBM PC 后,微软提供了 MS-DOS。MS-DOS 的早期设计、命令风格以及整体使用方式,都明显受到了 CP/M 时代的影响。 所以今天再看到 CP/M 的界面,会有一种很有意思的感觉:它看起来很像一个“DOS 之前的 DOS”。如果把个人电脑操作系统的发展画成一棵家谱,那么 CP/M 无疑是其中非常重要的一位祖先,而 DOS、Windows 以及后来整个 PC 软件生态的发展,都可以从那个时代找到不少影子。 [caption id="attachment_72994" align="alignnone" width="816"]
CP/M操作系统[/caption]
[show_posts keyword="操作系统"]
[show_file file="/var/www/wp-post-common/justyy.com/nostalgic.php"]
英文:CP/M - The Operating System That Came Before MS-DOS | Are you this old? Apple CP/M - 1980 Microsoft | Are you this old? Apple CP/M - 1980 Microsoft
2026-09-19 17:54:08
人在海外多年,每到中秋总会多几分“每逢佳节倍思亲”的感触。今年因为朋友做的冰皮月饼,媳妇也被勾起了兴趣,买食材、刷教程、用小美做紫薯馅和咸蛋黄月饼,还把做好的月饼送给朋友。看着她在厨房里忙活,也让我想起了刚来剑桥以及疫情期间那些在家做糕点的日子。月饼或许只是节日的一种形式,但一家人在一起,为生活花点时间折腾,这些平凡的瞬间,本身就是一种团圆。每到中秋节,总会多几分“每逢佳节倍思亲”的感觉。尤其是在海外生活多年以后,很多中国传统节日反而不像小时候那样,早早就在日历上等着了。 其实每年中秋节快到的时候,我似乎总是最后一个意识到的人。 通常都是某一天去中超买东西,突然看到货架上摆满了各种月饼,才反应过来:哦,中秋节快到了。又或者朋友圈里有人开始晒自己做的月饼,我才意识到又到这个季节了。 至于中秋节具体是哪一天,我往往是不知道的。只知道大概是在秋天,天气开始转凉的时候。 上周,我和媳妇一起去朋友家参加团契。朋友自己做了冰皮月饼,大家一起吃了几个。没想到媳妇回来以后就被“种草”了,觉得自己也应该试试看。 于是接下来的几天,家里就进入了“月饼实验室”模式。 先是在网上各种买食材,然后刷小红书看教程,再把家里的小美 cooker 搬出来研究配方。先折腾紫薯馅,后来又开始做咸蛋黄馅,一做还不是几个,而是一批一批地做。 做多了以后,自己当然也吃不完,于是又装成一盒一盒,送给几个朋友尝尝。 我估计媳妇做月饼的动力大概有两个:一是自己嘴馋,二是纯粹想折腾一下。 我还问她:“为什么不直接买呢?省时省力,想吃什么口味都有。” 她的回答也很直接:“外面卖的哪有自己做的健康。” 这倒也是。自己做,至少糖放多少、油放多少、里面是什么材料,心里都有数。至于到底比外面卖的健康多少,那就另说了。毕竟为了做这一批月饼,这几天厨房也没少折腾。 看着她忙着做月饼,我倒是突然想起了很多年前。 媳妇刚来剑桥的时候还没有工作,时间比较多,经常在家里给我做各种糕点、蛋糕和饼干。那时候隔三差五就能看到她研究一个新配方,然后厨房里摆满各种烤盘、模具和原材料。 后来工作越来越忙,孩子也越来越大,这种慢慢花几个小时研究一种点心的闲情逸致,反而越来越少了。 仔细想想,上一次她这么有时间在家里折腾吃的,好像还是疫情期间。 那时候大家都被要求尽量待在家里,我在家办公,媳妇当时在 Tesco 超市工作,因为疫情期间的一些安排,有一段时间也不用去上班,收入还有保障。突然多出来的大把时间,让大家的生活节奏一下子慢了下来。 那一阵子,家里也经常做各种吃的。 现在回头看,那段时间虽然有很多不方便,但一家人长时间待在一起,也留下了一些很特别的记忆。 所以这次看到媳妇重新开始研究月饼,我突然觉得,做不做月饼本身其实没有那么重要。 重要的是,生活里又出现了这种愿意花几个小时,为家里人折腾一点东西的心情。 人在海外久了,中秋节也许没有国内那么浓的节日气氛,没有满街的月饼广告,也没有几天前就开始讨论放假和团圆。但有时候,一个朋友做的月饼、一盒自己折腾出来的点心,就能把这种熟悉的节日感觉重新带回来。 而所谓“团圆”,大概也不一定非得是一大家人坐在同一张桌子旁。 一家人在一起,厨房里有人忙着做月饼,孩子偶尔过来偷吃一个,做多了再给朋友送几盒——这种普普通通的日子,本身也已经是一种团圆。 又快到中秋了。 以前觉得月饼只是中秋节的一种食品,现在反而越来越觉得,它更像是一种提醒:提醒你秋天到了,也提醒你,在忙忙碌碌的生活里,偶尔还可以停下来,想想家,想想以前的日子,也珍惜一下现在身边的人。 [caption id="attachment_72974" align="alignnone" width="2048"]
老婆做出来的第一个月饼。[/caption]
[caption id="attachment_72975" align="alignnone" width="1152"]
馅饼的馅/紫薯/用小美cooker做。[/caption]
[caption id="attachment_72976" align="alignnone" width="1152"]
冰皮月饼装盒 放冰箱冷藏。[/caption]
[caption id="attachment_72977" align="alignnone" width="1152"]
大版本的汤圆,然后再用磨具压成月饼形状。[/caption]
[caption id="attachment_72978" align="alignnone" width="1152"]
制作月饼的过程,并不简单,也挺耗时的。[/caption]
[caption id="attachment_72979" align="alignnone" width="1152"]
烤出来的月饼是金黄的,很香[/caption]
[caption id="attachment_72980" align="alignnone" width="1537"]
媳妇做月饼 做了好几盒[/caption]
[caption id="attachment_72981" align="alignnone" width="1537"]
媳妇批量做月饼,这个是咸蛋黄馅的,要放烤箱里烤。[/caption]
[caption id="attachment_72982" align="alignnone" width="1024"]
老婆做月饼[/caption]
[caption id="attachment_73005" align="alignnone" width="1152"]
这么一坨紫薯馅[/caption]
[show_posts keyword="糕点"]
2026-09-17 23:04:12
去剑桥Perse私校接娃时,偶遇一辆挂着“ACE IT”车牌的奥迪。这块车牌很可能是“ACE 1T”,读起来有“漂亮地搞定”的意思。参考类似号码的挂牌价,它或许价值几万英镑。一次普通的接娃经历,让我见识了英国个性车牌的身价,也找到了一句给娃加油的英语。[caption id="attachment_72954" align="alignnone" width="2048"]
ACE IT豪车车牌[/caption]
昨天去剑桥的Perse私校接娃放学。娃第一次参加学校课后的Duke of Edinburgh’s Award活动,也就是爱丁堡公爵奖项目,通常简称DofE。
在校园里等娃的时候,我看到一辆奥迪,车尾的车牌一下子吸引了我的注意:ACE IT。
从照片看,应该是奥迪 SQ8,属于Q8车系的高性能大型SUV。
判断依据是它的溜背造型、贯穿式尾灯、车尾左侧的S系列标识,以及双边四出圆形排气口。
这辆车本身也不便宜:目前英国官网的SQ8新车起价约 £104,310(10.4万英镑)。不过,照片里这辆的具体年款和配置,仅凭外观还不能确定。这样的豪车配个豪车车牌自然很正常。
平时在Perse接送孩子,经常能看到各种豪车。看得多了,有时候也会忍不住开个玩笑:这里的学生家长,除了我,是不是都挺有钱的?
不过,这次让我多看了几眼的,是那块很有意思的车牌。短短几个字符,居然刚好能读成一句英文。
ACE1X也得2万5000英镑[/caption]
光一个登记号码,开价就接近两万五千英镑。