Java实现打印功能

JPG图片文件格式打印实现

打印JPG图片格式的文件,本次采用的Java原生的打印方式。

public static void main(String[] argv) throws Exception {File file = new File("E:\\a.jpg");String printerName = "HP MFP M436 PCL6";//打印机名包含字串PDFPrint(file,printerName);}
// 传入文件和打印机名称
public static void JPGPrint(File file,String printerName) throws PrintException {if (file == null) {System.err.println("缺少打印文件");}InputStream fis = null;try {// 设置打印格式,如果未确定类型,可选择autosenseDocFlavor flavor = DocFlavor.INPUT_STREAM.JPEG;// 设置打印参数PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();aset.add(new Copies(1)); //份数//aset.add(MediaSize.ISO.A4); //纸张// aset.add(Finishings.STAPLE);//装订aset.add(Sides.DUPLEX);//单双面// 定位打印服务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++) {System.out.println(printServices[i].getName());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, aset);} catch (FileNotFoundException e1) {e1.printStackTrace();} finally {// 关闭打印的文件流if (fis != null) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}}
}
}

PDF文件格式打印实现

使用Apache PDFbox来实现进行PDF文件格式的打印

1.PDF文件格式打印实现

<dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.6</version>
</dependency>
public static void main(String[] args) throws Exception {
String pdfFile = "E:\\a.pdf";//文件路径
File file = new File(pdfFile);
String printerName = "HP MFP M436 PCL6";//打印机名包含字串
print(file,printerName);
}
public static void PDFprint(File file ,String printerName) throws Exception {
PDDocument document = null;
try {
document = PDDocument.load(file);
PrinterJob printJob = PrinterJob.getPrinterJob();
printJob.setJobName(file.getName());
if (printerName != null) {
// 查找并设置打印机
//获得本台电脑连接的所有打印机
PrintService[] printServices = PrinterJob.lookupPrintServices();                			 if(printServices == null || printServices.length == 0) {
System.out.print("打印失败,未找到可用打印机,请检查。");
return ;
}
PrintService printService = null;
//匹配指定打印机
for (int i = 0;i < printServices.length; i++) {
System.out.println(printServices[i].getName());
if (printServices[i].getName().contains(printerName)) {
printService = printServices[i];
break;
}
}
if(printService!=null){
printJob.setPrintService(printService);
}else{
System.out.print("打印失败,未找到名称为" + printerName + "的打印机,请检查。");
return ;
}
}
//设置纸张及缩放
PDFPrintable pdfPrintable = new PDFPrintable(document, Scaling.ACTUAL_SIZE);
//设置多页打印
Book book = new Book();
PageFormat pageFormat = new PageFormat();
//设置打印方向
pageFormat.setOrientation(PageFormat.PORTRAIT);//纵向
pageFormat.setPaper(getPaper());//设置纸张
book.append(pdfPrintable, pageFormat, document.getNumberOfPages());
printJob.setPageable(book);
printJob.setCopies(1);//设置打印份数
//添加打印属性
HashPrintRequestAttributeSet pars = new HashPrintRequestAttributeSet();
pars.add(Sides.DUPLEX); //设置单双页
printJob.print(pars);
}finally {
if (document != null) {
try {
document.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
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;
}

2.java 利用 pdfbox 实现PDF转为图片

    <dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.16</version></dependency><dependency><groupId>org.apache.pdfbox</groupId><artifactId>fontbox</artifactId><version>2.0.16</version></dependency>
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.icepdf.core.exceptions.PDFException;
import org.icepdf.core.exceptions.PDFSecurityException;
import org.icepdf.core.pobjects.Document;
import org.icepdf.core.pobjects.Page;
import org.icepdf.core.util.GraphicsRenderingHints;import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;public class PDF2ImageUtil {/*** 经过测试,dpi为96,100,105,120,150,200中,* 120,150,200显示效果较为清晰,体积稳定,dpi越高图片体积越大* 分享遇到的坑:* 1.如何解决 Linux 环境下乱码的问题:重写 UnixFontDirFinder 类,修改 Linux 环境下获取字体文件的路径,改为取项目里的字体文件(使用 pdfbox 转图片时的方法,使用 icepdf 请自行研究)* 2.如果后续遇到乱码的问题,查看日志看看缺少什么字体,然后将字体文件上传到项目的 src/main/resources/fonts 目录下即可*/public static final float DEFAULT_DPI = 200;public static final String DEFAULT_FORMAT = "jpg";/*** pdf转图片,demo* (使用 pdfbox)* @param pdfPath PDF路径* @imgPath img路径* @page_end 要转换的页码,也可以定义开始页码和结束页码,根据需求自行添加*/public static void pdfToImage(String pdfPath, String imgPath,int page_end) {try {//图像合并使用参数// 总宽度int width = 0;// 保存一张图片中的RGB数据int[] singleImgRGB;int shiftHeight = 0;//保存每张图片的像素值BufferedImage imageResult = null;//利用PdfBox生成图像PDDocument pdDocument = PDDocument.load(new File(pdfPath));PDFRenderer renderer = new PDFRenderer(pdDocument);//循环每个页码for (int i = 0, len = pdDocument.getNumberOfPages(); i < len; i++) {if (i==page_end) {BufferedImage image = renderer.renderImageWithDPI(i, DEFAULT_DPI, ImageType.RGB);int imageHeight = image.getHeight();int imageWidth = image.getWidth();//计算高度和偏移量//使用第一张图片宽度;width = imageWidth;//保存每页图片的像素值imageResult = new BufferedImage(width, imageHeight, BufferedImage.TYPE_INT_RGB);//这里有高度,可以将imageHeight*len,我这里值提取一页所以不需要singleImgRGB = image.getRGB(0, 0, width, imageHeight, null, 0, width);// 写入流中imageResult.setRGB(0, shiftHeight, width, imageHeight, singleImgRGB, 0, width);}else i**粗体**f(i>page_end) {continue;}}pdDocument.close();// 写图片ImageIO.write(imageResult, DEFAULT_FORMAT, new File(imgPath));} catch (Exception e) {e.printStackTrace();}}/*** 将PDF转化为图片* (使用 pdfbox)* @param pdDocument PDF对象* @param page_end 要转换的页码,发票一般是一页,取第一页* @return*/public static BufferedImage pdfToImage(PDDocument pdDocument,int page_end) {//保存每张图片的像素值BufferedImage imageResult = null;try {//图像合并使用参数// 总宽度int width = 0;// 保存一张图片中的RGB数据int[] singleImgRGB;int shiftHeight = 0;//利用PdfBox生成图像PDFRenderer renderer = new PDFRenderer(pdDocument);//循环每个页码for (int i = 0, len = pdDocument.getNumberOfPages(); i < len; i++) {if (i==page_end) {BufferedImage image = renderer.renderImageWithDPI(i, DEFAULT_DPI, ImageType.RGB);int imageHeight = image.getHeight();int imageWidth = image.getWidth();//计算高度和偏移量//使用第一张图片宽度;width = imageWidth;//保存每页图片的像素值imageResult = new BufferedImage(width, imageHeight, BufferedImage.TYPE_INT_RGB);//这里有高度,可以将imageHeight*len,我这里值提取一页所以不需要singleImgRGB = image.getRGB(0, 0, width, imageHeight, null, 0, width);// 写入流中imageResult.setRGB(0, shiftHeight, width, imageHeight, singleImgRGB, 0, width);}else if(i>page_end) {continue;}}pdDocument.close();} catch (Exception e) {e.printStackTrace();}return imageResult;}/*** 将pdf转为图片(不建议使用)*(使用 icepdf)* @param pdfContent pdf数据流* @param zoom 缩略图显示倍数,1表示不缩放,0.3则缩小到30%,倍数越大越清晰,图片也越大,转换得也越慢* @return* @throws PDFException* @throws PDFSecurityException* @throws IOException*/public static ByteArrayOutputStream tranferPDF2Img(byte[] pdfContent, float zoom) throws PDFException, PDFSecurityException, IOException {Document document = null;float rotation = 0f;// 旋转角度if(pdfContent == null){throw new RuntimeException("pdf文件内容不能为空");}ByteArrayInputStream bin = new ByteArrayInputStream(pdfContent);ByteArrayOutputStream out =  new ByteArrayOutputStream();document = new Document();document.setInputStream(bin, null);int maxPages = document.getPageTree().getNumberOfPages();for (int i = 0; i < maxPages; i++) {BufferedImage img = null;try {img = (BufferedImage) document.getPageImage(i, GraphicsRenderingHints.SCREEN, Page.BOUNDARY_CROPBOX, rotation, zoom);} catch (InterruptedException e) {e.printStackTrace();}try {ImageIO.write(img, DEFAULT_FORMAT, out);} catch (IOException e) {throw new RuntimeException("pdf内容读取异常", e);}img.flush();}return out;}}

获取到流后调用方法转为图片返回给前台

// 开发中可以直接读取文件,测试、生产时代码中改为加载 InputStream
PDDocument pdDocument = PDDocument.load(new File("F:\\destop\\1.pdf"));
BufferedImage bufferedImage= PDF2ImageUtil.pdfToImage(pdDocument, 0);
ImageIO.write(bufferedImage, "jpg", outImage);    

遇到的问题
当时放到测试环境后一直显示乱码,看了下报错是说字体不存在。第一个想法是在主机上安装字体,但是又有问题了,生产不可能这样吧,运维也不同意啊。
在这里插入图片描述

想想还是研究研究 pdfbox 的源码吧,分析后发现它是根据不同系统来读取字体的文件夹的,然后一个同事建议我重写读写 Linux 系统文件的类,指向我们项目的文件夹,然后在项目新建一个文件夹来存放需要的字体。

Linux 读取的是以下这几个目录: “/usr/local/fonts”, “/usr/local/share/fonts”, “/usr/share/fonts”, “/usr/X11R6/lib/X11/fonts”

MAC: “/Library/Fonts/”, “/Library/Fonts/”, “/System/Library/Fonts/”, “/Network/Library/Fonts/”

Windows: C:\Windows\Fonts

说干就干,将目录指向我新建的font文件夹,果然ok了。 需要注意的是,后面如果pdf有用到新的字体,就需要将对应的字体下载下来,放到该目录下。

package org.apache.fontbox.util.autodetect;import com.ai.ecs.h5.view.common.pdf.PdfController;public class UnixFontDirFinder extends NativeFontDirFinder {public UnixFontDirFinder() {}protected String[] getSearchableDirectories() {return new String[]{PdfController.class.getResource("/").getPath()+"/fonts/"};}
}

3.java 往 pdf 插入数据 (pdfbox+poi)

指定页码插入/替换
pdfbox好像没有专门提供这个方法,但是现有的方法多重组合起来也能实现这个功能,

需求:一个pdf文件A有10页,现在想在第6页插入一页新的pdf文件B,插入完成后整个pdf文件A变成11页。

思路1(插入):
  先将这个10的pdf拆分成10个1页的pdf,按顺序放好,文件名分别是:1.pdf、2.pdf…10.pdf。再拆分到第6页的时候将文件B放进来,重命名问6.pdf,原本pdf文件A里面的第6页重命名为7.pdf,依次后推,最后的得到的1.pdf----->11.pdf一共11个文件

然后使合并功能将这个11个pdf按顺序合并。

思路2(替换):
  在插入的基础上,拆分的时候将pdf文件A里面的第6个页丢弃,使用新的页面来代替它命名6.pdf,然后合并就完事了。

1.pom<!--pdfbox-->
<dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox-tools</artifactId><version>2.0.25</version>
</dependency>
<dependency><groupId>net.sf.cssbox</groupId><artifactId>pdf2dom</artifactId><version>2.0.1</version>
</dependency><!--poi-->
<dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.10</version>
</dependency>
<dependency><groupId>com.itextpdf.tool</groupId><artifactId>xmlworker</artifactId><version>5.5.10</version>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.15</version>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-scratchpad</artifactId><version>3.15</version>
</dependency>2.实现方法/**from fhadmin.cn* 指定页码插入页* @param filename1  源pdf路径* @param filename2  需要插入的pdf路径* @param number     插入的页码* @param newfilename   全新pdf的路径* @throws Exception*/
public void insertPage(String filename1,String filename2,int number,String newfilename,String tempPath) throws Exception {PDDocument pdf1 = PDDocument.load(new File(filename1));PDDocument pdf2 = PDDocument.load(new File(filename2));//1、将第一个pdf按页码全部拆开Splitter splitter = new Splitter();List<PDDocument> Pages = splitter.split(pdf1);Iterator<PDDocument> iterator = Pages.listIterator();PDFMergerUtility PDFmerger = new PDFMergerUtility();int i = 1;while(iterator.hasNext()) {if(i==number){System.out.println("当前插入页码:"+number);pdf2.save(tempPath+"/"+ i +".pdf");i++;}PDDocument pd = iterator.next();String tempFile = tempPath+"/"+ i +".pdf";System.out.println("开始拆分:"+tempFile);pd.save(tempFile);i++;}//2、开始重组PDFmerger.setDestinationFileName(newfilename);//上面的i最后多加了一次,这里不取等for(int j=1;j<i;j++){String tempFile = tempPath+"/"+ j +".pdf";System.out.println("开始合并:"+tempFile);PDFmerger.addSource(tempFile);}//合并文档PDFmerger.mergeDocuments();System.out.println("文档合并完成");pdf1.close();pdf2.close();
}3.测试
//from fhadmin.cn
@Test
void insertPage() throws Exception {PdfUtils pdfUtils = new PdfUtils();String filename1 = "F:\\Users\\admin\\Desktop\\A.pdf";String filename2 = "F:\\Users\\admin\\Desktop\\B.pdf";String newfilename = "F:\\Users\\admin\\Desktop\\newA.pdf";String tempPath = "F:\\Users\\admin\\Desktop\\temp";int insertNum = 32;pdfUtils.insertPage(filename1,filename2,insertNum,newfilename,tempPath);
}

4.使用 Apache PDFBox 操作PDF文件

Apache PDFBox的主要功能如下:

  • 从PDF文件中提取Unicode文本。
  • 将单个PDF拆分成多个文件或合并多个PDF文件。
  • 从PDF表单中提取数据或填写PDF表单。
  • 验证PDF文件是否符合 PDF/A-1b 标准。
  • 使用标准的Java打印API打印PDF文件。
  • 将PDF另存为图像文件,例如PNG或JPEG。
  • 从头开始创建PDF,包括嵌入字体和图像。
  • 对PDF文件进行数字签名。
<dependency><groupId>org.apache.pdfbox</groupId><artifactId>pdfbox</artifactId><version>2.0.28</version>
</dependency>

创建PDF文档

import java.io.File;
import java.io.IOException;import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.font.PDType1Font;public class CreatePDF {public static void main(String[] args) {PDDocument document = new PDDocument();PDPage page = new PDPage();document.addPage(page);PDType1Font font = PDType1Font.HELVETICA_BOLD;try {PDPageContentStream contentStream = new PDPageContentStream(document, page);contentStream.beginText();contentStream.setFont(font, 12);contentStream.newLineAtOffset(100, 700);contentStream.showText("Hello, World!");contentStream.endText();contentStream.close();document.save(new File("one-more.pdf"));document.close();System.out.println("PDF created successfully.");} catch (IOException e) {e.printStackTrace();}}
}

这个代码段创建一个新的PDF文档,并在其第一页上写入"Hello, World!"。我使用了Helvetica Bold字体,并将其大小设置为12。
接下来,我将文本显示在PDF页面上,并使用contentStream.close()方法关闭PDPageContentStream对象。
最后,我将文档保存为"one-more.pdf"文件,然后关闭PDDocument对象。
读取PDF文件

import java.io.File;
import java.io.IOException;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;public class ReadPDFExample {public static void main(String[] args) {// 创建文件对象File file = new File("one-more.pdf");try {// 创建 PDF 文档对象PDDocument document = PDDocument.load(file);// 创建 PDF 文本剥离器PDFTextStripper stripper = new PDFTextStripper();// 获取 PDF 文件的全部内容String text = stripper.getText(document);// 输出 PDF 文件的全部内容System.out.println(text);// 关闭 PDF 文档对象document.close();} catch (IOException e) {e.printStackTrace();}}
}

首先,创建一个文件对象,然后使用 PDDocument 类的静态方法 load() 加载 PDF 文件并创建一个 PDF 文档对象。
然后,我们创建一个 PDFTextStripper 对象,并使用它的 getText() 方法获取 PDF 文件的全部内容。
最后,我们输出 PDF 文件的全部内容,并关闭 PDF 文档对象。
输出内容就是之前我们写入的
插入图片

import java.io.File;
import java.io.IOException;import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;public class InsertImageInPDF {public static void main(String[] args) {try {// 加载PDF文件PDDocument document = PDDocument.load(new File("one-more.pdf"));// 获取第一页PDPage page = document.getPage(0);// 加载图像文件PDImageXObject image = PDImageXObject.createFromFile("one-more.jpg", document);// 在指定位置插入图像PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true, true);contentStream.drawImage(image, 200, 500, image.getWidth(), image.getHeight());// 关闭流contentStream.close();// 保存修改后的PDF文件document.save("one-more-jpg.pdf");// 关闭文档document.close();System.out.println("PDF created successfully.");} catch (IOException e) {e.printStackTrace();}}
}

读取图片

import java.io.IOException;
import java.util.List;import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;public class ReadPDFImagesExample {public static void main(String[] args) {try {// 加载PDF文件PDDocument document = PDDocument.load(new File("one-more-jpg.pdf"));PDPageTree pageTree = document.getPages();// 遍历每个页面for (PDPage page : pageTree) {int pageNum = pageTree.indexOf(page) + 1;int count = 1;System.out.println("Page " + pageNum + ":");for (COSName xObjectName : page.getResources().getXObjectNames()) {PDXObject pdxObject = page.getResources().getXObject(xObjectName);if (pdxObject instanceof PDImageXObject) {PDImageXObject image = (PDImageXObject) pdxObject;System.out.println("Found image with width "+ image.getWidth()+ "px and height "+ image.getHeight()+ "px.");String fileName = "one-more-" + pageNum + "-" + count + ".jpg";ImageIO.write(image.getImage(), "jpg", new File(fileName));count++;}}}document.close();} catch (IOException e) {e.printStackTrace();}}
}

我们使用PDDocument类从指定的PDF文件中加载文档,并遍历每个页面以查找其中的图像。

对于每个页面,我们获取其资源(包括图像)并检查其中是否存在图像。

如果存在,则我们遍历它们,并使用PDImageXObject对象获取它们的属性,例如宽度和高度。

然后,使用ImageIO把图片保存到本地文件系统。

5.PDFBox创建并打印PDF文件, 以及缩放问题的处理.

创建PDF文件

      public static byte[] createHelloPDF() {ByteArrayOutputStream out = new ByteArrayOutputStream();try {PDDocument doc = new PDDocument();PDPage page = new PDPage();doc.addPage(page);PDFont font = PDType1Font.HELVETICA_BOLD;PDPageContentStream content = new PDPageContentStream(doc, page);content.beginText();content.setFont(font, 20);content.moveTextPositionByAmount(250, 700);content.drawString("Hello Print!");content.endText();content.close();doc.save(out);doc.close();} catch (Exception e) {e.printStackTrace();}return out.toByteArray();}

这边如果不把他save到byte[]里, 而是直接close, 返回PDDocument 给外部文件.
可能会出现Cannot read while there is an open stream writer

打印文件

         // 获取本地创建的空白PDF文件PDDocument document = PDDocument.load(createHelloPDF());// 加载成打印文件PDFPrintable printable = new PDFPrintable(document);PrinterJob job = PrinterJob.getPrinterJob();job.setPrintable(printable);job.print();

如需要打印自定义纸张, 参加另外一篇博客 使用PDFBox打印自定义纸张的PDF

如果想要读取本地pdf文件, 那就更简单了, 直接

        InputStream in = new FileInputStream("d:\\cc.pdf");PDDocument document = PDDocument.load(in); 

缩放问题
不过发现打印出来的pdf文件存在缩放问题. 显得边距很大, 能跑马.
研究了下, 发现PDFPrintable可以接受是否缩放的参数.

          public enum Scaling {// 实际大小ACTUAL_SIZE,// 缩小SHRINK_TO_FIT,// 拉伸STRETCH_TO_FIT,// 适应SCALE_TO_FIT;private Scaling() {}}

因此只要在 new PDFPrintable(document), 传入Scaling, 就不会缩放了.

Scaling.ACTUAL_SIZE

6.Java调用PDFBox打印自定义纸张PDF

打印对象
一份设置为A3纸张, 页面边距为(10, 10, 10, 10)mm的PDF文件.
PageFormat
默认PDFPrintable无法设置页面大小.

         PDFPrintable printable = new PDFPrintable(document);PrinterJob job = PrinterJob.getPrinterJob();job.setPrintable(printable);

需要把它放到一个Book中, 再设置即可

         Book book = new Book();book.append(printable, pageFormat);printerJob.setPageable(book);printerJob.print();

设置纸张属性

         Paper paper = new Paper();paper.setSize(width, height);// 设置边距paper.setImageableArea(marginLeft, marginRight, width - (marginLeft + marginRight), height - (marginTop + marginBottom));// 自定义页面设置PageFormat pageFormat = new PageFormat();// 设置页面横纵向pageFormat.setOrientation(PageFormat.PORTRAIT);pageFormat.setPaper(paper);

注意: 这边计量单位都是在dpi 72下的尺寸.

如果拿到是mm, 需要转为px. 例如10mm转换

10 * 72 * 10 / 254 = 28px

如果打印出现了截断, 一般是因为没有添加自定义纸张导致的.
Java读取打印机自定义纸张.

         InputStream in = new FileInputStream("d:\\a3.pdf");PDDocument document = PDDocument.load(in);PDFPrintable printable = new PDFPrintable(document, Scaling.ACTUAL_SIZE);PrinterJob printerJob = PrinterJob.getPrinterJob();PaperSize a3 = PaperSize.PAPERSIZE_A3;// A3 纸张在72 dpi下的宽高 841 * 1190int width = a3.getWidth().toPixI(72);int height = a3.getHeight().toPixI(72);// 10mm边距, 对应 28pxint marginLeft = 28;int marginRight = 28;int marginTop = 28;int marginBottom = 28;Paper paper = new Paper();paper.setSize(width, height);// 设置边距paper.setImageableArea(marginLeft, marginRight, width - (marginLeft + marginRight), height - (marginTop + marginBottom));// 自定义页面设置PageFormat pageFormat = new PageFormat();// 设置页面横纵向pageFormat.setOrientation(PageFormat.PORTRAIT);pageFormat.setPaper(paper);Book book = new Book();book.append(printable, pageFormat);printerJob.setPageable(book);printerJob.print();

word文件格式打印实现

有两种:一种是直接使用jacob进行打印;另外一种则是转换为pdf进行打印

1.Word文件采用jacob插件进行打印实现。

Jacob是一个 Java到微软的com接口的桥梁。使用Jacob允许任何JVM访问com对象,从而使Java应用程序能够调用com对象。如果你要对 Word、Excel 进行处理,Jacob是一个好的选择。

优点:可以很好的处理word文档的相关操作。

缺点:必须手动引入dll文件,暂时未找到方法设置打印相关参数,只能暂时实现静默打印,还需安装office2003以上版本(lz是office365,未激活也可)。

具体实现如下:

①下载jacob.zip ,对应(86/64)的dll文件放在%Java_Home%jre/bin目录下。

下载地址:https://sourceforge.net/projects/jacob-project/

②导入jacob.jar到工程中

在工程中创建lib文件夹保存jacob.jar:reseources—lib—jacob.jar
添加Maven依赖:

        <!--添加本地的jacob.jar包-->
<dependency>
<groupId>com.jacob</groupId>
<artifactId>jacob</artifactId>
<version>1.19</version>
<scope>system</scope>
<systemPath>${basedir}/src/main/resources/lib/jacob.jar</systemPath>
</dependency>
public static void main(String[] args) {
String filePath = "E:\\a.docx";//文件路径
String printerName = "HP MFP M436 PCL6";//打印机名包含字串
printWord(filePath,printerName);
}
public static void printWord(String filePath, String printerName){
//        初始化线程
ComThread.InitSTA();
ActiveXComponent word = new ActiveXComponent("Word.Application");
//设置打印机名称
word.setProperty("ActivePrinter", new Variant(printerName));
// 这里Visible是控制文档打开后是可见还是不可见,若是静默打印,那么第三个参数就设为false就好了
Dispatch.put(word, "Visible", new Variant(false));
// 获取文档属性
Dispatch document = word.getProperty("Documents").toDispatch();
// 打开激活文挡
Dispatch doc=Dispatch.call(document, "Open", filePath).toDispatch();
//Dispatch doc = Dispatch.invoke(document, "Open", Dispatch.Method,
//  new Object[] { filePath }, new int[1]).toDispatch();
try{
Dispatch.callN(doc, "PrintOut");
System.out.println("打印成功!");
}catch (Exception e){
e.printStackTrace();
System.out.println("打印失败");
}finally {
try {
if (doc != null) {
Dispatch.call(doc, "Close", new Variant(0));//word文档关闭
}
} catch (Exception e2) {
e2.printStackTrace();
}
//退出
word.invoke("Quit", new Variant[0]);
//释放资源
ComThread.Release();
ComThread.quitMainSTA();
}
}

2.先将word转化为pdf文件,然后打印pdf

具体实现步骤如下:

①因为转化也是使用jacob插件,所以也需要根据第一种方法一样引入jacob相关依赖和文件

②打印pdf文件时,使用的是上面讲述的pdfbox插件,所以也需要引入pdfbox的依赖

        <dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.6</version>
</dependency>

首先将word文件转化为pdf文件

//word转化pdf,传入转换前的文件路径(例:"E:\\a.docx")和转换后的文件路径(例:"E:\\a.pdf")
public static void wordToPDF(String sFilePath,String toFilePath) {
System.out.println("启动 Word...");
long start = System.currentTimeMillis();
ActiveXComponent app = null;
Dispatch doc = null;
try {
app = new ActiveXComponent("Word.Application");
app.setProperty("Visible", new Variant(false));
Dispatch docs = app.getProperty("Documents").toDispatch();
doc = Dispatch.call(docs, "Open", sfilePath).toDispatch();
System.out.println("打开文档:" + sfilePath);
System.out.println("转换文档到 PDF:" + toFilePath);
File tofile = new File(toFilePath);
if (tofile.exists()) {
tofile.delete();
}
Dispatch.call(doc, "SaveAs", toFilePath, // FileName
17);//17是pdf格式
long end = System.currentTimeMillis();
System.out.println("转换完成..用时:" + (end - start) + "ms.");
} catch (Exception e) {
System.out.println("========Error:文档转换失败:" + e.getMessage());
} finally {
Dispatch.call(doc, "Close", false);
System.out.println("关闭文档");
if (app != null)
app.invoke("Quit", new Variant[]{});
}
// 如果没有这句话,winword.exe进程将不会关闭
ComThread.Release();
}

然后打印pdf文件(这里传入的文件为上面word转化生成的pdf文件)

//这里传入的文件为word转化生成的pdf文件
public static void PDFprint(File file ,String printerName) throws Exception {
PDDocument document = null;
try {
document = PDDocument.load(file);
PrinterJob printJob = PrinterJob.getPrinterJob();
printJob.setJobName(file.getName());
if (printerName != null) {
// 查找并设置打印机
//获得本台电脑连接的所有打印机
PrintService[] printServices = PrinterJob.lookupPrintServices();                			 if(printServices == null || printServices.length == 0) {
System.out.print("打印失败,未找到可用打印机,请检查。");
return ;
}
PrintService printService = null;
//匹配指定打印机
for (int i = 0;i < printServices.length; i++) {
System.out.println(printServices[i].getName());
if (printServices[i].getName().contains(printerName)) {
printService = printServices[i];
break;
}
}
if(printService!=null){
printJob.setPrintService(printService);
}else{
System.out.print("打印失败,未找到名称为" + printerName + "的打印机,请检查。");
return ;
}
}
//设置纸张及缩放
PDFPrintable pdfPrintable = new PDFPrintable(document, Scaling.ACTUAL_SIZE);
//设置多页打印
Book book = new Book();
PageFormat pageFormat = new PageFormat();
//设置打印方向
pageFormat.setOrientation(PageFormat.PORTRAIT);//纵向
pageFormat.setPaper(getPaper());//设置纸张
book.append(pdfPrintable, pageFormat, document.getNumberOfPages());
printJob.setPageable(book);
printJob.setCopies(1);//设置打印份数
//添加打印属性
HashPrintRequestAttributeSet pars = new HashPrintRequestAttributeSet();
pars.add(Sides.DUPLEX); //设置单双页
printJob.print(pars);
}finally {
if (document != null) {
try {
document.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
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;
}
File file=new File(toFilePath);
if(file.exists()&&file.isFile())
file.delete();

参考链接

java 打印pdf_java打印pdf文件

java 利用 pdfbox 实现PDF转为图片

java 往 pdf 插入数据 (pdfbox+poi)

使用 Apache PDFBox 操作PDF文件

PDFBox创建并打印PDF文件, 以及缩放问题的处理.

Java调用PDFBox打印自定义纸张PDF

【2023】java打印PDF(不需要调用浏览器直接静默打印)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/876768.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vite+vue3项目,开发时候正常,打包后router-view不渲染

这是个很奇怪的问题&#xff0c;但是基本上命名或者引入文件的方式导致的。要么文件名与系统的某些标签名一样&#xff0c;要么就是routes写成了routers。还有一种就是导入方式错误的 错误截图&#xff1a; 正确引入截图&#xff1a;

Flink大状态作业调优——DataStream篇

一、Flink 状态&#xff08;State&#xff09;简介 在流式计算中有些操作一次处理一个独立的事件(比如解析一个事件), 有些操作却需要记住多个事件的信息(比如窗口操作)。那些需要记住多个事件信息的操作就是有状态的。流式计算分为无状态计算和有状态计算两种情况。状态可以理…

Word题库转Excel关键字快速查询题库

一、前言 内部培训会有Word版本题库&#xff0c;考核时如果使用Word、Excel、PDF等文档进行关键字查询题目体验不佳。so&#xff0c;撸个软件吧&#xff01;   20240728更新&#xff1a;支持更多题库类型。 二、Word题库转Excel 1、Word题库格式要求 内容格式要求事例题目…

在 Postman 中设置全局 token

目录 问题描述解决方案 问题描述 在使用 Postman 进行接口测试时&#xff0c;经常会遇到在 Header 中添加 token 的情况。当接口数量较多时&#xff0c;需要为每个接口进行设置&#xff0c;而且当 token 失效时需要重新获取并设置&#xff0c;这样一来效率较低。 解决方案 下…

wpf中开发独立模块功能和左侧1个菜单的框架演示

此篇文章适用于有一定经验的wpf开发者&#xff0c;并且是团队协作开发模式&#xff0c;并且业务与此比较相近的话&#xff0c;用起来非常的方便。 我们在开发wpf程序的时候&#xff0c;比如1&#xff0c;2个人&#xff0c;那肯定随便怎么开发&#xff0c;都没事&#xff0c;代码…

Matlab M_map工具箱绘制Interrupted Mollweide Projection

GMT自带了许多的地图投影&#xff0c;但是对于Interrupted Mollweide投影效果却不好。 作为平替的m_map工具箱中带有的投影类型可完美解决这一问题。 Interrupted Mollweide Projection长这样 全球陆地 全球海洋 使用Matlab工具箱m_map展示全球海平面变化的空间分布 addpath(…

【Dart 教程系列第 49 篇】什么是策略设计模式?如何在 Dart 中使用策略设计模式

这是【Dart 教程系列第 49 篇】&#xff0c;如果觉得有用的话&#xff0c;欢迎关注专栏。 博文当前所用 Flutter SDK&#xff1a;3.22.1、Dart SDK&#xff1a;3.4.1 文章目录 一&#xff1a;什么是策略设计模式&#xff1f;二&#xff1a;为什么要使用策略设计模式&#xff1…

UG NX2406 安装教程

软件介绍 UG是一个交互式CAD/CAM(计算机辅助设计与计算机辅助制造)系统&#xff0c;它功能强大&#xff0c;可以轻松实现各种复杂实体及造型的建构。 它在诞生之初主要基于工作站&#xff0c;但随着PC硬件的发展和个人用户的迅速增长&#xff0c;在PC上的应用取得了迅猛的增长…

西蒙学习法

西蒙学习法 一根筋&#xff0c;挖死坑&#xff1b;会思考&#xff0c;持续不断的思考&#xff1b;会问问题&#xff0c;有深度的问题&#xff1b;一直想一个问题的解决办法&#xff1b; 资料 《世界十大学习方法》之西蒙学习法

【HarmonyOS】应用推送使用个推SDK如何实现?

【HarmonyOS】应用推送使用个推SDK如何实现&#xff1f; 前言 个推和极光都是市面上很成熟的推送第三方SDK了。今天讲讲个推SDK在鸿蒙中如何集成使用。 存在即合理&#xff0c;三方SDK推送给我们带来了极大的好处&#xff0c;首先在服务器后台处理一套API就可搞定&#xff0…

Matlab 命令行窗口默认输出(异常)

目录 前言Matlab 先验知识1 异常输出的代码2 正常输出的代码 前言 在单独调试 Matlab 写的函数时出现不想出现的异常打印值&#xff0c;逐个注释排查才找到是 if elseif else 代码块的问题&#xff0c;会默认打印输出 else 部分第一个返回值的值&#xff08;下方代码中的 P值&…

基于jeecgboot-vue3的Flowable流程仿钉钉流程设计器-抄送服务处理

因为这个项目license问题无法开源&#xff0c;更多技术支持与服务请加入我的知识星球。 1、因为仿钉钉设计器里抄送人是一个服务任务&#xff0c;所以要根据这个服务任务进行处理 2、前端就是一个抄送&#xff0c;选择人 3、这里用了jeecg的选择人组件 <el-form-item prop…

昇思25天学习打卡营第10天|xiaoyushao

从今天开始做一些实践应用&#xff0c;今天分享的是FCN图像语义分割。 全卷积网络&#xff08;Fully Convolutional Networks&#xff0c;FCN&#xff09;是UC Berkeley的Jonathan Long等人于2015年在Fully Convolutional Networks for Semantic Segmentation一文中提出的用于图…

培养前端工程化思维,不要让一行代码毁了整个程序

看《阿丽亚娜 5 号&#xff08;Ariane 5&#xff09;火箭爆炸》有感。 1、动手写项目之前&#xff0c;先进行全局性代码逻辑思考&#xff0c;将该做的事情&#xff0c;一些细节&#xff0c;统一建立标准&#xff0c;避免为以后埋雷。 2、避免使用不必要或无意义的代码、注释。…

极简Springboot+Mybatis-Plus+Vue零基础萌新都看得懂的分页查询(富含前后端项目案例)

目录 springboot配置相关 依赖配置 yaml配置 MySQL创建与使用 &#xff08;可拿软件包项目系统&#xff09; 创建数据库 创建数据表 mybatis-plus相关 Mapper配置 ​编辑 启动类放MapperScan 启动类中配置 添加config配置文件 Springboot编码 实体类 mapperc(Dao…

【第一篇章】初识XGBoost 揭开神秘面纱

XGBoost发展历程 XGBoost显著优势 XGBoost核心概念 XGBoost&#xff08;eXtreme Gradient Boosting&#xff09;是一种在机器学习领域广泛使用的集成学习算法&#xff0c;特别是在分类、回归和排序任务中表现出色。其基本原理建立在决策树、梯度提升和损失函数优化等核心概念之…

shell-awk命令详解

目录 一.概述 二.工作原理 三.工作流程 1.运行模式 2.运行流程 四.基本语法 1.命令格式 2.常用变量  五.变量类型 1.内建变量 2.内置变量 3.BEGIN END运算  4.awk高级用法 5.awk if语句 6.BEGIN END循环 一.概述 AWK是一种处理文本文件的语言&#xff0c;是一…

2024世界技能大赛某省选拔赛“网络安全项目”B模块--操作系统取证解析

2024世界技能大赛某省选拔赛“网络安全项目”B模块--操作系统取证解析 任务一、操作系统取证解析:总结:任务一、操作系统取证解析: A 集团某电脑系统被恶意份子攻击并控制,怀疑其执行了破坏操作,窃取了集团内部的敏感信息,现请分析 A 集团提供的系统镜像和内存镜像,找到…

国产大模型的逆袭:技术路径的策略与实践

〔探索AI的无限可能&#xff0c;微信关注“AIGCmagic”公众号&#xff0c;让AIGC科技点亮生活〕 一.聚焦长文本&#xff0c;国产大模型已有赶超GPT之势 1.1 理科能力差距较大&#xff0c;注重文科能力的提升 整体比较而言&#xff0c;国内大模型与GPT-4&#xff08;官网&…

树与二叉树【数据结构】

前言 之前我们已经学习过了各种线性的数据结构&#xff0c;顺序表、链表、栈、队列&#xff0c;现在我们一起来了解一下一种非线性的结构----树 1.树的结构和概念 1.1树的概念 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一…