在我们的实际工作中,经常需要实现打印功能。但由于历史原因,Java 提供的打印功能一直都比较弱。实际上最初的 jdk 根本不支持打印,直到 jdk1.1 才引入了很轻量的打印支持。实际上,SUN 公司也一直致力于 Java 打印功能的完善,而 Java2 平台则终于有了一个健壮的打印模式的开端, jdk1.4 则提供了一套完整的"Java 打印服务 API" (Java Print Service API),它对已有的打印功能是积极的补充。
这里打印对象主要是图片和pdf文件两种常见形式,其他office文件可以通过相应程序转成pdf进行打印,比如aspose(收费,需要破解)/openoffice(需要先搭建本地服务)/Jacob(只有windows)
首先要保证电脑GUI打印能正常运行,否则连打印机都没有连接,那怎么打印?
打印JPG图片格式的文件,本次采用的Java原生的打印方式。jdk1.4之后对打印功能有了很好的支持。Java 的打印 API 主要存在于 java.awt.print
包中。而 jdk1.4 新增的类则主要存在于 javax.print 包及其相应的子包 javax.print.event
和 javax.print.attribute
中。其中** javax.print 包中主要包含打印服务的相关类,而 javax.print.event 则包含打印事件的相关定义,javax.print.attribute 则包括打印服务的可用属性列表等**。可以很好的解决打印JPG图片格式的需求。
优点:jdk的原生支持的打印功能,可直接使用,支持设置各项打印参数。
缺点:局限性较大,只能打印一些图片和文本格式的文件。
public class PrintUtil {
/**
* 打印图片
* @param file
* @param printerName
* @throws PrintException
*/
public static void JPGPrint(File file,String printerName) throws PrintException {
if (file == null||printerName==null) {
System.err.println("缺少打印文件或者缺少打印机参数");
}
InputStream fis = null;
try {
// 设置打印格式,如果未确定类型,可选择autosense
// 设置为jpg格式
DocFlavor flavor = DocFlavor.INPUT_STREAM.JPEG;
// 设置打印参数
PrintRequestAttributeSet hashset = new HashPrintRequestAttributeSet();
//份数
hashset.add(new Copies(1));
//装订
//hashset.add(Finishings.STAPLE);
//单双面
hashset.add(Sides.DUPLEX);
// 颜色
hashset.add(Chromaticity.COLOR);
// 定位打印服务
PrintService printService = null;
if (printerName != null) {
//获得本台电脑连接的所有打印机
PrintService[] printServices = PrinterJob.lookupPrintServices();
if(printServices == null || printServices.length == 0) {
System.out.print("打印失败,未找到可用打印机,请检查。");
return ;
}
//匹配指定打印机
for (int i = 0;i < printServices.length; i++) {
if (printServices[i].getName().contains(printerName)) {
printService = printServices[i];
break;
}
}
if(printService==null){
System.out.print("打印失败,未找到名称为" + printerName + "的打印机,请检查。");
return ;
}
}
// 构造待打印的文件流
fis = new FileInputStream(file);
Doc doc = new SimpleDoc(fis, flavor, null);
// 创建打印作业
DocPrintJob job = printService.createPrintJob();
job.print(doc, hashset);
} catch (FileNotFoundException e1) {
System.err.println("文件未找到");
e1.printStackTrace();
} finally {
// 关闭打印的文件流
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws Exception {
JPGPrint(new File("D:\\share\\111.jpg"),"MI");
}
}
这里pdf打印可能和硬件有关系,需要安装Adobe Reader,而且现在pdf也不使用此方法打印,可以用作借鉴
public class PrintUtil {
/**
* 打印服务
* @param file 文件
* @Param printerName 打印机名字
* @param num 打印份数
*/
public static void paperPrint(File file, String printerName, int num){
// 构建打印请求属性集
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
// 设置打印格式
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
// 查找所有的打印服务
PrintService[] printServices = PrintServiceLookup.lookupPrintServices(flavor, pras);
// 打印服务
PrintService printService = null;
for (PrintService ps : printServices) {
String psName = ps.toString();
// 选用指定打印机,需要精确查询打印机就用equals,模糊查询用contains,这里使用了模糊查找
if (psName.contains(printerName)) {
printService=ps;
break;
}
}
// 如果找不到打印机
if(printService == null){
System.err.println("找不到打印机");
return;
}
// 文件不存在
if (!file.exists() || !file.isFile()) {
System.err.println("文件不存在");
return;
}
String fileName = file.getName();
// 获取图片后缀名,设置打印文件格式
String suffix = fileName.substring(fileName.lastIndexOf(".") + 1);
switch (suffix) {
case "jpg":
case "jpeg":
flavor = DocFlavor.INPUT_STREAM.JPEG;
break;
case "png":
flavor = DocFlavor.INPUT_STREAM.PNG;
break;
case "pdf":
flavor = DocFlavor.INPUT_STREAM.PDF;
break;
case "gif":
flavor = DocFlavor.INPUT_STREAM.GIF;
break;
default:
System.err.println("其他类别文件不支持打印");
return;
}
// 设置打印文件名
pras.add(new JobName(fileName, Locale.CHINA));
// 设置打印方向
pras.add(OrientationRequested.LANDSCAPE);
// 设置打印区域
//MediaPrintableArea mp = new MediaPrintableArea(0, 100, 230, 203, Size2DSyntax.MM);
//pras.add(mp);
// 设置彩打或者黑白打印
pras.add(Chromaticity.MONOCHROME);
try {
FileInputStream fis = new FileInputStream(file);
HashDocAttributeSet das = new HashDocAttributeSet();
for (long i = 0; i < num; i++) {
// 使用打印服务生成打印任务
DocPrintJob job = printService.createPrintJob();
// 获取需要打印的文档类doc
SimpleDoc doc = new SimpleDoc(fis, flavor, das);
// 监听打印任务
job.addPrintJobListener(new PrintJobListener() {
@Override
public void printDataTransferCompleted(PrintJobEvent pje) {
System.out.println("成功发送任务:" + fileName);
}
@Override
public void printJobCompleted(PrintJobEvent pje) {
System.out.println("打印任务完成!");
}
@Override
public void printJobFailed(PrintJobEvent pje) {
System.out.println("打印任务失败:" + fileName);
}
@Override
public void printJobCanceled(PrintJobEvent pje) {
System.out.println("取消打印任务!");
}
@Override
public void printJobNoMoreEvents(PrintJobEvent pje) {
System.out.println("没有更多方法提供打印机调用!");
}
@Override
public void printJobRequiresAttention(PrintJobEvent pje) {
System.out.println("纸张已用完");
}
});
job.print(doc, pras);
}
} catch (PrintException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
paperPrint(new File("D:\\share\\111.png"),"MI",1);
//paperPrint(new File("D:\\share\\123.pdf"),"MI",1);
}
}
这里使用Apache PDFbox来实现进行PDF文件格式的打印。Apache PDFbox是一个开源的、基于Java的、支持PDF文档生成的工具库,它可以用于创建新的PDF文档,修改现有的PDF文档,还可以从PDF文档中提取所需的内容。Apache PDFBox还包含了数个命令行工具。在此,我们只研究打印功能。
首先导入依赖
<dependency>
<groupId>org.apache.pdfboxgroupId>
<artifactId>pdfboxartifactId>
<version>2.0.6version>
dependency>
具体代码实现
public class PrintUtil {
public static PrinterJob getPrintServiceByName(String printerName) throws Exception{
PrinterJob job = PrinterJob.getPrinterJob();
// 遍历查询打印机名称
boolean flag = false;
for (PrintService ps : PrinterJob.lookupPrintServices()) {
String psName = ps.toString();
// 选用指定打印机,需要精确查询打印机就用equals,模糊查询用contains,这里使用了模糊查找
if (psName.contains(printerName)) {
flag = true;
job.setPrintService(ps);
break;
}
}
if(!flag){
System.err.println("未找到打印机");
throw new RuntimeException("打印失败,未找到名称为" + printerName + "的打印机,请检查你的打印机名字");
}
return job;
}
/**
* 获取打印纸的大小范围
* @return
*/
public static Paper getPaper() {
Paper paper = new Paper();
// 默认为A4纸张,对应像素宽和高分别为 595, 842
int width = 595;
int height = 842;
// 设置边距,单位是像素,10mm边距,对应 28px
int marginLeft = 10;
int marginRight = 0;
int marginTop = 10;
int marginBottom = 0;
paper.setSize(width, height);
// 下面一行代码,解决了打印内容为空的问题
paper.setImageableArea(marginLeft, marginRight, width - (marginLeft + marginRight), height - (marginTop + marginBottom));
return paper;
}
/**
* 设置打印属性
* @param
*/
public static void paperPDFPrint(PDDocument document, PrinterJob job) {
try {
// 设置纸张及缩放
PDFPrintable pdfPrintable = new PDFPrintable(document, Scaling.ACTUAL_SIZE);
// 设置多页打印
Book book = new Book();
// 设置打印格式
PageFormat pageFormat = new PageFormat();
//设置纸张
pageFormat.setPaper(getPaper());
// 设置打印纸的方向,这是纵向
pageFormat.setOrientation(PageFormat.PORTRAIT);
// 设置一些属性 是否缩放 打印张数等
book.append(pdfPrintable, pageFormat, document.getNumberOfPages());
job.setPageable(book);
// 设置打印份数
job.setCopies(1);
//添加打印属性
HashPrintRequestAttributeSet pars = new HashPrintRequestAttributeSet();
// 设置单双页
pars.add(Sides.ONE_SIDED);
// 设置彩打或者黑白打印
pars.add(Chromaticity.MONOCHROME);
// 打印质量
pars.add(PrintQuality.NORMAL);
// 这是直接打印
job.print(pars);
} catch (PrinterException e) {
System.err.println("未正常连接打印机");
e.printStackTrace();
} catch (Exception e){
System.err.println("打印机打印异常");
e.printStackTrace();
}
}
/**
* 打印pdf文件
* @param pdfPath
* @param printerName
* @return
* @throws Exception
*/
public static PDDocument printPdf(String pdfPath, String printerName) throws Exception {
File file = new File(pdfPath);
PDDocument document = PDDocument.load(file);
PrinterJob job = getPrintServiceByName(printerName);
paperPDFPrint(document, job);
return document;
}
public static void main(String[] args) throws Exception {
printPdf("D:\\share\\123.pdf","MI");
}
}
参考文章:
https://blog.csdn.net/vatxiongxiaohui/article/details/83985896
https://blog.csdn.net/weixin_45944086/article/details/108148264
https://blog.csdn.net/weixin_46031754/article/details/121670267