如何使用JavaScript构建基于浏览器的图片故事板转PDF工具

如何使用JavaScript构建基于浏览器的图片故事板转PDF工具

💡 原文英文,约7100词,阅读约需26分钟。
📝

内容提要

本教程介绍如何用三个文件在浏览器中构建“图片故事板转PDF”工具:用户导入图片,为每帧填写标题、描述和时长,选择单页、网格、带笔记面板或胶片条布局,预览后导出可打印PDF。文章重点讲解用createImageBitmap修正手机照片方向、按文件名自然排序、以PDF点为单位统一布局、Canvas文字换行、IndexedDB保存草稿,以及用PDF-lib生成“JPEG照片+透明PNG文字层”的清晰PDF。所有处理均在本地完成,图片不上传服务器。

🔎

延伸解读

文字转图片的取舍:可读但不可搜

文章将PDF中的文字绘制为300dpi的透明PNG层,而非嵌入字体。这样做的好处是能显示任意语言(包括阿拉伯语、日语等),且无需处理字体嵌入问题。代价是PDF中的文字无法被选中或搜索,对于主要打印查看的故事板通常可接受。若需要可搜索文本,则需改用PDF-lib的fontkit嵌入字体,但会失去多语言显示的便利性。

双图层PDF:平衡清晰度与文件大小

工具没有将整页渲染为单一图像,而是把照片以JPEG格式嵌入(按用户选择的dpi缩放),文字和线条则作为透明PNG覆盖在上层。JPEG适合照片,PNG保持文字锐利,同时通过按页面实际尺寸计算图片像素,避免嵌入原始大图导致文件膨胀。这种分层策略在保证打印质量的同时控制了文件体积。

本地处理与草稿保存的隐私考量

所有图片处理均在浏览器内完成,不上传服务器,适合未公开的客户素材。草稿通过IndexedDB保存原始图片Blob和文字,而非localStorage(容量小且仅存字符串)。但需注意:若浏览器隐私模式或存储被阻止,保存会失败,工具会提示用户先下载PDF。此外,草稿恢复时重新生成缩略图,确保数据一致性。

布局与绘制分离:预览与PDF一致性的关键

代码将布局计算(以PDF点为单位)与绘制分离,同一套布局数据同时用于屏幕预览和300dpi PDF生成,仅通过缩放因子k转换。这避免了预览与输出不一致的问题。此外,图片按比例适配单元格(类似object-fit: contain),不拉伸不裁剪,确保画面不变形。文字换行通过Canvas手动测量实现,超长描述以省略号截断。

❓

Q&A

这个图片故事板转PDF工具支持哪些布局方式?

支持四种布局:单页(每页一张大图)、网格(一览整个序列)、带笔记面板(右侧有横线供手写笔记)、胶片条(带齿孔,经典电影胶片外观)。

为什么这个工具要把文字画在Canvas上再嵌入PDF,而不是直接用PDF-lib写文字?

因为PDF-lib的标准字体只支持基本拉丁字符,无法显示印地语、阿拉伯语、日语等文字。Canvas可以使用设备已有字体绘制任何文字,所以工具将文字以300dpi画在Canvas上,再作为透明PNG图层嵌入PDF。代价是PDF中的文字不可选择或搜索,但故事板主要用于打印查看,通常可以接受。

如何处理手机照片方向不正确(横竖颠倒)的问题?

使用createImageBitmap并设置imageOrientation: 'from-image',让浏览器在解码时自动应用EXIF旋转信息。如果浏览器不支持或失败,则回退到使用img元素加载,现代浏览器默认也会应用EXIF旋转。

为什么用IndexedDB保存草稿而不是localStorage?

localStorage只能存储字符串,且大多数浏览器限制约5MB,不到两张手机照片的大小。IndexedDB可以直接存储Blob对象,且容量大得多,适合保存原始图片文件和用户输入的文字。

生成PDF时如何保证照片清晰同时文件不会太大?

采用双层方案:照片以JPEG格式按用户选择的DPI(300或150)嵌入,每张图片根据其在页面上的显示尺寸调整分辨率(小图不放大);文字、标签和线条则作为一张300dpi的透明PNG覆盖在页面上。这样JPEG适合照片,PNG保持文字锐利,文件大小可控。

工具如何对导入的图片文件进行排序?

使用localeCompare并设置numeric: true选项进行自然排序,这样“shot-2.jpg”会排在“shot-10.jpg”前面,符合人们命名文件的习惯。

删除帧后可以撤销吗?如何实现?

可以。删除帧时,工具会保存最后删除的帧及其位置到state.lastDeleted,并显示“撤销删除”按钮。点击撤销后,帧会被插回原位置(如果列表已变短则放到末尾)。

🏷️

标签

➡️

继续阅读