java添加图片水印工具类

java添加图片水印工具类

支持为xls、xlsx、doc、docx、ppt、pptx、pdf、各类图片文件、视频文件 添加png图片水印。

效果图

在这里插入图片描述

依赖工具包:

* pdf - itext
* word ppt - spire (解除页数限制)
* excel - poi
* 视频 - ffmpeg

maven坐标:

        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-scratchpad</artifactId>
            <version>4.1.0</version>
        </dependency>
				<!-- easypoi -->
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-spring-boot-starter</artifactId>
            <version>4.1.1</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-base</artifactId>
            <version>4.1.1</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-web</artifactId>
            <version>4.1.1</version>
        </dependency>
        <dependency>
            <groupId>cn.afterturn</groupId>
            <artifactId>easypoi-annotation</artifactId>
            <version>4.1.1</version>
        </dependency>
         <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>ooxml-schemas</artifactId>
            <version>1.4</version>
        </dependency>
       
         <!-- pdf加水印-->
   			<dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13</version>
        </dependency>
         <dependency>
            <groupId>e-iceblue</groupId>
            <artifactId>spire.office.free</artifactId>
            <version>5.2.0</version>
        </dependency>
        
        <dependency>
            <groupId>ws.schild</groupId>
            <artifactId>jave-all-deps</artifactId>
            <version>3.0.1</version>
            <exclusions>
                <!--  排除windows 32位系统      -->
                <exclusion>
                    <groupId>ws.schild</groupId>
                    <artifactId>jave-nativebin-win32</artifactId>
                </exclusion>
                <!--  排除linux 32位系统      -->
                <exclusion>
                    <groupId>ws.schild</groupId>
                    <artifactId>jave-nativebin-linux32</artifactId>
                </exclusion>
                <!-- 排除Mac系统-->
                <exclusion>
                    <groupId>ws.schild</groupId>
                    <artifactId>jave-nativebin-osx64</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

代码

1. 核心工具类

import cn.hutool.core.io.FileUtil;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.spire.doc.Document;
import com.spire.doc.FileFormat;
import com.spire.doc.PictureWatermark;
import com.spire.presentation.*;
import com.spire.presentation.collections.SlideCollection;
import com.spire.presentation.drawing.FillFormatType;
import org.apache.poi.hslf.usermodel.*;
import org.apache.poi.hssf.usermodel.HSSFSheet;
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.sl.usermodel.PictureData;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
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.XSSFRelation;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;
import ws.schild.jave.info.VideoSize;
import ws.schild.jave.process.ProcessWrapper;
import ws.schild.jave.process.ffmpeg.DefaultFFMPEGLocator;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Dimension2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;

import static java.lang.Long.SIZE;

/**
 * 添加水印工具类
 * pdf - itext
 * doc/docx ppt/pptx - spire
 * excel - poi
 * 视频 - ffmpeg
 *
 * @author narnew
 */
public class WatermarkUtil {
    private static final Logger LOG = LoggerFactory.getLogger(WatermarkUtil.class);

    /**
     * 水印内容
     */
    public static final String WATER_MARK_TEXT = "水印文字";
  
    /**
     * 字体
     * 初步筛选出Graphics2D支持中文的字体有:
     * Arial Unicode MS、Dialog、DialogInput、Microsoft JhengHei、Microsoft JhengHei Light、Microsoft JhengHei UI、Microsoft JhengHei UI Light、Microsoft YaHei UI、Microsoft YaHei UI Light、
     * MS Gothic、MS PGothic、MS UI Gothic、SansSerif、Serif、仿宋、华文中宋、华文仿宋、华文宋体、华文彩云、华文新魏、华文楷体、华文琥珀、华文细黑、华文行楷、华文隶书、宋体、幼圆、微软雅黑、微软雅黑 Light、新宋体、
     * 方正姚体、方正舒体、楷体、等线、等线 Light、隶书、黑体
     * ————————————————
     * 原文链接:https://blog.csdn.net/u010663021/article/details/110877418
     */
    public static final String FONT_NAME = "Serif";


    private static final String DEFAULT_MARK_IMG_PATH = "static/template/watermark.png";
  
    /**
     * @param filePath 生成临时保存路径
     * @return 临时保存路径
     */
    public static String getSavePath(String filePath) {
        return filePath.substring(0, filePath.lastIndexOf("/") + 1) + "out_" + System.currentTimeMillis() + "_" + StrUtil.subAfter(filePath, "/", true);
    }

    /**
     * 根据文字构造水印图片
     *
     * @param text 水印文本内容
     * @return {@link BufferedImage}
     */
    @Deprecated
    public static BufferedImage createWatermarkImage(String text, int width, int height) {

        Font font = new Font(FONT_NAME, Font.PLAIN, height / 30);

        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();
        // 1.0f为透明度 ,值从0-1.0,依次变得不透明
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_ATOP, 0.5f));
        // 设定画笔颜色
        g.setColor(new Color(243, 28, 28));
        // 设置画笔字体
        g.setFont(font);
        // 设定倾斜度
        g.shear(0.1, -0.26);
        // 设置字体平滑 消除文字锯齿
        g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        //消除画图锯齿
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        //相当于margin-top
        int y = 8 * font.getSize();
        int x = 0;
        // 画出字符串
        for (int i = 0; i < 5; i++) {
            g.drawString(text, x, y);
            y += 10 * font.getSize();
        }
        g.dispose();
        return image;
    }

    /**
     * 用默认图片自适应文件尺寸
     */
    public static BufferedImage readAndResizePNGImage(int width, int height) {
        return readAndResizePNGImage(width, height, DEFAULT_MARK_IMG_PATH);
    }

    /**
     * 根据宽高重新调整水印图片比例大小
     *
     * @param width       文件宽
     * @param height      文件高
     * @param markImgPath 水印图片路径
     * @return BufferedImage
     */
    public static BufferedImage readAndResizePNGImage(int width, int height, String markImgPath) {

        double heightNew = height;
        double widthNew = width;
        double scale;

        ClassPathResource resource = new ClassPathResource(markImgPath);

        try {
            // 读取输入的PNG图片
            BufferedImage originalImage = ImageIO.read(resource.getInputStream());
            int MARK_HEIGHT = originalImage.getHeight();
            int MARK_WIDTH = originalImage.getWidth();
            //计算缩放比例
            //取较长的一边
            if (width * MARK_HEIGHT < height * MARK_WIDTH) {
                scale = heightNew / MARK_HEIGHT;
                widthNew = scale * MARK_WIDTH;
            } else {
                scale = widthNew / MARK_WIDTH;
                heightNew = (scale * MARK_HEIGHT);
            }
            //缩放
            BufferedImage scaledImage = new BufferedImage((int) widthNew, (int) heightNew, originalImage.getType());
            Graphics graphics = scaledImage.createGraphics();
            graphics.drawImage(originalImage, 0, 0, (int) widthNew, (int) heightNew, null);
            graphics.dispose();
            // 创建一个透明的新图片,宽度和高度为新指定的尺寸
            BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            // 获取新图片的Graphics2D对象,用于绘制新图片
            Graphics2D g2d = resizedImage.createGraphics();
            // 设置Graphics2D对象的绘制质量为高质量
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
            // 循环绘制原始图片,实现平铺效果
            for (int y = 0; y < height; y += scaledImage.getHeight()) {
                for (int x = 0; x < width; x += scaledImage.getWidth()) {
                    g2d.drawImage(scaledImage, x, y, null);
                }
            }
            // 释放资源
            g2d.dispose();
            return resizedImage;
        } catch (IOException e) {
            LOG.error(e.getMessage(), e);
            throw new CoreException(ErrorCodeEnum.SYS_ERROR);
        }
    }

    /**
     * excel文件添加水印图片
     *  @param filePath 文件路径
     * @throws IOException io操作异常
     */
    public static String setWaterMarkToExcel(String filePath) throws IOException {
        ClassPathResource resource = new ClassPathResource(DEFAULT_MARK_IMG_PATH);
        BufferedImage bfi = ImageIO.read(resource.getInputStream());
        String savePath = FileProcessingUtil.getSavePath(filePath);

        FileOutputStream os = new FileOutputStream(savePath);
        ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
        ImageIO.write(bfi, "png", byteArrayOut);
        String type = ExcelFileUtil.getType(filePath);
        if ("xls".equals(type)) {
            // 创建新的.xlsx文件
            try (FileInputStream fis = new FileInputStream(filePath);
                 XSSFWorkbook newWorkbook = new XSSFWorkbook()) {
                // 读取旧版的.xls文件
                Workbook oldWorkbook = WorkbookFactory.create(fis);
                // 读取旧版的Sheet并复制到新的Workbook中
                for (int i = 0; i < oldWorkbook.getNumberOfSheets(); i++) {
                    HSSFSheet oldSheet = (HSSFSheet) oldWorkbook.getSheetAt(i);
                    XSSFSheet newSheet = newWorkbook.createSheet(oldSheet.getSheetName());
                    ExcelFileUtil.copySheets(oldSheet, newSheet);
                }
                setWaterMarkToSheet(os, byteArrayOut, newWorkbook);
            }
        }
        if ("xlsx".equals(type)) {
            //xlsx
            try (XSSFWorkbook workbook = new XSSFWorkbook(filePath)) {
                setWaterMarkToSheet(os, byteArrayOut, workbook);
            }
        }
        return savePath;
    }

    private static void setWaterMarkToSheet(FileOutputStream os, ByteArrayOutputStream byteArrayOut, XSSFWorkbook workbook) throws IOException {
        int pictureIdx = workbook.addPicture(byteArrayOut.toByteArray(), Workbook.PICTURE_TYPE_PNG);
        POIXMLDocumentPart poixmlDocumentPart = workbook.getAllPictures().get(pictureIdx);
        for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
            XSSFSheet xssfSheet = workbook.getSheetAt(i);
            PackagePartName ppn = poixmlDocumentPart.getPackagePart().getPartName();
            String relType = XSSFRelation.IMAGES.getRelation();
            PackageRelationship pr = xssfSheet.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);
            xssfSheet.getCTWorksheet().addNewPicture().setId(pr.getId());
        }
        workbook.write(os);
    }


    /**
     * word文档设置水印图片
     *
     * @param filePath 文件路径
     * @throws IOException ioexception
     */
    public static String setWaterMarkToWord(String filePath) throws IOException {
        Document document = new Document();
        document.loadFromFile(filePath);
        Dimension2D pageSize = document.getLastSection().getPageSetup().getPageSize();
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        BufferedImage bfi = readAndResizePNGImage((int)pageSize.getWidth(), (int) (pageSize.getHeight()));
        ImageIO.write(bfi, "png", out);

        PictureWatermark picture = new PictureWatermark();
        InputStream input = new ByteArrayInputStream(out.toByteArray());
        //设置图片
        picture.setPicture(input);       
        //是否冲刷,true->图片色彩变淡,false->原色彩
        picture.isWashout(false);
        //保存文档
        document.setWatermark(picture);
        String savePath = FileProcessingUtil.getSavePath(filePath);
        document.saveToFile(savePath, FileFormat.Docx);

        return savePath;
    }

    /**
     * pdf加水印图片
     *
     * @param filePath 文件路径
     * @return {@link String}
     * @throws IOException       ioexception
     * @throws DocumentException 文件异常
     */
    public static String setWaterMarkToPdf(String filePath) throws IOException, DocumentException {

        PdfReader reader = new PdfReader(filePath);
        //获取首页尺寸 定制水印大小
        com.itextpdf.text.Rectangle ps = reader.getPageSize(1);
//        BufferedImage bfi = createWatermarkImage(WATER_MARK_TEXT, (int) ps.getWidth(), (int) ps.getHeight());
        BufferedImage bfi = readAndResizePNGImage((int) ps.getWidth(), (int) ps.getHeight());
        //保存路径
        String savePath = FileProcessingUtil.getSavePath(filePath);
        PdfStamper stamper = new PdfStamper(reader, Files.newOutputStream(Paths.get(savePath)));
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ImageIO.write(bfi, "png", out);
        //将图片放入pdf中
        com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(out.toByteArray());
        //获取pdf页数
        int num = reader.getNumberOfPages();
        com.itextpdf.text.Rectangle pageSize;
        float width;
        float height;
        for (int i = 1; i < num + 1; i++) {
            //得到页面大小
            pageSize = reader.getPageSize(i);
            width = pageSize.getWidth();
            height = pageSize.getHeight();
            //水印图片设置在内容之上,之下用getUnderContent
//            PdfContentByte pdfContentByte = stamper.getUnderContent(i);
            PdfContentByte pdfContentByte = stamper.getOverContent(i);
            //设置图片的位置,参数Image.UNDERLYING是作为文字的背景显示。
            image.setAlignment(com.itextpdf.text.Image.UNDERLYING);
            //设置图片的绝对位置
            image.scaleToFit(width, height);
            image.setAbsolutePosition((width - image.getScaledWidth()) / 2, (height - image.getScaledHeight()) / 2);
            pdfContentByte.addImage(image);
        }
        stamper.close();
        reader.close();
        return savePath;
    }


    /**
     * PPT设置水印图片
     *
     * @param filePath 原始文件路径
     * @return 新文件保存路径
     */
    public static String setPPTWaterMarkPic(String filePath) {
        String savePath = FileProcessingUtil.getSavePath(filePath);
        if (PowerPointTypeDetectionUtil.isPpt(filePath)) {
            //ppt
            try (HSLFSlideShow ppt = new HSLFSlideShow(new HSLFSlideShowImpl(filePath));
                 FileOutputStream out = new FileOutputStream(savePath)) {
                java.awt.Dimension pgsize = ppt.getPageSize();
                BufferedImage bfi = readAndResizePNGImage(pgsize.width, pgsize.height);
                ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
                ImageIO.write(bfi, "png", byteArrayOut);
                HSLFPictureData pd = ppt.addPicture(byteArrayOut.toByteArray(), PictureData.PictureType.JPEG);
                HSLFPictureShape pictNew = new HSLFPictureShape(pd);
                pictNew.setAnchor(new java.awt.Rectangle(0, 0, pgsize.width, pgsize.height));
                for (HSLFSlide slide : ppt.getSlides()) {
                    slide.addShape(pictNew);
                }
                ppt.write(out);
            } catch (IOException e) {
                LOG.error(e.getMessage(), e);
                throw new CoreException(ErrorCodeEnum.FILE_NOT_EXISTS);
            }
        } else {
            //pptx
            try (
                    XMLSlideShow slideShow = new XMLSlideShow(Files.newInputStream(Paths.get(filePath)));
                    FileOutputStream out = new FileOutputStream(savePath)
            ) {
                int height = (int) slideShow.getPageSize().getHeight();
                int width = (int) slideShow.getPageSize().getWidth();
                //获取水印
                BufferedImage bfi = readAndResizePNGImage(width, height);
                ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
                ImageIO.write(bfi, "png", byteArrayOut);
                PictureData pictureData = slideShow.addPicture(byteArrayOut.toByteArray(), PictureData.PictureType.PNG);
                for (XSLFSlide slide : slideShow.getSlides()) {
                    XSLFPictureShape pictureShape = slide.createPicture(pictureData);
                    pictureShape.setAnchor(new java.awt.Rectangle(0, 0, width, height));
                }
                slideShow.write(out);
            } catch (IOException e) {
                LOG.error("生成PPT文件失败:" + e,e);
                throw new CoreException(ErrorCodeEnum.FILE_SAVE_FAIL, "生成PPT文件失败");
            }
        }
        return savePath;
    }

    /**
     * ppt加水印文字
     *
     * @param filePath 原始文件路径
     * @return {@link String} 新文件保存路径
     */
    public static String setWaterMarkToPpt(String filePath) throws Exception {
        Presentation ppt = new Presentation();
        ppt.loadFromFile(filePath);
        //获取指定幻灯片
        SlideCollection slides = ppt.getSlides();
        //获取PPT宽高
        double widthOrig = ppt.getSlideSize().getSize().getWidth();
        //设置文本水印文本宽和高
        int width = 180;
        int height = 50;
        for (int k = 0; k < slides.size(); k++) {
            //起始坐标
            float x = (float) ((widthOrig / 3) - 100 - (2 * width / 3));
            float y = 40;
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 3; j++) {
                    //绘制文本,设置文本格式并将其添加到第一张幻灯片
                    Rectangle2D.Double rect = new Rectangle2D.Double(x, y, width, height);
                    IAutoShape shape = slides.get(k).getShapes().appendShape(ShapeType.RECTANGLE, rect);
                    shape.getFill().setFillType(FillFormatType.NONE);
                    shape.getShapeStyle().getLineColor().setColor(Color.white);
                    shape.setRotation(-30);
                    shape.getLocking().setSelectionProtection(true);
                    shape.getLine().setFillType(FillFormatType.NONE);
                    shape.getTextFrame().setText(WATER_MARK_TEXT);
                    shape.setShapeArrange(ShapeAlignmentEnum.ShapeArrange.BringToFront);
                    PortionEx textRange = shape.getTextFrame().getTextRange();
                    textRange.getFill().setFillType(FillFormatType.SOLID);
                    textRange.getFill().getSolidColor().setColor(Color.pink);
                    textRange.setFontHeight(20);
                    x += (100 + widthOrig / 6);
                }
                x = (float) ((widthOrig / 3) - 100 - (2 * width / 3));
                y += (100 + ppt.getSlideSize().getSize().getHeight() / 7);
            }
        }
        //保存文档
        String savePath = FileProcessingUtil.getSavePath(filePath);
        ppt.saveToFile(savePath, com.spire.presentation.FileFormat.PPSX_2013);
        ppt.dispose();
        return savePath;
    }


    /**
     * 图片加水印
     *
     * @param filePath 文件路径
     * @return {@link String}
     */
    public static String setWaterMarkToImg(String filePath) throws IOException {

        //获取画布
        BufferedImage read = ImageIO.read(new File(filePath));
        Graphics2D graphics = read.createGraphics();

        //缩放水印图片
        int width = read.getWidth();
        int height = read.getHeight();
        BufferedImage bfi = readAndResizePNGImage(width, height);
        //设置比例
        float f = 1.0f;
        //获取缩放后的宽度
        int w = (int) (width * f);
        int h = (int) (height * f);
        //缩放图片
//        Image image = bfi.getScaledInstance(w, h, Image.SCALE_SMOOTH);
        //alpha 设置透明度,0->1,逐渐不透明
        //SRC_ATOP 重叠模式:源置顶,取并集
        graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 1.0F));
        //添加水印并设置在图片的右下角
        graphics.drawImage(bfi, read.getWidth() - w, read.getHeight() - h, null);
        //释放资源
        graphics.dispose();
        //保存图片
        String savePath = FileProcessingUtil.getSavePath(filePath);
        ImageIO.write(read, filePath.substring(filePath.lastIndexOf(".") + 1), new File(savePath));
        return savePath;
    }


    /**
     * 视频加水印
     *
     * @param videoPath 视频源地址
     * @return 保存路径
     */
    public static String setWaterMarkToVideo(String videoPath) {

        //获取原视频分辨率 以生成适配水印图案
        VideoSize videoSize = VideoUtil.getVideoSize(videoPath);

        String videoSavePath = FileProcessingUtil.getSavePath(videoPath);
        try (ProcessWrapper ffmpeg = new DefaultFFMPEGLocator().createExecutor()) {
            //读取水印图片
            BufferedImage bufferedImage = readAndResizePNGImage(videoSize.getWidth(), videoSize.getHeight(), "static/template/videoWaterMark.png");
            File tempImg = FileUtil.createTempFile(".png", true);
            ImageIO.write(bufferedImage, "png", tempImg);
            long start = System.currentTimeMillis();
            LOG.info("开始添加水印....");

            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(videoPath);
            ffmpeg.addArgument("-i");
            ffmpeg.addArgument(tempImg.getPath());
            ffmpeg.addArgument("-filter_complex");
            ffmpeg.addArgument("overlay");
            ffmpeg.addArgument(videoSavePath);
            ffmpeg.execute();
            try (BufferedReader br = new BufferedReader(new InputStreamReader(ffmpeg.getErrorStream()))) {
                blockFfmpeg(br);
            }
            long end = System.currentTimeMillis();
            LOG.info("添加水印完成={},耗时{}秒", videoSavePath, (end - start) / 1000);
            if (tempImg.delete()) {
                LOG.info("删除临时水印图片");
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw new CoreException(ErrorCodeEnum.SYS_ERROR, "添加水印失败");
        }
        return videoSavePath;
    }




    /**
     * 等待命令执行成功,退出
     *
     * @param br br
     * @throws IOException io
     */
    private static void blockFfmpeg(BufferedReader br) throws IOException {
        String line;
        // 该方法阻塞线程,直至合成成功
        while ((line = br.readLine()) != null) {
            doNothing(line);
        }
    }

    /**
     * 打印日志,调试阶段可解开注释,观察执行情况
     *
     * @param line 每行内容
     */
    private static void doNothing(String line) {
//        LOG.info(line);
    }



}
2.表格文件工具类

import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.ReadingOrder;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.Units;
import org.apache.poi.xssf.usermodel.*;
import org.springframework.util.CollectionUtils;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 表格文件工具类
 */
public class ExcelFileUtil {

    private static final String XLS_TYPE = "xls";
    private static final String XLSX_TYPE = "xlsx";


    /**
     * 表格文件类型解析
     * 取文件的前8个字节来判断
     * 用于区分xls和xlsx文件的真实类型,防止用户篡改文件类型
     */
    public static String getType(String filePath) {
        try (FileInputStream fis = new FileInputStream(filePath)) {
            byte[] header = new byte[8];
            if (fis.read(header)==8) {
                if (isXLSFile(header)) {
                    return XLS_TYPE;
                } else if (isXLSXFile(header)) {
                    return XLSX_TYPE;
                } else {
                    return "Unknown file format.";
                }
            }else {
                throw new CoreException(ErrorCodeEnum.FILE_READ_FAIL);
            }
        } catch (IOException e) {
            throw new CoreException(ErrorCodeEnum.FILE_READ_FAIL);
        }
    }

    private static boolean isXLSFile(byte[] header) {
        return header[0] == (byte) 0xD0 && header[1] == (byte) 0xCF &&
                header[2] == (byte) 0x11 && header[3] == (byte) 0xE0 &&
                header[4] == (byte) 0xA1 && header[5] == (byte) 0xB1 &&
                header[6] == (byte) 0x1A && header[7] == (byte) 0xE1;
    }

    private static boolean isXLSXFile(byte[] header) {
        return header[0] == (byte) 'P' && header[1] == (byte) 'K';
    }


    /**
     * 复制工作簿
     * @param source 源文件
     * @param destination 目标文件
     */
    public static void copySheets(HSSFSheet source, XSSFSheet destination) {

        int maxColumnNum = 0;
        // 获取全部的合并单元格
        List<CellRangeAddress> cellRangeAddressList = source.getMergedRegions();
        for (int i = source.getFirstRowNum(); i <= source.getLastRowNum(); i++) {
            HSSFRow srcRow = source.getRow(i);
            XSSFRow destRow = destination.createRow(i);
            if (srcRow != null) {
                // 拷贝行
                copyRow(destination, srcRow, destRow, cellRangeAddressList);
                if (srcRow.getLastCellNum() > maxColumnNum) {
                    maxColumnNum = srcRow.getLastCellNum();
                }
            }
        }
        for (int i = 0; i <= maxColumnNum; i++) {
            destination.setColumnWidth(i, source.getColumnWidth(i));
        }

        // 拷贝图片
        copyPicture(source, destination);
    }


    // 拷贝行
    private static void copyRow(XSSFSheet destSheet, HSSFRow srcRow, XSSFRow destRow,
                                List<CellRangeAddress> cellRangeAddressList) {

        // 拷贝行高
        destRow.setHeight(srcRow.getHeight());

        for (int j = srcRow.getFirstCellNum(); j <= srcRow.getLastCellNum() && j >= 0; j++) {
            HSSFCell oldCell = srcRow.getCell(j);
            XSSFCell newCell = destRow.getCell(j);
            if (oldCell != null) {
                if (newCell == null) {
                    newCell = destRow.createCell(j);
                }
                // 拷贝单元格
                copyCell(oldCell, newCell, destSheet);

                // 获取原先的合并单元格
                CellRangeAddress mergedRegion = getMergedRegion(cellRangeAddressList, srcRow.getRowNum(),
                        (short) oldCell.getColumnIndex());

                if (mergedRegion != null) {
                    // 参照创建合并单元格
                    CellRangeAddress newMergedRegion = new CellRangeAddress(mergedRegion.getFirstRow(),
                            mergedRegion.getLastRow(), mergedRegion.getFirstColumn(), mergedRegion.getLastColumn());
                    destSheet.addMergedRegion(newMergedRegion);
                }
            }
        }

    }

    // 拷贝单元格
    private static void copyCell(HSSFCell oldCell, XSSFCell newCell, XSSFSheet destSheet) {

        HSSFCellStyle sourceCellStyle = oldCell.getCellStyle();
        XSSFCellStyle targetCellStyle = destSheet.getWorkbook().createCellStyle();

        if (sourceCellStyle == null) {
            sourceCellStyle = oldCell.getSheet().getWorkbook().createCellStyle();
        }

        targetCellStyle.setFillForegroundColor(sourceCellStyle.getFillForegroundColor());
        // 设置对齐方式
        targetCellStyle.setAlignment(sourceCellStyle.getAlignment());
        targetCellStyle.setVerticalAlignment(sourceCellStyle.getVerticalAlignment());

        // 设置字体
        XSSFFont xssfFont = destSheet.getWorkbook().createFont();
        HSSFFont hssfFont = sourceCellStyle.getFont(oldCell.getSheet().getWorkbook());
        copyFont(xssfFont, hssfFont);
        targetCellStyle.setFont(xssfFont);
        // 文本换行
        targetCellStyle.setWrapText(sourceCellStyle.getWrapText());

        targetCellStyle.setBorderBottom(sourceCellStyle.getBorderBottom());
        targetCellStyle.setBorderLeft(sourceCellStyle.getBorderLeft());
        targetCellStyle.setBorderRight(sourceCellStyle.getBorderRight());
        targetCellStyle.setBorderTop(sourceCellStyle.getBorderTop());
        targetCellStyle.setBottomBorderColor(sourceCellStyle.getBottomBorderColor());
        targetCellStyle.setDataFormat(sourceCellStyle.getDataFormat());
        targetCellStyle.setFillBackgroundColor(sourceCellStyle.getFillBackgroundColor());
        targetCellStyle.setFillPattern(sourceCellStyle.getFillPattern());

        targetCellStyle.setHidden(sourceCellStyle.getHidden());
        targetCellStyle.setIndention(sourceCellStyle.getIndention());
        targetCellStyle.setLeftBorderColor(sourceCellStyle.getLeftBorderColor());
        targetCellStyle.setLocked(sourceCellStyle.getLocked());
        targetCellStyle.setQuotePrefixed(sourceCellStyle.getQuotePrefixed());
        targetCellStyle.setReadingOrder(ReadingOrder.forLong(sourceCellStyle.getReadingOrder()));
        targetCellStyle.setRightBorderColor(sourceCellStyle.getRightBorderColor());
        targetCellStyle.setRotation(sourceCellStyle.getRotation());

        newCell.setCellStyle(targetCellStyle);

        switch (oldCell.getCellType()) {
            case STRING:
                newCell.setCellValue(oldCell.getStringCellValue());
                break;
            case NUMERIC:
                newCell.setCellValue(oldCell.getNumericCellValue());
                break;
            case BLANK:
                newCell.setCellType(CellType.BLANK);
                break;
            case BOOLEAN:
                newCell.setCellValue(oldCell.getBooleanCellValue());
                break;
            case ERROR:
                newCell.setCellErrorValue(oldCell.getErrorCellValue());
                break;
            case FORMULA:
                newCell.setCellFormula(oldCell.getCellFormula());
                break;
            default:
                break;
        }

    }

    // 拷贝字体设置
    private static void copyFont(XSSFFont xssfFont, HSSFFont hssfFont) {
        xssfFont.setFontName(hssfFont.getFontName());
        xssfFont.setBold(hssfFont.getBold());
        xssfFont.setFontHeight(hssfFont.getFontHeight());
        xssfFont.setCharSet(hssfFont.getCharSet());
        xssfFont.setColor(hssfFont.getColor());
        xssfFont.setItalic(hssfFont.getItalic());
        xssfFont.setUnderline(hssfFont.getUnderline());
        xssfFont.setTypeOffset(hssfFont.getTypeOffset());
        xssfFont.setStrikeout(hssfFont.getStrikeout());
    }

    // 根据行列获取合并单元格
    public static CellRangeAddress getMergedRegion(List<CellRangeAddress> cellRangeAddressList, int rowNum, short cellNum) {
        for (int i = 0; i < cellRangeAddressList.size(); i++) {
            CellRangeAddress merged = cellRangeAddressList.get(i);
            if (merged.isInRange(rowNum, cellNum)) {
                // 已经获取过不再获取
                cellRangeAddressList.remove(i);
                return merged;
            }
        }
        return null;
    }

    // 拷贝图片
    private static void copyPicture(HSSFSheet source, XSSFSheet destination) {
        // 获取sheet中的图片信息
        List<Map<String, Object>> mapList = getPicturesFromHSSFSheet(source);
        if (CollectionUtils.isEmpty(mapList)) {
            return;
        }
        XSSFDrawing drawing = destination.createDrawingPatriarch();

        for (Map<String, Object> pictureMap : mapList) {

            HSSFClientAnchor hssfClientAnchor = (HSSFClientAnchor) pictureMap.get("pictureAnchor");

            HSSFRow startRow = source.getRow(hssfClientAnchor.getRow1());
            float startRowHeight = startRow == null ? source.getDefaultRowHeightInPoints() : startRow.getHeightInPoints();

            HSSFRow endRow = source.getRow(hssfClientAnchor.getRow1());

            float endRowHeight = endRow == null ? source.getDefaultRowHeightInPoints() : endRow.getHeightInPoints();

            // hssf的单元格,每个单元格无论宽高,都被分为 宽 1024个单位 高 256个单位。
            // 32.00f 为默认的单元格单位宽度 单元格宽度 / 默认宽度 为像素宽度
            XSSFClientAnchor xssfClientAnchor = drawing.createAnchor(
                    (int) (source.getColumnWidth(hssfClientAnchor.getCol1()) / 32.00f
                            / 1024 * hssfClientAnchor.getDx1() * Units.EMU_PER_PIXEL),
                    (int) (startRowHeight / 256 * hssfClientAnchor.getDy1() * Units.EMU_PER_POINT),
                    (int) (source.getColumnWidth(hssfClientAnchor.getCol2()) / 32.00f
                            / 1024 * hssfClientAnchor.getDx2() * Units.EMU_PER_PIXEL),
                    (int) (endRowHeight / 256 * hssfClientAnchor.getDy2() * Units.EMU_PER_POINT),
                    hssfClientAnchor.getCol1(),
                    hssfClientAnchor.getRow1(),
                    hssfClientAnchor.getCol2(),
                    hssfClientAnchor.getRow2());
            xssfClientAnchor.setAnchorType(hssfClientAnchor.getAnchorType());

            drawing.createPicture(xssfClientAnchor,
                    destination.getWorkbook().addPicture((byte[]) pictureMap.get("pictureByteArray"),
                            Integer.parseInt(pictureMap.get("pictureType").toString())));

            System.out.println("imageInsert");
        }
    }

    /**
     * 获取图片和位置 (xls)
     */
    private static List<Map<String, Object>> getPicturesFromHSSFSheet(HSSFSheet sheet) {
        List<Map<String, Object>> mapList = new ArrayList<>();
        HSSFPatriarch drawingPatriarch = sheet.getDrawingPatriarch();
        if (drawingPatriarch == null) {
            return null;
        }
        List<HSSFShape> list = drawingPatriarch.getChildren();
        for (HSSFShape shape : list) {
            if (shape instanceof HSSFPicture) {
                Map<String, Object> map = new HashMap<>();
                HSSFPicture picture = (HSSFPicture) shape;
                HSSFClientAnchor cAnchor = picture.getClientAnchor();
                HSSFPictureData pdata = picture.getPictureData();
                map.put("pictureAnchor", cAnchor);
                map.put("pictureByteArray", pdata.getData());
                map.put("pictureType", pdata.getPictureType());
                map.put("pictureSize", picture.getImageDimension());
                mapList.add(map);
            }
        }
        return mapList;
    }

}
3. PPT工具类


import java.io.FileInputStream;
import java.io.IOException;

public class PowerPointTypeDetectionUtil {

    /**
     * 取文件的前8个字节来判断
     * 用于区分ppt和pptx文件的真实类型,防止用户篡改文件类型
     * @param filePath 文件路径
     * @return 是否为ppt
     */
    public static boolean isPpt(String filePath) {
        try (FileInputStream fis = new FileInputStream(filePath)) {
            byte[] headerBytes = new byte[8];
            fis.read(headerBytes);
            return (headerBytes[0] == (byte) 0xD0 &&
                    headerBytes[1] == (byte) 0xCF &&
                    headerBytes[2] == (byte) 0x11 &&
                    headerBytes[3] == (byte) 0xE0 &&
                    headerBytes[4] == (byte) 0xA1 &&
                    headerBytes[5] == (byte) 0xB1 &&
                    headerBytes[6] == (byte) 0x1A &&
                    headerBytes[7] == (byte) 0xE1);
        } catch (IOException e) {
            e.printStackTrace();
            throw new CoreException(ErrorCodeEnum.FILE_READ_FAIL);
        }

    }

}
4. 视频工具类
package com.bigdatacd.file.processing.util;

import cn.hutool.core.io.FileUtil;
import com.bigdatacd.data.commons.enums.ErrorCodeEnum;
import com.bigdatacd.data.commons.exception.CoreException;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ws.schild.jave.MultimediaObject;
import ws.schild.jave.info.MultimediaInfo;
import ws.schild.jave.info.VideoSize;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class VideoUtil {
    private static final Logger LOG = LoggerFactory.getLogger(VideoUtil.class);

    /**
     * 读取视频 获取分辨率
     *
     * @param FileUrl 视频地址
     * @return VideoSize
     */
    public static VideoSize getVideoSize(String FileUrl) {
        File source = new File(FileUrl);
        try {
            MultimediaObject instance = new MultimediaObject(source);
            MultimediaInfo result = instance.getInfo();
            return result.getVideo().getSize();
        } catch (Exception e) {
            LOG.error(e.getMessage(), e);
            throw new CoreException(ErrorCodeEnum.FILE_READ_FAIL);
        }

    }


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值