java实现预览服务器文件,不进行下载,并增加水印效果

news2025/1/3 22:05:22

通过文件路径获取文件,对不同类型的文件进行不同处理,将Word文件转成pdf文件预览,并早呢更加水印,暂不支持Excel文件,如果浏览器不支持PDF文件预览需要下载插件。文中currentUser.getUserid(),即为增加的水印内容,需要替换掉,字符串类型的。

加水印用的包是pdfbox,不是itext7,这两个包有的方法名一致,但是穿的参数类型不一致,引用的包不对,会报错。BufferedImage引用的是java.awt.image.BufferedImage引用成pdfbox的也会报错,有报错的参数注意一下引用的包。

<dependency>
    <groupId>org.apache.pdfbox</groupId>
    <artifactId>pdfbox</artifactId>
    <version>2.0.24</version>
</dependency>
@RequestMapping("previewFile")
	public void download(String src,HttpServletRequest request,HttpServletResponse response) throws Exception {
		
		String filePath = src;
		System.out.println("filePath:" + filePath);
		File f = new File(filePath);
		if (!f.exists()) {
			response.sendError(404, "File not found!");
			return;
		}
		String fileName = f.getName();
		String extension = getFileExtension(f.getName());

		BufferedInputStream br = new BufferedInputStream(new FileInputStream(f));

		byte[] bs = new byte[1024];
		int len = 0;
		response.reset(); // 非常重要
		URL u = new URL("file:///" + filePath);
		//String contentType = u.openConnection().getContentType();
		String contentType = "";

		if(extension.equals("pdf")){
			contentType = "application/pdf";
			br = addWatermarkToPdf(filePath, currentUser.getUserid());
		}else if (extension.equals("txt")){
			contentType = "text/plain";
		}else if (extension.equals("doc") || extension.equals("docx")){
			contentType = "application/pdf";
			try {
				br = convertToPdf(filePath,currentUser.getUserid());
			}catch (Exception e){
			}
		}else if (extension.equals("jpg") || extension.equals("jpeg")){
			contentType = "image/jpeg";
			br = createWatermarkedImage(filePath, currentUser.getUserid());
		}else if (extension.equals("png")){
			contentType = "image/png";
			br = createWatermarkedImage(filePath, currentUser.getUserid());
		}else if (extension.equals("gif")){
			contentType = "image/gif";
			br = createWatermarkedImage(filePath, currentUser.getUserid());
		}
		//Document docsss = new Document(filePath);


		response.setContentType(contentType+"; charset=UTF-8");
		response.setHeader("Content-Disposition", "inline;filename="
				+ fileName);
		// 文件名应该编码成utf-8,注意:使用时,我们可忽略这句
		OutputStream out = response.getOutputStream();
		while ((len = br.read(bs)) > 0) {
			out.write(bs, 0, len);
		}
		out.flush();
		out.close();
		br.close();
	}


	public static BufferedInputStream createWatermarkedImage(String imagePath, String watermarkText) throws IOException {

		// 读取原始图片
		File file = new File(imagePath);
		BufferedImage targetImg = ImageIO.read(new FileInputStream(file));
		int height = targetImg.getHeight();
		int width = targetImg.getWidth();

		//-------------------------文字水印 start----------------------------
		BufferedImage waterMarkImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		// 创建画笔
		Graphics2D graphics2D = waterMarkImage.createGraphics();
		// 绘制原始图片
		graphics2D.drawImage(targetImg, 0, 0, width, height, null);

		// 设置水印颜色
		graphics2D.setColor(new Color(255, 255, 255, 255));

		double scale = 1.0;
		if(width < height){
			scale = (double) width / height;
		}
		int fontSize = (int) Math.ceil((double) (height / 25) * scale);
		// 设置字体 画笔字体样式为微软雅黑,加粗,文字大小按比例给
		graphics2D.setFont(new Font("微软雅黑", Font.BOLD, fontSize));

		float alpha = 0.7f; // 设置透明度为50%
		AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
		graphics2D.setComposite(composite);

		// 水印旋转度
		graphics2D.rotate(Math.toRadians(-25), (double) width / 2, (double) height / 2);

		int x = -width * 3;
		int y;
		// 计算水印文字的宽度
		FontMetrics fontMetrics = graphics2D.getFontMetrics();
		int watermarkWidth = fontMetrics.stringWidth(watermarkText);
		// 水印横向间隔
		int positionWidth = (int)(width * 0.12);
		// 水印竖向间隔
		int positionHeight  = (int)(height * 0.12);

		while (x < width * 3) {
			y = -height * 3;
			while (y < height * 3) {
				graphics2D.drawString(watermarkText, x, y);
				y += fontSize + positionWidth;
			}
			x += watermarkWidth + positionHeight;
		}

		graphics2D.dispose();
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		ImageIO.write(waterMarkImage, "png", outputStream);
		byte[] imageBytes = outputStream.toByteArray();

		return new BufferedInputStream(new ByteArrayInputStream(imageBytes));
	}

	public static BufferedInputStream addWatermarkToPdf(String filePath,String userId) throws IOException {
		// 加载PDF文档
		PDDocument document = PDDocument.load(new File(filePath));
		try {
			// 遍历所有页面
			for (PDPage page : document.getPages()) {

				// 获取页面的媒体框(即页面的大小)
				PDRectangle mediaBox = page.getMediaBox();
				float pageWidth = mediaBox.getWidth();
				float pageHeight = mediaBox.getHeight();
				// 创建内容流,使用APPEND模式
				PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true);
				// 设置水印字体和大小
				contentStream.setFont(PDType1Font.HELVETICA_BOLD, 36);
				// 设置水印颜色(RGB)
				contentStream.setNonStrokingColor(200, 200, 200);

				// 设置文本水印的参数
				String watermarkText = userId;
				PDType1Font font = PDType1Font.HELVETICA_BOLD;
				float fontSize = 20;
				float textWidth = font.getStringWidth(watermarkText) / 1000 * fontSize;
				float textHeight = fontSize;
				float xStep = pageWidth / 4; // 文本在x轴上的重复间隔
				float yStep = pageHeight / 12; // 文本在y轴上的重复间隔,可以根据需要调整

				// 绘制文本水印
				for (float y = 0; y < pageHeight; y += yStep) {
					for (float x = 0; x < pageWidth; x += xStep) {
						// 设置文本颜色(RGB),这里使用白色以确保在红色背景上可见
						contentStream.setStrokingColor(255, 255, 255);

						// 设置字体和大小
						contentStream.beginText();
						contentStream.setFont(font, fontSize);
						contentStream.newLineAtOffset(x, y);

						// 设置文本旋转
						//contentStream.newLineAtOffset(xx, yy);
						//contentStream.setTextMatrix(0, -0.5f, 0.5f, 0, 0, 0);
						contentStream.setTextMatrix(0.5f, 0.5f, -0.5f, 0.5f, x, y);
						contentStream.showText(watermarkText);
						contentStream.endText();
					}
				}
				// 关闭内容流
				contentStream.close();
			}
			ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
			document.save(outputStream);
			document.close();
			return new BufferedInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
			// 保存并关闭PDF文档
			//document.save(new File("watermarked.pdf"));
			//document.close();
		} finally {
			if (document != null) {
				document.close();
			}
		}
	}

	public static String getFileExtension(String fileName) {
		if (fileName == null || fileName.isEmpty()) {
			return "";
		}
		int dotIndex = fileName.lastIndexOf('.');
		if (dotIndex == -1 || dotIndex == fileName.length() - 1) {
			// No dot found or dot is at the end (e.g., "file.")
			return "";
		}
		return fileName.substring(dotIndex + 1);
	}
	public static BufferedInputStream convertToPdf(String wordFilePath,String userId) throws Exception {
		// 加载Word文档
		Document doc = new Document(wordFilePath);
		// 创建一个字节数组输出流来保存PDF内容
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		// 设置PDF保存选项(可选,这里使用默认设置)
		PdfSaveOptions saveOptions = new PdfSaveOptions();
		// 将文档保存为PDF格式到字节数组输出流中
		doc.save(byteArrayOutputStream, saveOptions);

		if (byteArrayOutputStream.size() == 0) {
			throw new IllegalArgumentException("ByteArrayOutputStream is empty");
		}

		// 将ByteArrayOutputStream的内容转换为ByteArrayInputStream
		ByteArrayInputStream bais = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());

		// 使用PDDocument.load方法将流转换为PDDocument对象
		PDDocument pdDocument = PDDocument.load(bais);
		// 关闭ByteArrayInputStream
		bais.close();


		// 将字节数组转换为字节输入流
		ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
		// 返回BufferedInputStream
		return addWatermarkToWord(pdDocument,userId);
	}

	public static BufferedInputStream addWatermarkToWord(PDDocument document,String userId) throws IOException {
		// 加载PDF文档
		//PDDocument document = PDDocument.load(new File(filePath));
		try {
			// 遍历所有页面
			for (PDPage page : document.getPages()) {

				// 获取页面的媒体框(即页面的大小)
				PDRectangle mediaBox = page.getMediaBox();
				float pageWidth = mediaBox.getWidth();
				float pageHeight = mediaBox.getHeight();
				// 创建内容流,使用APPEND模式
				PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true);
				// 设置水印字体和大小
				contentStream.setFont(PDType1Font.HELVETICA_BOLD, 36);
				// 设置水印颜色(RGB)
				contentStream.setNonStrokingColor(200, 200, 200);

				// 设置文本水印的参数
				String watermarkText = userId;
				PDType1Font font = PDType1Font.HELVETICA_BOLD;
				float fontSize = 20;
				float textWidth = font.getStringWidth(watermarkText) / 1000 * fontSize;
				float textHeight = fontSize;
				float xStep = pageWidth / 4; // 文本在x轴上的重复间隔
				float yStep = pageHeight / 12; // 文本在y轴上的重复间隔,可以根据需要调整

				// 绘制文本水印
				for (float y = 0; y < pageHeight; y += yStep) {
					for (float x = 0; x < pageWidth; x += xStep) {
						// 设置文本颜色(RGB),这里使用白色以确保在红色背景上可见
						contentStream.setStrokingColor(255, 255, 255);

						// 设置字体和大小
						contentStream.beginText();
						contentStream.setFont(font, fontSize);
						contentStream.newLineAtOffset(x, y);

						// 设置文本旋转
						//contentStream.newLineAtOffset(xx, yy);
						//contentStream.setTextMatrix(0, -0.5f, 0.5f, 0, 0, 0);
						contentStream.setTextMatrix(0.5f, 0.5f, -0.5f, 0.5f, x, y);
						contentStream.showText(watermarkText);
						contentStream.endText();
					}
				}
				// 关闭内容流
				contentStream.close();
			}
			ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
			document.save(outputStream);
			document.close();
			return new BufferedInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
			// 保存并关闭PDF文档
			//document.save(new File("watermarked.pdf"));
			//document.close();
		} finally {
			if (document != null) {
				document.close();
			}
		}
	}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2269359.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

图像处理-Ch5-图像复原与重建

Ch5 图像复原 文章目录 Ch5 图像复原图像退化与复原(Image Degradation and Restoration)噪声模型(Noise Models)i.i.d.空间随机噪声(Generating Spatial Random Noise with a Specified Distribution)周期噪声(Periodic Noise)估计噪声参数(Estimating Noise Parameters) 在仅…

Mac 环境 VVenC 编译与编码命令行工具使用教程

VVenC VVenC 是一个开源的高效视频编码器&#xff0c;专门用于支持 H.266/VVC (Versatile Video Coding) 标准的编码。H.266/VVC 是继 HEVC (H.265) 之后的新一代视频编码标准&#xff0c;主要目的是提供比 HEVC 更高的压缩效率&#xff0c;同时保持或提高视频质量。H.266/VVC…

HTML——41有序列表

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>有序列表</title></head><body><!--有序列表&#xff1a;--><!--1.列表中各个元素在逻辑上有先后顺序&#xff0c;但不存在一定的级别关系-->…

详细教程:SQL2008数据库备份与还原全流程!

数据的安全性至关重要&#xff0c;无论是操作系统、重要文件、磁盘存储&#xff0c;还是企业数据库&#xff0c;备份都是保障其安全和完整性的关键手段。拥有备份意味着即使发生误删、系统崩溃或病毒攻击等问题&#xff0c;也能迅速通过恢复功能解决&#xff0c;避免数据丢失带…

IDEA工具使用介绍、IDEA常用设置以及如何集成Git版本控制工具

文章目录 一、IDEA二、建立第一个 Java 程序三、IDEA 常用设置四、IDEA 集成版本控制工具&#xff08;Git、GitHub&#xff09;4.1 IDEA 拉 GitHub/Git 项目4.2 IDEA 上传 项目到 Git4.3 更新提交命令 一、IDEA 1、什么是IDEA&#xff1f; IDEA&#xff0c;全称为 IntelliJ ID…

STM32 I2C通信协议

单片机学习&#xff01; 文章目录 目录 文章目录 前言 一、I2C通信 1.1 I2C总线 1.2 I2C通信线 1.3 同步半双工且数据应答 1.4 一主多从 二、硬件电路 2.1 I2C电路模型 2.2 I2C接线要求 2.3 I2C上拉电阻作用 三、I2C时序基本单元 3.1 起始终止条件 3.1.1 起始条件 3.1.2 终止条…

在线免费批量生成 Word 文档工具

为了方便的批量生成 Word 文档&#xff0c;写了个在线 Word 文档批量生成工具&#xff0c;可以根据 Excel 数据和 Word 模板批量生成大量个性化的 Word 文档。适用于需要批量生成格式统一但内容不同的文档场景。比如&#xff1a; 批量生成证书、奖状批量生成合同、协议批量生成…

再见了我的2024

目录 户外运动 阅读及影视剧欣赏 提升专业技能 外婆走了 消费分析 小妹家的二宝 2024 summary 2025年几个小目标 2024生活记录 2024年最后一天&#xff0c;就这样过去了。 总是来不及好好地告个别&#xff0c;就像我们的年老的亲人一样&#xff0c;见一面&#xff0c;少…

Java工程师实现视频文件上传minio文件系统存储及网页实现分批加载视频播放

Java工程师实现minio存储大型视频文件网页实现分批加载视频播放 一、需求说明 老板给我出个题目&#xff0c;让我把的电影文件上传到minio文件系统&#xff0c;再通过WEB端分配加载视频播放&#xff0c;类似于我们普通的电影网站。小编把Java代码共享出来。是真正的能拿过来直…

Three.js教程004:坐标辅助器与轨道控制器

文章目录 坐标辅助器与轨道控制器实现效果添加坐标辅助器添加轨道控制器完整代码完整代码下载坐标辅助器与轨道控制器 实现效果 添加坐标辅助器 创建坐标辅助器: const axesHelper = new Three.AxesHelper(5);添加到场景中: scene.

【优选算法 分治】深入理解分治算法:分治算法入门小专题详解

快速排序算法 (1) 快速排序法 (2) 快排前后指针 (3) 快排挖坑法 颜色分类 题目解析 算法原理 算法原理和移动零非常相似 简述移动零的算法原理 cur 在从前往后扫描的过程中&#xff0c;如果扫描的数符合 f 性质&#xff0c;就把这个数放到 dest 之…

Qt5 中 QGroupBox 标题下沉问题解决

我们设置了QGroupBox 样式之后,发现标题下沉了,那么如何解决呢? QGroupBox {font: 12pt "微软雅黑";color:white;border:1px solid white;border-radius:6px; } 解决后的效果 下面是解决方法: QGroupBox {font: 12pt "微软雅黑";color:white;bo…

sentinel-请求限流、线程隔离、本地回调、熔断

请求限流&#xff1a;控制QPS来达到限流的目的 线程隔离&#xff1a;控制线程数量来达到限流的目录 本地回调&#xff1a;当线程被限流、隔离、熔断之后、就不会发起远程调用、而是使用本地已经准备好的回调去提醒用户 服务熔断&#xff1a;熔断也叫断路器&#xff0c;当失败、…

体验Cursor一段时间后的感受和技巧

用这种LLM辅助的IDE一段时间了&#xff0c;断断续续做了几个小项目了&#xff0c;总结一下整体的感受和自己的一些使用经验。 从Cursor开始又回到Cursor 第一个真正开始使用的LLM的辅助开发IDE就是Cursor&#xff0c;Github的Copilot支持尝试过&#xff0c;但是并没有真正的在…

【数据仓库】hadoop3.3.6 安装配置

文章目录 概述下载解压安装伪分布式模式配置hdfs配置hadoop-env.shssh免密登录模式设置初始化HDFS启动hdfs配置yarn启动yarn 概述 该文档是基于hadoop3.2.2版本升级到hadoop3.3.6版本&#xff0c;所以有些配置&#xff0c;是可以不用做的&#xff0c;下面仅记录新增操作&#…

宽带、光猫、路由器、WiFi、光纤之间的关系

1、宽带&#xff08;Broadband&#xff09; 1.1 宽带的定义宽带指的是一种高速互联网接入技术&#xff0c;通常包括ADSL、光纤、4G/5G等不同类型的接入方式。宽带的关键特点是能够提供较高的数据传输速率&#xff0c;使得用户可以享受到稳定的上网体验。 1.2 宽带的作用宽带是…

[2025] 如何在 Windows 计算机上轻松越狱 IOS 设备

笔记 1. 首次启动越狱工具时&#xff0c;会提示您安装驱动程序。单击“是”确认安装&#xff0c;然后再次运行越狱工具。 2. 对于Apple 6s-7P和iPad系列&#xff08;iOS14.4及以上&#xff09;&#xff0c;您应该点击“Optinos”并勾选“允许未经测试的iOS/iPadOS/tvOS版本”&…

Linux SVN下载安装配置客户端

参考&#xff1a; linux下svn服务器搭建及使用&#xff08;包含图解&#xff09;_小乌龟svn新建用户名和密码-CSDN博客 1.ubuntu安装svn客户端 “subversion” sudo apt-get update sudo apt-get install subversion 查看安装的版本信息&#xff0c;同时看是否安装成功 s…

【Windows】Windows系统查看目录中子目录占用空间大小

在对应目录下通过powershell命令查看文件夹及文件大小&#xff0c;不需要管理员权限。 以下为方式汇总&#xff1a; 方式1&#xff08;推荐&#xff0c;免费下载使用&#xff0c;界面友好&#xff09;&#xff1a; 使用工具以下是一些第三方工具treesize_free https://www.ja…

【论文阅读笔记】IceNet算法与代码 | 低照度图像增强 | IEEE | 2021.12.25

目录 1 导言 2 相关工作 A 传统方法 B 基于CNN的方法 C 交互方式 3 算法 A 交互对比度增强 1)Gamma estimation 2)颜色恢复 3)个性化初始η B 损失函数 1)交互式亮度控制损失 2)熵损失 3)平滑损失 4)总损失 C 实现细节 4 实验 5 IceNet环境配置和运行 1 下载…