[{"data":1,"prerenderedAt":421},["ShallowReactive",2],{"project-image-workshop":3,"all-projects-nav":326,"project-posts-image-workshop":417},{"id":4,"title":5,"architecture":6,"body":7,"category":233,"client":234,"cover":235,"date":236,"demo":6,"demoMobile":6,"description":224,"extension":237,"featured":238,"features":239,"github":206,"manual":255,"meta":309,"modules":310,"navigation":311,"order":312,"path":313,"seo":314,"slug":315,"stem":316,"summary":317,"techStack":318,"visible":311,"year":324,"__hash__":325},"projects\u002Fprojects\u002Fimage-workshop.md","图片工坊 · 离线批量图片处理",null,{"type":8,"value":9,"toc":223},"minimark",[10,14,18,21,24,27,30,37,40,43,46,55,58,61,64,132,135,175,178,198,201,211,214],[11,12,13],"h2",{"id":13},"缘起",[15,16,17],"p",{},"它起于一个很具体的观察：内网办公的人压图，靠的是系统自带的「画图」——缩到 50% 再另存，压完要么糊了、要么还是超。",[15,19,20],{},"这种电脑上，装软件要审批，文件出不去，在线压缩网站第一步就打不开。而真实需求非常具体：系统只收 5MB 的附件，扫描件一动 40MB。市面上没有一个现成工具是为这个环境做的。",[15,22,23],{},"所以做的东西也很具体：一个装进去就能用、全程不联网、把原图保护好的批量压图工具。",[11,25,26],{"id":26},"背景",[15,28,29],{},"目标用户不是设计师也不是程序员，是单位里要交材料的人。这决定了两件事：",[15,31,32,36],{},[33,34,35],"strong",{},"参数得替用户做掉。","「质量 75」「DPI」「色彩空间」这些词对目标用户没有意义，他们心里只有一个数——系统限的 5MB。所以产品形态是「填一个想要的体积，工具自己想办法压到那个数」，中间的工程决策（二分找最高达标质量、PNG 没有质量旋钮只能缩尺寸、压得太狠要提醒）全部沉到实现里。",[15,38,39],{},"**信任要靠如实报告攒。**内网装一个软件有成本，装完发现「悄悄把图压糊了」就再也不用了。所以每一张图发生了什么都有交代：重新保存了几张、哪几张压到了屏幕清晰度、哪几张不支持、哪几张本来就很省空间——不支持的就明说不支持，不悄悄跳过。",[11,41,42],{"id":42},"方案",[15,44,45],{},"**三条图片规则，选着用。**压到指定体积、限制宽高上限、转成哪种格式——三条可以单用也可以同用；体积与尺寸冲突时体积优先。文件夹直接拖进去，递归扫描、按路径去重，默认双 worker 并行。",[15,47,48,49,54],{},"**PDF 免规则，拖进去就压。**内嵌 JPEG 按质量 75 重存、满页扫描图压到 150 DPI 屏幕清晰度、再做无损结构优化；文字和矢量内容字节级不动。加密的、带签名的直接拒绝——改了签名就失效，这种忙不能帮。这套纯 Go 实现的完整决策过程写在了博客长文",[50,51,53],"a",{"href":52},"\u002Fblog\u002Fpure-go-pdf-compression","《不引 Ghostscript：我用纯 Go 给 PDF 做了一场「压缩手术」","里。",[15,56,57],{},"**原图零写入。**处理结果先进应用内暂存区，原图所在的文件夹一个字节都不动；点「下载」才保存到用户选的文件夹，先写临时文件再原子落位，失败不留半成品。这是第一版直接写回原图旁边、被真实使用者纠正之后改的——隐性约束不是一次想全的，是踩出来的。",[15,59,60],{},"**界面说人话。**用户可见文案有一张术语表当单一真相：「压到了屏幕清晰度」而不是「降采样」、「不支持的图片类型」而不是「JBIG2\u002FCCITT」、已经满足设置的图叫「无需处理」而不是「已达标跳过」。Go 侧返回的提示与前端界面同表取词，改词先改表。",[11,62,63],{"id":63},"技术架构",[65,66,67,80],"table",{},[68,69,70],"thead",{},[71,72,73,77],"tr",{},[74,75,76],"th",{},"模块",[74,78,79],{},"技术选型",[81,82,83,92,100,108,116,124],"tbody",{},[71,84,85,89],{},[86,87,88],"td",{},"桌面运行时",[86,90,91],{},"Wails v2（Go 后端 + Vue3 前端），hash 路由适配打包形态",[71,93,94,97],{},[86,95,96],{},"后端",[86,98,99],{},"Go 1.26 + GORM + SQLite（纯 Go 驱动，无 CGO）",[71,101,102,105],{},[86,103,104],{},"图像处理",[86,106,107],{},"标准库 + golang.org\u002Fx\u002Fimage，目标体积两层搜索（二分质量 + 平方根缩尺寸）",[71,109,110,113],{},[86,111,112],{},"PDF 压缩",[86,114,115],{},"pdfcpu 做解析回写底座，图像重压缩对象级自研（质量 75、仅更小才替换、150 DPI 降采样）",[71,117,118,121],{},[86,119,120],{},"工程化",[86,122,123],{},"Makefile 统一入口 + 架构护栏 + 依赖登记制 + OpenSpec 变更治理",[71,125,126,129],{},[86,127,128],{},"交付",[86,130,131],{},"macOS dmg \u002F Windows NSIS \u002F 麒麟 deb，CI 三平台打包并附 SHA256SUMS",[15,133,134],{},"几个值得说的做法：",[136,137,138,145,151,162],"ul",{},[139,140,141,144],"li",{},[33,142,143],{},"编解码全纯 Go","：不引任何需要外部编译器的图像依赖，同一套代码交叉出三平台（含信创 arm64）安装包，麒麟构建钉死 Ubuntu 20.04 容器对齐 glibc 2.31。",[139,146,147,150],{},[33,148,149],{},"约定编译成会红的检查","：仓库里有 1802 行护栏测试——前后端契约常量双向核对、日志\u002F事件\u002F版本注入这类「漏了不报错」的接线逐条验证、依赖必须登记、分层纪律强制。任何靠解析源码做断言的护栏，解析到 0 个目标必须报错，防止护栏自己失效了还亮绿灯。",[139,152,153,156,157,161],{},[33,154,155],{},"版本号四处同源","：",[158,159,160],"code",{},"wails.json"," 是唯一真相，构建时渲染进安装包与二进制，护栏核对一致性。",[139,163,164,156,167,170,171,174],{},[33,165,166],{},"图标资产单源派生",[158,168,169],{},"build\u002F*.svg"," 是唯一源，",[158,172,173],{},"make icon"," 派生全部平台图标并登记哈希，派生物不许手改。",[11,176,177],{"id":177},"成果",[136,179,180,186,192],{},[139,181,182,185],{},[33,183,184],{},"已发版","：v0.2.0 打 tag 自动构建三平台安装包与校验和，GitHub Release 可下载；从第一个提交到交付 0.1.0 用了两周，PDF 压缩作为 0.2.0 的主体功能补齐。",[139,187,188,191],{},[33,189,190],{},"质量可数","：功能代码约 4400 行，测试与护栏约 6200 行（其中护栏 1802 行）；10 份架构决策记录；PDF 压缩 spike 实测整文件 -42.9%、渲染像素差 0.41\u002F765（肉眼不可辨）。",[139,193,194,197],{},[33,195,196],{},"自用与家人使用中","：家里交材料的活儿现在都走它。没有对外推广，没有用户数可以报，这一栏不填好看的假数字。",[11,199,200],{"id":200},"体验",[15,202,203,204,210],{},"源码在 ",[50,205,209],{"href":206,"rel":207},"https:\u002F\u002Fgithub.com\u002FBenny66\u002Ffile-processor",[208],"nofollow","github.com\u002FBenny66\u002Ffile-processor","，Release 页有三平台安装包；没有网页版 demo，桌面工具想用起来就是装一个。",[15,212,213],{},"想验两件事的话：",[215,216,217,220],"ol",{},[139,218,219],{},"拖一个 300 DPI 的扫描件 PDF 进去，点开始。结果消息会写「重新保存了 x 张图片，其中 y 张压到了屏幕清晰度」——体积通常能掉一个数量级。",[139,221,222],{},"把压好的文件再拖进去跑一遍。这一遍会全部显示「已经很省空间」，一个字节都不会再动——逐张「仅更小才替换」的意义就在这。",{"title":224,"searchDepth":225,"depth":225,"links":226},"",2,[227,228,229,230,231,232],{"id":13,"depth":225,"text":13},{"id":26,"depth":225,"text":26},{"id":42,"depth":225,"text":42},{"id":63,"depth":225,"text":63},{"id":177,"depth":225,"text":177},{"id":200,"depth":225,"text":200},"desktop","个人项目","https:\u002F\u002Fname.os.bennywen.xyz\u002Fbennywen.xyz\u002Fassets\u002Ffile-processer\u002F%E5%B7%A5%E4%BD%9C%E5%8F%B0-%E5%A4%84%E7%90%86%E7%BB%93%E6%9E%9C.png","2026-10-24","md",false,[240,243,247,251],{"title":241,"description":242,"image":235},"批量处理与汇总","队列逐项显示状态与节省比例，汇总条给出成功、失败、跳过与累计节省；压得太狠的会明确标出「画质变差了」",{"title":244,"description":245,"image":246},"单张对比","原图与结果并排，按最长边等比缩小，棋盘格表示透明区域，两侧尺寸与体积一目了然","https:\u002F\u002Fname.os.bennywen.xyz\u002Fbennywen.xyz\u002Fassets\u002Ffile-processer\u002F%E5%8D%95%E5%BC%A0%E5%AF%B9%E6%AF%94.png",{"title":248,"description":249,"image":250},"常用设置","把常用参数起名存档，一键套用；套用只改参数、不会自动开始处理","https:\u002F\u002Fname.os.bennywen.xyz\u002Fbennywen.xyz\u002Fassets\u002Ffile-processer\u002F%E9%A2%84%E8%AE%BE%E7%AE%A1%E7%90%86.png",{"title":252,"description":253,"image":254},"设置页","隐私声明与历史记录占用管理，和首屏同一口径——不联网、不上传","https:\u002F\u002Fname.os.bennywen.xyz\u002Fbennywen.xyz\u002Fassets\u002Ffile-processer\u002F%E8%AE%BE%E7%BD%AE%E9%A1%B5%E9%9D%A2.png",{"specs":256,"modules":275,"deploy":298,"limits":302},[257,260,263,266,269,272],{"label":258,"value":259},"交付形态","一个安装包装进系统就能用（macOS dmg \u002F Windows NSIS \u002F 银河麒麟 deb），不需要另装运行环境（Windows 需系统自带或随装 WebView2）",{"label":261,"value":262},"运行要求","macOS 10.13 及以上（Universal 二进制）；Windows 10\u002F11；银河麒麟 V10 SP1（2203，glibc 2.31）",{"label":264,"value":265},"输入支持","JPEG、PNG、WebP、BMP、TIFF、静态 GIF 与 PDF（只压缩、输出仍是 PDF）；单文件上限 512 MB、单图上限一亿像素",{"label":267,"value":268},"隐私边界","全程离线——不上传、不联网、无遥测；输出是全新编码，GPS 与拍摄信息一并剥离",{"label":270,"value":271},"数据存放","常用设置与最近 30 次历史存本机 SQLite；没有账号、没有云同步",{"label":273,"value":274},"适用规模","面向个人与内网办公的单机使用，默认 2 个 worker 并行",[276,279,282,285,288,290,293,296],{"name":277,"desc":278},"批量导入","文件与文件夹直接拖入，递归扫描、按路径去重；处理中界面不卡，单张失败不影响整批",{"name":280,"desc":281},"格式转换","JPEG \u002F PNG \u002F WebP 互转，「自动」档逐格式竞速取最小；格式以内容探测为准，扩展名骗不了它",{"name":283,"desc":284},"目标体积","二分搜索能达标的最高质量，质量到底仍超标再按比例缩尺寸，留 5% 余量防四舍五入反弹",{"name":286,"desc":287},"宽高上限盒","等比缩放进盒，不裁切、不拉伸、不放大；与目标体积冲突时体积优先",{"name":112,"desc":289},"内嵌 JPEG 按质量 75 重存（仅更小才替换）、满页扫描图压到 150 DPI 屏幕清晰度、无损结构优化；文字一字不动",{"name":291,"desc":292},"暂存与下载","结果先进应用内暂存区，原图所在文件夹零写入；点「下载」才落盘，先写临时文件再原子落位，失败不留半成品",{"name":294,"desc":295},"历史记录","最近 30 次处理可回看——什么时候、用了什么设置、每张结果如何，没下载的随时再保存",{"name":248,"desc":297},"参数起名存档一键套用，应用重启恢复上次使用的设置",[299,300,301],"怎么装：GitHub Release 下载对应平台安装包；个人分发未做签名，首次打开会被系统拦一次，按 README 步骤放行即可（每台机器一次）","怎么核对：安装包经网盘或聊天工具转发后，用 Release 附带的 SHA256SUMS.txt 校验和核对","怎么维护：设置与历史存在系统应用数据目录；从源码构建走 make build \u002F test \u002F lint，打包走 make package",[303,304,305,306,307,308],"不支持 AVIF \u002F HEIC 与动图：避免三平台系统编解码依赖；iPhone 默认存的 HEIC 需先转 JPEG","扫描页压到屏幕清晰度：满页扫描图默认 150 DPI，屏幕阅读够用、打印可能不够；非满页插图不缩像素","部分 PDF 图片不重存：传真码（JBIG2\u002FCCITT）、Flate 截图、CMYK\u002F索引色保持原样并如实计数；加密与带签名的 PDF 直接拒绝处理","不保留 ICC 色彩配置：广色域图片可能轻微偏色，交材料够用、印刷不建议","未做代码签名与公证：个人分发不办证书，他人首次打开会被 Gatekeeper \u002F SmartScreen 拦一次","麒麟与信创 arm64 尚未真机验收：deb 由 CI 产出并在容器内验证安装，真机全流程未跑",{},8,true,20,"\u002Fprojects\u002Fimage-workshop",{"title":5,"description":224},"image-workshop","projects\u002Fimage-workshop","给「不能联网的电脑」做的批量压图工具：拖进文件夹，压到指定体积、限住宽高、转格式，PDF 直接拖进去就能压——全程不上传、不联网、不碰原图",[319,320,321,322,323],"Go","Wails v2","Vue3","Pinia","SQLite","2026","4zr-Rbn3HladZhKxMwFqTB3zn7LuVWTqJBk0koN9r5s",[327,328,333,339,344,349,355,359,364,367,372,378,384,388,393,397,401,405,409,413],{"title":5,"slug":315,"order":312,"year":324,"date":236,"category":233},{"title":329,"slug":330,"order":331,"year":324,"date":332,"category":233},"Morrow · 桌面健康提醒","morrow",19,"2026-10-23",{"title":334,"slug":335,"order":336,"year":324,"date":337,"category":338},"家教学情管理系统","tutor-analytics",17,"2026-09-30","operations",{"title":340,"slug":341,"order":342,"year":324,"date":337,"category":343},"闲鱼素材工坊","xianyu-content-gen",18,"ai",{"title":345,"slug":346,"order":347,"year":324,"date":348,"category":343},"电商详情页 AI 生成客户端","ecom-detail-ai",16,"2026-09-29",{"title":350,"slug":351,"order":352,"year":324,"date":353,"category":354},"Wails 桌面端脚手架基座","wails-bailer-starter",15,"2026-09-15","toolkit",{"title":356,"slug":357,"order":310,"year":324,"date":358,"category":354},"多端管理脚手架基座","admin-scaffold","2026-09-04",{"title":360,"slug":361,"order":362,"year":324,"date":363,"category":338},"公车车辆管理系统","bus-admin-system",1,"2026-09-02",{"title":365,"slug":366,"order":225,"year":324,"date":363,"category":338},"设备出租订单管理系统","rental-order-manager",{"title":368,"slug":369,"order":370,"year":324,"date":371,"category":343},"家庭绿植管家","family-plant-manager",3,"2026-08-19",{"title":373,"slug":374,"order":375,"year":376,"date":377,"category":343},"古诗词AI取名工具","chinese-poetry-give-name",7,"2025","2026-06-22",{"title":379,"slug":380,"order":381,"year":376,"date":382,"category":383},"企业固定资产管理系统","asset-admin",4,"2026-06-16","admin",{"title":385,"slug":386,"order":387,"year":376,"date":382,"category":343},"知祖AI","kingpt",5,{"title":389,"slug":390,"order":391,"year":376,"date":382,"category":392},"深圳房产智能分析平台","sz-realestate",6,"data",{"title":394,"slug":395,"order":396,"year":376,"date":382,"category":383},"工厂轻量化智能排班系统","staff-scheduling",9,{"title":398,"slug":399,"order":400,"year":376,"date":382,"category":338},"电商服装仓库物流管理系统","clothing-warehouse",10,{"title":402,"slug":403,"order":404,"year":376,"date":382,"category":343},"知识库问答系统","kb-qa",11,{"title":406,"slug":407,"order":408,"year":376,"date":382,"category":383},"企业微信邮箱运营管理系统","mail-manager",12,{"title":410,"slug":411,"order":412,"year":376,"date":382,"category":338},"Switch 电玩库存管理系统","switch-manager",13,{"title":414,"slug":415,"order":416,"year":376,"date":382,"category":383},"学生宿舍管理系统","dorm-manager",14,[418],{"title":419,"slug":420,"date":236,"links":6},"不引 Ghostscript：我用纯 Go 给 PDF 做了一场「压缩手术」","pure-go-pdf-compression",1792857942217]