POI excel 添加水印 xls,xlsx

依赖jar包

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

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.2.8</version>
</dependency>

package com.excelTool.util;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.imageio.ImageIO;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.hssf.model.InternalSheet;
import org.apache.poi.hssf.record.ContinueRecord;
import org.apache.poi.hssf.record.RecordBase;
import org.apache.poi.hssf.record.StandardRecord;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
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.IndexedColors;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.LittleEndianOutput;
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;

public class ExcelWaterMarkUtil {
	private final static Logger logger = LoggerFactory.getLogger(ExcelWaterMarkUtil.class);
	public static void main(String[] args) {
		String filePath = excelWaterMarkForXlsx("C:\\123.xlsx","牛哄哄");
		String filePath1 = excelWaterMarkForXls("C:\\1234.xls","牛哄哄");
	}

	/**
	 *  xlsx 类型添加水印
	 * @param inputFilePath
	 * @param text
	 * @return
	 */
	public static String excelWaterMarkForXlsx(String inputFilePath,String text) {
		FileInputStream is = null;
		FileOutputStream out = null;
		XSSFWorkbook workbook = null;
		ByteArrayOutputStream os = null;
		try {
			//生成水印图片并导出字节流
			BufferedImage image = FontImageUtil.createWatermarkImage(new FontImageUtil.Watermark(true,text, null,null));
			os = new ByteArrayOutputStream();
			ImageIO.write(image, "png", os);
			//获取excel工作簿
			is = new FileInputStream(inputFilePath);
			workbook = new XSSFWorkbook(is);
			int pictureIdx = workbook.addPicture(os.toByteArray(), Workbook.PICTURE_TYPE_PNG);
			POIXMLDocumentPart poixmlDocumentPart = workbook.getAllPictures().get(pictureIdx);
			//获取每个Sheet表并插入水印
			for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
				XSSFSheet sheet1 = workbook.getSheetAt(i);
				PackagePartName ppn = poixmlDocumentPart.getPackagePart().getPartName();
				String relType = XSSFRelation.IMAGES.getRelation();
				//add relation from sheet to the picture data
				PackageRelationship pr = sheet1.getPackagePart().addRelationship(ppn, TargetMode.INTERNAL, relType, null);
				//set background picture to sheet
				sheet1.getCTWorksheet().addNewPicture().setId(pr.getId());
			}
			//生成添加水印的excel文件
			File f = new File(inputFilePath);
			String outputFilePath = f.getParent() + File.separator+System.currentTimeMillis()+ f.getName();
			out = new FileOutputStream(outputFilePath);
			workbook.write(out);
			return outputFilePath;
		} catch (Exception e) {
			logger.error("excel文件添加水印异常",e);
		}finally {
			if (is != null){
				try {
					is.close();
				}catch (Exception e){
					logger.error("excel输入文件关闭异常",e);
				}
			}
			if (out != null){
				try {
					out.close();
				}catch (Exception e){
					logger.error("excel输出文件关闭异常",e);
				}
			}
			if (workbook != null){
				try {
					workbook.close();
				}catch (Exception e){
					logger.error("excel工作簿关闭异常",e);
				}
			}
			if (os != null){
				try {
					os.close();
				}catch (Exception e){
					logger.error("水印图片字节流关闭异常",e);
				}
			}
		}
		return "";
	}

	/**
	 *  xls 类型添加水印
	 * @param inputFilePath
	 * @param text
	 * @return
	 */
	public static String excelWaterMarkForXls(String inputFilePath,String text) {
		FileInputStream is = null;
		FileOutputStream out = null;
		HSSFWorkbook workbook = null;
		ByteArrayOutputStream os = null;
		//水印图片
		String tarImgPath = "";
		try {
			//生成水印图片并导出字节流
			BufferedImage image = FontImageUtil.createWatermarkImage(new FontImageUtil.Watermark(true,text, null,null));
			File f1 = new File(inputFilePath);
			tarImgPath = f1.getParent() + File.separator+System.nanoTime()+text+ ".png";
			FileOutputStream outImgStream = new FileOutputStream(tarImgPath);
			ImageIO.write(image, "png", outImgStream);

			//获取excel工作簿
			is = new FileInputStream(inputFilePath);
			workbook = new HSSFWorkbook(is);

			//获取每个Sheet表并插入水印
			// get bytes of the image file
			byte[] data = getBackgroundBitmapData(tarImgPath); //PNG must not have transparency
			for (int k = 0; k < workbook.getNumberOfSheets(); k++) {
				HSSFSheet sheet1 = workbook.getSheetAt(k);

				Field _sheet = HSSFSheet.class.getDeclaredField("_sheet");
				_sheet.setAccessible(true);
				InternalSheet internalsheet = (InternalSheet)_sheet.get(sheet1);
				// get List of RecordBase
				Field _records = InternalSheet.class.getDeclaredField("_records");
				_records.setAccessible(true);
				@SuppressWarnings("unchecked")
				List<RecordBase> records = (List<RecordBase>)_records.get(internalsheet);



				// do creating BitmapRecord and ContinueRecords from the data in parts of 8220 bytes
				BitmapRecord bitmapRecord;
				List<ContinueRecord> continueRecords = new ArrayList<>();
				int bytes;

				if (data.length > 8220) {
					bitmapRecord = new BitmapRecord(Arrays.copyOfRange(data, 0, 8220));
					bytes = 8220;
					while (bytes < data.length) {
						if ((bytes + 8220) < data.length) {
							continueRecords.add(new ContinueRecord(Arrays.copyOfRange(data, bytes, bytes + 8220)));
							bytes += 8220;
						} else {
							continueRecords.add(new ContinueRecord(Arrays.copyOfRange(data, bytes, data.length)));
							break;
						}
					}
				} else {
					bitmapRecord = new BitmapRecord(data);
				}

				// add the records after PageSettingsBlock
				int i = 0;
				for (RecordBase r : records) {
					if (r instanceof org.apache.poi.hssf.record.aggregates.PageSettingsBlock) {
						break;
					}
					i++;
				}
				records.add(++i, bitmapRecord);
				for (ContinueRecord continueRecord : continueRecords) {
					records.add(++i, continueRecord);
				}

//				// debug output
//				for (RecordBase r : internalsheet.getRecords()) {
//					System.out.println(r);
//				}
			}
			//生成添加水印的excel文件
			File f = new File(inputFilePath);
			String outputFilePath = f.getParent() + File.separator+System.currentTimeMillis()+ f.getName();
			out = new FileOutputStream(outputFilePath);
			logger.info(outputFilePath);
			outImgStream.close();
			boolean res = new File(tarImgPath).delete();
			workbook.write(out);
			return outputFilePath;
		} catch (Exception e) {
			logger.error("excel文件添加水印异常",e);
		}finally {
			if (is != null){
				try {
					is.close();
				}catch (Exception e){
					logger.error("excel输入文件关闭异常",e);
				}
			}
			if (out != null){
				try {
					out.close();
				}catch (Exception e){
					logger.error("excel输出文件关闭异常",e);
				}
			}
			if (workbook != null){
				try {
					workbook.close();
				}catch (Exception e){
					logger.error("excel工作簿关闭异常",e);
				}
			}
			if (os != null){
				try {
					os.close();
				}catch (Exception e){
					logger.error("水印图片字节流关闭异常",e);
				}
			}
			new File(tarImgPath).delete();
		}
		return "";
	}
	static byte[] getBackgroundBitmapData(String filePath) throws Exception {

		//see https://www.openoffice.org/sc/excelfileformat.pdf - BITMAP

		// get file byte data in type BufferedImage.TYPE_3BYTE_BGR
		FileInputStream fio = new FileInputStream(filePath);
		BufferedImage in = ImageIO.read(fio);
		BufferedImage image = new BufferedImage(in.getWidth(), in.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
		Graphics2D graphics = image.createGraphics();
		graphics.drawImage(in, null, 0, 0);
		graphics.dispose();

		// calculate row size (c)
		int rowSize = ((24 * image.getWidth() + 31) / 32) * 4;

		ByteArrayOutputStream output = new ByteArrayOutputStream(image.getHeight() * rowSize * 3 + 1024);

		// put the record headers into the data
		ByteBuffer header = ByteBuffer.allocate(8 + 12);
		header.order(ByteOrder.LITTLE_ENDIAN);

		// Undocumented XLS stuff
		header.putShort((short) 0x09);
		header.putShort((short) 0x01);
		header.putInt(image.getHeight() * rowSize + 12); // Size of image stream

		// BITMAPCOREHEADER (a)
		header.putInt(12);

		header.putShort((short) image.getWidth());
		header.putShort((short) image.getHeight()); // Use -height if writing top-down

		header.putShort((short) 1); // planes, always 1
		header.putShort((short) 24); // bitcount

		output.write(header.array());

		// Output rows bottom-up (b)
		Raster raster = image.getRaster()
				.createChild(0, 0, image.getWidth(), image.getHeight(), 0, 0, new int[]{2, 1, 0}); // Reverse BGR -> RGB (d)
		byte[] row = new byte[rowSize]; // padded (c)

		for (int i = image.getHeight() - 1; i >= 0; i--) {
			row = (byte[]) raster.getDataElements(0, i, image.getWidth(), 1, row);
			output.write(row);
		}
		fio.close();

		return output.toByteArray();
	}

	static class BitmapRecord extends StandardRecord {

		//see https://www.openoffice.org/sc/excelfileformat.pdf - BITMAP

		byte[] data;

		BitmapRecord(byte[] data) {
			this.data = data;
		}

		@Override
		public int getDataSize() {
			return data.length;
		}

		@Override
		public short getSid() {
			return (short)0x00E9;
		}
		@Override
		public void serialize(LittleEndianOutput out) {
			out.write(data);
		}
	}

	static class ContinueRecord extends StandardRecord {

		//see https://www.openoffice.org/sc/excelfileformat.pdf - CONTINUE

		byte[] data;

		ContinueRecord(byte[] data) {
			this.data = data;
		}
		@Override
		public int getDataSize() {
			return data.length;
		}
		@Override
		public short getSid() {
			return (short)0x003C;
		}
		@Override
		public void serialize(LittleEndianOutput out) {
			out.write(data);
		}
	}
}
package com.excelTool.util;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.util.StringUtils;

public class FontImageUtil {
	/**
	 * 水印内容类
	 */
	public static class Watermark {
		private Boolean enable;
		private String text;
		private String dateFormat;
		private String color;

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

		public Watermark() {
		}

		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;
		}
	}

	/**
	 * 生成水印图片
	 * @param watermark
	 * @return
	 */
	public static BufferedImage createWatermarkImage(Watermark watermark) {
		if (watermark == null) {
			watermark = new Watermark();
			watermark.setEnable(true);
			watermark.setText("内部资料");
			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 (StringUtils.isEmpty(watermark.getText())) {
				watermark.setText("内部资料");
			}
			if (StringUtils.isEmpty(watermark.getColor())) {
				watermark.setColor("#C5CBCF");
			}
		}
		String[] textArray = watermark.getText().split("\n");
		Font font = new Font("microsoft-yahei", Font.PLAIN, 20);
		Integer width = 400;
		Integer height = 200;

		BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		// 背景透明 开始
		Graphics2D g = image.createGraphics();
//		image = g.getDeviceConfiguration().createCompatibleImage(width, height);
//		g.dispose();
		// 背景透明 结束
		g.setColor(Color.white);
		g.fillRect(0, 0, width , height);

		g.setColor(new Color(Integer.parseInt(watermark.getColor().substring(1), 16)));// 设定画笔颜色
		g.setFont(font);// 设置画笔字体
		g.shear(0.1, -0.26);// 设定倾斜度


		//        设置字体平滑
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

		int y = 50;
		for (int i = 0; i < textArray.length; i++) {
			g.drawString(textArray[i], 0, y);// 画出字符串
			y = y + font.getSize();
		}
		SimpleDateFormat sdf = new SimpleDateFormat(watermark.getDateFormat());
		g.drawString(sdf.format(new Date()), 0, y);// 画出字符串

		g.dispose();// 释放画笔
		return image;

	}
}

在使用POI库操作Excel文件时,可以通过添加水印的方式来给Excel文件添加背景图案或文字标识。下面是一个简单的示例代码来演示如何使用POI添加水印。 首先,我们需要导入POI库的相关类: ``` import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFSheet; ``` 然后,我们需要加载Excel文件并创建一个工作簿对象: ``` String filePath = "path/to/excel/file.xlsx"; Workbook workbook = new XSSFWorkbook(filePath); ``` 接下来,创建一个新的工作表对象,并获取当前工作表的绘图对象: ``` Sheet sheet = workbook.createSheet(); Drawing drawing = sheet.createDrawingPatriarch(); ``` 创建一个文本对象,并设置文本内容以及位置: ``` ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 1, 2, 3, 4); TextShape text = drawing.createTextbox(anchor); text.setText("水印文字"); ``` 设置文本样式、字体、颜色等: ``` text.setLineStyle(LineStyle.NONE); text.setNoFill(true); text.setVerticalAlignment(VerticalAlignment.CENTER); text.setHorizontalAlignment(HorizontalAlignment.CENTER); text.setFontFamily("宋体"); text.setFontSize(20); text.setFillColor(IndexedColors.GREY_25_PERCENT.getIndex()); ``` 最后,保存修改并关闭Excel文件: ``` FileOutputStream fileOut = new FileOutputStream("path/to/output/file.xlsx"); workbook.write(fileOut); fileOut.close(); workbook.close(); ``` 通过以上代码,我们可以将"水印文字"添加Excel文件的水印。可以根据自己的需求调整水印的位置、样式和内容等。同时需要注意的是,以上代码适用于POI版本为4.1.2。 希望以上内容对您有所帮助。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值