office及pdf类型文件加水印,文件流和本地路径形式工具类整合

文章详情:

  1. 从本地读取office及pdf文件,添加水印并保存到本地的工具类方法。
  2. 魔改的通过传入文件流添加水印并返回的工具类方法,适用于minio等等各种方式。
  3. 修复补充的.doc格式的文件水印方法,以及特殊的.ppt格式的文件水印方法。
  4. 必要的依赖添加列表
  5. 针对于minio的文件水印service层使用方法示例,并将添加水印后的文件作为http响应返回。
  6. Controller层使用示例

2025-2-18日修改 补充.ppt后缀与.doc后缀文件的水印添加

.ppt文件 本地使用用例

/** * PPT设置水印 适用于ppt文件  本地用例方法 * * @parampath      源PPT文件路径 * @paramtargetpath 目标PPT文件路径 * @parammarkStr   水印文本 * @throwsIOException */
public static void setPPTWaterMark(String path, String targetpath, String markStr) throws IOException {
    HSLFSlideShow slideShow = null;
    FileOutputStream out = null;
    try {
        slideShow = new HSLFSlideShow(new FileInputStream(path));

        // 获取水印图片ByteArrayOutputStream os = getImage(markStr);
        HSLFPictureData pictureData = slideShow.addPicture(os.toByteArray(), PictureData.PictureType.PNG);

        for (HSLFSlide slide : slideShow.getSlides()) {
            // 创建水印图片形状HSLFPictureShape pictureShape = new HSLFPictureShape(pictureData);
            // 设置水印位置和大小java.awt.Rectangle anchor = new java.awt.Rectangle();
            anchor.width = 500;
            anchor.height = 500;
            anchor.x = 100; // 水印在幻灯片上的X坐标anchor.y = 100; // 水印在幻灯片上的Y坐标pictureShape.setAnchor(anchor);
            slide.addShape(pictureShape);
        }

        out = new FileOutputStream(targetpath);
        slideShow.write(out);
    } catch (IOException e) {
        throw new RuntimeException("setPPTWaterMark fail:生成ppt文件失败", e);
    } finally {
        if (slideShow != null) {
            try {
                slideShow.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (out != null) {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

.doc文件 文件流使用用例

修改为根据后缀名的不同选择不同文件格式的处理方法。

完整方法如下,适用于.doc和.docx

/** * word文字水印  文件流形式使用 * * @paraminputStream * @paramoutputStream * @parammarkStr */
public static void addWordWaterMark(InputStream inputStream, OutputStream outputStream, String markStr, String fileName) {

    // 获取文件扩展名String fileExtension = FilenameUtils.getExtension(fileName).toLowerCase();

    // 根据文件扩展名确定文件格式FileFormat fileFormat;
    if ("doc".equals(fileExtension)) {
        fileFormat = FileFormat.Doc; // 对于.doc文件使用Doc格式} else if ("docx".equals(fileExtension)) {
        fileFormat = FileFormat.Docx_2013; // 对于.docx文件使用Docx_2013格式} else {
        throw new IllegalArgumentException("Unsupported file format: " + fileExtension);
    }

    //加载示例文档Document doc = new Document();
    doc.loadFromStream(inputStream, fileFormat);
    //添加艺术字并设置大小ShapeObject shape = new ShapeObject(doc, ShapeType.Text_Plain_Text);
    shape.setWidth(80);
    shape.setHeight(20);
    //设置艺术字文本内容、位置及样式shape.setVerticalPosition(30);
    shape.setHorizontalPosition(20);
    shape.setRotation(315);
    shape.getWordArt().setFontFamily("宋体");
    shape.getWordArt().setText(markStr);
    shape.setFillColor(Color.red);
    shape.setLineStyle(ShapeLineStyle.Single);
    shape.setStrokeColor(new Color(192, 192, 192, 255));
    shape.setStrokeWeight(1);

    Section section;
    HeaderFooter header;
    for (int n = 0; n < doc.getSections().getCount(); n++) {
        section = doc.getSections().get(n);
        //获取section的页眉header = section.getHeadersFooters().getHeader();
        Paragraph paragraph;

        if (header.getParagraphs().getCount() > 0) {
            //如果页眉有段落,取它第一个段落paragraph = header.getParagraphs().get(0);
        } else {
            //否则新增加一个段落到页眉paragraph = header.addParagraph();
        }
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 3; j++) {
                //复制艺术字并设置多行多列位置shape = (ShapeObject) shape.deepClone();
                shape.setVerticalPosition(50 + 150 * i);
                shape.setHorizontalPosition(20 + 160 * j);
                paragraph.getChildObjects().add(shape);
            }
        }
    }
    // 保存文档到输出流doc.saveToStream(outputStream, fileFormat);
}
  1. 添加必要依赖
<!--水印相关   start-->
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext-asian</artifactId>
    <version>5.2.0</version>
</dependency>
<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.13</version>
</dependency>
<dependency>
    <groupId>com.lowagie</groupId>
    <artifactId>itext</artifactId>
    <version>2.1.7</version>
</dependency>

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.17</version>
</dependency>

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.17</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <version>3.17</version>
</dependency>

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>ooxml-schemas</artifactId>
    <version>1.0</version>
</dependency>

<!-- word -->
<dependency>
    <groupId>e-iceblue</groupId>
    <artifactId>spire.doc.free</artifactId>
    <version>5.2.0</version>
</dependency>
<!-- excel  -->
<dependency>
    <groupId>e-iceblue</groupId>
    <artifactId>spire.xls.free</artifactId>
    <version>5.1.0</version>
</dependency>
<dependency>
    <groupId>e-iceblue</groupId>
    <artifactId>spire.pdf.free</artifactId>
    <version>5.1.0</version>
</dependency>
<!-- ppt -->
<dependency>
    <groupId>e-iceblue</groupId>
    <artifactId>spire.presentation.free</artifactId>
    <version>5.1.0</version>
</dependency>
<!--水印相关   end--><!--minio相关   -->
<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.2.1</version>
    <exclusions>
        <exclusion>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.10.0</version>
</dependency>
  1. 在pom.xml文件中添加远程仓库

e-iceblue是Spire系列产品的开发商,Spire系列包括了用于处理Office文档(如Word、Excel、PPT)的Java库。

<repositories>
    <repository>
        <id>com.e-iceblue</id>
        <name>e-iceblue</name>
        <url>https://repo.e-iceblue.cn/repository/maven-public/</url>
    </repository>
</repositories>
  1. 工具类整合
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.*;
import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.HeaderFooter;
import com.spire.doc.Section;
import com.spire.doc.documents.Paragraph;
import com.spire.doc.documents.ShapeLineStyle;
import com.spire.doc.documents.ShapeType;
import com.spire.doc.fields.ShapeObject;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xslf.usermodel.XMLSlideShow;
import org.apache.poi.xslf.usermodel.XSLFPictureShape;
import org.apache.poi.xslf.usermodel.XSLFSlide;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.Color;
import java.awt.Font;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;

public class WaterMarkUtils {

//    public static void main(String[] args) {//        String markText = "青岛研究院";////        String oldFile = "E:/ylnew/test.doc";//        String newFile = "E:/ylnew/1/test.doc";//        addWordWaterMark(oldFile,newFile,markText);////        String oldFilea = "E:/ylnew/test.docx";//        String newFilea = "E:/ylnew/1/test.docx";//        addWordWaterMark(oldFilea,newFilea,markText);//////        String oldFile1 = "E:/ylnew/test.pdf";//        String newFile1 = "E:/ylnew/1/test.pdf";//        addPDFWaterMark(oldFile1,newFile1,markText);////        String oldFile2 = "E:/ylnew/test.xls";//        String newFile2 = "E:/ylnew/1/test.xls";//        setExcelWaterMark(oldFile2,newFile2,markText);////        String oldFile2a = "E:/ylnew/test.xlsx";//        String newFile2a = "E:/ylnew/1/test.xlsx";//        setExcelWaterMark(oldFile2a,newFile2a,markText);////        String oldFile4 = "E:/ylnew/test.pptx";//        String newFile4 = "E:/ylnew/1/test.pptx";//        setPPTWaterMark(oldFile4,newFile4,markText);////        // ppt格式暂不可行,待添加////        String oldFile4a = "E:/ylnew/test.ppt";////        String newFile4a = "E:/ylnew/1/test.ppt";////        setPPTWaterMark(oldFile4a,newFile4a,markText);////    }/**     *     * @paramwb   Excel Workbook     * @paramsheet  需要打水印的Excel     * @paramwaterRemark  水印文字     * @paramstartXCol   水印起始列     * @paramstartYRow  水印起始行     * @parambetweenXCol  水印横向之间间隔多少列     * @parambetweenYRow  水印纵向之间间隔多少行     * @paramXCount    横向共有水印多少个     * @paramYCount    纵向共有水印多少个     * @paramwaterRemarkWidth   水印图片宽度为多少列     * @paramwaterRemarkHeight   水印图片高度为多少行     * @throwsIOException     */public static void putWaterRemarkToExcel(Workbook wb, Sheet sheet, String waterRemark, int startXCol,
                                             int startYRow, int betweenXCol, int betweenYRow, int XCount, int YCount, int waterRemarkWidth,
                                             int waterRemarkHeight) throws IOException {

        // 加载图片ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
        BufferedImage bufferImg = createWaterMarkImage(waterRemark);
        ImageIO.write(bufferImg, "png", byteArrayOut);
        // 开始打水印Drawing drawing = sheet.createDrawingPatriarch();
        Drawing<?> drawingPatriarch = sheet.getDrawingPatriarch();
        // 按照共需打印多少行水印进行循环for (int yCount = 0; yCount < YCount; yCount++) {
            // 按照每行需要打印多少个水印进行循环for (int xCount = 0; xCount < XCount; xCount++) {
                // 创建水印图片位置int xIndexInteger = startXCol + (xCount * waterRemarkWidth) + (xCount * betweenXCol);
                int yIndexInteger = startYRow + (yCount * waterRemarkHeight) + (yCount * betweenYRow);
                /*                 * 参数定义: 第一个参数是(x轴的开始节点); 第二个参数是(是y轴的开始节点); 第三个参数是(是x轴的结束节点);                 * 第四个参数是(是y轴的结束节点); 第五个参数是(是从Excel的第几列开始插入图片,从0开始计数);                 * 第六个参数是(是从excel的第几行开始插入图片,从0开始计数); 第七个参数是(图片宽度,共多少列);                 * 第8个参数是(图片高度,共多少行);                 */ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, xIndexInteger,
                        yIndexInteger, xIndexInteger + waterRemarkWidth, yIndexInteger + waterRemarkHeight);

                Picture pic = drawing.createPicture(anchor,
                        wb.addPicture(byteArrayOut.toByteArray(), Workbook.PICTURE_TYPE_PNG));
                pic.resize();
            }
        }
    }

    // 本地路径使用public static void setExcelWaterMark(String inputSrc, String outputSrc, String waterMarkName){
        try {
            //读取excel文件Workbook wb =null;
            if (inputSrc.endsWith("xls")) {
                wb = new HSSFWorkbook(new FileInputStream(inputSrc));
            }else if (inputSrc.endsWith("xlsx")){
                wb = new XSSFWorkbook(new FileInputStream(inputSrc));
            }
            //获取excel sheet个数int sheets = wb.getNumberOfSheets();
            //循环sheet给每个sheet添加水印for (int i = 0; i < sheets; i++) {
                Sheet sheet = wb.getSheetAt(i);
                //获取excel实际所占行int row = sheet.getFirstRowNum() + sheet.getLastRowNum();
                //获取excel实际所占列Row row1 = sheet.getRow(sheet.getFirstRowNum());
                if (row1==null){
                    continue;
                }
                int cell = sheet.getRow(sheet.getFirstRowNum()).getLastCellNum() + 1;
                //根据行与列计算实际所需多少水印putWaterRemarkToExcel(wb, sheet, waterMarkName, 0, 0, 6, 8, cell / 6 + 1, row / 8 + 1, 0, 0);

                //设置为受保护sheet.protectSheet(waterMarkName);
            }
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            try {
                wb.write(os);
            } catch (IOException e) {
                e.printStackTrace();
            }
            wb.close();
            byte[] content = os.toByteArray();
            // Excel文件生成后存储的位置。File file1 = new File(outputSrc);
            OutputStream fos = null;
            try {
                fos = new FileOutputStream(file1);
                fos.write(content);
                os.close();
                fos.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }


    // 文件流形式使用public static void setExcelWaterMark(InputStream inputStream, OutputStream outputStream, String waterMarkName, String fileName){
        try {
            //读取excel文件Workbook wb =null;
            if (fileName.endsWith("xls")) {
                wb = new HSSFWorkbook(inputStream);
            }else if (fileName.endsWith("xlsx")){
                wb = new XSSFWorkbook(inputStream);
            }else {
                throw new IllegalArgumentException("Unsupported file type: " + fileName);
            }
            //获取excel sheet个数int sheets = wb.getNumberOfSheets();
            //循环sheet给每个sheet添加水印for (int i = 0; i < sheets; i++) {
                Sheet sheet = wb.getSheetAt(i);
                //获取excel实际所占行int row = sheet.getFirstRowNum() + sheet.getLastRowNum();
                //获取excel实际所占列Row row1 = sheet.getRow(sheet.getFirstRowNum());
                if (row1==null){
                    continue;
                }
                int cell = sheet.getRow(sheet.getFirstRowNum()).getLastCellNum() + 1;
                //根据行与列计算实际所需多少水印putWaterRemarkToExcel(wb, sheet, waterMarkName, 0, 0, 6, 8, cell / 6 + 1, row / 8 + 1, 0, 0);

                //设置为受保护sheet.protectSheet(waterMarkName);
            }

            // 将Workbook写入到输出流wb.write(outputStream);
            wb.close();
            outputStream.close();

        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }


    public static BufferedImage createWaterMarkImage(String waterMark) {
        String[] textArray = waterMark.split("\n");
        Font font = new Font("microsoft-yahei", Font.PLAIN, 20);
        Integer width = 500;
        Integer height = 200;
        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("#C5CBCF".substring(1), 16)));// 设定画笔颜色g.setFont(font);// 设置画笔字体g.shear(0.1, -0.26);// 设定倾斜度// 设置字体平滑g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        int y = 150;
        for (int i = 0; i < textArray.length; i++) {
            g.drawString(textArray[i], 0, y);// 画出字符串y = y + font.getSize();
        }
        g.dispose();// 释放画笔return image;
    }


    // 文件流形式使用public static void setPPTWaterMark(InputStream inputStream, OutputStream outputStream, String markStr, String fileName) {
        XMLSlideShow slideShow = null;
        try {
            slideShow = new XMLSlideShow(inputStream);
            // 获取水印ByteArrayOutputStream os = getImage(markStr);
            org.apache.poi.sl.usermodel.PictureData pictureData1 = slideShow.addPicture(os.toByteArray(), org.apache.poi.sl.usermodel.PictureData.PictureType.PNG);
            for (XSLFSlide slide : slideShow.getSlides()) {
                XSLFPictureShape pictureShape = slide.createPicture(pictureData1);
                // 设置水印位置,这里需要根据实际需求调整//pictureShape.setAnchor(new Rectangle(250, 0, 500, 500));pictureShape.setAnchor(pictureShape.getAnchor());
            }
            // 直接写入提供的输出流slideShow.write(outputStream);
        } catch (IOException e) {
//            log.error("setPPTWaterMark setPPTWaterMark fail: " + e.getMessage());throw new RuntimeException("setPPTWaterMark fail: 生成PPT文件失败", e);
        } finally {
            if (slideShow != null) {
                try {
                    slideShow.close();
                } catch (IOException e) {
//                    log.error("setPPTWaterMark Error closing slide show: " + e.getMessage());}
            }
        }
    }

    /**     * 本地文件路径PPT设置水印并保存到本地  适用于pptx文件     *     * @parampath     * @paramtargetpath     * @parammarkStr     * @throwsIOException     */public static void setPPTWaterMark(String path, String targetpath, String markStr) {
        XMLSlideShow slideShow = null;
        try {
            slideShow = new XMLSlideShow(new FileInputStream(path));
        } catch (IOException e) {
//            log.error("setPPTWaterMark fail:", e);throw new RuntimeException("setPPTWaterMark fail:获取PPT文件失败");
        }
        ByteArrayOutputStream os = null;
        FileOutputStream out = null;
        try {
            //获取水印os = getImage(markStr);
            org.apache.poi.sl.usermodel.PictureData pictureData1 = slideShow.addPicture(os.toByteArray(), org.apache.poi.sl.usermodel.PictureData.PictureType.PNG);
            for (XSLFSlide slide : slideShow.getSlides()) {
                XSLFPictureShape pictureShape = slide.createPicture(pictureData1);
//                pictureShape.setAnchor(new java.awt.Rectangle(250, 0, 500, 500));pictureShape.setAnchor(pictureShape.getAnchor());
            }
            out = new FileOutputStream(targetpath);
            slideShow.write(out);
        } catch (IOException e) {
//            log.error("setPPTWaterMark fail:" + e);throw new RuntimeException("setPPTWaterMark fail:生成ppt文件失败");
        } finally {
            if (slideShow != null) {
                try {
                    slideShow.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**     * 获取水印文字图片流     *     * @paramtext     * @return*/private static ByteArrayOutputStream getImage(String text) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        try {
            // 导出到字节流BBufferedImage image = createWaterMarkImageBig(text);
            ImageIO.write(image, "png", os);
        } catch (IOException e) {
//            log.error("getImage fail: 创建水印图片IO异常", e);//            throw new MyException(ResultCode.FAILURE, "getImage fail: 创建水印图片IO异常");}
        return os;
    }

    /**     * 根据文字生成水印图片(大号 平铺)     *     * @paramtext     * @return*/public static BufferedImage createWaterMarkImageBig(String text) {
        Integer width = 1000;
        Integer height = 800;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// 获取bufferedImage对象Font font = new Font("宋体", Font.PLAIN, 70);
        Graphics2D g2d = image.createGraphics();
        image = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
        g2d.dispose();
        g2d = image.createGraphics();
        //设置字体颜色和透明度g2d.setColor(new Color(0, 0, 0, 60));
        //设置字体g2d.setStroke(new BasicStroke(1));
        //设置字体类型  加粗 大小g2d.setFont(font);
        //设置倾斜度g2d.rotate(Math.toRadians(-30), (double) image.getWidth() / 2, (double) image.getHeight() / 2);
        FontRenderContext context = g2d.getFontRenderContext();
        Rectangle2D bounds = font.getStringBounds(text, context);
        double x = (width - bounds.getWidth()) / 2;
        double y = (height - bounds.getHeight()) / 2;
        double ascent = -bounds.getY();
        double baseY = y + ascent;
        //写入水印文字原定高度过小,所以累计写水印,增加高度g2d.drawString(text, (int) x, (int) baseY);
        //设置透明度g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
        //释放对象g2d.dispose();
        return image;
    }



    /**     * word文字水印  文件流形式使用     *     * @paraminputStream     * @paramoutputStream     * @parammarkStr     */public static void addWordWaterMark(InputStream inputStream, OutputStream outputStream, String markStr) {
        //加载示例文档Document doc = new Document();
        doc.loadFromStream(inputStream, FileFormat.Docx_2013);
        //添加艺术字并设置大小ShapeObject shape = new ShapeObject(doc, ShapeType.Text_Plain_Text);
        shape.setWidth(80);
        shape.setHeight(20);
        //设置艺术字文本内容、位置及样式shape.setVerticalPosition(30);
        shape.setHorizontalPosition(20);
        shape.setRotation(315);
        shape.getWordArt().setFontFamily("宋体");
        shape.getWordArt().setText(markStr);
        shape.setFillColor(Color.red);
        shape.setLineStyle(ShapeLineStyle.Single);
        shape.setStrokeColor(new Color(192, 192, 192, 255));
        shape.setStrokeWeight(1);

        Section section;
        HeaderFooter header;
        for (int n = 0; n < doc.getSections().getCount(); n++) {
            section = doc.getSections().get(n);
            //获取section的页眉header = section.getHeadersFooters().getHeader();
            Paragraph paragraph;

            if (header.getParagraphs().getCount() > 0) {
                //如果页眉有段落,取它第一个段落paragraph = header.getParagraphs().get(0);
            } else {
                //否则新增加一个段落到页眉paragraph = header.addParagraph();
            }
            for (int i = 0; i < 4; i++) {
                for (int j = 0; j < 3; j++) {
                    //复制艺术字并设置多行多列位置shape = (ShapeObject) shape.deepClone();
                    shape.setVerticalPosition(50 + 150 * i);
                    shape.setHorizontalPosition(20 + 160 * j);
                    paragraph.getChildObjects().add(shape);
                }
            }
        }
        // 保存文档到输出流doc.saveToStream(outputStream, FileFormat.Docx_2013);
    }


    // 本地文件路径形式public static void addWordWaterMark(String inputPath, String outPath, String markStr) {
        //加载示例文档Document doc = new Document();
        doc.loadFromFile(inputPath);
        //添加艺术字并设置大小ShapeObject shape = new ShapeObject(doc, ShapeType.Text_Plain_Text);
        shape.setWidth(80);
        shape.setHeight(20);
        //设置艺术字文本内容、位置及样式shape.setVerticalPosition(30);
        shape.setHorizontalPosition(20);
        shape.setRotation(315);
        shape.getWordArt().setFontFamily("宋体");
        shape.getWordArt().setText(markStr);
        shape.setFillColor(Color.red);
        shape.setLineStyle(ShapeLineStyle.Single);
        shape.setStrokeColor(new Color(192, 192, 192, 255));
        shape.setStrokeWeight(1);

        Section section;
        HeaderFooter header;
        for (int n = 0; n < doc.getSections().getCount(); n++) {
            section = doc.getSections().get(n);
            //获取section的页眉header = section.getHeadersFooters().getHeader();
            Paragraph paragraph;

            if (header.getParagraphs().getCount() > 0) {
                //如果页眉有段落,取它第一个段落paragraph = header.getParagraphs().get(0);
            } else {
                //否则新增加一个段落到页眉paragraph = header.addParagraph();
            }
            for (int i = 0; i < 4; i++) {
                for (int j = 0; j < 3; j++) {
                    //复制艺术字并设置多行多列位置shape = (ShapeObject) shape.deepClone();
                    shape.setVerticalPosition(50 + 150 * i);
                    shape.setHorizontalPosition(20 + 160 * j);
                    paragraph.getChildObjects().add(shape);
                }
            }
        }
        //保存文档doc.saveToFile(outPath, FileFormat.Docx_2013);
    }


    /**     *pdf文件添加文字水印  源文件路径与输出文件路径不能一样     *     * @paraminput         原PDF位置     * @paramoutput        输出文件的位置     * @paramwaterMarkName 页脚添加水印     */public static void addPDFWaterMark(String input, String output, String waterMarkName) {
        BufferedOutputStream bos = null;
        try {
            bos = new BufferedOutputStream(new FileOutputStream(new File(output)));
            com.itextpdf.text.pdf.PdfReader reader = new com.itextpdf.text.pdf.PdfReader(input);
            com.itextpdf.text.pdf.PdfStamper stamper = new com.itextpdf.text.pdf.PdfStamper(reader, bos);

            // 获取总页数 +1, 下面从1开始遍历int total = reader.getNumberOfPages() + 1;
            // 使用classpath下面的字体库com.itextpdf.text.pdf.BaseFont base = null;
            try {
                base = com.itextpdf.text.pdf.BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", com.itextpdf.text.pdf.BaseFont.EMBEDDED);
            } catch (Exception e) {
                // 日志处理e.printStackTrace();
            }
            // 间隔int interval = -15;
            // 获取水印文字的高度和宽度int textH = 0, textW = 0;
            JLabel label = new JLabel();
            label.setText(waterMarkName);
            FontMetrics metrics = label.getFontMetrics(label.getFont());
            textH = metrics.getHeight();
            textW = metrics.stringWidth(label.getText());
            System.out.println("textH: " + textH);
            System.out.println("textW: " + textW);

            // 设置水印透明度com.itextpdf.text.pdf.PdfGState gs = new com.itextpdf.text.pdf.PdfGState();
            gs.setFillOpacity(0.2f);
            gs.setStrokeOpacity(0.7f);

            com.itextpdf.text.Rectangle pageSizeWithRotation = null;
            PdfContentByte content = null;
            for (int i = 1; i < total; i++) {
                // 在内容上方加水印content = stamper.getOverContent(i);
                // 在内容下方加水印// content = stamper.getUnderContent(i);content.saveState();
                content.setGState(gs);

                // 设置字体和字体大小content.beginText();
                content.setFontAndSize(base, 20);

                // 获取每一页的高度、宽度pageSizeWithRotation = reader.getPageSizeWithRotation(i);
                float pageHeight = pageSizeWithRotation.getHeight();
                float pageWidth = pageSizeWithRotation.getWidth();

                // 根据纸张大小多次添加, 水印文字成30度角倾斜for (int height = interval + textH; height < pageHeight; height = height + textH * 6) {
                    for (int width = interval + textW; width < pageWidth + textW; width = width + textW * 2) {
                        content.showTextAligned(Element.ALIGN_LEFT, waterMarkName, width - textW, height - textH, 30);
                    }
                }

                content.endText();
            }

            // 关流stamper.close();
            reader.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            throw new RuntimeException("PDF makewater fail:文件未找到");
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("PDF makewater fail:IO异常");
        } catch (DocumentException e) {
            e.printStackTrace();
            throw new RuntimeException("PDF makewater fail:文档异常");
        }

    }


    // 文件流形式使用public static void addPDFWaterMark(InputStream inputStream, OutputStream outputStream, String waterMarkName, String fileName) {
        try {
            PdfReader reader = new PdfReader(inputStream);
            PdfStamper stamper = new PdfStamper(reader, outputStream);

            int total = reader.getNumberOfPages() + 1;
            BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);

            int interval = -15;
            int textH = 0, textW = 0;
            JLabel label = new JLabel();
            label.setText(waterMarkName);
            FontMetrics metrics = label.getFontMetrics(label.getFont());
            textH = metrics.getHeight();
            textW = metrics.stringWidth(label.getText());

            PdfGState gs = new PdfGState();
            gs.setFillOpacity(0.2f);
            gs.setStrokeOpacity(0.7f);

            com.itextpdf.text.Rectangle pageSizeWithRotation = null;
            PdfContentByte content = null;
            for (int i = 1; i < total; i++) {
                content = stamper.getOverContent(i);
                content.saveState();
                content.setGState(gs);

                content.beginText();
                content.setFontAndSize(base, 20);

                pageSizeWithRotation = reader.getPageSizeWithRotation(i);
                float pageHeight = pageSizeWithRotation.getHeight();
                float pageWidth = pageSizeWithRotation.getWidth();

                for (int height = interval + textH; height < pageHeight; height = height + textH * 6) {
                    for (int width = interval + textW; width < pageWidth + textW; width = width + textW * 2) {
                        content.showTextAligned(Element.ALIGN_LEFT, waterMarkName, width - textW, height - textH, 30);
                    }
                }

                content.endText();
            }

            stamper.close();
            reader.close();
        } catch (IOException | DocumentException e) {
            e.printStackTrace();
            throw new RuntimeException("PDF makewater fail: " + e.getMessage(), e);
        }
    }



}
  1. 针对于minio的文件水印service层使用方法示例,并将添加水印后的文件作为HTTP响应返回。

接受minio的源文件路径sourceObjectPath和HTTP响应对象response作为参数

并根据文件扩展名判断文件类型,根据类型的不同调用不同的水印添加方法,不同的文件返回是需要设置不同的响应头

// office水印方法
@Override
public void getWatermarkedFileOfOffice(String sourceObjectPath, HttpServletResponse response) {

    System.out.println("sourceObjectPath: " + sourceObjectPath);
    // 检查源桶中的文件是否存在boolean objectExists = false;
    try {
        minioClient.statObject(
                StatObjectArgs.builder()
                        .bucket(minIOWatermarkConfig.getBucketName())
                        .object(sourceObjectPath)
                        .build()
        );
        objectExists = true; // 如果没有抛出异常,则对象存在} catch (ErrorResponseException e) {
        if ("NoSuchKey".equals(e.errorResponse().code())) {
            System.err.println("源文件不存在: " + minIOWatermarkConfig.getBucketName() + "/" + sourceObjectPath);
            return; // 结束方法执行,因为源文件不存在} else {
            throw new RuntimeException(e);
        }
    } catch (Exception e) {
        throw new RuntimeException(e);
    }

    // 如果文件存在,执行后续操作if (objectExists) {
        try {

            String fileName = sourceObjectPath.substring(sourceObjectPath.lastIndexOf('/') + 1);
            System.out.println("开始下载:"+fileName);
            // 下载文件  office文件处理逻辑try (InputStream fileStream = minioClient.getObject(
                    GetObjectArgs.builder().bucket(minIOWatermarkConfig.getBucketName()).object(sourceObjectPath).build())) {
                System.out.println(fileName + "下载结束");

                // 将文件流转换为字节数组ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                int nRead;
                byte[] data = new byte[1024];
                while ((nRead = fileStream.read(data, 0, data.length)) != -1) {
                    buffer.write(data, 0, nRead);
                }
                buffer.flush();
                byte[] byteArray = buffer.toByteArray();

                // 将字节数组转换为输入流InputStream inputStream = new ByteArrayInputStream(byteArray);
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

                String markText = "watermark";


                if (sourceObjectPath.endsWith(".doc") || sourceObjectPath.endsWith(".docx")){
                    // 添加水印WaterMarkUtils.addWordWaterMark(inputStream, outputStream, markText);
                }else if (sourceObjectPath.endsWith(".xls") || sourceObjectPath.endsWith(".xlsx")){
                    WaterMarkUtils.setExcelWaterMark(inputStream, outputStream, markText, fileName);
                }else if (sourceObjectPath.endsWith(".pptx")){
                    WaterMarkUtils.setPPTWaterMark(inputStream, outputStream, markText, fileName);
                }else if (sourceObjectPath.endsWith(".pdf")){
                    WaterMarkUtils.addPDFWaterMark(inputStream, outputStream, markText, fileName);
                }else {
                    log.error("文件类型暂不支持添加水印");
                }

                // 设置响应头信息String contentType = "application/octet-stream"; // 默认为二进制流,适用于未知的文件类型String lowerCaseFileName = fileName.toLowerCase();
                if (lowerCaseFileName.endsWith(".pdf")) {
                    contentType = "application/pdf"; // PDF 文档} else if (lowerCaseFileName.endsWith(".doc") || lowerCaseFileName.endsWith(".docx")) {
                    contentType = lowerCaseFileName.endsWith(".doc") ? "application/msword" : "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; // Word 文档} else if (lowerCaseFileName.endsWith(".xls") || lowerCaseFileName.endsWith(".xlsx")) {
                    contentType = lowerCaseFileName.endsWith(".xls") ? "application/vnd.ms-excel" : "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; // Excel 表格} else if (lowerCaseFileName.endsWith(".ppt") || lowerCaseFileName.endsWith(".pptx")) {
                    contentType = lowerCaseFileName.endsWith(".ppt") ? "application/vnd.ms-powerpoint" : "application/vnd.openxmlformats-officedocument.presentationml.presentation"; // PowerPoint 演示文稿}
                response.setContentType(contentType);
                response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
//                response.setHeader("Content-Disposition", "inline; filename=\"" + tempFile.getName() + "\"");    attachment 下载  inline显示//                // 定义要保存到本地的文件路径 进行测试//                String localFilePath = "E:/ylnew/2/1.docx";//                try (FileOutputStream localFileStream = new FileOutputStream(localFilePath)) {//                    outputStream.writeTo(localFileStream);//                }// 将输出流转换为输入流以上传//                InputStream uploadStream = new ByteArrayInputStream(outputStream.toByteArray());//                // 上传文件至minio//                minioClient.putObject(//                        PutObjectArgs.builder().bucket(minIOWatermarkConfig.getBucketName()).object(sourceObjectPath + "_watermarked.docx")//                                .stream(uploadStream, uploadStream.available(), -1)//                                .contentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document")//                                .build());//                System.out.println("水印添加成功,文件已上传至Minio服务器。");// 使用文件输入流读取文件返回到服务端try (InputStream ServerResStream = new ByteArrayInputStream(outputStream.toByteArray());
                     OutputStream outputStreamServer = response.getOutputStream()) {
                    byte[] buffer1 = new byte[4096];
                    int bytesRead;
                    while ((bytesRead = ServerResStream.read(buffer1)) != -1) {
                        outputStreamServer.write(buffer1, 0, bytesRead);
                    }
                    outputStreamServer.flush();
                }

            }
        } catch (Exception e) {
            // 异常处理log.error("Error processing file", e);
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }
}
  1. Controller层使用示例
/** * 根据userFileId来下载水印文件 * * @paramhttpServletRequest * @paramhttpServletResponse * @param userfileId */
@Operation(summary = "下载水印文件", description = "下载水印文件接口", tags = {"filetransferwatermark"})
@MyLog(operation = "下载水印文件", module = CURRENT_MODULE)
@RequestMapping(value = "/downloadfile/watermark", method = RequestMethod.GET)
public void downloadFileWatermark(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, String userfileId) {
    ...
    httpServletResponse.setContentType("application/force-download");// 设置强制下载不打开filetransferService.downloadFileWatermark(httpServletResponse, downloadFileDTO);
    判断文件类型是否可以加水印
        fileWatermarkService.getWatermarkedFileOfOffice(文件路径, httpServletResponse);
    ...
}
点赞

当前页面评论已关闭。

隐藏
变装