accept属性仅提示文件类型,无法真正识别黑白扫描件;需结合前端扩展名与大小校验、后端魔数及色彩空间解析、ocr预处理三重校验才能可靠拦截。

accept 属性只能提示,不能真正限制黑白扫描件
accept 属性在 <input type="file"> 上起的是浏览器文件选择对话框的过滤作用,不是类型拦截。它无法识别“黑白扫描件”这种语义——浏览器不理解什么是“黑白”,也不知道 PDF 里是不是单色位图。你写 accept=".pdf,.tiff,.jpg" 或 accept="application/pdf,image/tiff",只是让对话框默认只显示这些后缀或 MIME 的文件,用户点一下“所有文件”就全出来了。
常见错误现象:accept="black-and-white" 会完全失效(浏览器不认识这个值);accept="image/*" 看似方便,但会放行彩色照片、带 Alpha 通道的 PNG、甚至截图类图片,和“黑白扫描件”目标严重偏离。
前端 JS 检查文件名和 size 是最低成本兜底
虽然不可靠,但能快速拦截明显错配的文件,比如用户随手拖了个 50MB 的视频进来。关键点是别信 file.type,它常为空或被伪造:
- 用
file.name提取扩展名:比如file.name.split('.').pop().toLowerCase()得到"pdf"或"tif" - 白名单限定扩展名:只接受
["pdf", "tiff", "tif", "jpg", "jpeg"](注意.jpg和.jpeg是两个不同扩展名) - 检查大小是否合理:黑白扫描件单页 PDF 通常在 100KB–2MB 之间,超 5MB 就大概率不是扫描件,可 warn 或拒绝
- 避免只看
file.size就放行——有些恶意 PDF 压缩后体积很小,但内容仍是彩色或含脚本
后端必须用魔数(magic bytes)校验真实格式与色彩空间
这是唯一可信的防线。黑白扫描件本质是两类文件:
-
PDF:需解析文件头 + 检查 `/ColorSpace` 是否为
/DeviceGray或/Indexed(且基色空间为 Gray),并确认无 `/RGB` 或 `/CMYK` 资源引用 -
TIFF/JPEG:读前 12–32 字节判断是否为灰度模式(如 TIFF 中
PhotometricInterpretation = 1,JPEG 中 SOF0 段的采样因子为1x1) - PHP 可用
finfo_open(FILEINFO_RAW)+ 手动比对,或调用identify -format '%r' xxx.tif(ImageMagick) - Node.js 推荐
file-type包 + 自定义 TIFF/PDF 解析逻辑,不要只依赖req.file.mimetype - Python 用
pdfminer或pypdf提取色彩空间信息,别用mimetypes.guess_type()
真正拦住“伪黑白”的地方在 OCR 预处理或业务层规则
很多所谓“黑白 PDF”其实是彩色文档转成 PDF 后没做图像压缩/降色,表面看是单页,实际每张图都是 RGB 三通道。这类文件只有在 OCR 引擎(如 Tesseract)预分析阶段才能暴露——它会报 Warning: Invalid resolution 0 dpi. Using 70 instead. 或直接跳过灰度转换步骤。
所以,如果你的系统后续要做 OCR 或结构化提取,建议把“强制转灰度 + 二值化”作为上传后的必经流水线,并在该步失败时拒绝入库。这比在上传接口硬拦更自然,也更贴近真实业务约束。
容易被忽略的一点:Windows 用户双击 PDF 用 Adobe Reader 打开时看到的是灰度效果,不代表文件内嵌图像是灰度——那是渲染器做的实时转换。文件真实结构,必须靠解析器读原始数据流才能确认。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











