把一份 PDF 转成长图发出去,对方回一句"字看不清,能重发吗",这事我今年至少遇到过五次。奇怪的地方在于:原 PDF 在电脑上放大到 400% 依然锐利,可一旦变成图片,字就开始发虚、发毛、边缘起毛刺,有的甚至在手机上一缩小,整段文字直接糊成一团灰。很多人第一反应是"工具不行",换个网站、换个软件再试,结果还是老样子。问题基本不在工具的好坏上,而在于 PDF 转长图这个动作里藏着两层你可能没注意到的降质环节,大多数工具默认只做了第一层,第二层则交给了你根本没权限控制的平台。这篇文章我把 2026 年重新实测的三条路线完整拆开:它们各自在哪一步把字弄糊了、参数该怎么算、以及那套能稳定出清字的本地方案到底怎么落地。做过文档处理、做过内容分发、或者只是偶尔要把合同和课件转成一张长图发群里的人,都可以照着抄。
1. 先搞清楚"糊"发生在哪一步,不然换十个工具也没用
1.1 PDF 里的字有两种血统,决定了你的清晰度天花板
同样是 PDF,内部结构可能天差地别。一种是文字型:页面里存的是字符编码加字体引用,渲染时由引擎按当前分辨率实时"画"出字形,本质是矢量的,你给它 600dpi 它就能画出 600dpi 的锐利边缘。另一种是扫描型:整页就是一张位图,可能是当年用扫描仪以 200dpi 扫进去的,也可能是手机拍照后套进 PDF 的,页面里的"文字"其实只是像素点,没有任何字符信息。
这两种血统的处理逻辑完全相反。文字型 PDF 你该做的是"尽量用高分辨率重新渲染";扫描型 PDF 你该做的是"别超过它原始像素,超了也是插值糊出来的假清晰"。判断方法非常简单:打开 PDF,用鼠标去框选一段正文,能选中、能复制,基本就是文字型;怎么拖都选不中,或者选中后复制出来是一堆乱码和空白,多半是扫描型或图片型。还有一个更硬的判据——把页面放大到 800%,文字边缘依然干净利落的是矢量,出现明显马赛克方块的就是位图。
我在实际处理中遇到的最坑情况是"混合型":正文是文字,但页眉页脚的 Logo、表格里的印章、公式截图是位图。这种文档你按 300dpi 渲染,正文会清晰到过分,而那些位图元素该糊还是糊,因为它们的原始像素就那么多。这时候不要怀疑参数设错了,去查一下页面里嵌入图像的实际尺寸,你会发现它本来就只有 300×120 像素,铺在 5 厘米宽的区域内,等效下来还不到 150dpi。
1.2 栅格化那一步,才是真正的分水岭
PDF 转长图的本质叫栅格化(rasterize):把页面描述翻译成一张像素网格。这一步的核心参数只有一个——缩放倍率,它通常以 DPI(每英寸点数)来表达。换算关系不难,PDF 的内部坐标单位是"点"(pt),1 点等于 1/72 英寸,所以:
缩放倍率 = 目标 DPI / 72 输出像素宽 = 页面宽度(pt) × 目标 DPI / 72反过来,如果我们已知纸张的物理宽度,用毫米算更直观:
输出像素宽 = 纸张宽(mm) / 25.4 × 目标 DPI 目标 DPI = 输出像素宽 × 25.4 / 纸张宽(mm)拿最常见的 A4 举例,宽 210mm。如果工具以 96dpi 输出,宽度是 210/25.4×96 ≈ 794 像素;如果以 150dpi 输出,是 1240 像素;300dpi 则是 2480 像素。这三个数字看起来只是"宽一点窄一点",但对文字的影响是断崖式的。
关键在于字号。一个 10.5pt 的正文,在 96dpi 下字身高度只有 10.5/72×96 = 14 像素,去掉字身内部的留白,实际笔画高度可能只有 9 到 10 像素,横画的粗细不到 1 像素。这种尺寸下,任何抗锯齿都会把黑色笔画摊成灰色,笔画密集的字(比如"囊""疆"这类)直接糊成一坨。而在 300dpi 下,同样的字号有 43 像素高,笔画粗细 4 像素左右,边缘干净得能数清。
所以那句"PDF 转长图字糊了",九成以上的真实原因是:你的工具在用 96dpi 或 72dpi 渲染。屏幕截图的默认就是 96dpi 逻辑像素,浏览器打印成图片很多时候也是按 96dpi 走,在线转换站为了控制服务器开销和输出体积,默认值往往就在 96 到 150 之间。它们不是不能出清晰的图,是默认没给你清晰。
1.3 被绝大多数人忽略的第二刀:你的长图在手机上被缩小了
这是我觉得最值得单独拿出来说的一点,因为它解释了为什么有些人把 DPI 调到 300 了,发出去还是被说糊。
长图在手机上的显示规则是"按屏幕宽度等比铺满"。一台逻辑宽度 1080 像素的手机,无论你给它的图是 794 像素宽还是 2480 像素宽,它都会先缩放到 1080 像素宽再显示。这意味着:
- 你的图宽 794px,会被放大 1.36 倍显示,插值放大,本来就不锐利的边缘进一步发虚;
- 你的图宽 2480px,会被缩小到 1080px 显示,缩小过程用双线性或双三次重采样,锐利的黑字边缘会重新变柔,但整体观感仍然远好于前者;
- 只有当你的图宽接近甚至略大于 1080px 时,缩放比接近 1,显示效果最接近"所见即所得"。
换句话说,长图有一个"有效分辨率"的概念,它等于图片宽度和显示宽度之间的比例关系。你把 A4 页面渲染成 1080 像素宽,等效 DPI 大约是 130;渲染成 1440 像素宽,等效 174;渲染成 2480 像素宽,等效 300,但在 1080 宽的屏幕上被压回 130 左右的实际观感——只是压缩算法比放大算法温和得多,边缘不会糊成灰雾。
结论是:给移动端看的长图,宽度做到 1440 到 1620 像素是性价比最高的区间,等效 DPI 落在 175 到 195 之间,正文小字在手机上清晰锐利,文件体积也可控。一味追求 300dpi 只会让 PNG 体积翻三倍,最后还是要被平台的压缩算法砍一刀。当然,如果这张长图是要打印的、或者要在电脑上放大看细节的,那就老老实实 300dpi,规则不同。
2. 三条路线逐个实测:它们分别在哪儿把字弄丢了
2.1 方法一:截屏拼接,最快的路也是最糊的路
这条路几乎人人都会用:打开 PDF 阅读器,调好窗口大小,一屏一屏截下来,再用拼图工具接上。手机上同理,很多系统自带"滚动截屏",一划到底自动拼。
它的致命问题不在拼接,而在截屏那一刻的像素密度就已经被锁死了。屏幕上 1 个 CSS 像素对应 PDF 的 1/96 英寸,你在阅读器里以"适合宽度"显示 A4 页面时,页面在屏幕上大概占 700 到 900 像素宽,正好就是 96dpi 左右的渲染结果。这时候你截图,拿到的就是一份 96dpi 的位图,后面无论怎么拼、怎么存无损 PNG,都改变不了这个事实——信息在第一步就丢了。
更麻烦的是几个附带问题。第一,截屏会带上阅读器的界面元素:工具栏、滚动条、页面阴影、页码标签,拼完之后这些横向色块横在长图中间,非常难看,后期还得逐条裁掉。第二,屏幕缩放比例会影响结果:把系统显示缩放设成 150%,截出来的字确实会清晰一些,但如果阅读器窗口宽度没跟着变,页面反而被挤小了,得不偿失。第三,多页拼接时的对齐全靠手,稍有偏差就会出现错位、重叠、或者中间夹一条白缝。
我自己试过的最优截屏方案是:先把阅读器缩放调到 150% 以上,窗口拉到最大,让页面宽度在屏幕上超过 1400 像素,再截图并用工具做重叠区域的自动对齐。这样能摸到 144dpi 左右的水平,勉强能用,但一份 20 页的文档要截 40 多张图,手工时间接近二十分钟,完全不划算。手机端的滚动截屏稍微省事,但手机屏幕逻辑宽度普遍是 1080 或 1170,等效 DPI 也就 130 上下,且系统会自动做压缩,长图超过一万像素高还会主动降采样。
2.2 方法二:在线转换站,省事但你把参数控制权全交出去了
上传 PDF、选"转为长图"、等几秒、下载。这条路体验最好,坑也最隐蔽。
第一个坑是服务端渲染分辨率不透明。绝大多数站点不给你选 DPI,就算给,选项也就是"普通/高清"这种模糊档位。实测下来,普通档基本是 96dpi,高清档多数在 150dpi 到 180dpi 之间,能做到 300dpi 的很少。原因很现实:300dpi 的 A4 单页就是 2480×3508 像素,二十页拼起来接近 7000 万像素,服务器的内存和带宽成本要翻好几倍。
第二个坑是压缩链路。服务器渲染完,为了控制返回体积,通常会走一遍 JPEG 编码,质量参数多半在 75 到 85 之间。JPEG 是块离散余弦变换,对文字这种高对比度、锐利边缘的内容极其不友好,8×8 的块边界上会出现"振铃"——黑字周围浮出一圈灰色的鬼影,小字号时这圈鬼影直接把字糊掉。你下载回来看到的"发虚",有时候根本不是分辨率不够,是 JPEG 振铃。
第三个坑是输出尺寸被统一。不少站点会把你上传的任意页面尺寸,统一塞进一个固定宽度的画布里,常见是 800 或 1080 像素宽。如果你的 PDF 是横向的 A4(宽 297mm),被压到 1080 宽之后等效 DPI 只有 92,糊得理直气壮。
还有两个非画质层面的问题值得提一句:文档要上传到第三方服务器,涉及合同、证件、内部资料的时候这条基本可以直接排除;以及大文件经常被拦,超过二三十兆或者超过五十页就提示失败,你花钱开会员也未必解决。
2.3 方法三:本地渲染加无缝拼接,参数全在你手里
这条路的思路很朴素:自己在本地把每一页按你指定的 DPI 渲染成位图,裁掉多余的页边,然后纵向无缝拼成一张。没有中间商,没有任何一次你没同意的重编码。
它解决的不只是清晰度。裁边这件事在另外两条路上几乎做不到——PDF 页面通常有 15 到 25 毫米的白边,页眉页脚还有页码和标题,拼成长图之后这些白边会变成一条条宽宽的空白带,阅读体验很差。本地渲染可以直接按内容边界裁剪,只留 4 到 8 毫米的呼吸空间,拼出来的图紧致得多,同样的文件高度能多塞三成内容。
输出的可控性也是碾压级的:无损 PNG 保证文字边缘绝不被压,唯一的有损环节(如果体积实在太大)由你自己决定在哪一步做、做到什么程度。十页 A4 在 174dpi 下大约是 1440×20000 像素,白底黑字的 PNG 用调色板量化之后通常只有 1.5 到 3MB,这个体积在聊天工具和内容平台里都不会触发重新压缩。
代价是需要一点准备工作:装个运行环境,跑一段脚本,或者至少会用命令行工具。但这段脚本写一次就能一直用,后面批量处理反而是三条路里最快的——一份五十页的文档,从渲染到出图不到十秒。
2.4 三组实测数据放在一张表里
下面是同一份文档(20 页,A4 纵向,文字型 PDF,正文 10.5pt,含两页跨页表格)在三条路线下的实测结果。环境是一台普通笔记本加一台主流安卓手机,数据取的是多次运行的中位数,供你判断量级。
| 维度 | 方法一 截屏拼接 | 方法二 在线转换 | 方法三 本地渲染拼接 |
|---|---|---|---|
| 输出宽度 | 794~1170 px | 800~1080 px | 自定,取 1440 px |
| 等效 DPI | 96~141 | 96~130 | 174 |
| 正文实际字高 | 13~19 px | 13~18 px | 24 px |
| JPEG 重编码 | 视中转工具而定 | 有,质量约 75~85 | 无 |
| 页边与工具栏残留 | 有,需手工裁 | 无,但白边很宽 | 按内容裁,留 6mm |
| 纯手工耗时 | 约 18 分钟 | 约 40 秒 | 约 8 秒 |
| 输出体积 | 4~6 MB | 1.5~3 MB | 1.8~2.6 MB |
| 超长文档稳定性 | 易错位、易漏页 | 常被页数或体积限制 | 稳定,可分段 |
| 文档外传 | 否 | 是 | 否 |
| 手机上放大后观感 | 明显发虚 | 轻微振铃、发虚 | 边缘干净 |
表格里最容易引起误判的是体积那一行。"方法三体积更大"并不代表它更差,恰恰相反——它把像素用在了刀刃上,而方法二省下来的那点体积,是用 JPEG 压缩换的,代价就是字的边缘。真要压体积,方法三也有的是办法,后面会讲。
3. 参数怎么算:宽度、DPI 和体积之间的三角平衡
3.1 从"最终在哪看"反推渲染 DPI
我见过太多人卡在这一步:知道要调 DPI,但不知道该调多少,干脆一律 300。这个思路在打印场景是对的,在长图场景是浪费,还可能帮倒忙。
正确的推导顺序是反过来走的。先确定这张长图的最终显示宽度,再反推渲染 DPI。常见场景的目标宽度可以这样定:
- 手机端阅读、发群、发内容平台:1440 px 宽最稳,兼容绝大多数屏幕,缩放比接近 1;
- 需要在电脑上双击打开看细节、或者含小号表格字:1800 px 宽;
- 要打印或者做二次设计素材:2520 px 宽以上,直接按 300dpi 走。
拿到目标宽度之后,代入公式算 DPI。A4 纵向宽 210mm:
目标 1440 px:DPI = 1440 × 25.4 / 210 ≈ 174 目标 1800 px:DPI = 1800 × 25.4 / 210 ≈ 218 目标 2520 px:DPI = 2520 × 25.4 / 210 ≈ 305如果是横向 A4(宽 297mm),同样 1440px 宽对应的 DPI 只有 123,这就解释了为什么横向文档转长图特别容易糊——它的物理宽度更大,同样像素数下密度被摊薄了。横向文档想要同等清晰度,宽度得按比例放大到 2000px 以上,或者干脆考虑横屏阅读而不是长图。
还有一个容易被忽略的细节:PDF 的页面尺寸未必是标准 A4。有些文档是 189mm×265mm 的"美式小开本",有些是从网页打印出来的、宽度乱七八糟的长条。所以稳妥的做法是直接从 PDF 里读出页面的点值(pt),用像素 = pt × DPI / 72来算,别靠纸张规格猜。
3.2 高度的天花板比宽度更凶险
宽度决定清晰度,高度决定"能不能打开"。长图的高度是所有平台的隐形雷区。
一般规律是这样的:高度在两万像素以内,基本所有平台和设备都能正常显示;超过两万,部分平台会在传输时自动降采样,甚至直接截断;超过三万,一些手机上会出现解码失败,图片位置显示一片空白或者只有顶部一小条。我遇到过最离谱的情况是图能下载、能预览缩略图,点开大图直接白屏,换台设备又正常——这就是典型的解码内存爆了。
所以拼接之前先算一下总高度:
单页高度(px) = 页面高度(pt) × DPI / 72 总高度 ≈ 单页高度 × 页数 − (页数−1) × 裁掉的页边像素20 页 A4、174dpi 的情况下,单页高 2034px,总高约四万像素,妥妥超标。解决方案有两个方向:降 DPI 或者切片。降 DPI 会牺牲清晰度,不推荐;切片才是正解——按每 6 到 8 页一张,拆成三到四张长图,每张控制在两万像素以内。切的时候一定要切在页与页的接缝处,千万别从一段正文中间劈开,读者翻到下一张发现上一句话断在半截,体验极差。
3.3 输出格式:PNG 不是唯一答案,但多数时候是
文字类长图的格式选择,优先级很明确。
PNG 是无损压缩,对白底黑字这种大片同色区域压缩效率极高,而且绝对不会在字的边缘制造任何鬼影,是首选。它的唯一缺点是体积,但这个问题在文字图上被严重高估了——一张 1440×20000 的纯文字 PNG,用 24 位真彩存可能要 5MB 以上,但如果内容只有黑白和少量灰阶,转成 8 位调色板(PNG-8,256 色)能直接砍掉六七成,画质肉眼看不出区别。
WebP 无损在同等画质下比 PNG 小 20% 到 30%,现代浏览器和主流 App 支持都不错,但它在某些老旧的聊天软件里会显示成静态首帧或直接不支持,跨平台分发时得掂量一下。WebP 有损压缩质量 85 以上时,文字边缘基本干净,是体积和画质之间不错的折中。
JPEG 是最后的选择,只在一个场景下用:体积被卡死到几百 KB,而你又必须发出去。用的时候质量不要低于 88,并且务必关掉色度子采样(4:4:4),否则黑字边缘会渗出彩色噪点,那是 JPEG 把亮度和色度分开压缩导致的典型问题。
4. 方法三的完整落地:从零到一张干净长图
4.1 环境准备少走弯路
本地渲染这条路,用 Python 生态最省事,核心就两件事:一个能把 PDF 页面渲染成位图的库,一个能处理位图和拼接的库。前者要选那种直接对接底层渲染引擎的,别选那种"先把 PDF 转成图片再给你"的封装层,多一层转换就多一次降质。后者用常见的图像处理库即可,主要用到它的画布创建、区域粘贴和裁剪功能。
环境上要注意三个点。第一,中文字体问题:文字型 PDF 如果内嵌了字体,渲染时用的是文档自带的字形,跟系统字体无关,不用担心;但如果 PDF 引用了未嵌入的字体,渲染器会去系统里找替代字体,找不到就用默认字形兜底,可能出现字宽变化甚至方块。遇到这种情况,系统里备一套完整的中文字体是必要的。第二,色彩空间:如果文档是 CMYK 或者带透明通道,渲染出来可能偏色或发灰,渲染时显式指定输出为 RGB 能规避大部分问题。第三,内存:高 DPI 渲染单页就是几千万像素,二十页一次性在内存里拼,普通机器容易吃满,所以要么分块处理,要么先渲染成临时文件再逐个读入拼接。
4.2 先给 PDF 做个体检,再决定参数
动手之前花三十秒做三件事,能省掉后面半小时的返工。
第一件,确认是不是文字型。用阅读器框选一段正文复制,能复制出正常文字就是。如果复制出来是乱码,试试换一段;如果整页都选不中,直接按图片型处理。
第二件,看页面实际尺寸。别假设是 A4,读一下第一页的宽高点值。顺手也检查一下所有页面尺寸是否一致——不一致的文档在拼接时会出大问题,需要统一画布宽度、每页居中或左对齐。
第三件,找内容边界。文字型 PDF 可以通过分析页面上的文字块位置,算出真正的内容范围,比固定的"裁 20 毫米白边"精确得多。如果没有这个能力,退而求其次:渲染一页出来,用图像的边缘检测找出非白色像素的包围盒,按那个范围裁,再留一点边距。这一步做得好不好,直接决定了长图是"紧凑好读"还是"一条条白带"。
4.3 渲染、裁边、拼接的核心逻辑
整个流程的骨架不复杂,我把关键逻辑用示意代码写出来,具体 API 名字按你手上库的写法替换即可。
# 示意代码:核心是三步——按 DPI 渲染、按内容裁边、纵向无缝拼接 TARGET_WIDTH_PX = 1440 # 1. 读页面尺寸,反推缩放倍率 page_w_pt = page.rect.width # PDF 用户单位,1pt = 1/72 英寸 zoom = TARGET_WIDTH_PX / page_w_pt # 直接得到倍率,比先算 DPI 再除 72 更直接 # 2. 渲染成位图(RGB,避免透明通道带来的灰底) bitmap = page.render(scale=zoom, colorspace="rgb") img = bitmap.to_pil() # 3. 按内容包围盒裁剪,四周留固定边距 box = find_content_bbox(img, threshold=245) # 找非白像素范围 margin = int(TARGET_WIDTH_PX * 0.004) # 约 6px,视觉上刚好不压抑 cropped = img.crop((box.left - margin, box.top - margin, box.right + margin, box.bottom + margin))拼接的时候有两个细节必须处理,否则会出白线。第一,所有页面必须用同一个画布宽度,不能各页各宽,宽度取ceil(TARGET_WIDTH_PX)之后固定下来,每页水平居中或者按裁剪后的实际宽度左对齐。第二,高度累加时用整数,别用浮点累加,浮点误差累积下来会让接缝处出现一行半透明的白线——这是因为粘贴位置的 y 坐标落到了小数上,图像库做了插值。我最初就是栽在这里,二十页拼完有十九条细白缝,排查了很久才定位到是坐标取整的问题。
# 示意代码:统一画布宽度 + 整数坐标累加 canvas_w = int(math.ceil(TARGET_WIDTH_PX)) total_h = sum(p.height for p in cropped_pages) # 全整数 canvas = new_canvas(canvas_w, total_h, "white") y = 0 for p in cropped_pages: offset_x = (canvas_w - p.width) // 2 # 整数除法 canvas.paste(p, (offset_x, y)) # y 是整数 y += p.height # 整数累加,无误差如果文档有明显的大块空白页(比如章节之间的隔页),可以在裁剪阶段直接跳过——判断标准是裁剪后的有效高度小于页面高度的 15%。这个处理很实用,我处理过一份技术手册,中间夹了七张空白页,不去掉的话长图里会出现七条又长又蠢的白色空档。
4.4 压体积和验画质,两个都不能省
出图之后先别急着发,两步检查。
压体积优先用无损手段。第一步做调色板量化:纯文字长图的颜色数通常不超过 16 种(黑、白、各种抗锯齿灰阶),转成 8 位调色板 PNG 后体积往往能腰斩。如果还不够,再考虑有损 WebP,质量从 90 往下试,到 82 左右是画质的拐点,再低就开始出现可见的字边模糊。
验画质的方法很简单但很有效:把长图按目标显示宽度(比如 1080px)缩小,然后在 100% 比例下看。这个视图模拟的就是手机上的实际观感。如果在这个尺寸下字依然清晰可辨,那发出去就是稳的;如果在这个尺寸下已经糊了,说明你的渲染 DPI 还不够,回去加宽。反过来,如果缩小之后清晰、原图放大到 200% 时边缘才开始发毛,那是完全正常的——没有任何一种栅格图像能做到无限放大不糊,只要目标场景下够用就行。
还有一个必做的检查:随机挑三页的接缝处,放大到 400% 看有没有白线、错位、重复行。接缝是这类操作最容易翻车的地方,而且一旦出问题,整张图就废了。
5. 踩过的坑:这些症状各自指向什么
5.1 参数明明拉满了,字还是虚的
这个症状最迷惑人,因为你会反复怀疑参数写错了。排查顺序按下面的来。
先看 PDF 是文字型还是扫描型。如果是扫描件,一切高 DPI 都是自欺欺人。判断依据:渲染出来的图放大到 300% 之后,如果文字的边缘是"方块状"的像素块,而不是平滑的灰度过渡,那就是原始的位图被插值放大了。这种情况唯一有效的解法是回到源头,找一份分辨率更高的原始文件,或者对原图做专门的锐化预处理再渲染。
如果确认是文字型却依然虚,检查渲染器的抗锯齿设置。有些库默认开启了"亚像素级抗锯齿",在低分辨率下会让字显得更柔和(也就是更糊),可以尝试关掉它、改用灰度抗锯齿,边缘会硬朗一些。还有一种可能是渲染时缩放倍率被限制在某个上限,你传了 4.2 它内部按 2 处理,这种情况只能分两步走:先按 2 倍渲染出位图,再对位图做一次高质量放大——但这终究是在补,能一步到位就别分两步。
最后一种隐蔽情况:文档里有"透明叠加层"。某些 PDF 为了做视觉效果,会把文字放在半透明的遮罩下面,渲染器处理透明度时可能引入额外的模糊。表现是整页文字都比周围元素虚一档,肉眼能看出不自然的柔化。
5.2 拼接处的白线和错位,八成是坐标取整的锅
前面提到过,白线的头号原因是粘贴坐标用了浮点数。第二个原因是每页的裁剪宽度不一致:第 1 页裁完是 1438px,第 2 页裁完是 1441px,如果画布宽度按第一页定了,第二页就会被裁掉或者留下空白。解决办法是画布宽度统一取所有页的最大值,或者干脆按目标宽度固定,每页居中。
错位和重复行的成因不太一样。如果你的 PDF 页面尺寸本身不一致(比如前面是 A4 纵向,中间插了一张 A3 横向折叠页),拼接时按各自尺寸渲染,就会出现一行内容被横着塞进去、和上下完全对不齐的情况。处理方式是在渲染前先统一页面宽度,超宽的页面按比例缩放到目标宽度,高度自然变矮,拼进去虽然视觉上有变化,但至少不会错位。
还有一种"假错位":接缝处上下两页的最后一行和第一行看起来重复了。这不是拼接错误,是原文档本身在页面底部和顶部有重复的页眉页脚或者固定表头。解法是在裁剪时把顶部和底部各多裁掉一点,或者按固定比例裁掉上下各 3% 的高度。
5.3 图能下载但打不开,或者只显示一条
这个症状基本可以锁定超尺寸问题。表现是:在缩略图里能看出是完整的,点开大图一片白,或者只显示最顶上一条窄带,往下滑动全是空白。
原因分两层。第一层是图片解码的内存限制,某些设备对单张图片的总像素数有上限,超过就解码失败,程序不会报错,只是默默显示不出来。第二层是平台传输时的自动降采样,长图在服务器端被重新编码,但因为高度太大,编码器分块处理时出错,返回了一张残缺的图。
应对方式就是前面说的切片。切片的粒度我一般按"每张控制在 15000 像素高以内"来切,这个值有足够的安全余量。切的时候记录好页码区间,命名带上序号,方便读者按顺序看。
顺带提醒一个容易被忽略的点:如果你是在某个平台的编辑器里直接粘贴长图,平台可能会在你不知情的情况下重新压缩。同样的文件,一次直接上传、一次通过编辑器插入,最终看到的画质可能不一样。稳妥的做法是先上传到图床或者文件传输,拿到原始链接之后再看实际效果。
6. 几个不太常见但很省事的做法
6.1 跨页表格的处理值得单独花五分钟
文档里最让人头疼的就是跨页长表格。默认处理方式下,表格在页边界被硬生生切断,表头只出现在第一页,拼成长图之后,后面几页的数据全是"无头"的,读者要往上翻很久才知道这一列是什么。
有两个改善思路。如果 PDF 是文字型且有结构信息,可以在拼接时识别出跨页表格,把首页的表头区域裁下来,作为一条细条插到后续每一页的顶部——这相当于手工给长图"重复表头"。这个处理要多写几十行代码,但对数据类文档的阅读体验提升是巨大的。更省事的办法是在源头上解决:如果原始文档是你自己产出的,导出 PDF 之前就设置好"重复标题行",转出来的 PDF 天然带重复表头,长图跟着就整齐了。
6.2 分片长图的一点点仪式感
既然超长文档必须切片,那就在切片上做点文章,让读者知道"这不是全部"。我的做法是在每张长图的最底部加一条浅浅的分隔,写上一句"第 1/3 张,接下页",字号小一点、颜色浅一点,不抢内容。实现上就是在拼接完成后,在画布底部再贴一小块白底区域,把文字画上去。
另外,切片时优先按章节断点切,而不是死板地按页数切。一章刚好结束在第 7 页,那就切在第 7 页,哪怕这张只有 14000 像素高、下一张很短。按内容逻辑切分,读者翻页的时候才不会觉得"话说到一半断了"。
6.3 批量处理和命名,能省下大量重复劳动
一旦脚本跑通,批量处理几乎零成本。我的习惯是把输入目录里所有 PDF 遍历一遍,输出文件名用"原文件名_宽度_页码区间"的格式,比如产品手册_1440px_p01-08.png。这样一眼就能看出这张图对应哪份文档、哪几页、什么分辨率,后面要重新生成或者替换某一段,直接按名字找,不用打开看。
批量的时候有个坑要注意:不要把所有文档用同一套参数硬套。前面说过,横向文档和纵向文档的等效 DPI 完全不同,小开本文档和大开本文档也不同。脚本里应该先读每份文档的页面尺寸,按目标宽度反算倍率,而不是写死一个 zoom 值。我最早的版本就是写死的,结果一批混合尺寸的文档里,纵向的都清晰,横向的全糊,排查了半天才发现是同一套参数用错了地方。
最后还是分享一个我自己反复验证过的心得:判断一张长图合不合格,不要在原图上放大看,把图缩到你目标设备的显示宽度再看。原图上放大到 400% 找瑕疵,能找到一万个"问题",但只要在 1080 像素宽的手机视图下字是清楚的,它就是一张合格的长图。清晰度这件事,永远相对于使用场景,没有绝对标准。