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 {
		// 设置打印格式,如果未确定类型,可选择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();

参考链接

java 打印pdf_java打印pdf文件

java 利用 pdfbox 实现PDF转为图片

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

使用 Apache PDFBox 操作PDF文件

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

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

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

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Summer524!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值