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

通过文件路径获取文件,对不同类型的文件进行不同处理,将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();
			}
		}
	}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ES IK分词器插件

前言 ES中默认了许多分词器&#xff0c;但是对中文的支持并不友好,IK分词器是一个专门为中文文本设计的分词工具&#xff0c;它不是ES的内置组件&#xff0c;而是一个需要单独安装和配置的插件。 Ik分词器的下载安装&#xff08;Winows 版本&#xff09; 下载地址&#xff1a;…

Oracle DG备库数据文件损坏修复方法(ORA-01578/ORA-01110)

今天负责报表的同事反馈在DG库查询时出现如下报错 ORA-01578:ORACLE数据块损坏(文件号6,块号 2494856)ORA-01110:数据文件6: /oradata/PMSDG/o1 mf users_molczgmn_.dbfORA-26040:数据块是使用 NOLOGGING 选项加载的 可以看到报错是数据文件损坏&#xff0c;提示了file id和b…

idea无法安装插件

目录 修改工具配置 本地安装 无法下载很多时候就是延迟太高导致的&#xff0c;我们先打开插件官网看一下 Python - IntelliJ IDEs Plugin | Marketplace 修改工具配置 1、配置代理&#xff08;点击 setting-点击 plugins-在点击 http proxy Settings&#xff09; 输入&…

Linux部署web项目【保姆级别详解,Ubuntu,mysql8.0,tomcat9,jdk8 附有图文】

文章目录 部署项目一.安装jdk1.1 官网下载jdk81.2 上传到Linux1.3 解压1.4 配置环境变量1.5 查看是jdk是否安装成功 二.安装TomCat2.1 官网下载2.2 上传到Linux2.3 解压2.4配置2.5 启动Tomcat2.6 验证是否成功 三.安装mysql四.部署javaweb项目4.1 打包4.2 启动tomcat 部署项目 …

服务器等保测评日志策略配置

操作系统日志 /var/log/message 系统启动后的信息和错误日志&#xff0c;是Red Hat Linux中最常用的日志之一 /var/log/secure 与安全相关的日志信息 /var/log/maillog 与邮件相关的日志信息 /var/log/cron 与定时任务相关的日志信息 /var/log/spooler 与UUCP和news设备相关的…

初学stm32 --- FSMC驱动LCD屏

目录 FSMC简介 FSMC框图介绍 FSMC通信引脚介绍 FSMC_NWE 的作用 FSMC_NWE 的时序关系 FSMC_NOE 的含义 FSMC_NOE 的典型用途 FSMC_NOE 的时序关系 使用FSMC驱动LCD FSMC时序介绍 时序特性中的 OE ILI9341重点时序&#xff1a; FSMC地址映射 HADDR与FSMC_A关系 LCD的…

业务模型与UI设计

业务数据模型的设计、UI设计这应该是程序设计中不可缺少的部分。做程序设计的前提应该先把这两块设计好&#xff0c;那么&#xff0c;来一个实际案例&#xff0c;看看这2块的内容。 汽车保养记录业务模型与UI设计&#xff1a; 一、【车辆清单】 记录车辆相关的数据&#xff0…

【JavaScript】变量-常量-数据类型-类型转换

目录 一、JavaScript 介绍 1. JavaScript &#xff08;是什么&#xff1f;&#xff09; 2. 作用&#xff08;做什么&#xff1f;&#xff09; 3. JavaScript的组成&#xff08;有什么&#xff1f;&#xff09; 3.1 ECMAScript: 3.2 Web APIs : 总结&#xff1a; 4. Jav…

day30-awk精讲

awk其实不仅仅是工具软件&#xff0c;还是一种编程语言。 不过&#xff0c;本文只介绍它的命令行用法&#xff0c;对于大多数场合&#xff0c;应该足够用了。 awk是什么 awk是一个强大的linux命令&#xff0c;有强大的文本格式化的能力&#xff0c;好比将一些文本数据格式化…

实战设计模式之建造者模式

概述 在实际项目中&#xff0c;我们有时会遇到需要创建复杂对象的情况。这些对象可能包含多个组件或属性&#xff0c;而且每个组件都有自己的配置选项。如果直接使用构造函数或前面介绍的工厂方法来创建这样的对象&#xff0c;可能会导致以下两个严重问题。 1、参数过多。当一个…

滤波器的主要参数

为什么选择高阶&#xff1a; 滤波器的主要参数通常包括以下几个方面&#xff1a; 截止频率 (Cutoff Frequency)&#xff1a; 这是滤波器能够有效通过或抑制信号的频率点。对于低通滤波器&#xff0c;信号低于截止频率的部分会被通过&#xff0c;高于截止频率的部分会被衰减。高…

HNSW概述

1. \textbf{1. } 1. 一些导论 1.1. \textbf{1.1. } 1.1. 朴素基于图的 ANN \textbf{ANN} ANN 1️⃣建图&#xff1a;对数据库中所有的点&#xff0c;构建 k -NN k\text{-NN} k-NN图(下图以 3 -NN 3\text{-NN} 3-NN为例) 2️⃣检索&#xff1a; GreedySearch \text{GreedySearch…

小程序学习07—— uniapp组件通信props和$emit和插槽语法

目录 一 父组件向子组件传递消息 1.1 props &#xff08;a&#xff09;传递静态或动态的 Prop &#xff08;b&#xff09;单向数据流 二 子组件通知父组件 2.1 $emit &#xff08;a&#xff09;定义自定义事件 &#xff08;b&#xff09;绑定自定义事件 三 插槽语法…

【视频笔记】基于PyTorch从零构建多模态(视觉)大模型 by Umar Jamil【持续更新】

视频链接: 基于PyTorch从零构建多模态(视觉)大模型 by Umar Jamil 从头编写一个视觉语言模型:PloyGamma,是谷歌的一个模型 1:原始图像 2:视觉编码器(本文是viT),通过对比学习进行训练。这个对比学习最开始是CLIP,后来被谷歌改成了SigLIP 3:线性投影层 4:如何将图…

UniApp | 从入门到精通:开启全平台开发的大门

UniApp | 从入门到精通:开启全平台开发的大门 一、前言二、Uniapp 基础入门2.1 什么是 Uniapp2.2 开发环境搭建三、Uniapp 核心语法与组件3.1 模板语法3.2 组件使用四、页面路由与导航4.1 路由配置4.2 导航方法五、数据请求与处理5.1 发起请求5.2 数据缓存六、样式与布局6.1 样…

《数据结构》期末考试测试题【中】

《数据结构》期末考试测试题【中】 21.循环队列队空的判断条件为&#xff1f;22. 单链表的存储密度比1&#xff1f;23.单链表的那些操作的效率受链表长度的影响&#xff1f;24.顺序表中某元素的地址为&#xff1f;25.m叉树第K层的结点数为&#xff1f;26. 在双向循环链表某节点…

Leffa 虚拟试衣论文笔记

Leffa: Learning Flow Fields in Attention for Controllable Person Image Generation https://github.com/xuanandsix/awesome-virtual-try-on-note/tree/main/Leffa 打开链接查看详情&#xff0c;更多虚拟试穿论文持续更新。

BP神经网络的反向传播算法

BP神经网络&#xff08;Backpropagation Neural Network&#xff09;是一种常用的多层前馈神经网络&#xff0c;通过反向传播算法进行训练。反向传播算法的核心思想是通过计算损失函数对每个权重的偏导数&#xff0c;从而调整权重&#xff0c;使得网络的预测输出与真实输出之间…

Git快速入门(三)·远程仓库GitHub以及Gitee的使用

目录 1. 远程仓库GitHub 1.1 登录 1.2 创建库 1.3 创建文件 1.4 修改文件 1.5 创建分支 1.6 删除库 1.7 将远程仓库下载到本地 1.7.1 关联登录 1.7.2 克隆 1.7.3 通过GitHub Desktop更改远程库 2. 远程仓库Gitee 2.1 登录 2.2 创建文件 2.3 关联…

【JVM】总结篇-字节码篇

字节码篇 Java虚拟机的生命周期 JVM的组成 Java虚拟机的体系结构 什么是Java虚拟机 虚拟机&#xff1a;指以软件的方式模拟具有完整硬件系统功能、运行在一个完全隔离环境中的完整计算机系统 &#xff0c;是物理机的软件实现。常用的虚拟机有VMWare&#xff0c;Visual Box&…