实现思路:
用Java调用本地打印机实现功能,将java程序打包成exe可执行文件,在本地注册表中新增URL协议,最后web端通过该协议实现启动本地exe程序进行打印
实现过程:
1、下载32位TSCActiveX.dll,并注册到windows环境中,指令为Regsvr32.exe TSCActiveX.dll 下载地址:https://download.csdn.net/download/u010188178/10642451
2、创建Java工程(这一步可以先不做,因为我用普通Java工程最终失败了,在这里只是为了说明当时的解决过程)
3、核心代码(见页面底端),这里需要引入外部包 jna-3.0.9.jar
4、添加入口类(main方法类),然后打包成jar文件
5、运行jar,java -jar ******.jar
此时发会报错“Class not fond”,找不到 com.sun.jna.Library,说明第三方包未能引入,解决方案:参考 https://blog.csdn.net/u010188178/article/details/82454220
问题解决,到这一步便可以运行jar文件调用本地打印。
6、使用exe4j将jar文件打包为exe文件 工具及使用说明的下载地址:https://download.csdn.net/download/u010188178/10643229
生成exe文件后,执行之。然后又报错:java.lang.NoClassDefFoundError: com/sun/jna/Library,与上面报错原因类似,找不到第三方包。
经过多次尝试失败,最终未能解决,因此回到上述提到的第“2”步,既然普通工程引入第三方jar包在自身打包过程会如此“不幸”,故想到使用maven来构建并打包项目;同时考虑到web端与exe运行程序之间的参数传递问题,因此我决定使用springboot+maven工程。核心代码不变,其他步骤同上,最终生成有效可执行exe文件。
7、添加自定义URL协议
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\TscPrint]
"URL Protocol"="D:\\test\\tsc_printer.exe"
@="TscPrintProtocol"
[HKEY_CLASSES_ROOT\TscPrint\DefaultIcon]
@="D:\\test\\tsc_printer.exe,1"
[HKEY_CLASSES_ROOT\TscPrint\shell]
[HKEY_CLASSES_ROOT\TscPrint\shell\open]
[HKEY_CLASSES_ROOT\TscPrint\shell\open\command]
@="\"D:\\test\\tsc_printer.exe\" \"%1\""
8、在页面上调用自定义协议启动打印程序
注意事项:
1、使用的是打印机的命令进行操作,这里需要jna的jar包,还有jdk要求是32位的,并且要要注册对应的dll,对应不同的系统要在不同的Windows下进行注册DLL,注册成功之后需要win+R ,调用并运行 Regsvr32.exe TSCActiveX.dll 指令
2、需要用到第三方jar包,jna
3、打印图片的指令“PUTPCX”仅支持单色PCX图像,上传到打印机前需要先将图片转换成单色PCX格式
转换步骤:
(1)将图片转换成单色位图,比如可使用windows自带的画图工具:打开图片-另存为单色位图
(2)将单色位图转换成PCX格式,比如可用PS工具将其另存为PCX
(讲一下当时解决这个问题的过程:调用打印机PUTPCX命令打印图片始终不能成功打印,然后阅读该型号打印机的编程API,提到该指令仅支持单色PCX图像,于是将矛头指向PCX;通过上网查询,了解PCX格式的头文件结构,单色应该具有这样2个特征,即文件头第3字节的“位/像素”值为1且第65字节平面数也为1;了解到这些后已经兴奋不已,因为自己在大学期间学过图相隐写技术,通过修改图像头文件的某些位置并不会让图片看起来有异样,于是就想当然的直接修改第3和第65字节的十六进制数值;然后保存图片,调用打印机,打印成功,但发现图片完全变了样,说明PCX格式文件头的这2个位置是不允许直接修改的;最后经技术负责人点拨,既然不知道怎样将PCX转换成单色,为何不先将其他格式图片转换成单色,再将其转换成PCX格式,经实验,方案可行。)
存在不足:
1.代码仅是技术上的实现,并未结合实际业务进行优化
2.暂不支持图片的打印(已解决)
3.不足之处,请批评指正,指正邮箱:[email protected]
核心代码:
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import com.sun.jna.Library;
import com.sun.jna.Native;
public class JavaPrinter {
private static JavaPrinter instance = null;
private JavaPrinter(){
}
public static JavaPrinter getInstance(){
if (instance == null) {
synchronized (JavaPrinter.class) {
if (instance == null) {
instance = new JavaPrinter();
}
}
}
return instance;
}
public interface TscLibDll extends Library {
TscLibDll INSTANCE = (TscLibDll) Native.loadLibrary("TSCLIB", TscLibDll.class);
int about();
int openport(String pirnterName);
int closeport();
int sendcommand(String printerCommand);
int setup(String width, String height, String speed, String density, String sensor, String vertical, String offset);
int downloadpcx(String filename, String image_name);
int barcode(String x, String y, String type, String height, String readable, String rotation, String narrow, String wide, String code);
int printerfont(String x, String y, String fonttype, String rotation, String xmul, String ymul, String text);
int clearbuffer();
int printlabel(String set, String copy);
int formfeed();
int nobackfeed();
int windowsfont(int x, int y, int fontheight, int rotation, int fontstyle, int fontunderline, String szFaceName, String content);
}
/**
* 打印入场券,宽高为80.6*201mm
* @param tscName 打印机名称
* @param title 打印标题
* @param others 除标题外的其他文字
* @param qrCode 二维码文字
* @param copies 打印份数
* @auther WolfShadow
* @date 2018年9月4日
*/
public void printTickt(String tscName, String title, List others, String qrCode, int copies){
System.setProperty("jna.encoding", "GBK");// 支持中文
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = df.format(new Date());
// TscLibDll.INSTANCE.about();
TscLibDll.INSTANCE.openport(tscName);
// TscLibDll.INSTANCE.downloadpcx("C:\\UL.PCX", "UL.PCX");
// 设定标签的宽度、高度、打印速度、打印浓度、感应器类别、Gap/Black mark垂直间距、Gap/Black mark偏移距离
TscLibDll.INSTANCE.setup("80.6", "201", "5", "8", "1", "2", "0");
TscLibDll.INSTANCE.clearbuffer();
// TscLibDll.INSTANCE.sendcommand("PUTPCX 550,10,\"UL.PCX\"");
/*
1、ActiveXprinterfont采用机器内置编码通常用来打英文。
2、ActiveXwindowsfont可以输出汉字,但是必须是系统中存在的字体。
TSCObj.ActiveXprinterfont ("a","b","c","d","e","f","g");
a:字符串,文字X方向起始点,以点表示。
b:字符串,文字Y方向起始点,以点表示。
c:內建字型名称,共12种(1: 8*12 dots 2: 12*20 dots 3: 16*24 dots 4: 24*32 dots 5: 32*48 dots TST24.BF2: 繁體中文 24*24 TST16.BF2: 繁體中文 16*16 TTT24.BF2: 繁體中文 24*24 (電信碼) TSS24.BF2: 簡體中文 24*24 TSS16.BF2: 簡體中文 16*16 K: 韓文 24*24 L: 韓文 16*16 )
d:字符串,旋转角度
e:字符串,X方向放大倍率1-8
f:字符串,Y方向放大倍率1-8
g:字符串,打印内容
ActiveXwindowsfont(a,b,c,d,e,f,g,h)
说明:使用Windows TTF字体打印文字。
参数:
a:整数类型,文字X方向起始点,以点表示。
b:整数类型,文字Y方向起始点,以点表示。
c:整数类型,字体高度,以点表示。
d:整数类型,旋转角度,逆时针方向旋转。0-旋转0°,90-旋转90°,180-旋转180°,270-旋转270°。
e:整数类型,字体外形。0:标签;1:斜体;2:粗体;3:粗斜体。
f:整数类型,下划线,0:无下划线;1:加下划线。
g:字符串类型,字体名称。如:Arial,Times new Roman。
h:字符串类型,打印文字内容。
int startX = 200, startY = 1300, angle = 90, rowHight = 50;
TscLibDll.INSTANCE.windowsfont(startX, startY, 42, angle, 2, 0, "Arial", title);
int index = 1;
for(String str : others){
TscLibDll.INSTANCE.windowsfont(startX+(index++)*rowHight, startY, 36, angle, 0, 0, "Arial", str);
}
/*
纠错级别:L、M、Q、H
*/
//var cmd = 'QRCODE 条码X方向起始点,条码Y方向起始点,纠错级别,二维码高度,A(A和M),旋转角度,M2(分为类型1和类型2),S1 (s1-s8,默认s7),\"1231你好2421341325454353\"';
String command = "QRCODE 200,600,Q,7,A,0,M2,S7,\"" + qrCode + "\""; // 打印二维码的参数和内容
TscLibDll.INSTANCE.sendcommand(command); // 传送指令
// (打印份数,每页打印张数)
TscLibDll.INSTANCE.printlabel(""+copies, "1");
TscLibDll.INSTANCE.closeport();
System.exit(0);
}
}