关于JAVA生成word、excel、pdf水印代码整合

本文介绍了如何使用Java技术,如ApachePOI处理Excel,ApacheXWPF处理Word,iTextPDF处理PDF,实现文件(如.docx,.xlsx,.pdf)添加水印的功能,包括文字水印和图片水印,以及版权保护措施。
摘要由CSDN通过智能技术生成

 通过借鉴其他csdn前辈的代码,优化后的整理,希望这些代码能更好的帮助其他人,欢迎读者提出建议继续优化(借鉴的地方比较多,时间也过的比较久了,忘了借鉴的网址了)

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.*;
import com.microsoft.schemas.office.office.CTLock;
import com.microsoft.schemas.vml.*;
import com.pccw.ihr.base.provider.util.IhrUserUtil;
import com.pccw.march.core.base.utils.login.LoginUser;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.openxml4j.opc.PackagePartName;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.TargetMode;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.apache.poi.xssf.usermodel.XSSFRelation;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFHeader;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.stereotype.Component;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Date;
import java.util.stream.Stream;

@Slf4j
@Component
public class WaterMarkUtil {

    public static void addWatermarkAndCopy(ByteArrayOutputStream byteArrayOutputStream, OutputStream os, String fileType) throws IOException {
        if (byteArrayOutputStream != null) {
            ByteArrayInputStream is = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            InputStream watermarkedStream = WaterMarkUtil.waterMarkfis(is, fileType);
            if (watermarkedStream != null) {
                try {
                    IOUtils.copy(watermarkedStream, os);
                } finally {
                    IOUtils.closeQuietly(watermarkedStream);
                }
            }
            IOUtils.closeQuietly(is);
            IOUtils.closeQuietly(byteArrayOutputStream);
        }
    }

    public static InputStream waterMark(String file, String fileName) throws FileNotFoundException {
        try (FileInputStream fis = new FileInputStream(file)) {
            String fileType = FilenameUtils.getExtension(fileName);
            return waterMarkfis(fis, fileType);
        } catch (IOException e) {
            log.error("文件添加水印失败" + e);
        }
        return null;
    }

    public static InputStream waterMarkfis(InputStream fis, String fileType) throws FileNotFoundException {
        try {
            String word = "";
            LoginUser loginUser = IhrUserUtil.getCurrentLoginUser();
            if (loginUser != null) {
                word = loginUser.getLoginAccount() + " " + loginUser.getAccountName();
            } else {
                word = DateFormatUtils.format(new Date(), "yyyy-MM-dd");
            }
            ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 二进制OutputStream
            if ("doc".equalsIgnoreCase(fileType) || "docx".equalsIgnoreCase(fileType)) {
                XWPFDocument doc = new XWPFDocument(fis);
                waterMarkDocXDocument(doc, word);
                doc.write(baos); // 文档写入流
            } else if ("xls".equalsIgnoreCase(fileType) || "xlsx".equalsIgnoreCase(fileType)) {
                XSSFWorkbook workbook = new XSSFWorkbook(fis); // 加载现有的工作簿
                addWorkbookWaterMark(workbook, word); // 水印信息
                workbook.write(baos);
            } else if ("pdf".equalsIgnoreCase(fileType)) {
                pdfWatermark(fis, baos, word, 2);
            }
            return new ByteArrayInputStream(baos.toByteArray());
        } catch (IOException | DocumentException e) {
            log.error("文件添加水印失败" + e);
        }
        return null;
    }

    /************************************************************ PDF水印设置 ************************************************************/
    /**
     * 给pdf添加文字水印
     *
     * @param os    添加水印后的pdf文件路径,如/Users/mimhope/Documents/abc_new.pdf
     * @param fis   添加水印前的pdf文件路径, 如/Users/mimhope/Documents/abc_old.pdf
     * @param word  水印文字
     * @param model 水印样式 1:平行居中 2:左右两边
     * @return
     * @throws DocumentException
     * @throws IOException
     */
    public static void pdfWatermark(InputStream fis, OutputStream os, String word, int model)
            throws DocumentException, IOException {
        PdfReader reader = new PdfReader(fis, "PDF".getBytes());
        PdfStamper stamper = new PdfStamper(reader, os);
        try {
            // 设置权限,防止修改和注释
            stamper.setEncryption(null, "super123456".getBytes(), PdfWriter.ALLOW_PRINTING | PdfWriter.ALLOW_MODIFY_CONTENTS, PdfWriter.STANDARD_ENCRYPTION_128);
            PdfContentByte content;
            // 创建字体,第一个参数是字体路径,itext有一些默认的字体比如说:
            BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
            PdfGState gs = new PdfGState();
            // 获取PDF页数
            int total = reader.getNumberOfPages();
            // 遍历每一页
            for (int i = 0; i < total; i++) {
                float width = reader.getPageSize(i + 1).getWidth(); // 页宽度
                float height = reader.getPageSize(i + 1).getHeight(); // 页高度
                content = stamper.getOverContent(i + 1);// 内容
                content.beginText();//开始写入文本
                gs.setFillOpacity(0.3f);//水印透明度
                content.setGState(gs);
                content.setColorFill(BaseColor.LIGHT_GRAY);
                content.setTextMatrix(70, 200);//设置字体的输出位置
                content.setColorFill(BaseColor.LIGHT_GRAY);
                if (model == 1) { //平行居中的3条水印
                    content.setFontAndSize(base, 20); //字体大小

                    //showTextAligned 方法的参数分别是(文字对齐方式,位置内容,输出水印X轴位置,Y轴位置,旋转角度)
                    content.showTextAligned(Element.ALIGN_CENTER, word, width / 2, 650, 30);
                    content.showTextAligned(Element.ALIGN_CENTER, word, width / 2, 400, 30);
                    content.showTextAligned(Element.ALIGN_CENTER, word, width / 2, 150, 30);
                } else { // 左右两边个从上到下4条水印
                    float rotation = 30;// 水印旋转度数

                    content.setFontAndSize(base, 20);
                    content.showTextAligned(Element.ALIGN_LEFT, word, 20, height - 50, rotation);
                    content.showTextAligned(Element.ALIGN_LEFT, word, 20, height / 4 * 3 - 50, rotation);
                    content.showTextAligned(Element.ALIGN_LEFT, word, 20, height / 2 - 50, rotation);
                    content.showTextAligned(Element.ALIGN_LEFT, word, 20, height / 4 - 50, rotation);

                    content.setFontAndSize(base, 22);
                    content.showTextAligned(Element.ALIGN_RIGHT, word, width - 20, height - 50, rotation);
                    content.showTextAligned(Element.ALIGN_RIGHT, word, width - 20, height / 4 * 3 - 50, rotation);
                    content.showTextAligned(Element.ALIGN_RIGHT, word, width - 20, height / 2 - 50, rotation);
                    content.showTextAligned(Element.ALIGN_RIGHT, word, width - 20, height / 4 - 50, rotation);
                }
                content.endText();//结束写入文本
                stamper.flush();
            }
        } finally {
            fis.close();
            stamper.close();
            reader.close();
        }
    }

    /************************************************************ Excel水印设置 ************************************************************/
    /**
     * 设置excel水印
     */
    static class FontImage {
        final static String[] TEXT = new String[]{"XXXX水印"};
        final static Integer fontSize = 24;

        /**
         * <p>Title: 设置水印相关信息 </p>
         * <p>Description: 水印信息 </p>
         */
        static class Watermark {
            private Boolean enable;
            private String[] text;
            private String dateFormat;
            private String color;

            public Watermark() {
            }

            public Watermark(Boolean enable, String[] text, String dateFormat, String color) {
                this.enable = enable;
                this.text = text;
                this.dateFormat = dateFormat;
                this.color = color;
            }

            public Boolean getEnable() {
                return enable;
            }

            public void setEnable(Boolean enable) {
                this.enable = enable;
            }

            public String[] getText() {
                return text;
            }

            public void setText(String[] text) {
                this.text = text;
            }

            public String getDateFormat() {
                return dateFormat;
            }

            public void setDateFormat(String dateFormat) {
                this.dateFormat = dateFormat;
            }

            public String getColor() {
                return color;
            }

            public void setColor(String color) {
                this.color = color;
            }
        }

        /**
         * <p>Title: 生成水印图片信息 </p>
         * <p>Description: 生成水印图片信息 </p>
         */
        public static BufferedImage createWatermarkImage(Watermark watermark) {
            if (watermark == null) {
                watermark = new Watermark();
                watermark.setEnable(true);
                watermark.setText(TEXT);
                watermark.setColor("#C5CBCF");
                watermark.setDateFormat("yyyy-MM-dd HH:mm");
            } else {
                if (StringUtils.isEmpty(watermark.getDateFormat())) {
                    watermark.setDateFormat("yyyy-MM-dd HH:mm");
                } else if (watermark.getDateFormat().length() == 16) {
                    watermark.setDateFormat("yyyy-MM-dd HH:mm");
                } else if (watermark.getDateFormat().length() == 10) {
                    watermark.setDateFormat("yyyy-MM-dd");
                }
                if (watermark.getText().length == 0) {
                    watermark.setText(TEXT);
                }
                if (StringUtils.isEmpty(watermark.getColor())) {
                    watermark.setColor("#C5CBCF");
                }
            }
            Font font = new Font("微软雅黑", Font.PLAIN, fontSize);
            Integer width = 500;
            Integer height = 100 * watermark.getText().length;
            // 设置最大的宽度
            for (int j = 0; j < watermark.getText().length; j++) {
                int textWidth = fontSize * watermark.getText()[j].length();
                if (textWidth > width) {
                    width = textWidth;
                }
            }
            height = (width / 2);
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            // 背景透明 开始
            Graphics2D g = image.createGraphics();
            image = g.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
            g.dispose();
            // 背景透明 结束
            g = image.createGraphics();
            // 设定画笔颜色
            g.setColor(new Color(Integer.parseInt(watermark.getColor().substring(1), 16)));
            // 设置画笔字体
            g.setFont(font);
            // 设定倾斜度
            g.shear(0, -0.3);
            // 消除文字锯齿
            g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
            //设置字体平滑
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            int y = (height / 2) + font.getSize() * 2;
            int x = 0;
            for (int j = 0; j < watermark.getText().length; j++) {
                String[] textArray = watermark.getText()[j].split("\n");
                y += 1 * (j + 1);
                // 计算文字长度,计算居中的x点坐标
                FontMetrics fm = g.getFontMetrics(font);
                int textWidth = fm.stringWidth(watermark.getText()[j]);
                x = (width - textWidth) / 2;

                for (int i = 0; i < textArray.length; i++) {
                    // 画出字符串
                    g.drawString(textArray[i], x, y);
                    y = y + font.getSize();
                }
            }
            g.dispose();// 释放画笔
            return image;
        }
    }

    /**
     * <p>Title: 添加水印 </p>
     * <p>Description: 添加水印 </p>
     *
     * @param workbook  工作薄
     * @param waterMark 水印信息
     */
    public static void addWorkbookWaterMark(Workbook workbook, String waterMark) {
        if (workbook != null) {
            XSSFWorkbook xssfWorkbook = (XSSFWorkbook) workbook;
            for (int i = 0; i < xssfWorkbook.getNumberOfSheets(); i++) {
                addWaterMark(xssfWorkbook, xssfWorkbook.getSheetAt(i), waterMark);
            }
        }
    }

    /**
     * <p>Title: 添加水印 </p>
     * <p>Description: 添加水印信息 </p>
     *
     * @param wb        工作薄
     * @param sheet     工作表
     * @param waterMark 水印信息
     */
    public static void addWaterMark(XSSFWorkbook wb, XSSFSheet sheet, String waterMark) {
        //是否添加水印
        if (StringUtils.isNotBlank(waterMark)) {
            FontImage.Watermark watermark = new FontImage.Watermark();
            watermark.setText(new String[]{waterMark});
            watermark.setEnable(true);
            BufferedImage image = FontImage.createWatermarkImage(watermark);
            // 导出到字节流B
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            try {
                ImageIO.write(image, "png", os);
            } catch (IOException e) {
                log.error("add watermark error: {}", e.getMessage());
            }
            int pictureIdx = wb.addPicture(os.toByteArray(), Workbook.PICTURE_TYPE_PNG);
            POIXMLDocumentPart poixmlDocumentPart = wb.getAllPictures().get(pictureIdx);
            PackagePartName ppn = poixmlDocumentPart.getPackagePart().getPartName();
            String relType = XSSFRelation.IMAGES.getRelation();
            //add relation from sheet to the picture data
            PackageRelationship pr = sheet.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);
            //set background picture to sheet
            sheet.getCTWorksheet().addNewPicture().setId(pr.getId());
        }
    }

    /************************************************************ word水印设置 ************************************************************/
    // word字体
    private static final String fontName = "宋体";
    // 字体大小
    private static final String fontSize = "0.2pt";
    // 字体颜色
    private static final String fontColor = "#d0d0d0";
    // 一个字平均长度,单位pt,用于:计算文本占用的长度(文本总个数*单字长度)
    private static final Integer widthPerWord = 10;
    // 与顶部的间距
    private static Integer styleTop = 0;
    // 文本旋转角度
    private static final String styleRotation = "20";

    /**
     * 给文档添加水印
     * 此方法可以单独使用
     *
     * @param doc
     * @param customText
     */
    public static void waterMarkDocXDocument(XWPFDocument doc, String customText) {
        // 把整页都打上水印
        for (int lineIndex = -5; lineIndex < 10; lineIndex++) {
            styleTop = 300 * lineIndex;
            waterMarkDocXDocument_0(doc, customText);
        }
    }

    /**
     * 为文档添加水印
     *
     * @param doc        需要被处理的docx文档对象
     * @param customText 需要添加的水印文字
     */
    public static void waterMarkDocXDocument_0(XWPFDocument doc, String customText) {
        // 水印文字之间使用8个空格分隔
        customText = customText + repeatString(" ", 8);
        // 一行水印重复水印文字次数
        customText = repeatString(customText, 10);
        // 如果之前已经创建过 DEFAULT 的Header,将会复用
        XWPFHeader header = doc.createHeader(HeaderFooterType.DEFAULT);
        int size = header.getParagraphs().size();
        if (size == 0) {
            header.createParagraph();
        }
        CTP ctp = header.getParagraphArray(0).getCTP();
        byte[] rsidr = doc.getDocument().getBody().getPArray(0).getRsidR();
        byte[] rsidrdefault = doc.getDocument().getBody().getPArray(0).getRsidRDefault();
        ctp.setRsidP(rsidr);
        ctp.setRsidRDefault(rsidrdefault);
        CTPPr ppr = ctp.addNewPPr();
        ppr.addNewPStyle().setVal("Header");
        // 开始加水印
        CTR ctr = ctp.addNewR();
        CTRPr ctrpr = ctr.addNewRPr();
        ctrpr.addNewNoProof();
        CTGroup group = CTGroup.Factory.newInstance();
        CTShapetype shapetype = group.addNewShapetype();
        CTTextPath shapeTypeTextPath = shapetype.addNewTextpath();
        shapeTypeTextPath.setOn(STTrueFalse.T);
        shapeTypeTextPath.setFitshape(STTrueFalse.T);
        CTLock lock = shapetype.addNewLock();
        lock.setExt(STExt.VIEW);
        CTShape shape = group.addNewShape();
        shape.setId("PowerPlusWaterMarkObject");
        shape.setSpid("_x0000_s102");
        shape.setType("#_x0000_t136");
        // 设置形状样式(旋转,位置,相对路径等参数)
        shape.setStyle(getShapeStyle(customText));
        shape.setFillcolor(fontColor);
        // 字体设置为实心
        shape.setStroked(STTrueFalse.FALSE);
        // 绘制文本的路径
        CTTextPath shapeTextPath = shape.addNewTextpath();
        // 设置文本字体与大小
        shapeTextPath.setStyle("font-family:" + fontName + ";font-size:" + fontSize);
        shapeTextPath.setString(customText);
        CTPicture pict = ctr.addNewPict();
        pict.set(group);
    }

    /**
     * 构建Shape的样式参数
     *
     * @param customText
     * @return
     */
    private static String getShapeStyle(String customText) {
        StringBuilder sb = new StringBuilder();
        // 文本path绘制的定位方式
        sb.append("position: ").append("absolute");
        // 计算文本占用的长度(文本总个数*单字长度)
        sb.append(";width: ").append(customText.length() * widthPerWord).append("pt");
        // 字体高度
        sb.append(";height: ").append("20pt");
        sb.append(";z-index: ").append("-251654144");
        sb.append(";mso-wrap-edited: ").append("f");
        // 设置水印的间隔,这是一个大坑,不能用top,必须要margin-top。
        sb.append(";margin-top: ").append(styleTop);
        sb.append(";mso-position-horizontal-relative: ").append("page");
        sb.append(";mso-position-vertical-relative: ").append("page");
        sb.append(";mso-position-vertical: ").append("left");
        sb.append(";mso-position-horizontal: ").append("center");
        sb.append(";rotation: ").append(styleRotation);
        return sb.toString();
    }

    /**
     * 将指定的字符串重复repeats次.
     */
    private static String repeatString(String pattern, int repeats) {
        StringBuilder buffer = new StringBuilder(pattern.length() * repeats);
        Stream.generate(() -> pattern).limit(repeats).forEach(buffer::append);
        return new String(buffer);
    }
}
 调用示例
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
wb.write(byteArrayOutputStream);
byteArrayOutputStream.flush();
WaterMarkUtil.addWatermarkAndCopy(byteArrayOutputStream, os, "xlsx");
return WaterMarkUtil.waterMark(file.toString(), doc.getDocumentName());
InputStream watermarkedStream = WaterMarkUtil.waterMarkfis(is, fileType);
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值