java将图片转为pdf并打印文字——自定义证书的实现

一、背景介绍

这周产品提了一个需求,提供一个空出一些位置的证书图片,将这张图片转为pdf,并将指定的文字(如:学生姓名)打印到证书上的指定位置,做了个demo来实现这个功能。

二、需求分析

实际上需求可以拆解为两个部分

  • 一是将一个url链接的图片转为pdf文件
  • 二是将文字印到图片的指定位置

三、引入依赖

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.13</version>
</dependency>
<dependency>
    <groupId>com.lowagie</groupId>
    <artifactId>itext</artifactId>
    <version>4.2.1</version>
</dependency>
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext-asian</artifactId>
    <version>5.2.0</version>
</dependency>

四、具体实现

4.1 将图片url转为byte[]数组

我们有一个url的图片地址,我们需要将它处理成二进制byte[]数组,方便进行后续操作。

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * @Author: KD
 * @Date: 2021/1/6 3:42 下午
 */
@Slf4j
@Data
public class FileUrlUtil {

    /**
     * 从指定url获取byte[]
     *
     * @param urlStr
     * @return
     */
    public static Pair<Boolean, byte[]> downloadFromUrl(String urlStr) {
        try {
            URL url = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection)url.openConnection();

            conn.setConnectTimeout(3*1000);
            InputStream inputStream = conn.getInputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            while((len = inputStream.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
            bos.close();
            byte[] data = bos.toByteArray();
            return Pair.of(true, data);
        } catch (IOException e) {
            log.error("Get bytes from failure");
            return Pair.of(false, null);
        }
    }
}

4.2 将图片转为pdf文件

这个方法参数是url地址,我们调用上面的转换方法把链接转为二进制数组,之后再把这个字节数组转为pdf文件。

public static ByteArrayOutputStream convert(String urlStr) {
    Document document = new Document();
    //设置文档页边距
    document.setMargins(0,0,0,0);
    Pair<Boolean, byte[]> pair = FileUrlUtil.downloadFromUrl(urlStr);
    if(!pair.getLeft()){
        throw new CodingCloudException("url转换错误");
    }
    byte[] bytes = pair.getRight();
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try {
        PdfWriter.getInstance(document, baos);
        //打开文档
        document.open();
        //获取图片的宽高
        Image image = Image.getInstance(bytes);
        float imageHeight=image.getScaledHeight();
        float imageWidth=image.getScaledWidth();
        //设置页面宽高与图片一致
        Rectangle rectangle = new Rectangle(imageWidth, imageHeight);
        document.setPageSize(rectangle);
        //图片居中
        image.setAlignment(Image.ALIGN_CENTER);
        //新建一页添加图片
        document.newPage();
        document.add(image);
        return baos;
    } catch (Exception ioe) {
        System.out.println(ioe.getMessage());
    } finally {
        //关闭文档
        document.close();
        try {
            baos.flush();
            baos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return null;
}

4.3 证书上打印文字

实际上我们是通过控制边距,将文字显示在我们想要的位置。

    /**
     * @param waterMarkName 你的水印
     * @return
     */
    public static ByteArrayOutputStream waterMark(byte[] bytes, String waterMarkName) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            PdfReader reader = new PdfReader(bytes);
            PdfStamper stamper = new PdfStamper(reader, baos);
            stamper.setEncryption(null, null, PdfWriter.ALLOW_PRINTING, PdfWriter.STANDARD_ENCRYPTION_40);
            //这里的字体设置比较关键,这个设置是支持中文的写法
            BaseFont base = BaseFont.createFont("STSong-Light",
                    "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
            int total = reader.getNumberOfPages() + 1;
            log.info("total:[{}]",total);
            PdfContentByte under;
            Rectangle pageRect = null;
            for (int i = 1; i < total; i++) {
                pageRect = stamper.getReader().
                        getPageSizeWithRotation(i);
                // 计算水印X,Y坐标
                float x = pageRect.getWidth()/2;
                float y = (pageRect.getHeight()/3)*2-150;
                // 获得PDF最顶层
                under = stamper.getOverContent(i);
                under.saveState();
                // set Transparency
                PdfGState gs = new PdfGState();
                // 设置透明度为0.2
                gs.setFillOpacity(1.f);
                under.setGState(gs);
                under.restoreState();
                under.beginText();
                under.setFontAndSize(base, 80);
                under.setColorFill(BaseColor.BLACK);

                // 水印文字
                under.showTextAligned(Element.ALIGN_CENTER
                        , waterMarkName, x,
                        y, 0);
                // 添加水印文字
                under.endText();
                under.setLineWidth(1f);
                under.stroke();
            }
            stamper.close();
            return baos;
    } catch (Exception e) {
        e.printStackTrace();
    }
        return null;
    }

4.4 Controller层

/**
 * @Author: KD
 * @Date: 2021/1/6 3:44 下午
 */
@Api(tags = "证书生成")
@Slf4j
@RestController
@RequestMapping(value = "/certificate")
public class CertificateController {

    @ResponseBody
    @GetMapping("/test")
    public ResponseEntity<Body<Void>> save(
            @ApiParam("资源名称") String url,
            @ApiParam("资源名称") String name,
            HttpServletResponse response) throws IOException {
        log.info("输入参数:url=[{}],name=[{}]",url,name);
        ByteArrayOutputStream bos = Convert2Pdf.convert(url);
        ByteArrayOutputStream res = Convert2Pdf.waterMark(bos.toByteArray(),name);
        OutputStream os = response.getOutputStream();
        os.write(res.toByteArray());
        return ResponseUtil.ok();
    }

}

五、测试效果

5.1 访问url

http://localhost:8380/api/competition/certificate/test?url=https://static.xiaohoucode.com/prod-env/images/coding-cloud-competition/module/de0fec795a52320c60b1042f6f784a09.jpeg&name=KD

两个参数分别为url和name,url是图片地址,name是想要打印的学生名字

5.2 效果图

在这里插入图片描述

如图所示,KD两个字母就是打印到PDF证书上的内容。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值