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(不需要调用浏览器直接静默打印)