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 {
// 设置打印格式,如果未确定类型,可选择autosense
DocFlavor 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 * 1190
int width = a3.getWidth().toPixI(72);
int height = a3.getHeight().toPixI(72);
// 10mm边距, 对应 28px
int 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();
参考链接