关于POI工具类绘制水印,箭头等功能
绘制水印:
/** * 绘制水印图片 * @param text * @param width * @param height * @return */ public static BufferedImage createWatermarkImage(String text, Integer width, Integer height) { java.awt.Font font = new java.awt.Font("microsoft-yahei", java.awt.Font.PLAIN, 20); 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 java.awt.Color(Integer.parseInt("C5CBCF", 16)));// 设定画笔颜色 g.setFont(font);// 设置画笔字体 g.shear(0.1, -0.26);// 设定倾斜度 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // 设置字体平滑 // 字体长度 //int markWidth = font.getSize() * getTextLength (text); int markWidth = font.getSize() * text.length(); // 字体高度 int markHeight = font.getSize(); // 循环添加水印 int x = 0; int y = 50; while (x < width) { while (y < height) { g.drawString (text, x, y); y += markHeight + 100; } x += markWidth + 150; y = 50; } g.dispose();// 释放画笔 return image; } /** * 为Excel打上水印工具函数 * 请自行确保参数值,以保证水印图片之间不会覆盖。 * 在计算水印的位置的时候,并没有考虑到单元格合并的情况,请注意 * @param wb Excel Workbook * @param sheet 需要打水印的Excel * @param waterRemarkPath 水印地址,classPath,目前只支持png格式的图片, * 因为非png格式的图片打到Excel上后可能会有图片变红的问题,且不容易做出透明效果。 * 同时请注意传入的地址格式,应该为类似:"\\excelTemplate\\test.png" * @throws IOException */ public static void putWaterRemarkToExcel(Workbook wb,Sheet sheet, BufferedImage waterRemarkPath) throws IOException{ //加载图片 ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(); if(null == waterRemarkPath) { throw new RuntimeException("向Excel上面打印水印,读取水印图片失败(2)。"); } ImageIO.write(waterRemarkPath,"png",byteArrayOut); //开始打水印 Drawing drawing = sheet.createDrawingPatriarch(); /* * 参数定义: * 第一个参数是(x轴的开始节点); * 第二个参数是(是y轴的开始节点); * 第三个参数是(是x轴的结束节点); * 第四个参数是(是y轴的结束节点); * 第五个参数是(是从Excel的第几列开始插入图片,从0开始计数); * 第六个参数是(是从excel的第几行开始插入图片,从0开始计数); * 第七个参数是(图片宽度,共多少列); * 第8个参数是(图片高度,共多少行); */ ClientAnchor anchor = drawing.createAnchor(0, 0, 255, 255, 0, 0, 1, 1); Picture pic = drawing.createPicture(anchor, wb.addPicture(byteArrayOut.toByteArray(), Workbook.PICTURE_TYPE_PNG)); pic.resize(); // 将表格设为只读,否则水印就没了意义 // sheet.protectSheet(UUID.randomUUID().toString()); }
插入箭头:
/** * 绘制箭头 * @param sheet * @param col1 第1个单元格的行号 * @param col1 第1个单元格的列号 * @param row1 第2个单元格的行号 * @param row2 第2个单元格的列号 */ public static void createArrow(XSSFSheet sheet, int col1, int row1, int col2, int row2){ // 计算偏移量 int dx1 = (sheet.getColumnWidth(col1)/2+500)*255; int dy1 = (sheet.getRow(row1).getHeight()+800)*255; int dx2 = (sheet.getColumnWidth(col2)/2+500)*255; int dy2 = (sheet.getRow(row2).getHeight()-200)*255; XSSFDrawing xssfdrawing = sheet.createDrawingPatriarch(); //顶级画布,只能有一个 /** 从左上角到右下角 */ if(col1 <= col2 && row1 <= row2) { XSSFClientAnchor xssfanchor = new XSSFClientAnchor(dx1,dy1,dx2,dy2,col1, row1,col2,row2); XSSFSimpleShape xssfshape = xssfdrawing.createSimpleShape(xssfanchor); xssfshape.setShapeType(ShapeTypes.LINE); xssfshape.setLineWidth(1.5); xssfshape.setLineStyle(0); xssfshape.setLineStyleColor(0, 0, 0); xssfshape.getCTShape().getSpPr().getLn().addNewTailEnd().setType(STLineEndType.TRIANGLE); } /** 从左下角到右上角 */ if(col1 <= col2 && row1 > row2) { // 方法只支持col1<col2且row1<row2的情况,所以此处需要反向传值,后面再反射显示 XSSFClientAnchor xssfanchor = new XSSFClientAnchor(dx1,dy1,dx2,dy2,col1, row2,col2,row1); XSSFSimpleShape xssfshape = xssfdrawing.createSimpleShape(xssfanchor); xssfshape.setShapeType(ShapeTypes.LINE); xssfshape.setLineWidth(1.5); xssfshape.setLineStyle(0); xssfshape.setLineStyleColor(0, 0, 0); xssfshape.getCTShape().getSpPr().getXfrm().setFlipV(true); // 将图形反射显示 xssfshape.getCTShape().getSpPr().getLn().addNewTailEnd().setType(STLineEndType.TRIANGLE); } /** 从右下角到左上角 */ if(col1 > col2 && row1 > row2) { XSSFClientAnchor xssfanchor = new XSSFClientAnchor(dx1,dy1,dx2,dy2,col2, row2,col1,row1); XSSFSimpleShape xssfshape = xssfdrawing.createSimpleShape(xssfanchor); xssfshape.setShapeType(ShapeTypes.LINE); xssfshape.setLineWidth(1.5); xssfshape.setLineStyle(0); xssfshape.setLineStyleColor(0, 0, 0); // 由于线是从左上角到右下角绘制,所以此处将箭头标在起点处 xssfshape.getCTShape().getSpPr().getLn().addNewHeadEnd().setType(STLineEndType.TRIANGLE); } /** 从右上角到左下角 */ if(col1 > col2 && row1 <= row2) { // 方法只支持col1<col2且row1<row2的情况,所以此处需要反向传值,后面再反射显示 XSSFClientAnchor xssfanchor = new XSSFClientAnchor(dx1,dy1,dx2,dy2,col2, row1,col1,row2); XSSFSimpleShape xssfshape = xssfdrawing.createSimpleShape(xssfanchor); xssfshape.setShapeType(ShapeTypes.LINE); xssfshape.setLineWidth(1.5); xssfshape.setLineStyle(0); xssfshape.setLineStyleColor(0, 0, 0); xssfshape.getCTShape().getSpPr().getXfrm().setFlipV(true); // 将图形反射显示 xssfshape.getCTShape().getSpPr().getLn().addNewHeadEnd().setType(STLineEndType.TRIANGLE); } }
插入图片:
/** * 插入图片 * @param wb * @param sheet * @param imgUrl * @param col1 * @param row1 * @param col2 * @param row2 */ public static void createPicture(XSSFWorkbook wb, XSSFSheet sheet, String imgUrl, int col1, int row1, int col2, int row2) { try { // 计算图片偏移量,使图片居中 int dx1 = sheet.getColumnWidth(col1)/2*255; int dy1 = ((row2-row1)*sheet.getRow(row1).getHeight()/2+600)*255; // 固定图片大小 double standardWidth = 2000; // 目标大小 double standardHeight = 600; double cellWidth = sheet.getColumnWidth(col1); // 计算单元格的长宽 double cellHeight = (row2-row1)*sheet.getRow(row1).getHeight(); double a = standardWidth / cellWidth; // 计算需要的长宽比例的系数 double b = standardHeight / cellHeight; ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(); InputStream input = getImageInputStream(imgUrl); byte[] buffer = new byte[100]; int n; while ((n = input.read(buffer)) != -1) { byteArrayOut.write(buffer, 0, n); } XSSFDrawing patriarch = sheet.createDrawingPatriarch(); XSSFClientAnchor anchor= new XSSFClientAnchor(dx1,dy1,0,0,col1,row1,col2,row2); Picture pict = patriarch.createPicture(anchor , wb.addPicture(byteArrayOut.toByteArray(),HSSFWorkbook.PICTURE_TYPE_JPEG)); pict.resize(a,b); input.close(); byteArrayOut.flush(); byteArrayOut.close();//不要忘记关闭InputStream 与ByteArrayOutputStream ,不然导出时会报错 }catch (Exception e) { e.printStackTrace(); } } //从存储图片的服务器读取图片流 private static InputStream getImageInputStream(String imgUrl) throws Exception{ HttpURLConnection httpURLConnection = null; InputStream inputStream = null; URL url = new URL(imgUrl); httpURLConnection = (HttpURLConnection) url.openConnection(); // 设置网络连接超时时间 httpURLConnection.setConnectTimeout(5000); // 设置应用程序要从网络连接读取数据 httpURLConnection.setDoInput(true); httpURLConnection.setRequestMethod("GET"); int responseCode = httpURLConnection.getResponseCode(); if (responseCode == 200) { // 从服务器返回一个输入流 inputStream = httpURLConnection.getInputStream(); } return inputStream; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探