条形码输出到pdf打印,封装工具类

最近项目需要用到条形码,对于资产进行管理追踪,所以相应的就需要用到生成条形码的工具,在网上查找了相关资料之后,目前有几类产品,google 的zxing 、jbarcode、barcode4j-light 等,他们的区别我不再说,很多人有写,最终我选择的是jbarcode,选择这个是因为这个jar 可以生成中文文字等等,像一些博客所写的那样,开始写的时候,我也是想把文字直接绘制在条形码图片中,但是绘制之后发现效果不理想,调整输出条形码图片更改它的宽度等等都不太方便,所以最后还是选择直接绘制出条形码,不加任何文字,然后将绘制出的图片输出流直接写入pdf中,因为条形码打印需要特定的标签打印机,所以对于纸张的大小我们需要调整pdf页面的大小,而不是选择A4之类的纸张填写内容。所以,综合以上想法,我们的操作步骤是:

1、绘制条形码图片

2、将条形码图片输出流输入进pdf页面表格中

3、导出pdf

效果如下:

《条形码输出到pdf打印,封装工具类》

这里我们需要引入jbarcode.jar(绘制条形码),jbarcode在maven上没有,所以需要手动下载jar包,然后导入自己本地maven仓库引用。

导入:打开cmd ,输入以下命令即可,只需要更改你下载jbarcode后存放的地址即可

mvn install:install-file -Dfile="D:\Apache Maven\jbarcode-0.2.8.jar" -DgroupId=org.jbarcode -DartifactId=jbarcode -Dversion=0.2.8 -Dpackaging=jar

另外需要引入itext、itext-asian ,这个是操作pdf的

maven依赖:

<properties>
     <jbarcode.version>0.2.8</jbarcode.version>
     <iText.version>4.2.1</iText.version>
     <iTextAsian.version>5.2.0</iTextAsian.version>
</properties>

<!--引入条形码生成工具-->
<dependency>
     <groupId>org.jbarcode</groupId>
     <artifactId>jbarcode</artifactId>
     <version>${jbarcode.version}</version>
</dependency>

<!-- pdf操作类-->
<dependency>
     <groupId>com.lowagie</groupId>
     <artifactId>iText</artifactId>
     <version>${iText.version}</version>
</dependency>

<dependency>
     <groupId>com.itextpdf</groupId>
     <artifactId>itext-asian</artifactId>
     <version>${iTextAsian.version}</version>
</dependency>

关于如何操作pdf,网上有很多资料可以借鉴

http://www.anyrt.com/blog/list/itextpdf.html#1

不过需要注意:这里面有一个我遇到的很奇葩的bug

插图图片时:

PdfPCell cell = new PdfPCell();
byte[] bt = barCodeImgStream.toByteArray();
com.lowagie.text.Image image = Image.getInstance(bt);
cell.setImage(image);

如果是先new一个单元格,然后装入图片,那么对于之前你设置的img图片的样式全部失效,需要注意

正确操作是:

byte[] bt = barCodeImgStream.toByteArray();
com.lowagie.text.Image image = Image.getInstance(bt);
image.scaleAbsoluteHeight(imgHeight);//设置图片的高
image.scaleAbsoluteWidth(imgWidth);//设置图片的宽
//重点,必须将设置的图片在单元格new时放进单元格,而不是后续cell.setImg(),不然对于图片的设置会失效
PdfPCell cell = new PdfPCell(image);

直接在new单元格时将图片对象放进去,这样图片之前的样式设置才会生效,这个问题真的郁闷了我好久

 

直接上代码了:不废话了:想起来了,我用了lombox,小伙伴记得加上这个插件,这个插件是用来省去我们写get、set的

package com.xxx.common.utils;

import com.lowagie.text.Image;
import com.lowagie.text.Rectangle;
import com.lowagie.text.*;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfPCell;
import com.lowagie.text.pdf.PdfPTable;
import com.lowagie.text.pdf.PdfWriter;
import com.xxx.common.core.domain.AjaxResult;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.jbarcode.JBarcode;
import org.jbarcode.JBarcodeFactory;
import org.jbarcode.encode.Code128Encoder;
import org.jbarcode.paint.TextPainter;
import org.jbarcode.util.ImageUtil;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *  
 *  * @projectName xxx
 *  * @title     BarCode2PdfUtil   
 *  * @package    com.xxx.common.utils  
 *  * @description    条形码序列号导出条形码至pdf
 *  * @author IT_CREAT     
 *  * @date  2019 2019/10/1 16:47  
 *  * @version V1.0.0 
 *  
 */
@Data
@NoArgsConstructor
public class BarCode2PdfUtil {

    // 设置条形码默认分辨率
    public static final int BARCODE_DPI = ImageUtil.DEFAULT_DPI;

    /**条形码字节输出流*/
    public List<ByteArrayOutputStream> barCodeOutPutStream = new ArrayList<>();

    /**pdf操作文件*/
    public Document pdfDocument = null;

    /**pdf文件输出流*/
    public OutputStream pdfOs = null;

    /**pdf文件构造输出流*/
    public PdfWriter pdfWriter = null;

    /**
     * 像素换算单位(1厘米约等于28.4像素)
     */
    public static float pixelUnitForCm = 28.4f;
    /**
     * 像素换算单位(1mm约等于2.84像素)
     */
    public static float pixelUnitForMm = 2.84F;

    /**
     * 设置一个标签纸大小的纸张
     */
    public static Rectangle LABLE_PAGE = new RectangleReadOnly(5.0f * pixelUnitForCm, 3.0f * pixelUnitForCm);

    /**
     * 字体大小
     */
    public float FONT_SIZE = 5F;
    /**
     * 声明图片固定高度12
     */
    public int imgHeight = 12;
    /**
     * 声明图片固定宽度110
     */
    public int imgWidth = 110;

    public static BarCode2PdfUtil create(){
        return new BarCode2PdfUtil();
    }


    public AjaxResult creatBarCode2Pdf(List<BarCodeData> barCodeDatas,String exportPath,String exportName){
        if(CollectionUtils.isEmpty(barCodeDatas)){
            return AjaxResult.error("条形码数据为空,装换失败");
        }
        try {
            //判断文件夹存在不,不存在则创建
            File file = new File(exportPath);
            if(!file.exists()){
                file.mkdir();
            }
            String outPath = exportPath + exportName;
            int index = 0;
            for (BarCodeData barCodeData:barCodeDatas){
                if(!ObjectUtils.isEmpty(barCodeData)){
                    //得到二维码输出流
                    ByteArrayOutputStream byteArrayOutputStream = creatBarCodeImg(barCodeData.getBarCode());
                    if(index == 0){
                        pdfOs = new FileOutputStream(new File(outPath));//得到pdf文件输出流
                        createDocumentAndOpen(pdfOs);//创建pdf操作类,并打开
                        pdfDataWrite(barCodeData.getBarCode(),byteArrayOutputStream,barCodeData.getHeadShowData());//写入数据
                    }else {
                        pdfDocument.newPage();//新建pdf页
                        pdfDataWrite(barCodeData.getBarCode(),byteArrayOutputStream,barCodeData.getHeadShowData());//写入数据
                    }
                    index ++;
                }
            }
            close();//关闭各种流
            return AjaxResult.success(outPath);
        }catch (Exception e){
            e.printStackTrace();
            return AjaxResult.error("转换条形码失败,多次尝试无果请联系管理员");
        }
    }

    public void close() throws Exception {
        //关闭条形码输出流
        if(!CollectionUtils.isEmpty(barCodeOutPutStream)){
            for (ByteArrayOutputStream outputStream:barCodeOutPutStream) {
                outputStream.close();
            }
        }
        //关闭pdf文件操作
        if(!ObjectUtils.isEmpty(pdfDocument)){
            pdfDocument.close();
        }
        //关闭pdf输出流
        if(!ObjectUtils.isEmpty(pdfOs)){
            pdfOs.close();
        }
        //关闭pdf构造出的输出流
        if(!ObjectUtils.isEmpty(pdfWriter)){
            pdfWriter.close();
        }
    }

    /**
     * 构造一个pdf操作文件
     */
    public void  createDocumentAndOpen(OutputStream pdfOs) throws Exception {
        if(pdfDocument == null){
            //设置纸张为A4标签纸,左右上下边距全部为5
            pdfDocument = new Document(LABLE_PAGE, 5, 5, 5, 5);
            // 构造好的pdf文件输出位置
            pdfWriter = PdfWriter.getInstance(pdfDocument, pdfOs);
            //打开文件
            pdfDocument.open();
        }
    }

    /**
     * 对pdf进行数据写入操作
     * @param barCode 条形码序列号
     * @param barCodeImgStream 条形码输出流
     * @param fontData 输出条形码头部显示数据
     * @throws Exception 异常
     */
    public void pdfDataWrite(String barCode, ByteArrayOutputStream barCodeImgStream,Map<String, String> fontData) throws Exception {
        //itext在pdf中输入中文字体(中文楷体)时:
        BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);

        //创建表格,表格中是可以继续嵌入表格的,指定表格为1列
        PdfPTable table = new PdfPTable(1);//1列
        table.setHorizontalAlignment(1);//设置水平居中
        table.setWidthPercentage(98);//设置table占页面比98%

        //创建装入头部中文信息的表格
        PdfPTable tableTop = new PdfPTable(new float[]{30f,50f});
        tableTop.setHorizontalAlignment(1);//设置水平居中
        if (!ObjectUtils.isEmpty(fontData) && fontData.size() > 0) {
            for (String key : fontData.keySet()) {
                String value = fontData.get(key);
                //创建一个单元格
                PdfPCell cell = new PdfPCell();
                //插入key键值
                Paragraph mess = new Paragraph(key, new com.lowagie.text.Font(bfChinese,FONT_SIZE));
                mess.setAlignment(Element.ALIGN_CENTER);//设置碎屏剧中
                cell.setPhrase(mess);//将字体装入单元格中
                setPdfPCellStyle(cell);//统一设置单元格水平垂直居中
                tableTop.addCell(cell);

                //插入key键value值
                cell = new PdfPCell();
                mess = new Paragraph(value, new com.lowagie.text.Font(bfChinese,FONT_SIZE));
                cell.setPhrase(mess);//将字体装入单元格中
                setPdfPCellStyle(cell);//统一设置单元格水平垂直居中
                tableTop.addCell(cell);
            }
        }
        table.addCell(tableTop);//向全局表格中装入头部信息子表格

        //创建底部装入条形码的表格
        PdfPTable tableFoot = new PdfPTable(1);
        tableFoot.setHorizontalAlignment(1);//设置水平居中
        if(!ObjectUtils.isEmpty(barCodeImgStream)){
            //插入条形码图片
            byte[] bt = barCodeImgStream.toByteArray();
            com.lowagie.text.Image image = Image.getInstance(bt);
            image.scaleAbsoluteHeight(imgHeight);//设置图片的高
            image.scaleAbsoluteWidth(imgWidth);//设置图片的宽
            //重点,必须将设置的图片在单元格new时放进单元格,而不是后续cell.setImg(),不然对于图片的设置会失效
            PdfPCell cell = new PdfPCell(image);
            setPdfPCellStyle(cell);//统一设置单元格水平垂直居中
            cell.setMinimumHeight(20);//设置最小高度
            cell.setBorderWidthBottom(0);//设置单元格底部边框为0
            tableFoot.addCell(cell);

            //插入条形码号
            Paragraph mess = new Paragraph(barCode, new com.lowagie.text.Font(bfChinese, 4));
            mess.setAlignment(Element.ALIGN_CENTER);
            cell = new PdfPCell();//重新new一个单元格
            cell.setBorderWidthTop(0);//设置单元格头部边框为0
            cell.setPhrase(mess);//将字体装入单元格中
            setPdfPCellStyle(cell);//统一设置单元格水平垂直居中
            tableFoot.addCell(cell);
        }
        table.addCell(tableFoot);//将底部子表格装入大表格中
        pdfDocument.add(table);//向页面中装入表格
    }

    /**
     * 通用统一需要设置的单元格样式,垂直水平居中
     *
     * @param cell1
     */
    public void setPdfPCellStyle(PdfPCell cell1) {
        //创建一个单元格
        cell1.setUseAscender(true);//开启这个水平居中生效
        cell1.setHorizontalAlignment(Element.ALIGN_CENTER); //水平居中
        cell1.setVerticalAlignment(Element.ALIGN_MIDDLE); //垂直居中
        cell1.setMinimumHeight(10);//设置最小高度
    }

    //毫米转像素
    public float mmTopx(float mm) {
        mm = (float) (mm * 2.84);
        return mm;
    }


    /**
     * 创建一个条形码图像
     * @param barCode 传入条形码
     * @throws Exception 异常
     */
    public ByteArrayOutputStream creatBarCodeImg(String barCode) throws Exception {
        BufferedImage image = creatBarCode().createBarcode(barCode);//得到一个图片操作对象
        //传入图片对象,指定图片格式,设置图片像素,也就是设置宽高
        ByteArrayOutputStream barCodeOutPut = new ByteArrayOutputStream();//创建一个字节输出流,让条形码输出到字节数组流中
        barCodeOutPutStream.add(barCodeOutPut);
        ImageUtil.encodeAndWrite(image, ImageUtil.PNG,barCodeOutPut,BARCODE_DPI,BARCODE_DPI);//执行绘制图像,会进入重写的静态内部内方法中
        return barCodeOutPut;
    }

    /**创建一个条形码实例*/
    public JBarcode creatBarCode(){
        // 生成code128
        JBarcode jbc = JBarcodeFactory.getInstance().createCode128();
        jbc.setEncoder(Code128Encoder.getInstance());
        jbc.setTextPainter(CustomTextPainter.getInstance());
        return jbc;
    }

    /**
     * 静态内部类 自定义的 TextPainter,
     * 允许定义字体,大小,文本等 参考底层实现:BaseLineTextPainter.getInstance()
     */
    protected  static class CustomTextPainter implements TextPainter {
        private static CustomTextPainter instance = new CustomTextPainter();

        public static CustomTextPainter getInstance() {
            return instance;
        }

        public void paintText(BufferedImage barCodeImage, String text, int width) {
            Graphics g2d = barCodeImage.getGraphics();
            g2d.fillRect(0, 0, barCodeImage.getWidth(), 0);
            g2d.fillRect(0, barCodeImage.getHeight(),barCodeImage.getWidth(),0);
        }
    }


    /**
     * 内部类,存放条形码所叙述句
     */
    @Data
    @NoArgsConstructor
    public static class BarCodeData{
        /**条形码编号*/
        private String barCode;
        /**头部显示数据*/
        private Map<String,String> headShowData;
    }

    public static void main(String[] args) {

        //模拟第一条数据
        HashMap<String, String> dataMap = new HashMap<>();
        dataMap.put("商品名称","苹果笔记本电脑");
        dataMap.put("联系人","张某某");
        dataMap.put("联系电话","18888889489");
        BarCodeData barCodeData = new BarCodeData();
        barCodeData.setBarCode("1231225411");
        barCodeData.setHeadShowData(dataMap);

        //模拟第二条数据
        HashMap<String, String> dataMap1 = new HashMap<>();
        dataMap1.put("商品名称","华为笔记本电脑");
        dataMap1.put("联系人","李某某");
        dataMap1.put("联系电话","17777779489");
        BarCodeData barCodeData1 = new BarCodeData();
        barCodeData1.setBarCode("1231225411");
        barCodeData1.setHeadShowData(dataMap1);

        ArrayList<BarCodeData> list = new ArrayList<>();
        list.add(barCodeData);
        list.add(barCodeData1);
        AjaxResult ajaxResult = BarCode2PdfUtil.create().creatBarCode2Pdf(list, "d:/file", "1.pdf");
        System.out.println(ajaxResult);
    }

}

这里有个封装的返回:(用过的细心地同学可以揣测出这是哪个框架)

package com.xxx.common.core.domain;

import java.util.HashMap;
import com.xxx.common.utils.StringUtils;

/**
 * 操作消息提醒
 * 
 * @author xxx
 */
public class AjaxResult extends HashMap<String, Object>
{
    private static final long serialVersionUID = 1L;

    /** 状态码 */
    public static final String CODE_TAG = "code";

    /** 返回内容 */
    public static final String MSG_TAG = "msg";

    /** 数据对象 */
    public static final String DATA_TAG = "data";

    /**
     * 状态类型
     */
    public enum Type
    {
        /** 成功 */
        SUCCESS(0),
        /** 警告 */
        WARN(301),
        /** 错误 */
        ERROR(500);
        private final int value;

        Type(int value)
        {
            this.value = value;
        }

        public int value()
        {
            return this.value;
        }
    }

    /**
     * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。
     */
    public AjaxResult()
    {
    }

    /**
     * 初始化一个新创建的 AjaxResult 对象
     * 
     * @param type 状态类型
     * @param msg 返回内容
     */
    public AjaxResult(Type type, String msg)
    {
        super.put(CODE_TAG, type.value);
        super.put(MSG_TAG, msg);
    }

    /**
     * 初始化一个新创建的 AjaxResult 对象
     * 
     * @param type 状态类型
     * @param msg 返回内容
     * @param data 数据对象
     */
    public AjaxResult(Type type, String msg, Object data)
    {
        super.put(CODE_TAG, type.value);
        super.put(MSG_TAG, msg);
        if (StringUtils.isNotNull(data))
        {
            super.put(DATA_TAG, data);
        }
    }

    /**
     * 返回成功消息
     * 
     * @return 成功消息
     */
    public static AjaxResult success()
    {
        return AjaxResult.success("操作成功");
    }

    /**
     * 返回成功数据
     * 
     * @return 成功消息
     */
    public static AjaxResult success(Object data)
    {
        return AjaxResult.success("操作成功", data);
    }

    /**
     * 返回成功消息
     * 
     * @param msg 返回内容
     * @return 成功消息
     */
    public static AjaxResult success(String msg)
    {
        return AjaxResult.success(msg, null);
    }

    /**
     * 返回成功消息
     * 
     * @param msg 返回内容
     * @param data 数据对象
     * @return 成功消息
     */
    public static AjaxResult success(String msg, Object data)
    {
        return new AjaxResult(Type.SUCCESS, msg, data);
    }

    /**
     * 返回警告消息
     * 
     * @param msg 返回内容
     * @return 警告消息
     */
    public static AjaxResult warn(String msg)
    {
        return AjaxResult.warn(msg, null);
    }

    /**
     * 返回警告消息
     * 
     * @param msg 返回内容
     * @param data 数据对象
     * @return 警告消息
     */
    public static AjaxResult warn(String msg, Object data)
    {
        return new AjaxResult(Type.WARN, msg, data);
    }

    /**
     * 返回错误消息
     * 
     * @return
     */
    public static AjaxResult error()
    {
        return AjaxResult.error("操作失败");
    }

    /**
     * 返回错误消息
     * 
     * @param msg 返回内容
     * @return 警告消息
     */
    public static AjaxResult error(String msg)
    {
        return AjaxResult.error(msg, null);
    }

    /**
     * 返回错误消息
     * 
     * @param msg 返回内容
     * @param data 数据对象
     * @return 警告消息
     */
    public static AjaxResult error(String msg, Object data)
    {
        return new AjaxResult(Type.ERROR, msg, data);
    }
}

 

    原文作者:IT_CREATE
    原文地址: https://blog.csdn.net/IT_CREATE/article/details/101878937
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞