news 2026/10/23 3:15:17

LODOP 6.057打印控件实战:套打坐标、静默输出与浏览器兼容避坑

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LODOP 6.057打印控件实战:套打坐标、静默输出与浏览器兼容避坑

简介:Lodop 6.057 打印控件资源包,适用于需要在 Chrome、IE、Firefox 等浏览器中实现本地打印的 Web 开发者。该版本发布于 2012 年,虽时间较早但稳定易用,作者称终身免费,入手简单、功能强悍,可满足票据、报表、标签等常见打印场景。压缩包共 50 个文件,以 47 个 HTML 示例页面为主,配合 LodopFuncs.js 封装脚本、CSS 样式和 install_lodop.exe 安装程序,基本覆盖安装、调用、预览、分页、样式调整等常用功能,整体仅 1.72MB。已有 1191 人学习下载。包内提供多组完整示例,既能看到前端如何引入控件、生成打印任务,也能了解不同纸张与排版参数的设置方法;开发者对照修改即可集成到自己的项目,省去大量摸索时间,尤其适合刚接触打印控件的初中级工程师。

1. 为什么还用 lodop 6.057:网页打印的硬骨头还是要控件啃

把 lodop 6.057(2012 最新版)打印控件从下载包里捡回来用,是我接手一个仓储打印模块时的事:拣货单、出库单、盘点标签都要通过浏览器打,可一到套打就翻车——底图对不上、多联单错位、批量打印只能一遍遍点预览。这个控件解决的是浏览器原生打印不擅长的场景:精确坐标排版、静默输出、条码和表格套打。它靠本地插件方式让网页直接驱动打印机,当年在 chrome、IE、firefox 三个浏览器上都走通了,而且不按年收费。

适合谁?被票据、单据、标签打印折磨的前后端开发者,以及要维护老打印系统又不打算重构的运维。下载包里带了安装程序、示例页和内置文档,照着下面流程就能把环境跑起来。

2. 安装与初始化:把 lodop 6.057 接进三个浏览器的正确姿势

2.1 解压后先分清三样东西

这类控件包解压之后,桌面上一般会有三样东西:安装程序、免注册版文件、示例页面。安装程序适合普通办公电脑,双击后向系统注册控件,装完就能被网页识别。免注册版文件适合企业批量部署,配合开机脚本或组策略推到几十台收银机、仓库电脑上,不用每台机都点一遍下一步。

示例页面是整个资源包里最重要的一份文件。我一般会先用文本编辑器打开它,里面通常已经写好了对象引用和打印测试按钮,直接放到内网 Web 目录里访问,就能判断控件装没装好。验证方式很简单:页面加载后,控制台里执行LODOP.VERSION,返回的字符串包含6.057就说明当前加载的正是这个版本。如果返回空或者页面直接报对象错误,说明装的是别的版本,或者 classid 对不上。

这里要提醒一个细节:资源包里的安装程序和你自己写的页面必须匹配。网页里通过<object>引用的 classid 在安装控件时会注册到系统里,如果页面里的 classid 写的是网上随便抄的,哪怕控件装了也会提示找不到对象。所以先打开包内自带的示例页面,把它里面那段对象引用原样复制到你项目的页面上,这能省掉后面一大半初始化报错。

2.2 网页里加载控件对象的两种方式

最老实的做法是在 HTML 里直接写一个<object>标签,id 固定为 LODOP。示例页面里通常就是这种写法。代码如下:

<body> <object id="LODOP" classid="clsid:00000000-0000-0000-0000-000000000000" width="0" height="0"></object> <script> function createLodop() { var obj = document.getElementById("LODOP"); if (obj && obj.VERSION) { return obj; } // 常见做法:动态创建一个 object 再挂到 body 上 obj = document.createElement("object"); obj.setAttribute("id", "LODOP"); // classid 以资源包自带的说明为准,不同版本有差异 obj.setAttribute("classid", "clsid:00000000-0000-0000-0000-000000000000"); document.body.appendChild(obj); return obj; } var LODOP = createLodop(); </script> </body>

上面的 classid 是占位示例,实际值必须从资源包示例页或控件自带文档里复制。如果下载包里带有封装好的 LodopFuncs.js,我一般直接引用它,里头的getLodop()函数已经把创建对象、版本校验、安装引导都包好了,比手工拼对象省心很多。动态创建对象的好处是页面初始化时不会被一个加载失败的插件卡住,其他业务脚本照常执行,等真正要打印时再调 LODOP。

那个<object>标签的width="0" height="0"不是随便写的。控件在页面上不需要占据可视区,但必须真实存在于 DOM 中,删掉标签再靠纯 JS 调用在某些 IE 内核版本里会失败。

2.3 三个浏览器的兼容配置:ActiveX、NPAPI 和 IE 模式

6.057 是 2012 年前后的版本,当时三个浏览器各自支持插件机制:IE 走 ActiveX,Chrome 和 Firefox 走 NPAPI。放在今天,这套配置思路要变。我一般这样落地:

浏览器6.057 时代的加载方式现在的实机状态我常用的落地策略
IE / Edge IE 模式ActiveX 受信任站点内网老环境仍然可用站点加入受信任区域,启用 ActiveX
ChromeNPAPI 插件新版已移除 NPAPI切 Edge IE 模式,或用企业版管控
FirefoxNPAPI 插件同样移除放弃直连,统一转 IE 兼容通道

内网环境里最常见的是 IE 和 Edge 的 IE 模式。要做的配置就三步:打开 Internet 选项,切到“安全”,选择“受信任的站点”,把页面地址加进去;再把“自定义级别”里与 ActiveX 相关的几个选项都改成“启用”。其中最容易卡住的是“对未标记为可安全执行脚本的 ActiveX 控件初始化并执行脚本”这一项,默认可能是提示,不改的话控件装好了页面仍然报未安装。

提示:内网页面如果走 HTTP,不加受信任站点会被当成低安全级别处理,ActiveX 直接禁用。先加站点再刷新,比反复卸载安装验签有效得多。

Chrome 那边今天的策略不是去改 Chrome,而是把整个应用切到 Edge 的 IE 模式。运维可以把内网页面地址配进 Edge 策略的“IE 模式站点列表”,用户点开就是 IE 内核。Firefox 则不建议再花时间,直接统一入口更省事。

3. 用 ADD_PRINT 拼一张套打凭证:坐标、单位和三种内容类型

3.1 PRINT_INIT 先打底:任务名和重复打印

LODOP 的每次打印都以PRINT_INIT开头,它负责创建一个全新的打印任务,清掉上一次遗留的内容。任务名要尽量传成“单据号+日期”这样的唯一字符串,比如LODOP.PRINT_INIT("SO20250501-001")。如果任务名重复,后一次打印会把内容追加到前一个任务里,批量场景很容易把上一单的明细带到下一单。

我一般会把初始化包成一个函数,统一设置纸张和默认份数:

function createTask(taskName) { if (!LODOP) { return -1; } var ret = LODOP.PRINT_INIT(taskName); if (ret < 0) { return ret; } // 第二个参数 1 表示纵向,后面的宽高传 0 则表示按系统驱动里的纸张定义 LODOP.SET_PRINT_PAGESIZE(1, 0, 0, "A4"); LODOP.SET_PRINT_COPIES(1); return 0; }

PRINT_INIT返回小于 0 的值表示初始化失败,最常见的原因是上一个打印任务还没结束,页面就触发了新的打印。所以涉及批量打印时,按钮回调里要加互锁,同一时间只允许一个任务在跑。

3.2 三种内容类型:TEXT、HTM、IMAGE

一张单据上不同区域用不同的 ADD_PRINT 方法。我的习惯是动态字段用ADD_PRINT_TEXT,复杂排版用ADD_PRINT_HTM,签名和底图用ADD_PRINT_IMAGE。三种方法的前四个参数完全一致:上边距、左边距、宽度、高度,单位都是 0.1 毫米。

方法适用内容注意事项
ADD_PRINT_TEXT单行文本定位最准,不换行,适合序号、金额字段
ADD_PRINT_HTMHTML 片段支持样式和表格,适合明细区域
ADD_PRINT_IMAGE本地图片或 base64本地路径要加 @ 前缀,文件不存在会静默丢图

示例代码:

LODOP.ADD_PRINT_TEXT(80, 20, 200, 20, "订单号:SO20250501-001"); LODOP.ADD_PRINT_HTM(110, 20, 900, 120, "<table border='1' cellspacing='0' cellpadding='2'>" + "<tr><td>品名</td><td>数量</td><td>金额</td></tr>" + "<tr><td>钢制支架</td><td>2</td><td>560.00</td></tr>" + "</table>" ); LODOP.ADD_PRINT_IMAGE(240, 20, 200, 60, "@D:\\sign\\signature.png");

ADD_PRINT_TEXT里的文本不能用\n强行换行,它不是一个文本块组件,换行应该拆成两行文本分两次输出,或者改用ADD_PRINT_HTM包一个<div>。ADD_PRINT_IMAGE的@前缀表示后面的路径是本地绝对路径,只在控件所在的机器上有效,前端页面在别的机器上访问就会取不到,所以签名这类图片我尽量转成 base64 拼进去,虽然占内存,但不会因为路径问题打出一片空白。

3.3 坐标单位:0.1 毫米和那台“骗你”的屏幕

LODOP 的坐标单位是 0.1 毫米,所以 A4 竖版纸的宽是 2100,高是 2970。设计器里拖动一个文本对象时看到的像素位置不能直接写进代码,要换算成单位值。我的换算函数长这样:

function mmToUnit(mm) { return Math.round(mm * 10); } // 在页面顶部 35mm、左侧 5mm 处输出内容 LODOP.ADD_PRINT_TEXT(mmToUnit(35), mmToUnit(5), 300, 100, "打印内容");

套打对不齐的根源往往不是坐标算错,而是打印机驱动里开了“缩放以适应纸张”。驱动面板默认可能把 100% 变成“适合打印”,或者 Windows 屏幕缩放影响了页面估算,最后打出来整体偏右上。我一般在部署时就把驱动的缩放固定为 100%,并且告诉使用的人不要改打印机属性里的纸张类型,必须和代码里声明的一致。这一条能解决掉一半的“设计器里好好的,打印出来歪了”的反馈。

3.4 条码、份数、多联

条码打印是仓库场景里的刚需。ADD_PRINT_BARCODE的第五个参数是条码类型,第六个参数是内容。我的建议是内容混合大小写字母和数字时一律用128类型,纯数字且位数固定可以试EAN13。

LODOP.ADD_PRINT_BARCODE(320, 20, 300, 100, "128", "SO20250501-001"); LODOP.SET_PRINT_COPIES(3); // 三联单

多联单打 3 份时,SET_PRINT_COPIES让打印机把当前页整页重复输出。如果单据页里混杂了多条明细,最好先把明细拼成一整页再设份数,否则每页重复的是同一个整页内容,拆页逻辑会乱。

4. 静默打印:LODOP.PRINT() 的无预览输出与打印机选择

4.1 无预览不是吞掉打印任务

PREVIEW()弹预览窗口给人确认,PRINT()不做预览直接发送到打印机。收银小票、批量发货单这类场景用的是PRINT()。但无预览不等于没任务,点击打印后任务仍然进入系统打印队列,如果打印机离线,任务会挂在队列里,后面再打的单子全堵在一起。

我见过把浏览器端 LODOP 和服务器端打印混淆的情况。LODOP 控件运行在用户浏览器的页面上,必须有一个人开着这个页面才能真正触发任务。要做服务端的定时批量打印,通常是另做一个自动页面,放到内网一台专用电脑上定时打开并执行LODOP.PRINT()。

静默打印前,我至少会检测一次打印机在线状态:

var count = LODOP.GET_PRINTER_COUNT(); if (count < 1) { alert("没有检测到可用打印机,请检查驱动"); return; }

虽然不能完全确认打印机纸张和墨盒状态,但至少能拦住“驱动都丢了”的场景。

4.2 打印机选择与份数参数

一台电脑接了两台打印机时,PRINT()默认走系统默认打印机,经常打错设备。我一般用关键字匹配的方式选择打印机:

function pickPrinter(keyword) { var count = LODOP.GET_PRINTER_COUNT(); for (var i = 0; i < count; i++) { var name = LODOP.GET_PRINTER_NAME(i); if (name.indexOf(keyword) >= 0) { return i; } } return -1; } var idx = pickPrinter("出库"); if (idx >= 0) { LODOP.SET_PRINTER_INDEX(idx); } LODOP.SET_PRINT_COPIES(2); LODOP.PRINT();

SET_PRINTER_INDEX传 -1 表示用系统默认打印机,传索引则从 0 开始。GET_PRINTER_COUNT返回的打印机数量包含虚拟打印机和已安装但未连接的驱动,所以仅凭数量判断在线情况不可靠。同一台网络打印机在不同电脑上名字可能带后缀,关键字匹配比硬编码索引稳定,硬编码索引在打印顺序变化时会打到隔壁那台。

4.3 设计器导出的语句,如何安全接进生产代码

LODOP 自带的设计器可以拖出套打模板并导出代码。导出的是一串ADD_PRINT_*语句,我一般把它嵌进生产代码时外面套一层固定模板:

LODOP.PRINT_INIT("导出模板-" + orderNo); LODOP.SET_PRINT_PAGESIZE(1, 0, 0, "A4"); // 下面是从设计器导出的语句块,其中变量由后台传入 LODOP.ADD_PRINT_TEXT(35, 10, 200, 30, orderNo); LODOP.ADD_PRINT_HTM(70, 10, 1000, 160, detailHtml); // 结束 LODOP.PRINT();

设计器导出的坐标是固定值,生产环境里不要通过 CSS 缩放去适配,改位置就在设计器里拖完重新导出。后台传过来的明细 HTML 要先做转义处理,否则拼接detailHtml时插入一段带引号的文本会把整个模板打崩。我在项目里会把<、>、&转成实体字符兜底,打印时再转回可见内容。

5. 避坑排查:6.057 用起来最常见的 5 个坑

5.1 现象:Chrome 打开示例页,控制台报 “LODOP is not defined”

原因:新版 Chrome 彻底移除了 NPAPI 插件支持,6.057 时代的老插件在现在的 Chrome 里根本不会被加载,所以全局没有 LODOP 对象。

解决:不要指望在现版 Chrome 里装个插件复活它。我现在的落地方式是让整个应用走 Edge 的 IE 模式,把站点地址配进策略的 IE 模式列表中,用户点开就是 IE 内核,LODOP 控件正常加载。如果团队确实要纯 Chrome,那就换支持插件的老内核浏览器,但安全补丁很难更上,内网可以接受,外网不建议。

5.2 现象:IE 里页面显示 “您还未安装控件”,但明明已经装好

原因:控件装进了系统,但浏览器的 ActiveX 安全策略把当前站点拦住了。内网 HTTP 地址默认可能被置为受限,或者“对未标记为可安全执行脚本的 ActiveX 控件初始化并执行脚本”还是“禁用”。

解决:把页面地址加入受信任站点,再在自定义级别里把所有与 ActiveX 运行相关的项改为“启用”,然后重启浏览器。注意这项配置是按站点生效的,换一个端口或换一条域名路径都要重新加。装完控件如果页面仍提示,先看 URL 协议是不是 HTTPS,受信任区域不认 IP 加端口的组合时,把地址改成域名再试。

5.3 现象:同一张模板,设计器里显示正常,打印出来整体偏移右上或左下

原因:打印机驱动把内容按“适合页面”缩放过了,或者 Windows 系统显示缩放到 125% 导致页面计算坐标时产生了偏差。我遇到的大部分套打偏移都来自这两个原因,而不是 LODOP 坐标算错。

解决:在打印机驱动属性里把缩放固定为 100%,并确认纸张类型与代码里SET_PRINT_PAGESIZE声明的一致。Windows 的显示缩放如果改不了,就在浏览器兼容视图或应用页面传入一个固定 DPI 参数,让页面不再跟随系统缩放。

5.4 现象:条码打出来很清晰,但扫码枪死活扫不出

原因:条码类型和内容不匹配。比如内容里混了字母却选 Code39,或者内容长度超过该条码类型的容量,打印机能输出图案,但扫码枪解码失败。

解决:内容含大小写字母和数字时选128类型;纯数字、位数固定且不超过 13 位可以试EAN13。条码下方通常会带一串供人识别的文本,把这段文本和实际内容逐字符对比,能发现是内容被截断还是条码类型选错,比反复换扫码枪更有效率。

5.5 现象:批量打印时任务重叠,最后一张带出前面页的内容

原因:页面上短时间内多次调用了LODOP.PRINT(),前一个任务还没完全从打印队列清空,新任务直接追加进去;或者任务名重复,控件把新内容并进了旧任务里。

解决:打印按钮回调里加一个pending标志,任务未结束前不允许再次提交;每次打印前重新调用PRINT_INIT创建一个全新任务,任务名带上单据号。批量列表场景还要注意,不要在一个循环里连续调PRINT(),改成每张单据触发一次独立任务,等上一张任务回调后再打下一张。

6. 一句代码验证控件状态:给接手的人留一份环境探测脚本

老打印模块最难排的往往是环境问题:控件版本不对、打印机驱动丢失、浏览器安全策略拦截。我现在会在系统里固定放一个诊断入口,执行一段探测脚本,先把环境状态拉出来再看业务代码。

function probeLodop() { var info = { ok: false, version: "unknown", printers: 0, pageOk: false }; try { var obj = document.getElementById("LODOP"); if (!obj) { obj = LODOP; } if (obj) { info.ok = true; info.version = obj.VERSION || "unknown"; info.printers = obj.GET_PRINTER_COUNT() || 0; info.pageOk = obj.PRINT_INIT("probe") >= 0; if (info.pageOk) { obj.PRINT_SETUP(); // 主动弹一次打印设置,验证驱动链路 } } } catch (e) { info.err = e.message; } return info; }

返回结果里version不是 6.057,就说明加载的不是资源包里那版控件,优先重装而不是查代码。printers为 0,说明系统里没有可用打印机或驱动已经损坏,直接去修驱动,不用在页面排版里找原因。pageOk为 false,说明对象存在但打印任务初始化失败,通常是上一个任务还卡在队列里,重启浏览器就能恢复。

我从那以后每次接手老打印项目,都会先强制跑一遍这段探测脚本,把环境问题从业务逻辑里剥出去再改代码,省下不少开会解释的时间。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/23 3:14:48

小样本学习实战:从原理到代码,解决图像分类数据稀缺难题

开头我从一个实际场景说起。我去年接了一个某工业质检项目&#xff0c;客户给的需求是识别产线上几种新产品的外观缺陷&#xff0c;但每个缺陷类型只有几十张图&#xff0c;多的也就一百来张。一开始想直接拿预训练的ResNet微调&#xff0c;发现效果不理想&#xff0c;几个缺陷…

作者头像 李华
网站建设 2026/10/23 3:14:47

AI产品落地实战:技术-场景适配与产品规划避坑指南

简介&#xff1a;这份PDF是《产品经理的AI实战》一书的读书笔记&#xff0c;面向AI产品经理、技术转产品人员及关注AI商业化的从业者&#xff0c;帮助读者快速理解人工智能产品从技术到商业落地的完整逻辑。笔记将原书三部分13章、216页内容精炼为28页&#xff0c;涵盖技术商业…

作者头像 李华
网站建设 2026/10/23 3:14:44

点开头目录全解析:从.git到.npm,哪些能删哪些不能?

很多开发者估计都有过这样的瞬间&#xff1a;刚拿到一台新电脑&#xff0c;或者打开项目目录准备排查磁盘空间&#xff0c;结果发现里面密密麻麻地躺着十几个点开头的文件夹——.git、.next、.cache、.npm、.vscode&#xff0c;还有一堆叫不上名字的.xxx。第一反应通常是“这是…

作者头像 李华
网站建设 2026/10/23 3:14:28

CO5300驱动IC数据手册深度解读:QSPI与MIPI DSI双接口及TE撕裂效应

简介&#xff1a;这份CO5300 AMOLED数据手册面向智能手表等嵌入式显示方案的硬件工程师与驱动开发者&#xff0c;用于解决OLED驱动IC选型、电路设计与底层驱动开发中的规格确认问题。资源包为1个PDF文件&#xff0c;大小约12.62MB&#xff0c;即Chipone官方发布的CO5300 OLED D…

作者头像 李华
网站建设 2026/10/23 3:14:11

wbengine.exe文件丢失报错?安全修复思路与实战排查指南

相信不少Windows用户都碰到过这样的弹窗&#xff1a;打开某个软件时&#xff0c;系统突然提示“找不到wbengine.exe”或者“wbengine.exe文件丢失”&#xff0c;应用直接退出&#xff0c;甚至开机的时候都会冒出一个报错框。大多数人第一反应是去搜索引擎找“wbengine.exe免费下…

作者头像 李华
网站建设 2026/10/23 3:14:03

H100规格书怎么读:FP8算力、NVLink互联与选型避坑指南

简介&#xff1a;NVIDIA H100 Tensor Core GPU官方数据手册&#xff08;Datasheet&#xff09;&#xff0c;面向数据中心架构师、AI平台工程师、HPC研究人员以及GPU选型决策者&#xff0c;帮助读者全面掌握Hopper架构在AI训练、大模型推理与高性能计算等场景下的技术能力与关键…

作者头像 李华