Java excel添加水印

Excel水印工具类

public class ExcelWaterRemarkUtils {

    /**
     * 宽度
     */
    private static final int WIDTH = 360;
    /**
     * 高度
     */
    private static final int HEIGHT = 150;
    /**
     * 水印横向位置
     */
    private static int positionWidth = 80;
    /**
     * 水印纵向位置
     */
    private static int positionHeight = 30;
    /**
     * 水印文字 字体类型、风格、大小
     * microsoft-yahei、微软雅黑、宋体
     */
    private static Font font = new Font("微软雅黑", Font.PLAIN, 20);
    /**
     * 设置水印图片路径
     */
    private static String imgPath = "E:\\水印.png";
    /**
     * 防止生产环境部署在docker或者linux服务器上,很有可能会引起中文水印乱码,成了方块的情况,这时候需要自己导入字体放到项目路径
     */
    private static Font fontEncode = SystemLoadFont.styleFont(imgPath, Font.PLAIN, 30);
    /**
     * 水印文字颜色
     * 最后一个参数(第四个参数)为水印透明度
     */
    private static Color color = new Color(0, 0, 0, 80);

    /**
     * 根据文字生成水印图片
     *
     * @param text 水印文字
     * @return
     */
    public static BufferedImage createWaterMarkImage(String text) {
        // 获取bufferedImage对象创建空白图片
        BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_ARGB);
        // 获取Graphics2d对象创建图片画笔
        Graphics2D g = image.createGraphics();
        // 设置背景透明度
        image = g.getDeviceConfiguration().createCompatibleImage(WIDTH, HEIGHT, Transparency.TRANSLUCENT);
        g.dispose();
        g = image.createGraphics();
        // 设置对线段的锯齿状边缘处理
        // g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        // 文字处理
        AttributedString ats = new AttributedString(text);

        ats.addAttribute(TextAttribute.FONT, font, 0, text.length());
        //ats.addAttribute(TextAttribute.FONT, fontEncode, 0, text.length());

        AttributedCharacterIterator iter = ats.getIterator();
        // 水印旋转
        g.rotate(Math.toRadians(-15), (double) image.getWidth() / 2, (double) image.getHeight() / 2);
        // 设置水印文字颜色
        g.setColor(color);
        // 设置水印字体加粗
        g.setStroke(new BasicStroke(1));

        // 设置水印文字Font
        g.setFont(font);
        //g.setFont(fontEncode);

        // 设置水印文字透明度
        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
        // 水印位置
        g.drawString(iter, positionHeight, positionWidth);
        // 释放资源
        g.dispose();
        return image;
    }

    /**
     * 为Excel打上水印工具函数 请自行确保参数值,以保证水印图片之间不会覆盖。
     *
     * @param wb              Excel Workbook
     * @param sheet           需要打水印的Excel
     * @param image           水印图片
     * @param startXCol       水印起始列
     * @param startYRow       水印起始行
     * @param betweenXCol     水印横向之间间隔多少列
     * @param betweenYRow     水印纵向之间间隔多少行
     * @param XCount          横向共有水印多少个
     * @param YCount          纵向共有水印多少个
     * @param waterMarkWidth  水印图片宽度为多少列
     * @param waterMarkHeight 水印图片高度为多少行
     * @throws IOException
     */
    public static void putWaterMarkToExcel(Workbook wb, Sheet sheet, BufferedImage image, int startXCol,
                                           int startYRow, int betweenXCol, int betweenYRow, int XCount, int YCount, int waterMarkWidth,
                                           int waterMarkHeight) throws IOException {
        // 加载图片
        ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
        if (null == image) {
            throw new RuntimeException("向Excel上面打印水印,读取水印图片失败!");
        }
        ImageIO.write(image, "png", byteArrayOut);

        // 开始打水印
        Drawing drawing = sheet.createDrawingPatriarch();

        // 按照共需打印多少行水印进行循环
        for (int yCount = 0; yCount < YCount; yCount++) {
            // 按照每行需要打印多少个水印进行循环
            for (int xCount = 0; xCount < XCount; xCount++) {
                // 创建水印图片位置
                int xIndexInteger = startXCol + (xCount * waterMarkWidth) + (xCount * betweenXCol);
                int yIndexInteger = startYRow + (yCount * waterMarkHeight) + (yCount * betweenYRow);
                /*
                 * 参数定义: 第一个参数是(x轴的开始节点); 第二个参数是(是y轴的开始节点); 第三个参数是(是x轴的结束节点);
                 * 第四个参数是(是y轴的结束节点); 第五个参数是(是从Excel的第几列开始插入图片,从0开始计数);
                 * 第六个参数是(是从excel的第几行开始插入图片,从0开始计数); 第七个参数是(图片宽度,共多少列);
                 * 第8个参数是(图片高度,共多少行);
                 */
                ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, xIndexInteger, yIndexInteger, xIndexInteger + waterMarkWidth, yIndexInteger + waterMarkHeight);
                Picture pic = drawing.createPicture(anchor,
                        wb.addPicture(byteArrayOut.toByteArray(), Workbook.PICTURE_TYPE_PNG));
                pic.resize();
            }
        }
    }

}

Excel导出方法

private void export(HttpServletResponse response, Workbook workbook, String fileName, String text) throws Exception {
        // 重置响应对象
        response.reset();
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8") + ".xls");
        response.setHeader("content-Type", "application/vnd.ms-excel");
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);

        // 写出数据输出流到页面
        try {
            OutputStream output = response.getOutputStream();
            BufferedOutputStream bufferedOutPut = new BufferedOutputStream(output);
            byte[] bytes = text.getBytes();
            text = new String(bytes, StandardCharsets.UTF_8);
            BufferedImage bufferedImage = ExcelWaterRemarkUtils.createWaterMarkImage(text);

            int sheets = workbook.getNumberOfSheets();
            //循环sheet给每个sheet添加水印
            for (int i = 0; i < sheets; i++) {
                Sheet sheet = workbook.getSheetAt(i);
                //获取excel实际所占行
                int row = sheet.getFirstRowNum() + sheet.getLastRowNum();
                //获取excel实际所占列
                int cell = sheet.getRow(sheet.getFirstRowNum()).getLastCellNum() + 1;
                for (int n = 0; n < cell; n++) {
                    sheet.autoSizeColumn((short) n, false);
                }
                //根据行与列计算实际所需多少水印
                ExcelWaterRemarkUtils.putWaterMarkToExcel(workbook, sheet, bufferedImage, 0, 0, 5, 5, cell / 5 + 1, row / 5 + 1, 0, 0);
                //excel加密只读
                //sheet.protectSheet(UUID.randomUUID().toString());
            }
            workbook.write(bufferedOutPut);
            bufferedOutPut.flush();
            bufferedOutPut.close();
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

防止中文水印乱码

public class SystemLoadFont {

    /**
     * 本地读取方法
     *
     * @param path     文件路径
     * @param style    字体样式
     * @param fontSize 字体大小
     * @return
     */
    public static java.awt.Font styleFont(String path, int style, float fontSize) {
        return SystemLoadFont.loadStyleFont(path, style, fontSize);
    }

    /**
     * @param fontFileName 外部字体名
     * @param style        字体样式
     * @param fontSize     字体大小
     * @return
     */
    public static Font loadStyleFont(String fontFileName, int style, float fontSize) {
        try {
            File file = new File(fontFileName);
            FileInputStream in = new FileInputStream(file);
            Font dynamicFont = Font.createFont(Font.TRUETYPE_FONT, in);
            Font dynamicFontPt = dynamicFont.deriveFont(style, fontSize);
            in.close();
            return dynamicFontPt;
        } catch (Exception e) {//异常处理
            e.printStackTrace();
            return new java.awt.Font("微软雅黑", Font.PLAIN, 20);
        }
    }

}

poi框架如何生成加密的Excel

参考:poi框架如何生成加密的EXCEL_hht15927087748的博客-CSDN博客_excel加密 poi

附:

easypoi 导出excel 不需要本地模版,本地图片 添加水印,加密的方式 - 不摸的个人空间 - OSCHINA - 中文开源技术交流社区

java excel添加水印 - 简书

转载请注明出处:BestEternity亲笔。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值